...
Promotions allow to apply discounts and gifts dynamically depending on contents of shopping cart, specific customer, triggered by coupon code (also known as promo code or voucher) or a combination of the three. In contrast to price lists which provide fixed predefined discounts promotions are determined and calculated during runtime to give the final price. More specifically every time shopping cart is modified in any way (e.g. currency change, items added or removed, billing or shipping address selected, shipping or payment method selected) it is recalculated taking into account all active promotions.
...
The following types of promotions are supported:
Promotion Type | Description | Run target |
---|---|---|
Item level | Order line discounts or gifts triggered by properties of SKU | Storefront, during cart calculation |
Order level | Order subtotal discounts or gifts triggered by overall order (usually total reaching a certain limit) | Storefront, during cart calculation |
Shipping level | Shipping costs discount | Storefront, during cart calculation |
Customer | Automatic customer profile tagging to put customers in different segments. Each tag can be used in promotion conditions at item, order and shipping level. | Admin, periodic bulk evaluation using customerTagJob |
Results of the item and order promotions being applied can be observed on mini cart and shopping cart page. Figure 1 shows an excessively complicated but illustrative demonstration of different promotions contributing to order at different levels, including coupon triggered discounts, gifts and compound discounts which are given on top of the multi buy sale price.
Figure 1: Default theme shopping cart page with promotions
...
Every time shopping can is recalculated the following processes are performed:
Phase | Process |
---|---|
1 | All gifts and promotions are removed from cart |
2 | For each item in cart currently active item level promotions are evaluated and the best value promotion(s) applied against sale price |
3 | Sub total for cart items is calculated |
4 | Order level promotions are evaluated against sub total object from phase 3 |
5 | Order total is calculated |
6 | Shipping level promotions are evaluated against order total from phase 5 |
7 | Final order totals are evaluated |
Note that during phases 2, 4 and 6 the promotions are applied sequentially. This means that discounts are not simply calculated in isolation but rather each promotion applies virtual discount and gradually decreases the price when there is a combination of several applicable promotions. This concept is best explained by few examples.
Example 1: non combinable
Rank | Promotion | Can be combined | Action |
---|---|---|---|
1 | A | 3% | |
2 | B | 5 off | |
3 | C | 5% |
If an item in cart costs 100 then the following calculations will apply
...
Example 2: non combinable
Rank | Promotion | Can be combined | Action |
---|---|---|---|
1 | A | 3% | |
2 | B | 5 off | |
3 | C | 5% |
If an item in cart costs 150 then the following calculations will apply
Code Block |
---|
Discount value for A = 3% Discount value for B = 5/150 = 3.33% Discount value for C = 5% C is highest at 5% and is chosen Item price = 100 - 5% = 142.50 |
Example 3: combinable
Rank | Promotion | Can be combined | Action |
---|---|---|---|
1 | A | 3% | |
2 | B | 5 off | |
3 | C | 5% |
If an item in cart costs 150 then the following calculations will apply
...
Since the expression written in Groovy here are some not so obvious things:
1 | Equals operator is "==" (double equals) or .equals() |
| ||
2 | The condition is a script and can have multiline Groovy code as long as the last line evaluates to true or false |
| ||
3 | There are some predefined variables that can be used in expression |
|
Using variables and Groovy syntax any condition can be written to represent promotion rule with conditions resembling a natural English language sentences.
Available variables for eligibility condition
Variable | Type | Description | Item Promo | Order Promo | Shipping Promo |
---|---|---|---|---|---|
actionContext | String | Promotion context as specified by the user | |||
promotion | Promotion 1 | Promotion domain object | |||
registered | Boolean | Flag to check if current user is logged in. true means registered logged in customer, falsemeans anonymous customer | |||
customer | Customer 1 | Customer domain object | |||
customerTags | List of String | Customer profile tags. Used for customer segmentation | |||
shoppingCart | ShoppingCart1 | ShoppingCart object. Total of the cart must not be used as it does not contain correct information | |||
shoppingCartItem | CartItem 1 | Current cart item being assessed for promotion eligibility | |||
shoppingCartItemTotal | Total 1 | Cart items total, which contains correct cart items total amount including item level promotions | |||
shoppingCartOrderTotal | Total 1 | Order sub total, which contains correct cart items total amount including item level promotions and order level promotions |
1 Links for specified variable types lead to their java definitions, which means is that you can reference any object's properties in the expression. For example to reference SKU code in a particular shopping cart the following syntax can be used shoppingCartItem.productSkuCode which corresponds to CartItem.getProductSkuCode() property or to reference first name of the customer use customer.firstname etc. To simplify: use variable name then full stop to indicate property then property name, which is method name (see Method Summary in javadocs) without "get" prefix and without brackets.
...
The following table shows actions supported by promotion types stated above:
Action | Context | Description | Item | Order | Shipping | Customer |
---|---|---|---|---|---|---|
Fixed Amount Off | Number representing amount. Currency is deduced from promotion currency. | Fixed amount off | Applied to item price. E.g. if sale price is 50 and amount off is 10 then final price would be 40 per unit | Applied to order subtotal. E.g. if subtotal (i.e. sum of all amounts for each cart item) is 1000 and amount off is 50 then final subtotal amount is 950 | Applied to shipping cost. E.g. if shipping is 10 and amount off is 5 then shipping cost due is 5 | |
Percent off | Number representing discount percentage (0-100) | Percent off the price, total or cost in proportion to sale price | Applied to sale price of the item. E.g. if sale price is 50 and percent off is 10 then final price would be 45 per unit | Applied to order subtotal. E.g. if subtotal (i.e. sum of all amounts for each cart item) is 1000 and percent off is 10 then final subtotal amount is 900 | Applied to shipping cost. E.g. if shipping is 10 and percent off is 5 then shipping cost due is 9.5 | |
Percent discount (non sale) 1 | Number representing discount percentage (0-100) | Percent off the price, total or cost in proportion to list price | Applied to list price of the item. E.g. if list price is 50 and percent off is 10 then final price would be 45 per unit | Applied to order subtotal (sum of all amounts for each cart items that do not have sale price). | ||
Gift | SKU code representing gift with optional multiplier parameter | Gift product added free to cart | Gift(s) are added to cart | Gift(s) are added to cart | ||
Tagging | Tag to be added to customer profile | Used by cron job to apply tags to customer profiles, which later on can be used in promotion eligibility conditions |
Tip |
---|
1 Non Non sale percent discount action is used to prevent double discounts on items that are on sale in price list. |
...
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Item | |
Currency | EUR | |
Condition | 'ME181C-A1-BK'.equals(shoppingCartItem.productSkuCode) | |
Action | Fixed Amount off | |
Action Context | 50 | EUR is inferred from currency set on promotion, thus this is 50EUR |
Discounts calculation:
Sale Price | Quantity | Discount | Final price | Total | Memo |
---|---|---|---|---|---|
45EUR | 1 | 45EUR | 0EUR | 0EUR | Discount cannot be greater than price |
150EUR | 1 | 50EUR | 100EUR | 100EUR | |
150EUR | 2 | 50EUR | 100EUR | 200EUR |
Example 2: order promotion "10 EUR off orders placed in August 2016".
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Order | |
Start date | 01-Aug-2016 | |
End date | 31-Aug-2016 | |
Currency | EUR | |
Condition | true | |
Action | Fixed Amount off | |
Action Context | 10 | EUR is inferred from currency set on promotion, thus this is 10EUR |
Discounts calculation:
Cart items total | Discount | Total | Memo |
---|---|---|---|
5EUR | 5EUR | 0EUR | Discount cannot be greater than price |
100EUR | 10EUR | 90EUR |
Example 3: shipping promotion "5 EUR off shipping on orders above 100EUR".
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Shipping | |
Currency | EUR | |
Condition | shoppingCartOrderTotal.subTotal >= 100.00 | |
Action | Fixed Amount off | |
Action Context | 5 | EUR is inferred from currency set on promotion, thus this is 5EUR |
Discounts calculation:
Order total | Number of deliveries | Delivery charge | Discount | Total | Memo |
---|---|---|---|---|---|
50EUR | 1 | 10EUR | 0EUR | 60EUR | |
150EUR | 1 | 10EUR | 5EUR | 155EUR | |
150EUR | 2 | 10EUR | 5EUR | 160EUR |
Percent Off
Percent off is calculated from current price of the item to produce the final price to be paid.
...
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Item | |
Currency | EUR | |
Condition | shoppingCartItem.price > 100.00 | |
Action | Percent Off | |
Action Context | 10 | % is inferred from the action type, thus this is 10% |
Discounts calculation:
Sale Price | Quantity | Discount | Final price | Total | Memo |
---|---|---|---|---|---|
45EUR | 1 | 45EUR | 4.50EUR | 40.50EUR | |
45EUR | 2 | 45EUR | 4.50EUR | 81.00EUR |
Example 2: order promotion "10% off orders placed by frequent buyers".
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Order | |
Currency | EUR | |
Condition | customerTags.contains('frequentbuyer') | |
Action | Percent Off | |
Action Context | 10 | % is inferred from the action type, thus this is 10% |
Discounts calculation:
Cart items total | Discount | Total | Memo |
---|---|---|---|
5EUR | 0.50EUR | 4.50EUR | |
100EUR | 10.00EUR | 90.00EUR |
Example 3: shipping promotion "Free shipping on orders above 100EUR".
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Shipping | |
Currency | EUR | |
Condition | shoppingCartOrderTotal.subTotal >= 100.00 | |
Action | Percent Off | |
Action Context | 100 | % is inferred from the action type, thus this is 100% i.e. free |
Discounts calculation:
Order total | Number of deliveries | Delivery charge | Discount | Total | Memo |
---|---|---|---|---|---|
50EUR | 1 | 10EUR | 10EUR | 50EUR | |
150EUR | 1 | 10EUR | 10EUR | 150EUR | |
150EUR | 2 | 10EUR | 10EUR | 150EUR |
Percent Off (non sale)
Percent off is calculated from list price of the item to produce the final price to be paid and is applied only if new discounted value is less than sale price. This means that if item had sale price which is better than discount given by this promotion then sale price from price list is used (customer best deal strategy).
...
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Item | |
Currency | EUR | |
Condition | shoppingCartItem.price > 100.00 | |
Action | Percent Off (non sale) | |
Action Context | 10 | % is inferred from the action type, thus this is 10% |
Discounts calculation:
List Price | Sale Price | Quantity | Discount | Final price | Total | Memo |
---|---|---|---|---|---|---|
45EUR | 40EUR | 1 | 45EUR | 4.50EUR | 40.00EUR | Sale price is used because 4.50 produced by promotion is less than sale discount 5.00EUR |
45EUR | 42EUR | 1 | 45EUR | 4.50EUR | 40.50EUR | Promotion price is used because 4.50 produced by promotion is less than sale discount 3.00EUR |
45EUR | 42EUR | 2 | 45EUR | 4.50EUR | 81.00EUR |
Example 2: order promotion "10% off orders placed by frequent buyers".
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Order | |
Currency | EUR | |
Condition | customerTags.contains('frequentbuyer') | |
Action | Percent Off (non sale) | |
Action Context | 10 | % is inferred from the action type, thus this is 10% |
Discounts calculation:
List price cart items total | Cart items total | Discount | Total | Memo |
---|---|---|---|---|
6EUR | 5EUR | 0.60EUR | 4.40EUR | The discount is calculated using list price total |
100EUR | 100EUR | 5.00EUR | 95.00EUR | The discount is calculated using list price total |
Gift
Gifts are items automatically added to cart with zero final price. Since every type of promotion is subject to best deal strategy, gifts promotional value is calculated from gift product price. The quantity of gifts to be added to the cart depends on the multiplier and differs slightly depending on the promotion level (item or order).
...
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Item | |
Action | Gift | |
Action Context | ABC001 | Simple SKU code, no multiplier |
Gifts calculation:
Ordered SKU Quantity | Gifts Added | Memo |
---|---|---|
1 | 1 | |
2 | 2 | |
N | N |
Example 2: Item level, exact multiplier
...
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Item | |
Action | Gift | |
Action Context | ABC001=2 | SKU code with exact multiplier of 2, i.e. buy 2 get 1 gift |
Gifts calculation:
Ordered SKU Quantity | Gifts Added | Memo |
---|---|---|
1 | 0 | |
2 | 1 | |
3 | 1 | |
4 | 2 | |
N | ROUND DOWN ( N / multiplier) |
Example 3: Item level, approximate multiplier
...
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Item | |
Action | Gift | |
Action Context | ABC001~2 | SKU code with exact multiplier of 2, i.e. buy 2 get 1 gift |
Gifts calculation:
Ordered SKU Quantity | Gifts Added | Memo |
---|---|---|
1 | 0 | |
2 | 1 | |
3 | 2 | |
4 | 2 | |
5 | 3 | |
N | ROUND UP ( N / multiplier) |
Example 4: Order level, no multiplier
...
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Order | |
Currency | EUR | |
Action | Gift | |
Action Context | ABC001 | One gift for order |
Gifts calculation:
Order Sub Total | Gifts Added | Memo |
---|---|---|
25 EUR | 1 | |
50 EUR | 1 | |
75 EUR | 1 | |
100 EUR | 1 | |
X | 1 |
Example 5: Order level, exact multiplier
...
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Order | |
Currency | EUR | |
Action | Gift | |
Action Context | ABC001=50 | One gift for order each 50 EUR |
Gifts calculation:
Order Sub Total | Gifts Added | Memo |
---|---|---|
25 EUR | 0 | |
50 EUR | 1 | |
75 EUR | 1 | |
100 EUR | 2 | |
X | ROUND DOWN ( X / multiplier) |
Example 6: Order level, approximate multiplier
...
Promotion configuration would have the following parameters:
Parameter | Value | Memo |
---|---|---|
Promotion type | Order | |
Currency | EUR | |
Action | Gift | |
Action Context | ABC001~50 | One gift for order each 50 EUR |
Gifts calculation:
Order Sub Total | Gifts Added | Memo | ||
---|---|---|---|---|
25 EUR | 1 |
| ||
50 EUR | 1 | |||
75 EUR | 2 | |||
100 EUR | 2 | |||
X | ROUND UP ( X / multiplier) |
Customer segmentation
In some cases promotion must apply to a specific segment of people, such as 'frequent buyers', 'UK buyers', 'Customers registered in August' or 'Newsletter subscribers'. It is easy to see that each segment can define very different groups of people with very diverse qualifying criteria, where each person may belong to none, few or all segments. In order to accomplish this YC recommends it is recommended to use customer tags, where each tag represents a segment that is easily understood by business user. Once customer profile tagging has been performed item, order and shipping level promotion can have simple conditions that check if customer belongs to a certain segment:
...
Each customer profile can contain zero or more tags associated with them (space separated). The tags can be manually managed via customer profile management but it may be troublesome if there are many accounts. To solve this problem YC the platform defines customer level promotions to tag profiles automatically. Customer level promotion allows to select customers that qualify to be put into a segment. Then customer profile can be automatically tagged using tag specified in promotion action context. The customer promotions are evaluated in YUM by a recurring job that is run in the background. Therefore all that is necessary is to define customer level promotions and enable them and YC will the platform will automatically start tagging customer profiles.
...
Because all promotion conditions are in fact Groovy scripts very complex rules can be crafted in customer promotion condition with ease. This is where YC promotion the promotion engine truly shines. Another benefit of this separation is that all complexity related to customer segmentation can be isolated into customer level promotions, which could be managed by skilled personnel with ease, leaving the day to day promotions based on tag checking very simple to craft by regular business users. This approach is straightforward, clean and simple, and flexible to avoid code changes and limitation to complex business marketing strategies.
...
Promotions are completely autonomous objects. They can be imported or entered through YUM as long as there is a reference to shop code and currency. Each promotion is bound to this pair to avoid confusion and simplify the process of discount calculation for shopping cart. This also gives flexibility to have separate promotion strategies defined for different currencies.
...
- Promotion code (visible to customer in default theme) which cannot be changed after the promotion is saved
- Shop code for the shop where this promotion will be used which cannot be changed after the promotion is saved
- Currency for discount calculations, which cannot be changed after the promotion is saved
- Valid from/to time period for which promotion is active for if it is enabled
...
Other properties refer to localised name and description, which can be used to communicate the information regarding this promotion to the customers. Alternatively business user can list this information on a promotion micro site where currently active promotions, their conditions and benefits can be clearly articulated to the customers.
...
Another use case would be distribution of promotion flyers or coupons in newspapers, whereby a special single use or multi use code is specified that can trigger discounts.
YC support The platform supports single use and multi use coupon codes, as well as coupon codes with limited use (e.g. first 1000 customers).
The validity of the coupon is determined by the promotion (see enabled flag and active to/from configuration on the "summary" tab).
...
Above examples are just few use cases, which demonstrate flexibility of YC the promotion engine. How promotions and coupons are used will depend on individual business marketing strategy.
...
In order to create a multi use coupon values in the coupon code generation form have to be filled in as follows:
Input | Required | Example value | Memo |
---|---|---|---|
Code | 2015AUG10OF | Simple easy to remember code, but it has to be unique | |
Usage limit | 100 | 100 means that this code can be used 100 times | |
Usage limit per customer | 1 | 1 means that each customer will only be able to use this code once |
Usage limits must be based on the marketing strategy and can contain any value that business user sees fit for the purpose - YC just the platform just makes sure that those limits are not violated.
...
Single use coupons usually refer to discounts given to specific users. They are generated in bulk sometimes in thousands, which is impractical when done manually. YC allows The platform allows to auto generate codes. All that is necessary is to specify usage limits and omit code. YC will The platform will interpret this request as auto-generation of single use codes in quantity set by usage limit.
In order to create X single use coupons values in the coupon code generation form have to be filled in as follows:
Input | Required | Example value | Memo |
---|---|---|---|
Code | Omitting code |
means that it needs to be auto generated | |||
Usage limit | 10 | 10 means that 10 coupon codes are required | |
Usage limit per customer | 1 | 1 means that each customer will only be able to use this code once |
Mixed use coupons
As already mentioned it is possible to add any type of coupons to any coupon triggered promotion at any time.
...
- for one off discount - generate single coupon code with usage limit one. E.g. for user Bob the code may be 'BOB0001'.
- for large campaigns - auto generate multiple coupon codes by entering number of coupons necessary into usage limit, which will generate that many single use coupons. Then download this list and maintain via import functionality from then on.
...
Validating promotions configuration
Price tester is a great tool that is available on promotion section of Admin allows validating various scenarios and see how promotions calculations are affected.