Important
You are browsing upcoming documentation for version 6.1 of OroCommerce, scheduled for release in 2025. Read the documentation for version 6.0 (the latest LTS version) to get up-to-date information.
See our Release Process documentation for more information on the currently supported and upcoming releases.
Add Expressions to Promotions
Expression language for promotions expressions is a user-friendly and business oriented extension of the Symfony Expression Language. It is easy to use and, on top of usual comparison and logical operators, it allows iterating through the collections of items using (collection).all and (collection).any operations. Keep in mind that out-of-the-box, you can add any custom fields to the required entity in addition to the attributes listed below.
Note
Note that the float values require using a number with a fractional part (a floating-point number), for example, lineItem.quantity != 1.0 instead of lineItem.quantity != 1.
Attributes Supported in Promotion Expressions
Attributes
Financial
shippingCost float
paymentMethod string
paymentMethods Collection string
currency string
subtotal float
Geographies
billingAddress
billingAddress.street string
billingAddress.street2 string
billingAddress.city string
billingAddress.regionName string
billingAddress.regionCode string
billingAddress.postalCode string
billingAddress.countryName string
billingAddress.countryIso3 string
billingAddress.countryIso2 string
To find the whole list of fields available for billingAddress, navigate to System > Entities > Entity Management > Order Address. More details on the entity fields management are described here.
shippingAddress
shippingAddress.street string
shippingAddress.street2 string
shippingAddress.city string
shippingAddress.regionName string
shippingAddress.regionCode string
shippingAddress.postalCode string
shippingAddress.countryName string
shippingAddress.countryIso3 string
shippingAddress.countryIso2 string
Business
Customer
customer.id int
customer.name string
customer.group.id int
customer.group.name string
customer.payment_term_7c4f1e8e.label string (Payment Term)
customer.payment_term_7c4f1e8e.id int (Payment Term)
To find the whole list of fields available for customer, navigate to System > Entities > Entity Management > Customer. More details on the entity fields management are described here.
Customer User
customerUser.id int
customerUser.email string
customerUser.firstName string
customerUser.middleName string
customerUser.lastName string
customerUser.lastName string (which is a customerUser.firstName ~ ‘ ‘ ~ customerUser.lastName, e.g. ‘Amanda Cole’)
To find the whole list of fields available for customerUser, navigate to System > Entities > Entity Management > Customer User. More details on the entity fields management are described here.
Note
Please note that if you enable guest checkout on your website, customerUser will be empty on the first two checkout steps. To prevent promotion calculation errors, you can add an additional condition, “customerUser and”, before the first usage of the customerUser variable, for example, subtotal > 500.0 and customerUser and customerUser.email = “”
Customer Group
customerGroup.id int
customerGroup.name string
Collections
lineItems is a collection of line items (products and their quantity, units, price) that are being ordered.
lineItems[X].product.unitPrecisions is a collection of unit precisions that is available in OroCommerce for the lineItem product in the order.
lineItems[X].product.inventoryLevels is a collection of inventory levels - available quantities of the particular product in various units in warehouses that are available in OroCommerce.
customer.users is a collection of customer users that belong to the customer the order is submitted for.
customerGroup.customers is a collection of customers that belong to the customer group.
lineItems Collection
Attributes
Note
Use the items with LineItem prefix when processing the lineItems collection using .any() and .all() expressions. Alternatively, address the item in the collection directly, e.g. lineItems[1].product.sku.
lineItem.product.id int
lineItem.product.sku string
lineItem.product.primaryUnitPrecision.id int
lineItem.product.primaryUnitPrecision.precision int
lineItem.product.primaryUnitPrecision.sell bool
lineItem.product.category.id int
lineItem.product.inventoryLevels collection
lineItem.productUnitCode string
lineItem.quantity float
lineItem.price.value float
lineItem.price.currency string
lineItem.product.unitPrecisions collection
To find the whole list of fields available for:
lineItem — navigate to System > Entities > Entity Management > Order Line Item
lineItem.product — navigate to System > Entities > Entity Management > Product
lineItem.product.productUnit — navigate to System > Entities > Entity Management > Product Unit
More details on the entity fields management are described here.
lineItems[X].product.unitPrecisions Collection
Attributes
Note
Use the items with unitPrecision prefix when processing the unitPrecisions collection using LineItem.product.unitPrecisions.any() and LineItem.product.unitPrecisions.all() expressions. Alternatively, address the item in the collection directly, e.g. LineItem.product.unitPrecisions[1].unit.code.
unitPrecision.unit.code string
unitPrecision.precision int
unitPrecision.sell bool
lineItems[X].product.inventoryLevels Collection
Attributes
Note
Use the items with inventoryLevel prefix when processing the inventoryLevels collection using LineItem.product.inventoryLevels.any() and LineItem.product.inventoryLevels.all() expressions. Alternatively, address the item in the collection directly, e.g. LineItem.product.inventoryLevels[1].warehouse.id.
inventoryLevel.id int
inventoryLevel.quantity int
inventoryLevel.productUnitPrecision.unit.code string
inventoryLevel.productUnitPrecision.precision int
inventoryLevel.productUnitPrecision.sell bool
inventoryLevel.warehouse.id int
inventoryLevel.warehouse.name string
To find the whole list of fields available for inventoryLevel, navigate to System > Entities > Entity Management > Inventory Level. More details on the entity fields management are described here.
customer.users Collection
Attributes
Note
Use the items with user prefix when processing the customer.users collection using customer.users.any() and customer.users.all() expressions. Alternatively, address the item in the collection directly, e.g. customer.users[1].email.
user.id int
user.email string
user.firstName string
user.middleName string
user.lastName string
customerGroup.customers Collection
Attributes
Note
Use the items with user prefix when processing the customerGroup.customers collection using customerGroup.customers.any() and customerGroup.customers.all() expressions. Alternatively, address the item in the collection directly, e.g. customerGroup.customers[1].name.
customer.id int
customer.name string
customer.group.id int
customer.group.name string
Expression Syntax
You can use the following elements to build the expression that identifies the cases when shipping or payment rule should be applied.
Supported Data
Text enclosed in quotes (’) or double quotes (“)
Numbers (e.g. 32)
Arrays (e.g. [1, 5], and [“Option A”, “Option B”])
Boolean values (true and false)
null
Attributes and data structures listed in the Attributes Supported in Promotion Expressions, e.g. subtotal > 100000 or lineItems.all(lineItem.quantity > 1000).
Use lineItems.all(expression) and lineItems.any(expression) to assess the collection of line items (products and their quantity, units, price, weight, and dimensions) in the order, quote or request for quote. Inside the expression, use lineItem.product.<fieldname> phrase to access the product field value. Separate the field from the item with a period.
Use lineItems.sum(expression) to sum up results of complex calculations that use the collection items and their properties as parameters. For example, you can get a total weight of the order using the following expression: lineItems.sum(lineItem.weight.value * lineItem.quantity).
Outside the collection operations, you can assess an element of the array using item[id].fieldname phrase (e.g. lineItems[1].product.price > 1000.00). Separate the field from the item with a period.
See more information about using collections in the Collection Validation section below.
Supported operators
Arithmetic:
add: +
subtract: -
multiply: *
divide: /
mod (a remainder of division): %
power: **
Operations with text:
concatenate: ~
Comparison:
equal: =
not equal: !=
less: <
more: >
less or equal: <=
more or equal: >=
matches (regexp)
in [“Option A”, “Option B”]
not in [“Option A”, “Option B”]
Logical:
and
or
not
..
(range, like in 1..10)
Collection Validation with any (OR) and all (AND) Operations
To validate all items in the collection (e.g. products in the order being submitted), or ensure that at least one value has a particular quality (e.g. it meets bulk quantity requirements), use items.all(sub-condition) and items.any(sub-condition) expression phrases. The sub-condition is an expression that applies to every item. Note that it is enclosed in brackets, and no single/double quotes (‘/”) are used as they are reserved for the text values.
When you are using all or any method, you provide the named collection of elements (e.g. products) and Oro automatically guesses the name of the single element (e.g. product). It is produced by stripping the trailing ‘s’ for countable nouns and by adding a leading ‘Item’ the uncountable ones, like in: milk.all(milkItem.isfresh).
The items.all(nested_expression) expression is true when the nested condition is satisfied for every item in the collection. When an item evaluation results in false, the items.all() immediately returns false without processing the remaining items.
Vise versa, items.any(nested_expression) is true if a nested expression evaluates to true for at least one item. Remaining items are not processed either.
Sample Expression
For example, you need to ensure that all products are available in the requested quantity in the particular warehouse (inventory levels in the warehouse A is greater than the line item quantity in the order).
You can refer to the Attributes Supported in Promotion Expressions to build the expression.
For expression evaluation, OroCommerce walks through the lineItems collection and for every item in the collection it checks that this product is available in the warehouse A in the units that were ordered, that it is enabled for sale from the warehouse A, and that it is in stock in the required quantity.
lineItems.all(
lineItem.product.inventoryLevels.any(
inventoryLevel.warehouse.name = 'Additional Warehouse'
and
inventoryLevel.quantity >= lineItem.quantity
and
inventoryLevel.productUnitPrecision.unit.code = lineItem.productUnit.code
and
inventoryLevel.productUnitPrecision.sell
)
)
lineItems.any(
lineItem.product.sku in ['SKU1', 'SKU2']
or
lineItem.product.sku not in ['SKU3', 'SKU4']
)
The lineItems.all(…) expression is a loop through the elements of lineItems collection. It exposes every element of the collection inside the loop (in round brackets) as a lineItem.
In the example, for every line item, the following condition is verified to be true:
...
lineItem.product.inventoryLevels.any(
inventoryLevel.warehouse.name = 'Additional Warehouse'
and
inventoryLevel.quantity >= lineItem.quantity
and
inventoryLevel.productUnitPrecision.unit.code = lineItem.productUnit.code
and
inventoryLevel.productUnitPrecision.sell
)
...
inventoryLevels is another collection being decomposed in the nested loop: lineItem.product.inventoryLevels.any(..)
Inside the loop, OroCommerce checks every inventory level to find the one that is related to the warehouse A and verify the remaining conditions to evaluate the quantity is enough, like the following:
inventoryLevel.productUnitPrecision.unit.code = lineItem.productUnit.code