+1-888-365-2779
Try Now
More in this section
Categories
Bloggers
Blogs RSS feed

Modify Ecommerce Discounts - add or remove using specific criteria

by Nikola Zagorchev

Sitefinity provides option to create discounts and apply them based on coupon code, new customers or for specific roles and users. However, sometimes different discounts should be applied based on whether the user is a new customer or have applied several different discount coupons. The applicable discount and those that will be applied are calculated in the DiscountCalculator. We will customize it and override methods in order to modify the discount applied.

Custom Discount Calculator

We will inherit from the default one and override the GetApplicableCartDiscounts method. We modify the discounts collection based on our criteria.

protected override IList<CartDiscount> GetApplicableCartDiscounts(CartOrder cartOrder, decimal subTotal, User user, List<Role> userRoles)
        {
            var all = base.GetApplicableCartDiscounts(cartOrder, subTotal, user, userRoles);
            var discounts = all;
            if (discounts != null)
            {
                // Get Discount with specific code
                var discount = discounts
                    .Where(d => d.DiscountType == DiscountType.Coupon && d.ParentDiscount.CouponCode.Contains("code"))
                    .FirstOrDefault();
 
                if (discount != null)
                {
                    var identity = ClaimsManager.GetCurrentIdentity();
                    if (identity != null && identity.UserId != null && identity.UserId != Guid.Empty)
                    {
                        User currentUser = UserManager.GetManager().GetUser(identity.UserId);
                        if (new CustomerRetriever().IsNewCustomer(currentUser))
                        {                       
                            // Apply only the coupon code discount
                            //for new customers and remove other discounts
                            discounts.Clear();
                            discounts.Add(discount);
                        }
                        else
                        {                      
                            // Remove discount if not new customer
                            discounts.Remove(discount);
                        }
                    }
                }
            }
 
            return discounts;
        }

Applying the Custom Discount Calculator

Unfortunately, the discount calculator is coupled to the EcommerceOrderCalculator and we will need to override the methods which use the default calculator and make them use our custom one:

public class EcommerceOrderCalculatorCustom : EcommerceOrderCalculator
    {
        protected override decimal GetWithoutShippingTax(CartOrder cartOrder, User user, List<Role> userRoles, bool useExchangeRate)
        {
            decimal taxOnTotalBasePrice = GetPreDiscountTax(cartOrder, useExchangeRate);
            decimal totalBasePrice = GetSubTotalWithoutTaxes(cartOrder, useExchangeRate);
 
            decimal totalBasePriceNoExchangeRate = GetTotalBasePriceNoExchangeRate(cartOrder);
 
            decimal discountTotal = new DiscountCalculatorCustom().CalculateAndApplyOrderDiscounts(cartOrder, totalBasePriceNoExchangeRate, user, userRoles, useExchangeRate);
 
            decimal withoutShippingTax = 0;
            var taxDisplayMode = EcommerceSettings.Taxes.TaxDisplayMode;
            if (taxDisplayMode == EcommerceConstants.OrdersConstants.ExcludingTax)
            {
                withoutShippingTax = EcommerceOrderCalculatorCustom.TaxIncludingDiscount(taxOnTotalBasePrice, totalBasePrice, discountTotal);
            }
            else
            {
                withoutShippingTax = taxOnTotalBasePrice;
            }
 
            return withoutShippingTax;
        }
 
        private static decimal TaxIncludingDiscount(decimal taxOnTotalBasePrice, decimal totalBeforeDiscounts, decimal discountAmount)
        {
            return totalBeforeDiscounts == 0m ? taxOnTotalBasePrice :
                taxOnTotalBasePrice * (totalBeforeDiscounts - discountAmount) / totalBeforeDiscounts;
        }
 
        protected override decimal GetDiscountTotal(CartOrder cartOrder, User user, List<Role> userRoles, bool useExchangeRate)
        {
            decimal totalBasePriceNoExchangeRate = GetTotalBasePriceNoExchangeRate(cartOrder);
            decimal exchangeRateSubTotal = GetSubTotalTaxInclusive(cartOrder, useExchangeRate);
            decimal sumRoundedOrderDiscounts = new DiscountCalculatorCustom().SumRoundedOrderDiscounts(cartOrder, exchangeRateSubTotal, totalBasePriceNoExchangeRate, user, userRoles, useExchangeRate);
            return sumRoundedOrderDiscounts;
        }
    }

Register the calculator in the Global application file:

protected void Application_Start(object sender, EventArgs e)
        {
            Telerik.Sitefinity.Abstractions.Bootstrapper.Initialized += new EventHandler<Telerik.Sitefinity.Data.ExecutedEventArgs>(Bootstrapper_Initialized);
 
        }
 
        protected void Bootstrapper_Initialized(object sender, Telerik.Sitefinity.Data.ExecutedEventArgs args)
        {
            if (args.CommandName == "Bootstrapped")
            {
              ObjectFactory.Container.RegisterType<IOrderCalculator, EcommerceOrderCalculatorCustom>(new TransientLifetimeManager(), new InjectionConstructor());
            }
        }

 

Show message for removed discounts

In order to inform the customer for the removed discounts, we will use a custom Discounts List control.

public class MyDiscountList : DiscountList
    {
        protected override void OnPreRender(EventArgs e)
        {
            var calc = new DiscountCalculatorCustom();
            var ordersManager = OrdersManager.GetManager();
            CartOrder shoppingCart = GetShoppingCartForUser(ordersManager);
            var items = new List<CartDiscount>();
            if (shoppingCart.UserId != null && shoppingCart.UserId != Guid.Empty)
            {
                var user = UserManager.GetManager().GetUser((Guid)shoppingCart.UserId);
                var roles = RoleManager.GetManager().GetRolesForUser(user.Id).ToList();
                items = calc.GetNotApplicableCartDiscounts(shoppingCart, shoppingCart.SubTotalDisplay, user, roles).ToList();
            }
            else
            {
                items = calc.GetNotApplicableCartDiscounts(shoppingCart, shoppingCart.SubTotalDisplay, null, null).ToList();
            }
            if (items != null && items.Count > 0)
            {
                var sb = new StringBuilder();
                sb.Append("The following discounts are not applicable:");
                foreach (var item in items)
                {
                    sb.Append(item.Title);
                    sb.Append(", ");
                }
                sb.Length -= 2;
                this.MessageLabel.Text = sb.ToString();
            }
 
            base.OnPreRender(e);
        }
}

The discount list is applied in the Shopping cart template:

<asp:UpdatePanel runat="server">
                  <ContentTemplate>
                      <div class="sfShoppingCartTotal">
                          <table class="sfShoppingCartDiscountList">
                              <tbody>
                                  <tr runat="server" ID="beforeDiscountRow">
                                      <th>
                                          <asp:Label ID="productTotalQuantityBeforeDiscountLabel" runat="server" />
                                          <asp:Label runat="server" Text="<%$ Resources:OrdersResources, Subtotal %>" CssClass="sfTxtLbl"/>:
                                      </th>
                                      <td>
                                          <asp:Label ID="totalPrice" runat="server" Text="" CssClass="sfTxtLbl" />
                                      </td>
                                  </tr>
                                  <cs:MyDiscountList runat="server" ID="discountRows"/>
                              </tbody>
                          </table>
                      </div>
                      <div class="sfTotalRowWrp">
                          <asp:Label ID="productTotalQuantity" runat="server" />
                          <asp:Label ID="subTotalLabel" runat="server" Text='<%$Resources:OrdersResources, SubtotalWithDiscounts %>' CssClass="sfTxtLbl" />:
                          <strong class="sfPriceTotal"><asp:Label ID="afterDiscountPrice" runat="server" Text="" CssClass="sfTxtLbl" /></strong>
                      </div>
                  </ContentTemplate>
              </asp:UpdatePanel>
              <asp:LinkButton id="updateButton" Text="<%$Resources:OrdersResources, Update %>" runat="server" CssClass="sfshoppingCartUpdateLnk" />

Here is a video of the discounts modification:

Unable to display content. Adobe Flash is required.

Full source can be found and forked on GitHub here.

Leave a comment