---
title: Customizing the shopping cart calculation
related:
  - https://docs.kentico.com/13/e-commerce-features/customizing-on-line-stores/e-commerce-customization-model.md
  - https://docs.kentico.com/13/e-commerce-features/developing-on-line-stores/implementing-a-checkout-process.md
  - https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/orders.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

The Xperience E-commerce Solution allows you to customize the shopping cart calculation engine. The system runs this calculation when working with the shopping cart during [checkout](https://docs.kentico.com/13/e-commerce-features/developing-on-line-stores/implementing-a-checkout-process.md) and when creating or editing [orders](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/orders.md). The calculation determines how the system applies [discounts](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts.md), handles [shipping costs](https://docs.kentico.com/13/e-commerce-features/configuring-on-line-stores/configuring-shipping-options.md), adds [taxes](https://docs.kentico.com/13/e-commerce-features/configuring-on-line-stores/configuring-taxes.md), etc.

For example, you can:

- Completely replace the shopping cart calculation with a custom solution
- Integrate custom steps into the calculation process

To customize the shopping cart calculation:

1. Prepare an assembly (_Class Library_ project) with class discovery enabled in your Xperience solution (or use an existing one). See [Adding custom assemblies](https://docs.kentico.com/13/custom-development/adding-custom-assemblies.md).
   - Reference the project from both your live site and Xperience administration (_CMSApp_) projects.
2. Create new classes that implement the [calculation interfaces](#calculation-interfaces-and-data-types) (described below).
3. Implement all methods required by the given interfaces.
4. Register your implementations of the interfaces using the **RegisterImplementation** assembly attribute (or use a _Factory_ class to serve instances dynamically in certain cases).

When you reload the website, the system uses the custom implementations when calculating the price totals and other data of shopping carts and orders.

> **Info:** In code, you can run the calculation for a shopping cart object (_ShoppingCartInfo_) by calling the object's **Evaluate()** method.

## Calculation interfaces and data types

> **Info:** All mentioned classes can be found in the **CMS.Ecommerce** namespace.

### Main calculation logic

The core shopping cart calculation is performed by the registered implementations of the following interfaces:

- **IShoppingCartCalculator**
- **IShoppingCartCalculationFactory** – serves an instance of a class implementing _IShoppingCartCalculator_ for each site. Must be implemented to use custom _IShoppingCartCalculator_ implementations.

Implementations of _IShoppingCartCalculator_ must contain the **Calculate** method. The method provides a **CalculatorData** parameter with the following properties:

- **Request** – a **CalculationRequest** object that contains the data of the processed shopping cart, such as a collection of cart items (products), the customer object, the cart currency, etc.
- **Result** – a **CalculationResult** object that stores the results of the calculation, such as shopping cart totals, discount summaries, tax summaries, etc.

> **Note:** **Note**: To ensure that your custom calculator implementations work without errors, you need to perform _null_ checks before accessing **CalculationRequest** properties. The system runs the calculation process during early stages of the shopping cart life cycle where many properties are not set yet. For example, the _CalculationRequest.PaymentOption_ property has a _null_ value when calculating shopping carts where the customer has not selected a payment option yet.

To fully replace the shopping cart calculation logic, the **Calculate** method of your _IShoppingCartCalculator_ implementation needs to process the data provided in **CalculatorData.Request** and set all available properties of **CalculatorData.Result**.

The default shopping cart calculation in Xperience uses a composite _IShoppingCartCalculator_ step, consisting of multiple other _IShoppingCartCalculator_ implementations that are executed in a specific order. See the [Default calculation pipeline](#default-calculation-pipeline) section for details.

### Integration with shopping carts

The E-commerce API uses the following interfaces to connect the main calculation logic to shopping cart objects:

- **IShoppingCartAdapterService** – prepares the data for the _IShoppingCartCalculator_ calculations and applies the results to the shopping cart. Implementations must contain the following methods:
  - **GetCalculationRequest**, **GetCalculationResult** – methods that initialize the _CalculationRequest_ and _CalculationResult_ objects for the calculation using the data of a specified shopping cart (_ShoppingCartInfo_).
  - **ApplyCalculationResult** – applies the results (_CalculationResult_) to the specified shopping cart (_ShoppingCartInfo_) after the calculation.

    > **Info:** You can create and register your own **IShoppingCartAdapterService** implementation if you need to add custom properties into the calculation data for use within _IShoppingCartCalculator_ classes:
    >
    > 1. Create custom classes that inherit from **CalculationRequest** or **CalculationResult**.
    > 2. Add properties to the classes according to your requirements.
    > 3. Define the **GetCalculationRequest** and **GetCalculationResult** methods within your _IShoppingCartAdapterService_ implementation and return instances of your derived request or result classes.
    > 4. If you need to use custom result properties to apply values to the shopping cart, convert the _CalculationResult_ parameter to your derived type within the **ApplyCalculationResult** method.
- **IShoppingCartEvaluator** – contains an _Evaluate_ method that encapsulates the entire shopping cart evaluation and calculation logic. The default implementation prepares the calculation data using _IShoppingCartAdapterService_, runs the calculation using _IShoppingCartCalculationFactory_, and ensures automatic adding of free products to shopping carts for [Buy X Get Y discounts](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-buy-x-get-y-discounts.md).

## Default calculation pipeline

The default shopping cart calculation in Xperience uses a composite implementation of the _IShoppingCartCalculator_ interface – the **ShoppingCartCalculatorCollection** class. The _ShoppingCartCalculatorCollection_ accepts an _IEnumerable_ collection of other _IShoppingCartCalculator_ instances (steps), calls the **Calculate** method of each step, and passes the **CalculatorData** between the steps.

The default calculation pipeline consists of the following steps (each step is an _IShoppingCartCalculator_ implementation):

|    | Calculation step           | Function                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| -- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1  | UnitPriceCalculator        | Calculates the unit price for all products in the shopping cart (including unit-level discounts – [catalog discounts](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-catalog-discounts.md) and [volume discounts](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-volume-discounts.md)).<br>Sets the following properties of each _CalculationResultItem_ in the _CalculationResult.Items_ collection:<br>_ItemUnitPrice_<br>_UnitDiscount_<br>_UnitDiscountSummary_                                                                                                                                                             |
| 2  | CartItemDiscountCalculator | Evaluates and calculates [Buy X Get Y discounts](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-buy-x-get-y-discounts.md) and [Product coupons](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-product-coupons.md) for the shopping cart.<br>Sets the _ItemDiscount_ and _ItemDiscountSummary_ properties for each _CalculationResultItem_ in the _CalculationResult.Items_ collection.<br>Adds any [coupon codes](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-coupon-codes.md) related to the applied discounts into the _CalculationResult.AppliedCouponCodes_ collection. |
| 3  | TotalValuesCalculator      | Calculates and sets the following total values:<br>_CalculationResult.Subtotal_<br>_CalculationResult.Total_<br>_CalculationResult.GrandTotal_<br>_CalculationResultItem.LineSubtotal_ for each item in the _CalculationResult.Items_ collection<br>At this point, the _Subtotal_, _Total_ and _GrandTotal_ values are all the same – a sum of the _LineSubTotal_ values for all items in _CalculationResult.Items_.                                                                                                                                                                                                                                                                                                            |
| 4  | OrderDiscountsCalculator   | Evaluates and calculates [order discounts](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-order-discounts.md) for the shopping cart.<br>Sets the _CalculationResult.OrderDiscount_ value.<br>Adds each applied order discount to the _CalculationResult.OrderDiscountSummary_ collection.<br>If any of the applied order discounts use a [coupon code](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-coupon-codes.md), adds the coupon codes to the _CalculationResult.AppliedCouponCodes_ collection.                                                                                                                         |
| 5  | TotalValuesCalculator      | Recalculates and sets the following total values:<br>_CalculationResult.Subtotal_<br>_CalculationResult.Total_<br>_CalculationResult.GrandTotal_<br>_CalculationResultItem.LineSubtotal_ for each item in the _CalculationResult.Items_ collection<br>The _CalculationResult.OrderDiscount_ value set by the previous step is now subtracted from the _Total_ and _GrandTotal_ values.                                                                                                                                                                                                                                                                                                                                          |
| 6  | ShippingCalculator         | Calculates the shipping price for the shopping cart.<br>Sets the _CalculationResult.Shipping_ value.<br>If any [free shipping offers](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-free-shipping-offers.md) with a [coupon code](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-coupon-codes.md) are applied, adds the coupon codes to the _CalculationResult.AppliedCouponCodes_ collection.                                                                                                                                                                                                                                 |
| 7  | TaxCalculator              | Calculates taxes for all _CalculationRequest.Items_ and the _CalculationResult.Shipping_ value.<br>Sets the overall _CalculationResult.Tax_ value.<br>Fills the _CalculationResult.TaxSummary_ collection based on the applied tax types.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| 8  | TotalValuesCalculator      | Recalculates and sets the following total values:<br>_CalculationResult.Subtotal_<br>_CalculationResult.Total_<br>_CalculationResult.GrandTotal_<br>_CalculationResultItem.LineSubtotal_ for each item in the _CalculationResult.Items_ collection<br>The _CalculationResult.Shipping_ and _CalculationResult.Tax_ values set by the previous steps are now added to the _Total_ and _GrandTotal_ values.                                                                                                                                                                                                                                                                                                                       |
| 9  | OtherPaymentsCalculator    | Calculates the values of [gift cards](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-gift-cards.md) applied to the shopping cart.<br>Sets the _CalculationResult.OtherPayments_ value.<br>Adds each applied gift card to the _CalculationResult.OtherPaymentsApplication_ summary collection.<br>Adds the [coupon code](https://docs.kentico.com/13/e-commerce-features/managing-on-line-stores/discounts/working-with-coupon-codes.md) of each applied gift card to the _CalculationResult.AppliedCouponCodes_ collection.                                                                                                                                                     |
| 10 | TotalValuesCalculator      | Recalculates and sets the following total values:<br>_CalculationResult.Subtotal_<br>_CalculationResult.Total_<br>_CalculationResult.GrandTotal_<br>_CalculationResultItem.LineSubtotal_ for each item in the _CalculationResult.Items_ collection<br>The _CalculationResult.OtherPayments_ value set by the previous step is now subtracted from the final _GrandTotal_ value.                                                                                                                                                                                                                                                                                                                                                 |

### Modifying the default calculation

You can use the **ShoppingCartCalculatorCollection** class to customize the shopping cart calculation while preserving the default calculation (or parts of it):

1. Prepare an _IEnumerable_ collection of **IShoppingCartCalculator** instances. Define your own calculation pipeline, consisting of the default calculation steps and your own custom _IShoppingCartCalculator_ steps.
2. Create and register a custom **IShoppingCartCalculationFactory** implementation.
3. Implement the **GetCalculator** method in the _IShoppingCartCalculationFactory_ class and return an instance of the default **ShoppingCartCalculatorCollection** class, with the prepared _IShoppingCartCalculator_ collection as the constructor parameter.

> **Note:** **Note**: If you have custom steps that modify the **Subtotal**, **Total** or **GrandTotal** values of the **CalculationResult**, you either need to run the steps after the last usage of the default **TotalValuesCalculator** step or you need to implement a custom calculator for the total values that reflects your customizations. Otherwise the _TotalValuesCalculator_ step performs the default calculation of the shopping cart totals, which overwrites any values assigned by custom steps.

## Example – Adding an extra charge calculation step

The following example demonstrates how to add a custom step to the shopping cart calculation, while preserving all of the default calculation logic. The step adds an extra charge to the total price of the shopping cart or order based on the selected payment option.

Prepare an assembly (_Class Library_ project) with class discovery enabled in your Xperience solution (or use an existing one). See [Adding custom assemblies](https://docs.kentico.com/13/custom-development/adding-custom-assemblies.md).

- Reference the project from both your live site and Xperience administration (_CMSApp_) projects.

Continue by creating custom implementations of the **IShoppingCartCalculationFactory** and **IShoppingCartCalculator** interfaces:

1. Add a new class under the custom project, implementing the **IShoppingCartCalculator** interface.

2. Implement the **Calculate** method to define the custom calculation logic that adds the extra charge to the shopping cart totals.

   ```csharp

   using CMS.Ecommerce;
   using CMS.Core;

   public class ExtraChargeShoppingCartCalculator : IShoppingCartCalculator
   {
       /// <summary>
       /// Runs shopping cart calculation based on specified calculation data.
       /// </summary>
       public void Calculate(CalculatorData calculationData)
       {
           CalculationRequest request = calculationData.Request;
           CalculationResult result = calculationData.Result;

           decimal extraCharge = 0;

           // Adds an extra charge of 5 (in the site's main currency) to the shopping cart totals
           // if the selected payment option's code name is 'custompayment'
           if (calculationData.Request.PaymentOption?.PaymentOptionName.ToLowerInvariant() == "custompayment")
           {
               extraCharge = 5m;

               // Uses the default Xperience currency API to convert the price
               // from the site's main currency into the requested currency (if necessary)
               ICurrencyConverterFactory currencyConverterFactory = Service.Resolve<ICurrencyConverterFactory>();
               ICurrencyConverter currencyConverter = currencyConverterFactory.GetCurrencyConverter(calculationData.Request.Site);

               string siteMainCurrencyCode = Service.Resolve<ISiteMainCurrencySource>().GetSiteMainCurrencyCode(calculationData.Request.Site);
               string currencyCode = calculationData.Request.Currency.CurrencyCode;

               extraCharge = currencyConverter.Convert(extraCharge, siteMainCurrencyCode, currencyCode);
           }

           result.Total += extraCharge;
           result.GrandTotal += extraCharge;
       }
   }

   ```

3. Add a new class under the custom project, implementing the _IShoppingCartCalculationFactory_ interface.

4. Prepare an _IEnumerable_ collection of _IShoppingCartCalculator_ instances matching the [default calculation steps](#default-calculation-pipeline), and add an instance of the custom _ExtraChargeShoppingCartCalculator_ step to the end.

5. Implement the **GetCalculator** method in the _IShoppingCartCalculationFactory_ class.

   - Return an instance of the default **ShoppingCartCalculatorCollection** class, with the prepared _IShoppingCartCalculator_ collection as the constructor parameter.

   ```csharp

   using System.Collections.Generic;

   using CMS;
   using CMS.Ecommerce;
   using CMS.DataEngine;

   // Registers the custom implementation of IShoppingCartCalculationFactory
   [assembly: RegisterImplementation(typeof(IShoppingCartCalculationFactory), typeof(CustomShoppingCartCalculationFactory))]

   public class CustomShoppingCartCalculationFactory : IShoppingCartCalculationFactory
   {
       // Provides an instance of the customized shopping cart calculator
       public IShoppingCartCalculator GetCalculator(SiteInfoIdentifier siteIdentifier)
       {
           // This sample does not parameterize the calculator based on the current site
           // Use the method's 'siteIdentifier' parameter if you need different calculation logic for each site
           return new ShoppingCartCalculatorCollection(CustomCalculationSteps);
       }

       // Defines a custom pipeline of calculation steps
       private static List<IShoppingCartCalculator> CustomCalculationSteps = 
           new List<IShoppingCartCalculator>
           {
               // The default calculation pipeline
               new UnitPriceCalculator(),
               new CartItemDiscountCalculator(),
               new TotalValuesCalculator(),
               new OrderDiscountsCalculator(),
               new TotalValuesCalculator(),
               new ShippingCalculator(),
               new TaxCalculator(),
               new TotalValuesCalculator(),
               new OtherPaymentsCalculator(),
               new TotalValuesCalculator(),

               // Adds the custom "extra charge" step to the end of the calculation
               new ExtraChargeShoppingCartCalculator()
           };
   }

   ```

6. Save all changes and **Build** the custom project.

The registered **CustomShoppingCartCalculationFactory** class provides an instance of **ShoppingCartCalculatorCollection** with an extended list of calculation steps. The calculation performs all of the default steps without any changes, and the custom **ExtraChargeShoppingCartCalculator** step at the end of the calculation pipeline adds an extra charge to orders that use the _"Custom payment"_ payment option.

> **Note:** **Note**: This basic example does not display any information about the reason for the price increase to customers or store administrators (for example in the shopping cart details during checkout, when editing orders, or in [invoices](https://docs.kentico.com/13/e-commerce-features/configuring-on-line-stores/configuring-invoices.md)). The total values of shopping carts or orders may appear inconsistent unless you add content explaining the price change (for example, you can mention the extra charge in the display name of the related payment option).
