Document Properties
KbidT24871
Last Modified04-Feb-2020
Added to KB10-Jul-2013
Public AccessEveryone
StatusOnline
Doc TypeGuidelines, Concepts & Cookbooks
Product
  • ICM 7.6
  • ICM 7.7
  • ICM 7.8
  • ICM 7.9
  • ICM 7.10

Concept - Taxation Calculation and Display

1 Introduction

With the advent of the B2B channel there is the requirement to display prices depending on customer's type. This way there might be users belonging to a B2B customer as well individual users in one channel. Net prices should be displayed to B2B users, whereas gross prices should be displayed to B2C customers.

Furthermore only one price type - either product's net or gross price - can be imported in Intershop 7's database. This way there will be no functionality to handle net as well as gross prices, both stored in the database, in the same channel at the same time. One price type is dynamically calculated from the other one stored in the database. In fact at runtime the tax that has to be applied to a net price (stored in the database) and the resulting gross price is dynamically calculated. Same way the net price is calculated by dynamically determining and subtracting the included tax from gross price, stored in the database.
For this reason new Taxation Services are implemented. This common interface of the Taxation Service supports tax calculation for different subjects to be taxed beyond a simple product price. Other taxable subjects might be shipping costs, payment costs, promotions, duties, fees or complex subjects, like entire baskets.

Based on the tax calculated using the Taxation Service, one price type can be determined from the other one. Note that it is not in the responsibility of the Taxation Service to calculate the price of a specific price type from the other one. Taxation Service only provides the functionality to calculate the tax that has to applied to or included in a given price. This way calculation net from gross price based on the included tax, provided by the Taxation Service, is in the responsibility of the calling business logic.

One precondition for calculating one price type from the other is a clear indicator, what prices are stored in the database at all. For this reason the new preference PricingScheme is introduced, to resolve the problem, that price type imported in database can only be determined by calculation relevant preference TaxationPolicy.

1.1 References

2 Functional Overview

2.1 Pricing Configurations

2.1.1 Price Type Indicator

Preference (PriceType: net|gross) indicates, whether imported prices have to be interpreted as net or gross prices.

2.1.2 Price Display

Preference (PriceDisplay: net|gross) indicates, whether prices have to be presented to a specific customer as net or gross prices. Furthermore this preference influences the basket calculation.

Note

The value of this preference is not an indicator, whether net or gross prices have been imported in the database any longer. This way a long-term Enfinity 2.x/EnfinitySuite 6.x/Intershop 7 semantically issue is resolved now, that results in a lot of confusion over the years.

2.1.3 Default Price Display

Preference (DefaultPriceDisplay: Individual Customer|Business Customer) select which price display is used for logged-out customers.

2.2 Taxation Services

2.2.1 Basket Taxation Service

2.2.1.1 Interface TaxationService

Taxation_Service_Class_Diagramm

Note

The basket TaxationService interface is the base of tangible taxation services for different subjects to be taxed. Intershop 7.4.1.0 introduces a Taxation Service for product prices, other subjects to be taxed might follow in future Intershop 7 versions.

TaxationService.java
public interface TaxationService<S, R extends TaxRecord>
{
    R getTaxRecord(S subject, Money price, TaxationContext context);
}

The method TaxationService::getTaxRecord(S subject, Money price, TaxationContext context) returns tax related information for the given price and the specified subject to be taxed. A tangible Taxation Service has to provide return values for subject and TaxRecord based on the subjects to be taxed, like product or basket related taxation services.

The result type TaxRecord only contains two methods:

TaxRecord.java
public interface TaxRecord
{
    Boolean isFailure();

    String getFailureCode();
}

If a tax calculation/retrieval finished with an error. All other tax relevant data have to be specified in derivations of TaxRecord, because the tax information might have a simple structure, e.g., in the case of a simple product price, or a complex one in case of an entire basket.

2.2.1.2 Interface TaxationContext

The TaxationContext interface can be used to pass additional information to the TaxationService that might be required for tax calculation, like the tax exempt flag.
Addresses passed in the TaxationContext can be used by the implementation for determining the correct tax jurisdiction.

TaxationContext.java
public interface TaxationContext
{
    Boolean isTaxExempt();

    AddressBO getInvoiceToAddress();

    AddressBO getShipToAddress();

    AddressBO getShipFromAddress();
}

2.2.2 Product Taxation Service

2.2.2.1 Interface ProductTaxationService

The ProductTaxationService is a specific type of the common TaxationService, used to determine taxes applied to/included in single product prices.

ProductTaxationService.java
public interface TaxationService<ProductTaxationSubject, SingleItemTaxRecord>
{
    SingleItemTaxRecord getTaxRecord(ProductTaxationSubject subject, Money price, TaxationContext context);
}

The method ProductTaxationService::getTaxRecord(S subject, Money price, TaxationContext context) returns tax related information for the given product and the specified price.

Note

It is up to the implementation if the TaxationService interface to interpret the specified price as net or gross price.

This way there are different implementations of this interface for the two scenarios:

Scenario 1: Specified price is interpreted as net price

The implementation of this interface interprets the specified price as net price. In this case the tax amount will be returned that is applied at the given price. This amount is calculated based on the given net price and the tax rate, that is assigned to the specified subject to be taxed.
In detail:

  • SingleItemTaxRecord::getCalculatedTax() returns the tax added to the given net price.
  • SingleItemTaxRecord::getTaxableAmount() returns the amount, the tax is calculated for. (In most cases this amount is equal to the given (net) price.)

Scenario 2: Specified price is interpreted as gross price

The implementation of this interface interprets the specified price as gross price. In this case the tax amount will be returned that is included in the given price. This amount is calculated based on the given gross price and the tax rate, that is assigned to the specified subject to be taxed.
In detail:

  • TaxRecord::getCalculatedTax() returns the tax included in the given gross price.
  • TaxRecord::getTaxableAmount() returns the amount, the included tax is calculated from. (In most cases this amount is equal to the net price.)

It is in the responsibility of the implementation to determine the tax rate for the given product.

2.2.2.2 Interface ProductTaxationSubject

In some scenarios the tax cannot be calculated with the information only contained at the product provided to the ProductTaxationService. One example is a warranty assigned to another product. The tax class of that dependent warranty is determined by the one specified for the product the warranty is assigned too. For this reason the type ProductTaxationSubject has been defined:

ProductTaxationSubject.java
public interface ProductTaxationSubject
{
    ProductBO getProduct();

    ProductBO getContextProduct();
}

The method ProductTaxationSubject::getProduct() provides the product the tax should be calculated for to the service. In case of a dependent warranty the method ProductTaxationSubject::getContextProduct() also provides the product the warranty is assigned to to the service.

2.2.2.3 Interface SingleItemTaxRecord

The SingleItemTaxRecord returned by the ProductTaxationService contains the tax information calculated/retrieved by the service.

SingleItemTaxRecord.java
public interface SingleItemTaxRecord extends TaxRecord, TaxItem
{
    /* --- from TaxRecord --- */

    Boolean isFailure();

    String getFailureCode();

    /* --- from SingleItemTaxRecord --- */

    Boolean hasMultipleTaxes();

    Collection<? extends TaxItem> getTaxItems();

    /* --- from TaxItem --- */

    String getSitus();

    Jurisdiction getJurisdiction();

    Money getCalculatedTax();

    BigDecimal getEffectiveTaxRate();

    Money getTaxableAmount();

    Money getNonTaxableAmount();
}

In net price based scenarios there might be (depending on the region and the taxation scheme) between zero and up to nine taxes applied to a single product (price), whereas in VAT based scenarios there is only one tax to product price. To cover all scenarios, the SingleItemTaxRecord may contain multiple taxes.

VAT based scenarios (EU)

  • SingleItemTaxRecord::hasMultipleTaxes() returns Boolean::FALSE
  • SingleItemTaxRecord::getTaxItems() - An empty Collection.
  • SingleItemTaxRecord::getSitus() - The situs/place of taxation.
  • SingleItemTaxRecord::getJurisdiction() - The jurisdiction, an area subject to its own distinct tax regulations.
  • SingleItemTaxRecord::getEffectiveTaxRate() - The valid VAT tax rate for the product.
  • SingleItemTaxRecord::getCalculatedTax() - The calculated VAT.
  • SingleItemTaxRecord::getTaxableAmount() - The net price.
  • SingleItemTaxRecord::getNonTaxableAmount()} - {{com.intershop.beehive.foundation.quantity.Money::NOT_AVAILABLE

Non-VAT based scenarios (North America/Canada)

  • SingleItemTaxRecord::hasMultipleTaxes() returns Boolean::FALSE
  • SingleItemTaxRecord::getTaxItems() - A Collection containing all tax items.
  • SingleItemTaxRecord::getSitus() - null
  • SingleItemTaxRecord::getJurisdiction() - null
  • SingleItemTaxRecord::getEffectiveTaxRate() - null
  • SingleItemTaxRecord::getCalculatedTax() - The sum of calculated tax amounts of all tax items returned by SingleItemTaxRecord::getTaxItems().
  • SingleItemTaxRecord::getTaxableAmount() - The net price.
  • SingleItemTaxRecord::getNonTaxableAmount()} - {{com.intershop.beehive.foundation.quantity.Money::NOT_AVAILABLE

2.3 Pricing Overview

Taxation_Net_Gross_Price_Determination

In contrast to previous Enfinity Suite/Intershop 7 versions the new approach clearly separates different functionalities by responsibilities. The Taxation Service is responsible for tax calculation. An extension of ProductBO type is responsible to determine product price either from the product data or a price lists. The product's net price can be calculated from gross price and vice versa, by adding/subtracting the tax, retrieved by calling the Taxation Service, to/from net/gross price.

Furthermore the basket calculation has not to calculate product price related taxes any longer, but retrieves the net or gross price directly from the ProductBO extension.

Note

In some scenarios the tax, even for product prices, is calculated at the end of the checkout process for the first time (North America/Canada).

3 Taxation Handling for Basket Calculation and Basket/Order Display

3.1 Interpretation of Prices and Costs

The interpretation of prices and costs as net or gross values is controlled by the PriceType configuration value. This way the decision, which calculation rule set has to be used for calculating the basket of a certain customer is met based on the specific value set for PriceType:

  • PriceType=net -> NetBasedCalculation_V2
  • PriceType=gross -> GrossBasedCalculation_V2

The ID of the chosen calculation rule set is stored at the line item container (basket/order) as part of the computed items.

Following prices and costs follow the value specified for PriceType:

  • Product prices
  • Discount amounts and thresholds
  • Shipping costs and thresholds
  • Payment costs and thresholds
  • Surcharges

3.2 Customer Specific Calculation Model

The calculation results displayed to the customer are controlled by the value of PriceDisplayType. The PriceDisplayType is part of the object PriceDisplayPreferences.

The PriceDisplayPreferences can be retrieved from the UserBO. Because it may not be available anymore later, a copy of the value is stored at the basket on its creation and updated on user change (login).
When placing the order the value is transferred and stored.

Disclaimer

The information provided in the Knowledge Base may not be applicable to all systems and situations. Intershop Communications will not be liable to any party for any direct or indirect damages resulting from the use of the Customer Support section of the Intershop Corporate Web site, including, without limitation, any lost profits, business interruption, loss of programs or other data on your information handling system.

Customer Support
Knowledge Base
Product Resources
Support Tickets