---
title: Customizing application of Buy X Get Y discounts
related:
  - https://docs.kentico.com/k9/e-commerce-features/customizing-and-developing-your-store/discount-related-customizing/customizing-evaluation-of-buy-x-get-y-discounts.md
  - https://docs.kentico.com/k9/e-commerce-features/managing-your-store/discounts/working-with-buy-x-get-y-discounts.md
  - https://docs.kentico.com/k9/e-commerce-features/managing-your-store/discounts.md
  - https://docs.kentico.com/k9/e-commerce-features/customizing-and-developing-your-store/e-commerce-customization-model.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).

If you want to modify the way [Buy X Get Y discounts](https://docs.kentico.com/k9/e-commerce-features/managing-your-store/discounts/working-with-buy-x-get-y-discounts.md) apply the discount on the shopping cart items, you need to override the **GetMultiBuyDiscountsApplicatorInternal** method in [theMultiBuyDiscountInfoProviderclass](https://docs.kentico.com/k9/e-commerce-features/customizing-and-developing-your-store/e-commerce-customization-model.md) of the **CMS.Ecommerce** namespace.

```csharp

/// <summary>
/// Returns an instance of the MultiBuyDiscountsApplicator class that applies
/// the Buy X Get Y discount on a shopping cart items.
/// </summary>
protected virtual MultiBuyDiscountsApplicator GetMultiBuyDiscountsApplicatorInternal()
{
    return new MultiBuyDiscountsApplicator();
}

```

Since the **GetMultiBuyDiscountsApplicatorInternal** method returns a **MultiBuyDiscountsApplicator** object, you need to create your own class that inherits from the **MultiBuyDiscountsApplicator** class.

## How it works by default

When the system needs to apply the specific Buy X Get Y discount, the **MultiBuyDiscountsEvaluator** class initializes the **MultiBuyDiscountsApplicator** class.

- The **ApplyDiscount** method remembers how many units of a specific item applied for the given Buy X Get Y discount.
  - The process of creating a record occurs in the **RememberDiscountApplication** method. The method adds the information about the discounted item and its number of units to the complete list of discounts application.
    - The process of getting the information for the specific discount occurs in the **GetDiscountsApplication** method. In case the discount has not been applied yet, it creates a new record for the discount.
- The **GetDiscountReport** method returns a **MultiBuyDiscountsReport** object with information about the discount and the items on which the discount was applied on.
- The **GetDiscountsSummary** method loops through all items on which the discount was applied on and adds them to the **DiscountSummaryItem** object, which contains the name of the discount, the saving and the saving in the main [currency](https://docs.kentico.com/k9/e-commerce-features/configuring-your-store/configuring-currencies.md). Then, the method returns a list of the **DiscountSummaryItem** objects.
  - The process of retrieving the savings occurs in the **GetSavings** method.

The information with all applications of all Buy X Get Y discounts is kept in the **DiscountApplications** property. The **DiscountApplications** is a dictionary that has every Buy X Get Y discount (of the **IMultiBuyDiscount** interface) as the key and another dictionary as the value. The other dictionary then has a specific shopping cart item (of the **ShoppingCartItemInfo** class) as the key and the number of the used items for the specific discount (**int**) as the value.

### Source code

**See the whole source code of the class**

```csharp

using System.Collections.Generic;
using System.Linq;

namespace CMS.Ecommerce
{
    // Dictionary with records of all applied Buy X Get Y discounts. The records than have another
    // dictionary with information about the application of specific items.
    using MultiBuyDiscountApplication = Dictionary<IMultiBuyDiscount, Dictionary<ShoppingCartItemInfo, int>>;

    /// <summary>
    /// Class applying a Buy X Get Y discount on the given shopping cart items.
    /// </summary>
    public class MultiBuyDiscountsApplicator : IMultiBuyDiscountsApplicator
    {
        #region "Variables and properties"
        private readonly MultiBuyDiscountApplication mDiscountApplications = new MultiBuyDiscountApplication();

        /// <summary>
        /// Records of all applied Buy X Get Y discounts that have records
        /// of the used items and the number of the used units of the items.
        /// </summary>
        protected MultiBuyDiscountApplication DiscountApplications
        {
            get
            {
                return mDiscountApplications;
            }
        }
        #endregion

        #region "IMultiBuyDiscountsApplicator methods"
        /// <summary>
        /// Resets the applicator to its initial state.
        /// </summary>
        public void Reset()
        {
        }

        /// <summary>
        /// Applies the discount to the given number of units of the given shopping cart item.
        /// </summary>
        /// <param name="discount">Discount to be applied.</param>
        /// <param name="itemToBeDiscounted">Shopping cart item on which the discount is applied on.</param>
        /// <param name="units">Number of units to be discounted.</param>
        public void ApplyDiscount(IMultiBuyDiscount discount, ShoppingCartItemInfo itemToBeDiscounted, int units)
        {
            // Creates a record that the discount was applied and what it was applied on.
            RememberDiscountApplication(discount, itemToBeDiscounted, units);
        }

        /// <summary>
        /// Checks whether the discount should add an autoadded product.
        /// The MultiBuyDiscountsAutoAdder class takes care of autoadding.
        /// </summary>
        /// <param name="discount">Discount to be checked.</param>
        public bool AcceptsMissedDiscount(IMultiBuyDiscount discount)
        {
            return false;
        }
        #endregion

        #region "Discount application summary"
        /// <summary>
        /// Returns the discount report.
        /// </summary>
        /// <returns>Returns the discount report.</returns>
        internal MultiBuyDiscountsReport GetDiscountReport()
        {
            return new MultiBuyDiscountsReport(GetDiscountsSummary(), mDiscountApplications);
        }

        /// <summary>
        /// Returns a list of all items on which the discount was applied.
        /// </summary>
        /// <returns>Returns a list of all items on which the discount was applied.</returns>
        protected virtual List<DiscountSummaryItem> GetDiscountsSummary()
        {
            var report = new List<DiscountSummaryItem>();

            // Loop through all applications of the discount.
            foreach (var discount in mDiscountApplications.Keys)
            {
                var discountedItems = mDiscountApplications[discount];

                // Calculate savings for the discount. The saving is calculated for every discounted item
                // as unit discount * number of units.
                var saved = discountedItems.Sum(item => GetSavings(discount, item.Key, item.Value, true));
                var savedInMainCurrency = discountedItems.Sum(item => GetSavings(discount, item.Key, item.Value, false));

                // Add the savings to the discount report.
                var log = new DiscountSummaryItem
                {
                    Name = discount.DiscountName,
                    Value = saved,
                    ValueInMainCurrency = savedInMainCurrency
                };
                report.Add(log);
            }

            return report;
        }

        /// <summary>
        /// Returns discount saving for one particular item.
        /// </summary>
        /// <param name="discount">Applied discount.</param>
        /// <param name="item">Discounted item.</param>
        /// <param name="units">Discounted units count.</param>
        /// <param name="applyExchangeRate">Indicates whether the exchange rate from the main currency is applied.</param>
        /// <returns>Returns discount saving for one particular item.</returns>
        protected double GetSavings(IMultiBuyDiscount discount, ShoppingCartItemInfo item, int units, bool applyExchangeRate)
        {
            double unitDiscount = ECommerceHelper.GetDiscountValue(item.UnitTotalPriceInMainCurrency, discount.Value, discount.IsFlat);
            if (applyExchangeRate)
            {
                unitDiscount = item.ApplyExchangeRate(unitDiscount);
            }
            return units * unitDiscount;
        }

        /// <summary>
        /// Stores information about the application of the discount on the particular item.
        /// </summary>
        /// <param name="discount">Discount applied on the item.</param>
        /// <param name="item">Item on which the discount was applied.</param>
        /// <param name="units">Number of the discounted units.</param>
        private void RememberDiscountApplication(IMultiBuyDiscount discount, ShoppingCartItemInfo item, int units)
        {
            Dictionary<ShoppingCartItemInfo, int> discountedItems = GetDiscountApplications(discount);

            // Add a record for the item discounted for the first time.
            if (!discountedItems.ContainsKey(item))
            {
                discountedItems.Add(item, 0);
            }

            // Increase number of item units discounted by the given discount.
            discountedItems[item] += units;
        }

        /// <summary>
        /// Gets all items on which the specific Buy X Get Y discount was applied.
        /// </summary>
        /// <param name="discount">Discount which was applied.</param>
        /// <returns>Returns all items on which the discount was applied.</returns>
        private Dictionary<ShoppingCartItemInfo, int> GetDiscountApplications(IMultiBuyDiscount discount)
        {
            // Create a record for the discount if not used yet.
            if (!mDiscountApplications.ContainsKey(discount))
            {
                mDiscountApplications.Add(discount, new Dictionary<ShoppingCartItemInfo, int>());
            }

            // Return the application record for the specific discount.
            return mDiscountApplications[discount];
        }
        #endregion
    }
}

```

## Creating a custom application process of Buy X Get Y discounts

To customize the Buy X Get Y discount application:

1. [Override theCMS.Ecommerce.MultiBuyDiscountInfoProvider.GetMultiBuyDiscountsApplicatorInternalmethod.](#customizing-the-multibuydiscountinfoprovider-class)
2. [Implement a class which inherits from theMultiBuyDiscountsApplicatorclass.](#customizing-the-multibuydiscountsapplicator-class)

### Customizing the MultiBuyDiscountInfoProvider class

Override the **GetMultiBuyDiscountsApplicatorInternal** virtual method to be able to integrate your custom **MultiBuyDiscountsApplicator** class.

1. Create a new class file in your project in Visual Studio, for example **CustomMultiBuyInfoProvider**\*\*.cs\*\* that inherits from the **MultiBuyDiscountInfoProvider** class.
2. Add the **CMS** and **CMS.Ecommerce** namespaces to the _using_ block.
3. Register the new InfoProvider class:

   ```csharp

   [assembly: RegisterCustomProvider(typeof(CustomMultiBuyInfoProvider))]

   ```
4. Override the **GetMultiBuyDiscountsApplicatorInternal**method with your custom (not yet existing) **MultiBuyDiscountsApplicator** class:

   ```csharp

   public class CustomMultiBuyInfoProvider : MultiBuyDiscountInfoProvider
   {
       protected override MultiBuyDiscountsApplicator GetMultiBuyDiscountsApplicatorInternal()
       {
           return new CustomMultiBuyApplicator();
       }
   }

   ```

   ![Creating the CustomMultiBuyInfoProvider class](https://docs.kentico.com/docsassets/k9/customizing-application-of-buy-x-get-y-discounts/creating_custommultibuyinfoprovider_class.png "Creating the CustomMultiBuyInfoProvider class")

The system now returns yet non-existing **CustomMultiBuyApplicator** when applying Buy X Get Y discounts. Continue with the next steps to achieve the desired functionality.

> **Tip:** You can apply a different logic and modify the shopping cart:
>
> ```csharp
>
> public class CustomShoppingCartInfoProvider : ShoppingCartInfoProvider
> {
>     protected override MultiBuyDiscountsApplicator EvaluateMultiBuyDiscountsInternal(ShoppingCartInfo cart)
>     {
>         // Discounts are applied in the applicator object.
>         CustomMultiBuyApplicator applicator = base.EvaluateMultiBuyDiscountsInternal(cart);
>
>         // ... Your logic with the applicator object ...
>
>         // Return the applicator.
>         return applicator;
>     }
> }
>
> ```

### Customizing the MultiBuyDiscountsApplicator class

Implement a class inheriting from the **MultiBuyDiscountsApplicator** class to provide your custom logic of evaluating Buy X Get Y discounts.

1. Create a new class file in your project in Visual Studio, for example **CustomMultiBuyApplicator.cs** that inherits from the **MultiBuyDiscountsApplicator** class.
2. Add the **CMS** and **CMS.Ecommerce** namespaces to the _using_ block.
3. Assign the inheritance from the **MultiBuyDiscountsEvaluator** class to the **CustomMultiBuyEvaluator** class:

   ```csharp

   public class CustomMultiBuyApplicator : MultiBuyDiscountsApplicator
   {
   }

   ```

   ![Creating the CustomMultiBuyApplicator class](https://docs.kentico.com/docsassets/k9/customizing-application-of-buy-x-get-y-discounts/creating_custommultibuyapplicator_class.png "Creating the CustomMultiBuyApplicator class")
4. Override the methods you want to change. The **MultiBuyDiscountsApplicator** class contains the following virtual method:

   - **protected virtual List\<DiscountSummaryItem> GetDiscountsSummary()** – Returns a list of all items on which the discount was applied.

     > **Tip:** You can access the **GetDiscountsSummary** method and modify the list with the discounted items:
     >
     > ```csharp
     >
     > protected override List<DiscountSummaryItem> GetDiscountsSummary()
     > {
     >     // You can access the DiscountApplications property here and apply your custom logic.
     >     YourLogic(DiscountApplications);
     >
     >     // Return the DiscountApplications property.
     >     return base.GetDiscountsSummary();
     > }
     >
     > ```

> **Tip:** See the complete default source code [above](#source-code).

The Buy X Get Y discounts are now applied according to your changes.
