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.
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;
}
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());
}
}
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:
Full source can be found and forked on GitHub here.
Nikola Zagorchev is a Tech Support Engineer at Telerik. He joined the Sitefinity Support team in March 2014.
Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.
Learn MoreSubscribe to get all the news, info and tutorials you need to build better business apps and sites
Progress collects the Personal Information set out in our Privacy Policy and the Supplemental Privacy notice for residents of California and other US States and uses it for the purposes stated in that policy.
You can also ask us not to share your Personal Information to third parties here: Do Not Sell or Share My Info
We see that you have already chosen to receive marketing materials from us. If you wish to change this at any time you may do so by clicking here.
Thank you for your continued interest in Progress. Based on either your previous activity on our websites or our ongoing relationship, we will keep you updated on our products, solutions, services, company news and events. If you decide that you want to be removed from our mailing lists at any time, you can change your contact preferences by clicking here.