In default, implementation VAT is calculated using EU VAT regulations.
Projects may implement other VAT rules for other markets.
EU VAT regulations
VAT calculation for ECommerce is implemented following EU VAT regulations, for common business scenarios.
- Default implementation supports items of multiple VAT bands in a single order.
- Exceptions and special rules are not implemented, and projects will need to implement them if the merchant's business qualifies for special VAT rules and exceptions.
Vat Calculation
The Vat attributed to a product is taken from the "tax class" of the product, for the country in which the order is originating. That is, the country of the website, and the connected "tax class".
Implementing VAT rules
To implement VAT rules, override the IVatRuleFactory class using the service decorator pattern, and implement a IVatRule.
VAT should be calculated for the whole order. Also, new row totals should be calculated. After implementation, the following conditions should always be true:
- "unit price including VAT" x Quantity = "Total price including VAT"
- "Total price including VAT" = "Total excluding VAT" + "Total VAT"
Example 1
Following is an example, where a different VAT rule is used, if the buyer is from Texas!
[Litium.Runtime.DependencyInjection.ServiceDecorator(typeof(IVatRuleFactory))]
internal class CustomVatRuleFactory : IVatRuleFactory
{
private IVatRuleFactory _parent;
private readonly IVatRule _texasSalesTaxRule;
public CustomVatRuleFactory(IVatRuleFactory parent, TexasSalesTaxRule texasSalesTaxRule)
{
_parent = parent; // impl instance of type MyServiceImpl
_texasSalesTaxRule = texasSalesTaxRule;
}
public IVatRule Create<T>(Order<T> order) where T : OrderRow
{
if(!string.IsNullOrEmpty(order?.BillingAddress?.Country))
{
if(order.BillingAddress.Country == "US")
{
// TODO: check customer is from Texas!
return _texasSalesTaxRule;
}
}
return _parent.Create(order); //Use default rule.
}
}
/// <summary>
/// Calculates Texas Sales Tax
/// </summary>
[Service(ServiceType = typeof(TexasSalesTaxRule))]
public class TexasSalesTaxRule : IVatRule
{
public void CalculateVat<T>(Order<T> order)
where T : OrderRow
{
//Calculate sales tax for Texas!
}
}
Example 2
Sometimes, the default VAT rule should be applied, and then the calculated VAT need to be modified. This is useful, if you would only like to modify certain values.
using Litium.Sales.Calculator;
using Litium.Sales;
namespace Litium.Accelerator.PriceRules
{
[Litium.Runtime.DependencyInjection.ServiceDecorator(typeof(IVatRuleFactory))]
public class SalesTaxCalculatorFactory : IVatRuleFactory
{
private IVatRuleFactory _parent;
public SalesTaxCalculatorFactory(IVatRuleFactory parent)
{
_parent = parent;
}
public IVatRule Create<T>(Order<T> order) where T : OrderRow
{
//Create the default rule.
var prorataVatRule = _parent.Create(order);
//we pass the default rule when creating our own rule, so we can use the default rule first.
var salesTaxRule = new SalesTaxRules(prorataVatRule);
return salesTaxRule;
}
}
public class SalesTaxRules : IVatRule
{
private IVatRule _prorataVatRule;
public SalesTaxRules() { }
public SalesTaxRules(IVatRule prorataVatRule)
{
_prorataVatRule =prorataVatRule;
}
public void CalculateVat<T>(Order<T> order) where T : OrderRow
{
//Use the default pro-rata calculator to initialize the VAT.
_prorataVatRule.CalculateVat(order);
//Apply the additional taxes.
ApplySalesTax(order);
}
private static void ApplySalesTax<T>(Order<T> order) where T : OrderRow
{
//Todo: Apply sales tax.
}
}
}
Tracking details about VAT calculation
After VAT calculation, orders keep track of VAT, the amount including VAT for each VAT rate.
If the sum of VAT or the amount including VAT is not matching the total VAT or the total including VAT, the rounding off is added in the VAT details.
An example of the VAT details for a row:
{
"description": "Order discount 10% when buying over 4000 SEK",
"quantity": 1.0,
"unitPriceIncludingVat": -930.19,
"unitPriceExcludingVat": -834.03,
"vatRate": 0.1153,
"totalIncludingVat": -930.19,
"totalExcludingVat": -834.03,
"totalVat": -96.16,
"vatDetails": [
{
"vatRate": 0.2500,
"amountIncludingVat": -159.79,
"vat": -16.51
},
{
"vatRate": 0.1200,
"amountIncludingVat": -350.60,
"vat": -36.23
},
{
"vatRate": 0.0600,
"amountIncludingVat": -419.80,
"vat": -43.38
},
{
"vatRate": 1.0,
"amountIncludingVat": 0.00,
"vat": -0.04
}
]
}
NOTE: The record containing "vatRate: 1.0" is the rounding off. Also the currency's minor unit is used for calculation.