I have created a custom ShippingRateProvider that works just fine in operation.
It uses the Dynamic Rate provider that comes with UCommerce based on Subtotal.
But I have discovered that it does one thing and one thing only, which is to create a shipping price to return to the order when the order is recalculated.
This is fine if that was all I needed.
However I would like to set a flag on the order that indicates that this custom rate was used.
This seems impossible (I tried it) as when the rate is in the middle of calculation, it is also in the middle of a transaction so I cannot update the order at the same time. All good to protect the process I suppose.
So I would like to be able to use the ShippingMethod that is associated with the order, to go find the rate ranges that were applied and find the From and To values.
What would be the right service to use to go from the order all the way through the properties to locate the ranges?
I have found the ShippingMethodService which is a start but it is not clear where to go from there. var shippingMethod = await _shippingMethodService.GetShippingMethodAsync(order.StoreId, "VariableRate");
If I’m reading your message correctly, you want the ranges from the shipping method settings so you can check which range the shipping price fell into? Is that correct?
This will give you the shipping method applied to your order, without hardcoding the alias:
if (order.ShippingInfo.ShippingMethodId.HasValue)
{
var shippingMethod = await _shippingMethodService
.GetShippingMethodAsync(order.ShippingInfo.ShippingMethodId.Value);
var usedCustomRate = shippingMethod.Alias == "VariableRate";
}
The shipping method only stores the configuration, not the result and nothing records which range was actually calculated for a given order, so you’d be taking the subtotal and matching it against the ranges yourself.
What’s the use case for needing the ranges on top of the alias?
Yes I found that function but did not know how to get to the ranges.
My use case is the need to identify when a specific range was used.
Range 1 is from 1c to $1499 and uses my custom PricePerCategory function.
Range 2 is from 1500 to $9999 and uses a fixed price of $0
Outside the rate range calculation, the resulting price is $0, so there is no way to know if the $0 was coming from Range 1 or Range 2.
IF Range 1 was used I need to flag the order, specifically if the PricePerCategory generates a $0 price.
Hence wanting to check what the From-To ranges definitions are, so that I can use the subtotal to determine if Range 1 was used to generate the zero price.
Could you not split those into two separate shipping providers, so one covers the 1c to $1499 range and the other covers the 1500 to $9999 range? That way you can easily identify which shipping provider was used?
Alternatively, I don’t know if @mattbrailsford can suggest if you can save and meta or state information from a shipping provider that you can use later. I can’t find anything from the docs.
I do seem to have cobbled up a solution after a lot of bumbling around what I could see of the UComm objects.
// get the method
if (order.ShippingInfo.ShippingMethodId.HasValue)
{
var shippingMethod = await _shippingMethodService.GetShippingMethodAsync(order.ShippingInfo.ShippingMethodId.Value);
if (shippingMethod.CalculationMode == ShippingCalculationMode.Dynamic)
{
var config = shippingMethod.CalculationConfig as DynamicRateShippingCalculationConfig;
if (config is not null && config.Rates.Count > 0)
{
// find the rate that the subtotal falls into
foreach (var currentRate in config.Rates)
{
decimal? actualFrom = GetPriceFromRate(order.CurrencyId, currentRate.From);
decimal? actualTo = GetPriceFromRate(order.CurrencyId, currentRate.To);
if (actualFrom is not null && actualTo is not null)
{
// is the order total within the rate range values
if ((actualFrom <= order.SubtotalPrice.Value.WithoutTax) && (actualTo >= order.SubtotalPrice.Value.WithoutTax))
{
// find rate where the RateProviderAlias == PricePerCategory that is enabled
var pricePerCategoryRate = currentRate.Values.FirstOrDefault(x => x.RateProviderAlias == rateProviderAlias
&& x.Value == "true");
// now set all the necessary conditions
// now I can do my tests and create a result
// ....
break;
}// if subtotal is in range
} // if found a range
} // next rate
} // config found and there are rates
} // if method is dynamic
} // if there is a method
Maybe not the most elegant but it arrives at the result that I need.
The most clumsy part of the code I have hidden away in the GetPriceFromRate(order.CurrencyId, currentRate.From) function. The price that I found the currentRate object is actually a string with a json set in it being {currencyId, decimal Value}.
Would have been nice to find a built-in method that converts that to a Price object but not too hard to deserialize and deal with.
I added a constant to my rateprovider so that I can get the Alias easily for matching. The Alias is actually set in the provider Attributes but it was not so easy to refer to that and I was over doing more spelunking.