Contact us on: +44 (0)1432 617 006

The Site Doctor Blog

Footprints in the snow of a warped mind

< Back to Blog

Prices including tax on uCommerce

Most of our retailers price point their products to include tax i.e. a shirt that costs you £100 would include a proportion of VAT that the retailer would have to pay (at the moment about £16.67).

One frustration I've had for a while with uCommerce is that although you can opt to show prices with VAT (below), this just toggles the display and the calculations are just the same. This means the website administrator has to enter the prices excluding VAT (in this instance £83.33).

SNAGHTML1121d35

That's not only a laborious task, prone to error for the editor but as we found out on Staunton Moods the other day, can also cause rounding issues when ordering in multiples. On digging into it, the product prices are stored to 4 decimal places whereas the tax is only stored to 2 decimal places so we ended up with the following scenario:

?179.99 inc VAT @ 21% = ?147.9338842975207 exc VAT (or ?147.9339 when rounded to 4dp)

Total Without Tax   ?147.9339 * 2       =  ?295.8678
Tax Total           ?31.07 * 2          =  ?62.14
Grand Total         ?295.8678 + ?62.14  =  ?358.0078 (or ?358.01 when rounded)

Thankfully it's surprisingly easy to resolve in uCommerce. After a little a little playing around with IPricingService and ITaxService on simplygigabyte.co.uk (a blank demo store install) I managed to resolve the issue. The trick is not to override the ITaxService as this results in double calculations. Instead just roll out your own IPricingService like so:

namespace SimplyGigabyteCommon.Catalog
{
    using System;

    using UCommerce;
    using UCommerce.Catalog;
    using UCommerce.EntitiesV2;

    public class TaxIncludedInPricePricingService : IPricingService
    {
        public Money GetProductPrice(Product product, PriceGroup priceGroup)
        {
            // Get the default pricing provider to get the product's price
            var pricingService = new PricingService();
            var incTax = pricingService.GetProductPrice(product, priceGroup);

            // Calculate the tax part of the price
            var tax = CalculateTax(priceGroup, incTax);

            // To avoid rounding issues, subtract the tax value from the item's price
            var excTax = incTax.Value - tax;

            // Return the excluding tax part (the tax can be calculated as normal 
            // with the standard TaxService
            return new Money(excTax, incTax.Culture, incTax.Currency);
        }

        private decimal CalculateTax(PriceGroup priceGroup, Money amount)
        {
            if (priceGroup == null)
                throw new ArgumentNullException("priceGroup");

            if (amount == null)
                throw new ArgumentException("amount");

            var incTax = amount.Value;
            var taxRate = priceGroup.VATRate;
            var priceTotal = 1 + taxRate;
            var tax = (incTax / priceTotal) * taxRate;
            return tax;
        }
    }
}

You'll then need to update your uCommerce configuration file to use your new IPricingService. In post v3 versions of uCommerce, the file is stored in /umbraco/ucommerce/configuration/Core.config.

Change:

<component id="PriceService" service="UCommerce.Catalog.IPricingService, UCommerce" type="UCommerce.Catalog.PricingService, UCommerce" />

To:

<component id="PriceService" service="UCommerce.Catalog.IPricingService, UCommerce" type="SimplyGigabyteCommon.Catalog.TaxIncludedInPricePricingService, SimplyGigabyteCommon" />

And that should be it -just make sure all your prices are updated to include tax in the admin area!

If you're running a pre v3 install then the logic is largely the same but instead of Money we've got PriceGroupPrice:

namespace StauntonMoods.Catalog
{
    using System;

    using UCommerce.Catalog;
    using UCommerce.EntitiesV2;

    public class TaxIncludedInPricePricingService : IPricingService
    {
        public PriceGroupPrice GetProductPrice(Product product, ProductCatalog catalog)
        {
            return this.GetProductPrice(product, catalog.PriceGroup);
        }

        public PriceGroupPrice GetProductPrice(Product product, PriceGroup priceGroup)
        {
            // Get the default pricing provider to get the product's price
            var pricingService = new PricingService();
            var incTax = pricingService.GetProductPrice(product, priceGroup);

            // Calculate the tax part of the price
            var tax = CalculateTax(priceGroup, incTax);

            // To avoid rounding issues, subtract the tax value from the item's price
            // you may also want to round the values here
            var excTax = incTax.Price.Value - tax;

            // Return the excluding tax part (the tax can be calculated as normal 
            // with the standard TaxService
            return new PriceGroupPrice
                {
                    Price = excTax, 
                    PriceGroup = priceGroup, 
                    Product = product
                };

        }

        private decimal CalculateTax(PriceGroup priceGroup, PriceGroupPrice amount)
        {
            if (priceGroup == null)
                throw new ArgumentNullException("priceGroup");

            if (amount == null)
                throw new ArgumentException("amount");

            var incTax = amount.Price.Value;
            var taxRate = priceGroup.VATRate;
            var priceTotal = 1 + taxRate;
            var tax = (incTax / priceTotal) * taxRate;
            return tax;
        }
    }
}

Also, in pre v3 versions of uCommerce, the file is stored in /umbraco/ucommerce/configuration/Components.config.

Author: Tim on

Liked this post? Got a suggestion? Leave a comment