Situation
Hybris 6.0 uses the brand-new rule-based promotion engine.
In past versions, the Hybris promotion engine was lacking in relation to Oracle ATG Web Commerce. The new engine provides the flexibility needed to generate all types of promotions simply and intuitively.
The new Promotion Engine is based on the Drools library. Drools is a powerful reasoning system. It allows you to define your business logic using business rules and change them at runtime. Hybris transparently converts promotions into Drools scripts. These scripts are used for shopping cart calculation along with the product and user data.

There is a rule context containing facts or objects. Hybris creates facts every time the promotion engine is executed. Facts are supposed to be plain old Java objects (POJOs). There is a set of standard Hybris data that is pushed into the Drools engine as facts (see the diagram).
Every rule consists of two parts: Condition and Action. The Condition part checks whether the state of facts (objects) in the rule context meets certain conditions. The Action part processes actions and evaluations when the condition part triggers. The Hybris promotion builder allows you to set up conditions and actions for business rules interactively, using the building blocks provided.

Hybris 6.0 documentation clearly explains how to create your own conditions and actions, as well as your own Drools rule templates.
Complexity
Facts are supposed to be plain old Java objects (POJOs), and they are created every time the promotion engine starts working. If you need to check the customer against a list of 1 million featured customers, the standard way is to create 1 million objects in memory and populate the working memory with these objects. Obviously, it doesn’t look right.
A couple of examples:
- Condition “The customer is in the list of TOP 1000 CUSTOMERS”
- Condition “The customer has more than 1 placed order”
Challenge
Find a solution for implementing these conditions.
For the first condition, the rule engine should be able to look up the current user in the long list of qualified customers. It is supposed that this list is stored as a separate entity.
The second condition is supposed to look up the customer’s orders. It is just a proof-of-concept task; in a real project, it is not a good idea to scan through orders every time you calculate the cart.
Solution
To push model data to the Drools engine, Hybris uses so-called rule-aware objects (RAO), namely their subtypes, RAO providers.
It is a little tricky to get it working because OOTB promotion RAOs are basically plain old Java objects and aren’t designed to work with Hybris services. They are expected to be declared as POJO beans, and there is no place to inject the flexible search inside.
See the technical details below.
Video (proof of concept)
Technical details
Impex
INSERT_UPDATE RuleConditionDefinition;id[unique=true] ;name[lang=en] ;priority;breadcrumb[lang=$lang] ;allowsChildren ;translatorId ;translatorParameters;categories(id)
;1000bestcustomers ;1000 best customers ;200 ;User ;false ;BestCustomersListTranslator;;customerTranslator
public class BestCustomersListTranslator implements RuleConditionTranslator {
@Override
public RuleIrCondition translate(final RuleCompilerContext context,
final RuleConditionData condition,
final RuleConditionDefinitionData conditionDefinition)
throws RuleCompilerException {
final RuleIrAttributeCondition qualifiedCustomers = new RuleIrAttributeCondition();
qualifiedCustomers.setVariable(context.generateVariable(QualifiedCustomersRAO.class));
qualifiedCustomers.setAttribute("bestcustomers");
qualifiedCustomers.setOperator(RuleIrAttributeOperator.EQUAL);
qualifiedCustomers.setValue(true);
irConditions.add(qualifiedCustomers);
final RuleIrGroupCondition irCustomerReviewCondition = new RuleIrGroupCondition();
irCustomerReviewCondition.setOperator(RuleIrGroupOperator.AND);
irCustomerReviewCondition.setChildren(irConditions);
return irCustomerReviewCondition;
}
}Provider class
@Override
protected Set<Object> expandRAO(final CartRAO cart, final Collection options) {
…
facts.add(qualifiedCustomersRAO);
…
}Creating the RAO
public class QualifiedCustomersRAO implements java.io.Serializable {
public boolean getbestcustomers() {
String currentUser = userService.getCurrentUser().getUid().toString();
final FlexibleSearchQuery query = new FlexibleSearchQuery("select * from {QualifiedCustomers}, {User} where {User.uid} = ? code and {User.pk} = {QualifiedCustomers.code}");
query.addQueryParameter("code", currentUser);
final SearchResult found = flexibleSearchService.search(query);
return (found.getTotalCount() > 0);
}
}Any questions?
Contact me privately using the form below or leave your comment on this article:
© Rauf Aliev, June 2016