This article is meant to give a rough overview of promotion actions. It is intended to discuss
For the implementation of a new action, please refer to the references section.
Now, from a customer's perspective the action represents the act of giving a discount or rebate, e.g., a gift, if the given basket meets the corresponding rule's condition. Without an action a promotion would never have an effect on basket calculation. However, from a programmer's and Commerce Management user's point of view an action not only comprises its execution but also its configuration. This configuration sometimes turns out to be quite complex.
As outlined in the Cookbook - Promotions (valid to 7.7), in order to introduce a new action to the system, a descriptor together with related configuration templates and an executor have to be implemented. Roughly speaking, the descriptor contains all properties, i.e., parameters that are used to describe, i.e., configure the action, whereas the executor mainly contains an execute()
method which is used to apply the action to a given basket whenever the conditions to do so are fulfilled. The action configuration is done in the Commerce Management application whereas action execution is triggered by basket calculation in the storefront.
Note
The promotion framework allows to create more complex promotions coming with a set of rules, e.g., if step 1 is fulfilled, discount 1 will be granted and if step 2 is fulfilled, discount 2 will be granted, and so on.
The calculation algorithm to apply a promotion evaluates the rules top down and always takes the first rule that matches. Left over rules will not be evaluated.
Note
It is not possible to configure one promotion with multiple actions, e.g., providing a item percentage off discount and a free shipping discount by entering one promotion code.
To configure such multiple actions multiple promotions need to be combined with each other.
Different actions or action types come along with different action descriptors. Each and every promotion action descriptor inherits from class PromotionActionDescriptor
. In this class the four configuration parameters that are common to all actions are defined and added to the list of configuration parameters of each action:
HasMaxPrice
: type Boolean
MaxPriceValue
: type Money
depending on HasMaxPrice
, constraint: value at least 0.01HasMaxApplications
: type Boolean
MaxApplications
: type Integer
depending on HasMaxApplications
, constraint: value at least 1MaxPrice denotes an upper bound for the amount of money to be granted by execution of the action for a given basket/order. So, parameter MaxPriceValue
is used to specify the upper bound and parameter HasMaxPrice
serves for activating this bound.
Example: Assume that HasMaxPrice
is true
and MaxPriceValue
is $20. Furthermore assume that the action is something like "50 percent off on order total" and the given order total is $1000. Then execution of the action for this order will yield a discount of no more than $20 instead of $500.
MaxApplications denotes an upper bound for the number of times a discount or rebate is allowed to be applied to an order or to an item, depending on the action application level being the whole order or single items.
Example: Assume that HasMaxApplications
is true
and MaxApplications
is 5.
Not in all cases the discount calculation with respect to MaxApplications
is that simple. However, in order to understand the calculation in other cases, you just have to keep three rules in mind.
In the Commerce Management application the four parameters are displayed as follows.
An explanation of which parameter can be found where is here:
Item Value Off
The decision how often an item value off discount is applied depends on multiple settings. If the discount is configured to be applied to all items, the setting of MaxApplications
is invalidated. If the action is configured to be applied to one cart item, then the exact amount of items defined with MaxApplications is discounted.
Item Percentage Off
The same rules apply when the discount is percentage off instead of value off.
Order Value Off
An order value off discount will be applied depending on the rebate condition and the setting of MaxApplications
. Let's say, we have a minimum order value condition of 50$. The discount is Order Value Off $ 5.00, the maximum number of applications per order is 4.Then the discount depends on your order value, from 50$ to 99,99$ it will be applied one time, from 100$ to 149,99$ two times and so on until the max application value is reached (in this case 4 times maximum). If there is no value for MaxApplications
configured the rule applies unlimited times.
Order Percentage Off
For an order percentage off discount the rule Percentage off on order total is applied at most once described above always applies.
A discount that is not necessarily to be applied to the cart as a whole but rather to a specific subset of cart items, where the subset specification is based on the condition, is called a conditional discount. Conditional discounts are represented by the class ConditionalDiscount
which directly inherits from PromotionActionDescriptor
. The configuration parameters added by ConditionalDiscount
are the following:
ConditionalItemsSelection
: type String
ConditionalItemsMinPrice
: type Double
, constraint: value at least 0.00ConditionalItemsSelection
is the crucial parameter used to specify the subset of cart items to which the discount is meant to apply. It can take four values with corresponding set interpretation:
InCart
: (the discount applies to) all cart items.Conditional
: all cart items which meet the condition of the rule (see jjjjjj above).NextConditional
: all cart items which meet the rule condition but do not count towards the minimum number of included items.Selected
: all cart items that belong to a group of products that you can define explicitly.Note
The minimum number of included items refers to a special rule condition: Apply the discount if there is a minimum number of items in the cart, e.g., three items. The three items in the cart that the cart calculation algorithm takes as a proof for the condition being fulfilled count towards the minimum number of items.
ConditionalItemsMinPrice
is used to define a price bound such that a cart item is not discounted if its price is below the bound. For example, if the bound is defined to be $20, then only items with a price of at least $20 are discounted.
In the back office the two parameters look like this:
Here is an explanation of which parameter is found where:
Note
Conditional discounts require a condition with non-empty item inclusions. This could be a promotion condition for the rule (1) or a condition within the action (2). If there is no condition given or the condition produces an empty inclusion list, the promotion will not be applied.
Examples for supported condition types:
(1)
(2)
A conditional discount that allows for a restriction with respect to the number of cart items it can be applied to is called item discount. The descriptor class of this type of action, class ItemDiscount
, directly inherits from class ConditionalDiscount
and adds three configuration parameters:
ItemsAffected
: type String
AffectedItemsNumber
: type Integer
, constraint: value at least 1PriceAffected
: type String
The configuration parameter ItemsAffected
is used to determine whether the discount is applied to all cart items or to a limited number of cart items. The values it can take and their respective interpretations are the following:
All
: no restriction with respect to the number of cart items to be discounted.Amount
: the number of cart items to be discounted is restricted by the value of configuration parameter AffectedItemsNumber
.The parameter PriceAffected
helps to determine the order in which the cart items are discounted. Two different orders are supported at the time being:
LowestPrice
: ascending with respect to item price.HighestPrice
: descending with respect to item price.Value LowestPrice
is more advantageous for the seller as it can help to reduce the cost caused by promotion actions. In contrast to this, the value HighestPrice
is more beneficial for the consumer because the discount granted is likely to be higher. Of course, the consumer's benefit may in the long term be profitable for the seller, too.
In the Commerce Management, the three parameters are displayed as follows:
The ID ItemPercentageOff
stands for an item discount which grants a certain percentage discount on the item price in the cart. As an item discount, its corresponding descriptor class ItemPercentageOffDiscount
directly inherits from class ItemDiscount
and adds just one self-evident configuration parameter to the various parameters of the item discount:
PercentageValue
: type Double
, constraint: value a valid percentage, i.e. between 0.01 and 100Among all descriptor classes mentioned so far, the class ItemPercentageOffDiscount
is the first that fully describes a certain action and not only adds some configuration parameters that are common to a type of action. Here, no further specialization is done.
The following screenshot shows the complete item percentage off discount configuration web form in Commerce Management with annotations:
The ID ItemTargetPriceDiscount
stands for an item discount that sets the price of cart items to a fixed lower value, if possible. Its descriptor class ItemTargetPriceDiscount
adds the following configuration parameter to those of the item discount:
TargetPrice
: type Money
Cart items with lower price than the target price, of course, do not get a higher price if the action is applied. The price of those items remains unchanged. Nevertheless, they are treated as if they were discounted. This has an exceptional effect in the following situation. Assuming that the action is defined to be "Item target price is $100 to be applied to 2 cart items, the maximum number of applications per order is 1", and PriceAffected
is LowestPrice
. If there are three items in the cart with price $70, $50, and $150, respectively, then action application has no visible effect on the cart because the two items discounted have a price lower than the target price. In order to prevent lower price items from being target price discounted you have to set ConditionalItemsMinPrice
to the same value as TargetPrice
.
So, item target price has to be applied with care. Another argument for applying this action with care is the absence of an upper bound for the price of a discounted item. In principle a cart item that costs $1.000.000 can be set to a target price of $1. This can, of course, be prevented by setting ConditionalItemsSelection
to Selected
and solely selecting suitable products.
The back office item target price discount configuration web form is not much different from the one of the item percentage off discount shown above. The only difference is that a target value can be set instead of a percentage value.
The ID ItemValueOffDiscount
stands for an item discount which reduces the item costs by a fixed value. Its descriptor class, ItemValueOffDiscount
, adds the following configuration parameter to the list of item discount parameters:
ValueOff
: type Money
Note
In case a cart item costs less than the discount, its price is simply reduced to zero.
The web form of the item value off discount differs from the one of the item percentage off discount simply in that the parameter ValueOff
can be set instead of parameter PercentageValue
.
Of all actions implemented so far shipping discounts are the most complex ones. On the one hand this is due to the fact that each of them can be configured to take effect on one of three levels: item, order or bucket. On the other hand it is because a variety of different shipping methods and shipping regions can be configured in such a way that the discount only applies if the choice of shipping method and region in the cart corresponds to those configured for the action.
Shipping discounts are conditional discounts, and as each of them potentially can take effect on one of the three levels item, order, and bucket, the descriptor class of shipping discounts, ShippingDiscount
, directly inherits from class ConditionalDiscount
.
At the moment the class ShippingDiscount
adds the following configuration parameters:
TargetAffected
: type String
ItemRestriction
: type Boolean
; depending on TargetAffected
AffectedItemsNumber
: type Integer
; depending on ItemRestriction
, constraint: value at least 1MethodsAffected
: type String
ShippingMethods
: type Collection
; depending on MethodsAffected
RegionsAffected
: type String
ShippingRegions
: type Collection
; depending on RegionsAffected
The parameter TargetAffected
is required to determine the discount level of effect, and hence, can take one of three values:
Order
: the order as a whole is discounted.Bucket
: the discount is applied bucket per bucket.Items
: discount application on item level, i.e., item per item.Solely in the case where the discount level of effect is Items
, parameters ItemRestriction
and AffectedItemsNumber
come into play. Then the role of these parameters is exactly the same as of the parameters ItemsAffected
and AffectedItemsNumber
defined for the item discount, respectively, with the only difference that ItemRestriction
takes a Boolean
value whereas ItemsAffected
takes one of the two strings All and Amount.
The only configuration parameter that an item discount has and a shipping discount on item level does not have is PriceAffected
. To introduce this parameter for shipping discounts, too, may be a reasonable new feature. Of course, PriceAffected
for shipping discounts would have to relate to the shipping costs rather than to the item costs.
Configuration parameter MethodsAffected
serves for determining whether to apply the discount for all shipping methods or for a selection of them. Similarly, parameter RegionsAffected
serves for determining whether to apply the discount for all shipping regions or just for a selection of them. Therefore the two values that these parameters can take are
All
andSelected
with the obvious meanings.
The related parameters ShippingMethods
and ShippingRegions
are, of course, effective if and only if value Selected
is configured. In this case ShippingMethods
stores a Collection
of selected shipping methods, and ShippingRegions
keeps track of the configured selection of shipping regions.
The following three shipping discount specializations are completely analogous to the corresponding specializations of the item discount. The difference is that the discount is granted rather for shipping than for item costs, and the level of effect can be either item (shipping), bucket (shipping), or order (shipping).
Note for shipping bucket discount
Since ICM 7.10.38.9-LTS:
In case the configured discount should only affect certain shipping areas (and not others), custom conditions can be defined via extensions. See Cookbook - Promotions | Recipe - Apply Shipping Discount Rules to Individual Buckets for further details.
See Item Percentage Off.
The following figure shows the shipping percentage off discount configuration web form with annotations:
The webforms of the remaining shipping discounts are completely analogous.
See Item Target Price.
See Item Value Off.
Non-conditional discounts apply to the order/cart as a whole, and hence, their descriptors inherit directly from PromotionActionDescriptor
. Other than the above shipping discounts the non-conditional discounts implemented so far tend to be quite simple and their webforms are self-explanatory.
The following two specializations are achieved in analogous manner to the corresponding specializations of the item discount, and hence, do not have to be described in detail. In order to understand the effect of these discounts, you just have to keep in mind that they are applied to the cart as a whole.
See Item Percentage Off.
See Item Value Off.
A free gift discount grants a configured number of selected products added to the cart as gift, where the number of gifts added can be regulated by means of the above-mentioned configuration parameters of the class PromotionActionDescriptor,
see Actions and Action Types Available.
We distinguish between two kinds of free gifts. An automatic gift visibly appears in the cart whereas the hidden gift is invisible to a consumer who puts products into a cart.
The descriptor classes of both gift types add a parameter:
LimitToMaxItemCount
: type Integer
, constraint: value at least 1which is used to determine the number of times the cart calculation algorithm attempts to add each of the selected gift products to a single cart.