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. promo1There is a rule context containing some facts or objects. Hybris creates facts every time the promotion engine is being executed. Facts are supposed to be plain old java objects (POJO). There is a set of standard hybris data that is being pushed into the drools engine as facts (see the diagram). Every rule consists of two parts – Condition and Action. The Condition part checks if the state of facts (objects) in the rule context met some conditions. The Action part processes actions and evaluations when the condition part triggers. Hybris promotion builder allows you to set up conditions and actions for the business rules interactively, using the building blocks provided. promo2.png Hybris 6.0 documentation explains clearly about the creating your own conditions and actions as well as you own drools rule templates.

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

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;
}
}

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 to this article: © Rauf Aliev, June 2016

Leave a Reply