Calculate Tax on a Single Variation

On a Episerver Commerce project I'm currently working on, prices are displayed primarily excluding Tax (because it is primarily targeted on B2B customers). So on the Market we set the setting 'Prices Include Tax' to false. However since B2C customers can also order from this site, the price including Tax should be displayed as well (next to the price without Tax)

Normally Tax is calculated on the cart, and based on the shipping address. So how can we calculate the Tax without adding the product to the Cart. You can't, so you have to create a dummy cart, add an address, and then calculate the tax using this cart.

This might sound daunting, but in fact it is not that complex at all.

What I ended up with is a HtmlHelper that will get the price including Tax for a variation.

public static class VariationTaxHelper
{
    private static readonly Injected<ICurrentMarket> _currentMarket;
    private static readonly Injected<IOrderRepository> _orderRepository;
    private static readonly Injected<IOrderGroupFactory> _orderGroupFactory;
    private static readonly Injected<ITaxCalculator> _taxCalculator;
    private static readonly Injected<IPromotionService> _promotionService;
    private static readonly Injected<ICurrencyService> _currencyService;

    private static IMarket CurrentMarket => _currentMarket.Service.GetCurrentMarket();

    public static Money PriceIncludingTax(this HtmlHelper helper, VariationContent variation)
    {
        // Create a temporary cart
        ICart cart = _orderRepository.Service.LoadOrCreateCart<ICart>(
               CustomerContext.Current.CurrentContactId, "TempCart", _currentMarket.Service);

        // Reads the selected currency from a cookie, defaults to Current Market DefaultCurrency
            cart.Currency = _currencyService.Service.GetCurrentCurrency();

    var address = _orderGroupFactory.Service.CreateOrderAddress(cart);
        address.CountryCode = CurrentMarket.Countries.FirstOrDefault();

    // Get the correct price for the currently logged in Contact
        var defaultPrice = PriceCalculationService.GetSalePrice(variation.Code, CurrentMarket.MarketId, cart.Currency);
        if (defaultPrice == null)
            return new Money(0, cart.Currency);

    // Check if any Item discounts should be applied 
        var discountedPrice = _promotionService.Service.GetDiscountPrice(
            defaultPrice.CatalogKey, CurrentMarket.MarketId, cart.Currency).UnitPrice;

    // Create a lineItem to add to the temporary Cart
        ILineItem lineItem = _orderGroupFactory.Service.CreateLineItem(variation.Code, cart);
        lineItem.Quantity = 1;
        lineItem.PlacedPrice = discountedPrice;
        lineItem.TaxCategoryId = variation.TaxCategoryId;
        cart.AddLineItem(lineItem);

    // Calculate the Tax amount using the ITaxCalculator
        var taxAmount = _taxCalculator.Service.GetSalesTax(lineItem, CurrentMarket,
            address, new Money(lineItem.PlacedPrice, cart.Currency));

    return new Money(discountedPrice.Amount + taxAmount.Amount , cart.Currency);
    }
}

Since our site is based on Episerver Foundation, any services you would be missing using this code can be found there.

Mark Prins

Mark Prins

Senior Microsoft .Net / Optimizely Developer @ Arlanet (part of Conclusion)