Modify Ecommerce Discounts - add or remove using specific criteria

Modify Ecommerce Discounts - add or remove using specific criteria

September 29, 2014 0 Comments

The content you're reading is getting on in years
This post is on the older side and its content may be out of date.
Be sure to visit our blogs homepage for our latest news, updates and information.

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.

Nikola Zagorchev

Nikola Zagorchev is a Tech Support Engineer at Telerik. He joined the Sitefinity Support team in March 2014.

Comments
Comments are disabled in preview mode.
Topics
 
 
Latest Stories in
Your Inbox
Subscribe
More From Progress
d12fcc0bdb669b804e7f71198c9619a7
5 Questions Automakers Should Ask to Improve Asset Uptime
Download Whitepaper
 
SF_MQ_WCM
2018 Gartner Magic Quadrant Web Content Management (WCM)
Download Whitepaper
 
What-Serverless-Means-For-Enterprice-Apps-Kinvey
What Serverless Means for Enterprise Apps
Watch Webinar