Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
This area is subject to change, and will be reworked. Refer to Marketing [BETA] for more information.
A Promotion is a marketing tool used to increase sales of certain products or product lines. Promotions provide a way to apply various discounts to the products, order totals or shipping.
Classes referred to here are available in the following namespaces:
Promotions are applied to individual SKUs as well as Carts. The PublicLayer/WebUtility/Helpers/StoreHelper.cs class (Mediachase.Commerce.Website.Helpers namespace) provides a convenient means to determine the discounted price for an SKU using the GetDiscountPrice() method. This will calculate promotions that are specific to an individual SKU (for instance buy SKU x, get $y off), if any exist.
This method simply returns the discounted price for that SKU. It does not include quantity-based promotions for the SKU (for instance buy 3 SKU xs and get %20 off the SKU price) and does not include order-wide promotion discounts (for instance if your cart subtotal before taxes and shipping is over $100, shipping is free). The StoreHelper calls the promotion engine to calculate the price for a SKU by calling PromotionHelper.Eval().
Promotions are also applied to a whole cart during checkout. This occurs in the CalculateDiscountActivity.cs in the BusinessLayer/OrderSystem/ActivityLibrary project (Mediachase.Commerce.Workflow.Activities.Cart namespace). This activity is included in two workflows: CartValidateWorkflow and CartPrepareWorkflow.
The CartValidateWorkflow is designed to calculate the subtotal for a cart, including promotions; the subtotal does not include calculating taxes and shipping charges. The CartPrepareWorkflow is designed to calculate the final state of a cart before the customer confirms the order purchase, including taxes and shipping charges. Discounts are set in the cart by setting discount properties and calculating the cart total with deductions for the discounts.
The discount properties include:
The CalculateDiscountActivity performs the discount calculations in the CalculateDiscounts() method.
After the CalculateDiscountActivity activity is run, the CalculateTotalsActivity calculates the totals for each lineitem, orderform, and shipment.
It performs these calculations to apply discounts:
Expressions is a core technology behind Marketing system. It allows for a very flexible and standards based way to extend different aspects of the system. Promotions, Customer Segments and Policies all rely on expressions. The architecture of Expression Manager is similar to the Provider model used in .NET Framework. The engine relies on external class to process the expression which can be specified in the configuration file. That class simply needs to implement IExpressionValidator interface and the actual implementation is up to that class.
With EPiServer Commerce we provide an implementation that relies on Windows for Workflow Foundation Rules Engine, so if you pick that you can use our Expression Editor to create expressions. The Expression Editor is located in the following path of your solution: BusinessLayer\MarketingSystem\ExpressionEditor
Refer also to Introduction to the Windows Workflow Foundation Rules Engine for more information.
EPiServer Commerce includes a Promotion Rules Engine designed to provide a flexible and fast framework to create different types of promotions that will be displayed on the front-end.
The Promotion Engine has two distinct use cases:
Promotions are created either using the graphical user interface in the administration console or by a developer. Most of the promotions can be created by using "Custom Promotion" type, which you can select when creating new promotion. In cases where promotions are very specific, a developer may need to create custom expressions and user interfaces.
There are three groups of promotions which determine in which scenario they are executed:
There are two distinct ways the promotions are applied to the product: during browsing or searching of catalog, and when viewing a shopping cart or checking out. They both rely on the MarketingContext.EvaluatePromotions method which cycles through each promotion prioritizing and filtering them.
The execution sequence for EvaluatePromotion is as follows:
During catalog browsing you would typically use relatively simple promotions that just apply to the individual products.
Catalog browsing execution sequence:
During step 1 we get the sale price, which will be used to calculate the base price for which discounts if any will be added.
Example: getting the sale price
decimal minQuantity = 1;
// get min quantity attribute
if (entry.ItemAttributes != null)
minQuantity = entry.ItemAttributes.MinQuantity;
// we can't pass qauntity of 0, so make it default to 1
if (minQuantity <= 0)
minQuantity = 1;
// Get sale price for the current user
Price price = StoreHelper.GetSalePrice(entry, minQuantity);
Next we need to setup the PromotionContext, which will provide context for our rules to execute against. Since there is just one product in this case, all we need to do is to create a new PromotionEntry object, which represents one product for our marketing system, and populate it with all the attributes (meta fields from the catalog entry) that might be used during promotion evaluation.
Other key concepts during this stage are:
Example: creating PromotionEntry object
// Create new promotion helper, which will initialize PromotionContext object for us and setup context dictionary
PromotionHelper helper = new PromotionHelper();
// Get current context
Dictionary<string, object> context = MarketingContext.Current.MarketingProfileContext;
// Create filter
PromotionFilter filter = new PromotionFilter();
filter.IgnoreConditions = false;
filter.IgnorePolicy = false;
filter.IgnoreSegments = false;
filter.IncludeCoupons = false;
// Create new entry
PromotionEntry promotEntry = new PromotionEntry(catalogName, String.Empty, entry.ID, price.Amount);
// Populate entry parameters
((IPromotionEntryPopulate)MarketingContext.Current.PromotionEntryPopulateFunctionClassInfo.CreateInstance()).Populate(ref promotEntry, entry);
PromotionEntriesSet sourceSet = new PromotionEntriesSet();
sourceSet.Entries.Add(promotEntry);
// Configure promotion context
helper.PromotionContext.SourceEntriesSet = sourceSet;
helper.PromotionContext.TargetEntriesSet = sourceSet;
// Only target entries
helper.PromotionContext.TargetGroup = PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Entry).Key;
Example: calling the eval method and returning the discounted price
// Execute the promotions and filter out basic collection of promotions, we need to execute with cache disabled, so we get latest info from the database
helper.Eval(filter);
// Check the count, and get new price
if (helper.PromotionContext.PromotionResult.PromotionRecords.Count > 0)
return ObjectHelper.CreatePrice(price.Amount - GetDiscountPrice(helper.PromotionContext.PromotionResult), price.CurrencyCode);
else
return price;
During step 2 we simply execute the promotion engine with all the information collected during step 1.
Example: executing the promotion engine
MarketingContext.Current.EvaluatePromotions(true, this.PromotionContext, filter);
Goes through each promotion, checks the policies, customer segments, dates and validates the expressions. When the promotion is successfully applied, it is typically added to the PromotionResult object as a PromotionItemRecord object, which contains information about the items affected and the discount applied.
During checkout more complex promotions can be used. In this case you are working in the context of the order system. You will no longer calculate discount directly, but through the use of workflow activities.
Execution sequence:
In this step you initiate the workflow. Typically the workflow will check if entries exist and are available, remove all the existing discounts and then execute the CalculateDiscountsActivity. This will be done during each step in the checkout process or when accessing the shopping cart.
The logic of discounts activity is very similar to the one used during browsing, with exception of two additional discount groups: Order and Shipment. The engine first calculates line item discounts, then order and then shipments.
Example: calculating discount for each individual order form
#region Determine Order level discounts
foreach (OrderForm form in order.OrderForms)
{
// Now process global order discounts
// Now start processing it
// Create source from current form
sourceSet = CreateSetFromOrderForm(form);
promoContext.SourceEntriesSet = sourceSet;
promoContext.TargetEntriesSet = sourceSet;
promoContext.TargetGroup = PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Order).Key;
}
// Evaluate conditions
MarketingContext.Current.EvaluatePromotions(useCache, promoContext, filter);
#endregion
Example: IPromotionEntryPopulate interface
((IPromotionEntryPopulate)MarketingContext.Current.PromotionEntryPopulateFunctionClassInfo.CreateInstance()).Populate(ref entry, lineItem);
This read-only property of the CustomerContact class is the actual customer group used by the promotion engine in both determining price and the CustomerGroup property one would use in a Customer Segment condition expression.
Refer to the Customers section in this documentation for more information about EffectiveCustomerGroup.
Last updated: Oct 21, 2014