Sunday, March 13, 2011

Fun with nopCommerce 1.8 Discounts - Part 1, 'Had Purchased' becomes 'Orders Over Amount'

I've begun toying with the nopCommerce Discount class in order to modify how certain out of the box discounts work. In this multi part series, I'll show you how you can modify this class to give you some different options when dealing with discounts. Today's post is all about the 'Had spent X.XX amount' discount.

This OOTB discount allows you to give customers a discount based on previous purchase history. For instance, if the customer had spent $300 yesterday, they may be eligible for a 10% discount today, based on the previous purchase amount.

This isn't bad, but what I really needed was the discount to be applied based on the subtotal in the current cart instead. This would give us the ability to give a '10% Discount on all orders over $100' style of promotion. Luckily, this is pretty easy, with just a little modification to the code.

First, we'll modify the Discount class, part the NopSolutions.NopCommerce.BusinessLogic.Promo.Discounts namespace. The method we'll be modifying is called CheckDiscountRequirements, which contains a case statement for each type of discount. We'll be modifying the DiscountRequirementEnum.HadSpentAmount type. Find this case, and comment out the code there:

#region Previous Code

//var orders = customer.Orders.FindAll(o=>o.OrderStatus == OrderStatusEnum.Complete);
//decimal spentAmount = orders.Sum(o=>o.OrderTotal);
//return spentAmount > this.RequirementSpentAmount;


Next, we add the new code that will work off the current cart subtotal instead of previous orders:

var cart = ShoppingCartManager.GetCurrentShoppingCart(ShoppingCartTypeEnum.ShoppingCart);
decimal subtotalBase = decimal.Zero;
string SubTotalError = ShoppingCartManager.GetShoppingCartSubTotal(cart,
NopContext.Current.User, out subtotalBase);
decimal currentSubtotal = CurrencyManager.ConvertCurrency(subtotalBase, CurrencyManager.PrimaryStoreCurrency, NopContext.Current.WorkingCurrency);
decimal spentAmount = currentSubtotal;
return spentAmount > this.RequirementSpentAmount;

This code does the following:
- Create a variable called cart, and set its value to the current shopping cart.
- Create a decimal variable that will hold the output of the GetShoppingCartSubTotal call
- Create a string called SubTotalError, which will hold any errors that may be generated. Call the GetShoppingCartSubTotal, which will populate our previous subtotalBase variable.
- Create a decimal variable called currentSubtotal, call the ConvertCurrency method to get the currentSubtotal.
- Finally return a boolean comparison of the currentSubtotal value to the RequirementSpentAmount which is controlled by the Discount class.

Next, to make it offical, we'll modify the DiscountRequirementEnum located in the NopSolutions.NopCommerce.BusinessLogic.Promo.Discounts namespace. We'll change HadSpentAmount to OrdersOverAmount, and update our CheckDiscountRequirements method to the new name:

case DiscountRequirementEnum.OrdersOverAmount:

Next, we'll need to update the DiscountInfoControl in the NopSolutions.NopCommerce.Web.Administration.Modules namespace. This is part of the administration area. We'll need to modify the TogglePanels method to use our new Enum:

pnlRequirementSpentAmount.Visible = (discountRequirement == DiscountRequirementEnum.OrdersOverAmount);

Finally, we'll update the Nop_DiscountRequirement table in the database and change the name of HadSpentAmount to OrdersOverAmount just to keep things in check.

That's it, you're done. You now have a new discount option that goes against the current subtotal in the cart.



  1. This is one of great article ! I was able o quickly dive deep into Discounts customizations with just reading this articles !

    Thanks and God Bless you :

  2. Hi

    I have been trying to update this code to work with Nop v1.9, but keep getting stack overflow errors - I believe caused from getting the cart subtotal. Have you managed to implement this using their IoC design pattern?