Hybris 6.0 promotion engine customization (PoC)
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. New Promotion Engine is based on Drools library. Drools is a powerful reasoning system. It allows you to define your business logic using business rules and change them in a runtime. Hybris transparently converts the promotions into the drools scripts. These scripts are used for the shopping cart calculation along with the product and user data.

Complexity
Facts are supposed to be plain old java objects (POJO) and they are created every time the promotion engine starts working. If you need to check the customer against a list of 1 mln featured customers, the standard way is to create 1 mln 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” and
- Condition “The customer has more than 1 placed order”
Challenge
Find a solution on how to implement these conditions. For the first condition the rule engine should be able to look up the current user in the long list of the qualified customers. It is supposed that this list is stored as a separate entity. The second condition is supposed to look up in the customer’s orders. It is just a proof-of-concept task, in the real project it is not a good to scan through orders every time you calculate the cart.Solution
In order to push model data to the drools engine hybris uses so called rule-aware objects (RAO), namely the subtypes of them, RAO Providers. It is a little tricky to get it work 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 are no place to inject the flexible request 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;;customer
;1000bestcustomers ;1000 best customers ;200 ;User ;false ;BestCustomersListTranslator;;customer
Translator
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;
}
}
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);
…
}
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);
}
}
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);
}
}