Can't set tax on the OrderGroup anymore

Vote:
 

We've recently upgraded from commerce 9 to commerce 12.  In the activity flows we have a custom tax activity where we manually set tax total on an order based on our tax rules.  After the upgrade the tax total is being set however when the cart is referenced anywhere outside the activity flow the tax total is 0.

Below is the custom activity we've been using in 9.  Where can we set tax total now?  Thank you

public class CustomCalculateTaxActivity : OrderGroupActivityBase
    {
        private Injected _salesTaxDataAccess;

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            ValidateRuntime();
            CalculateTax();
            return ActivityExecutionStatus.Closed;
        }

        private void CalculateTax()
        {
            if (OrderGroup.OrderForms == null || !OrderGroup.OrderForms.Any()) return;
            OrderGroup.OrderForms[0].TaxTotal = 0;
            
            var shippingAddress = OrderGroup.OrderAddresses.FirstOrDefault(x => x.Name == "ShippingAddress");
            if (shippingAddress == null)
                return;

            var taxableStates = _salesTaxDataAccess.Service.GetTaxableStates();
            if (!taxableStates.Contains(shippingAddress.State, StringComparer.InvariantCultureIgnoreCase))
                return;

            if (shippingAddress.State.IsNullOrWhiteSpace() || shippingAddress.PostalCode.IsNullOrWhiteSpace())
                return;

            var taxableTotal = OrderGroup.TaxableTotal();
            OrderGroup.OrderForms[0].TaxTotal = _salesTaxDataAccess.Service.GetTaxTotal(taxableTotal, OrderGroup.ShippingTotal, shippingAddress.State, shippingAddress.PostalCode);
        }
    }
#194164
Jun 14, 2018 18:19
Vote:
 

Take a look at this page:

https://world.episerver.com/documentation/upgrading/episerver-commerce/commerce-12/breaking-changes-commerce-12/

What probably messed things up for you is this part:

If you also look under the section "Changes to calculators" you'll see some things that are of interest to you as well.

I don't know in what order your activities run but I assume that whatever you set OrderForm.TaxTotal to in your activity is overwritten by another activity that runs later, probably one that calls the Calculators.

There's an IOrderFormCalculator where you should be able to add your tax calculation code instead if you want it to always run that code when the calculators are called.

#194167
Edited, Jun 14, 2018 21:16
Vote:
 

So it looks as though the order in which we called our activities was now causing the tax to get overriden by epi's calculation.  I moved the custom calculations for handling and tax to the end of the activity flow and that has seemed to work.

return activityFlow.Do<CustomValidateLineItemsActivity>()
                .Do<GetFulfillmentWarehouseActivity>()
                .Do<CheckInventoryActivity>()
                .Do<CustomProcessShipmentsActivity>()
                .Do<CalculateTotalsActivity>()
                .Do<CustomCalculateDiscountsActivity>()
                .Do<CustomValidateLineItemsActivity>()
                .Do<UpdateGiftItemActivity>()
                .Do<CalculateTotalsActivity>()
                .Do<CustomCalculateTaxActivity>()
                .Do<CustomApplyHandlingToTotals>();
                //.Do<UpdateTotalsActivity>();

Another issue, it looks like OrderGroup.OrderForms[0].TaxTotal and Total no longer are accurate, only OrderGroup.TaxTotal and Total.  Can you confirm this?  thanks

Also, the UpdateTotalsActivity seems to clear the tax calc as well, so i've commented it out.  That just seems to add together payment amounts.  ???

#194213
Jun 15, 2018 17:11
Vote:
 

I wouldn't recommend removing UpdateTotalsActivity, it's responsible for setting values properly on the various parts of an order (OrderGroup, OrderForm, Shipments, LineItems etc).

As mentioned above it would be better if you move your Handling and Tax calculation code to an appropriate Calculator. Maybe IOrderFormCalculator. Then you can remove your own activity and it will be handled by existing activities everytime.

You can read more about the calculators here:

https://world.episerver.com/documentation/developer-guides/commerce/orders/calculating-orders-intro/

Hopefully that will help you select the appropriate level calculator to add your code to.

#194216
Edited, Jun 15, 2018 18:28
Vote:
 

Hi Todd,

Jafet's comment was right. To customize the order form's tax total, you should customize the order form calculator instead of workflow activity (as the commerce 12 came out, almost tax business was moved from the workflow to calculators).

In this case, I thing you should simply override CalculateTaxTotal of DefaultOrderFormCalculator.cs, as sample code in here to reference.

public class OrderFormCalculatorOverridingDefault : DefaultOrderFormCalculator
{
    public OrderFormCalculatorOverridingDefault(IShippingCalculator shippingCalculator, ITaxCalculator taxCalculator)
        : base(shippingCalculator, taxCalculator)
    { }
    protected override Money CalculateTaxTotal(IOrderForm orderForm, IMarket market, Currency currency)
    {
        return new Money(0, currency); // return your custom tax here
    }
}

/Tuan

#194301
Jun 19, 2018 10:38
Vote:
 

Thank you all, I have overriden the DefaultOrderGroupCalculator and registered IOrderGroupCalculator with my custom class in StructureMap.  This seems to be working.

I'm still noticing that OrderGroup.OrderForm.Total does not reflect any tax, shipping total, etc..  OrderGroup.Total does.  Not a huge problem right now as both are accessible, but was just curious.

#194363
Jun 19, 2018 15:59
Vote:
 

@Todd: I have the same issue, I am not using workflow but upon using IOrderGroupCalculator my taxes are all zero. Did you have a work around for this?

#194517
Jun 22, 2018 19:40
Vote:
 

Yes, override the DefaultOrderGroupCalcultor and DefaultOrderFormCalculator, i'll post code below

1. Be sure to register your overrides with your IoC container:

container.Configure(x => x.For<IOrderGroupCalculator>().Use<CustomOrderGroupCalculator>());
            container.Configure(x => x.For<IOrderFormCalculator>().Use<CustomOrderFormCalculator>());

2. Override the calculators like below:

public class CustomOrderFormCalculator : DefaultOrderFormCalculator
    {
        private Injected<ICheckoutRepository> _checkoutRepository;
        private Injected<ISalesTaxDataAccess> _salesTaxDataAccess;

        public CustomOrderFormCalculator(IShippingCalculator shippingCalculator)
            : base(shippingCalculator)
        { }

        protected override Money CalculateShippingSubTotal(IOrderForm orderForm, IMarket market, Currency currency)
        {
            var cart = _checkoutRepository.Service.GetCart();
            if (cart == null)
                return new Money(0, Currency.USD);

            return new Money(cart.ShippingTotal, Currency.USD);
        }

        protected override Money CalculateHandlingTotal(IOrderForm orderForm, Currency currency)
        {
            var of = orderForm as OrderForm;
            if (of == null)
                return new Money(0, Currency.USD);

            decimal feeTotal = 0;
            foreach (var lineItem in of.LineItems)
            {
                feeTotal += CalculatorHelper.GetLineItemFreightFee(lineItem as ILineItem);
            }

            orderForm.HandlingTotal = feeTotal;
            of.HandlingTotal = feeTotal;

            return new Money(feeTotal, Currency.USD);
        }

        protected override Money CalculateTaxTotal(IOrderForm orderForm, IMarket market, Currency currency)
        {
            var of = orderForm as OrderForm;
            if (of == null)
                return new Money(0, Currency.USD);

            of.TaxTotal = 0;

            var shippingAddress = orderForm.Shipments.FirstOrDefault()?.ShippingAddress as OrderAddress;
            if (shippingAddress == null)
                return new Money(0, Currency.USD);

            var taxableStates = _salesTaxDataAccess.Service.GetTaxableStates();
            if (!taxableStates.Contains(shippingAddress.State, StringComparer.InvariantCultureIgnoreCase))
                return new Money(0, Currency.USD);

            if (shippingAddress.State.IsNullOrWhiteSpace() || shippingAddress.PostalCode.IsNullOrWhiteSpace())
                return new Money(0, Currency.USD);

            var taxableTotal = of.TaxableTotal();
            var taxTotal = _salesTaxDataAccess.Service.GetTaxTotal(taxableTotal, of.ShippingTotal, shippingAddress.State, shippingAddress.PostalCode);
            return new Money(taxTotal, Currency.USD);
        }
    }
public class CustomOrderGroupCalculator : DefaultOrderGroupCalculator
    {
        private Injected<ICheckoutRepository> _checkoutRepository;
        private Injected<ISalesTaxDataAccess> _salesTaxDataAccess;

        public CustomOrderGroupCalculator(IOrderFormCalculator orderFormCalculator)
            : base(orderFormCalculator)
        { }

        protected override Money CalculateShippingSubTotal(IOrderGroup orderGroup)
        {
            var cart = _checkoutRepository.Service.GetCart();
            if (cart == null)
                return new Money(0, Currency.USD);

            return new Money(cart.ShippingTotal, Currency.USD);
        }

        protected override Money CalculateHandlingTotal(IOrderGroup orderGroup)
        {
            var og = orderGroup as OrderGroup;
            if (og == null)
                return new Money(0, Currency.USD);

            var orderForm = og.OrderForms?.FirstOrDefault();
            if (orderForm == null)
                return new Money(0, Currency.USD);

            decimal feeTotal = 0;
            foreach (var lineItem in orderForm.LineItems)
            {
                feeTotal += CalculatorHelper.GetLineItemFreightFee(lineItem as ILineItem);
            }

            orderForm.HandlingTotal = feeTotal;
            og.HandlingTotal = feeTotal;

            return new Money(feeTotal, Currency.USD);
        }

        protected override Money CalculateTaxTotal(IOrderGroup orderGroup)
        {
            var og = orderGroup as OrderGroup;
            if (og == null)
                return new Money(0, Currency.USD);

            og.TaxTotal = 0;

            var shippingAddress = og.OrderAddresses.FirstOrDefault(x => x.Name == "ShippingAddress");
            if (shippingAddress == null)
                return new Money(0, Currency.USD);

            var taxableStates = _salesTaxDataAccess.Service.GetTaxableStates();
            if (!taxableStates.Contains(shippingAddress.State, StringComparer.InvariantCultureIgnoreCase))
                return new Money(0, Currency.USD);

            if (shippingAddress.State.IsNullOrWhiteSpace() || shippingAddress.PostalCode.IsNullOrWhiteSpace())
                return new Money(0, Currency.USD);

            var taxableTotal = og.TaxableTotal();
            var taxTotal = _salesTaxDataAccess.Service.GetTaxTotal(taxableTotal, og.ShippingTotal, shippingAddress.State, shippingAddress.PostalCode);
            return new Money(taxTotal, Currency.USD);
        }
    }
#194518
Jun 22, 2018 19:45
Vote:
 

@Todd Jasper: Thank you for the quick response, but how can we save the value in the orderform taxtotal now? Cause I dont think the property exists, so once the custom implementation spits out the value I plan to save it to the oderform taxtotal, which I am unable to do.

#194520
Jun 22, 2018 20:45
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.