Promotions in SAP Hybris (SAP Commerce Cloud) are powerful tools that enable businesses to drive sales and enhance customer engagement. They can be tailored to fit various marketing strategies and customer needs. Promotions in Hybris are essential for enhancing customer experience and boosting sales.
Promotions consists of the following modules: Promotion Engine module, Rule Engine module, Coupon module, and Timed Access Promotion Engine module.
The Promotion Engine lets you create and manage different types of promotions for your online store. You can use an easy drag-and-drop tool to combine conditions and actions to set up promotions. These promotions can be published one at a time or grouped into larger campaigns.
The Rule Engine helps you define business rules made up of specific conditions and actions. This allows you to apply promotions in a smart way, ensuring they follow the rules you set.
The Coupon Module allows you to create digital coupons that customers can use to get discounts when shopping online. This feature helps attract customers with special offers.
The Customer Coupon Module provides flexible options for coupon use. It allows customers to hold specific coupons for various purposes, such as marketing campaigns or one-time offers, based on what your business needs.
The Timed Access Promotion Engine Module offers a new way to run promotions that not only boost brand awareness but also improve customer satisfaction. It lets retailers create time-limited promotions, helping to sell surplus inventory while encouraging customers to buy quickly.
The Promotion Engine sequence diagram for a cart modification through the storefront, highlighting interactions with the Promotion Engine and Rule Engine in SAP Hybris Commerce.
1. Cart Update Trigger
When a product is added to the cart, a recalculation is triggered, which includes the reevaluation of promotions.
2. Update Promotions Call
The process calls the updatePromotions() method defined in the legacy PromotionService interface. The Promotion Engine implements this interface and overrides the legacy implementation when active. Thus, the call to updatePromotions() is routed to DefaultPromotionEngineService.
3. Undo Previous Results
All promotion results from the last evaluation are undo, including necessary database operations.
4. Preparation of Rule-Aware Objects (RAOs)
To prepare for promotion evaluation, the following steps occur:
The source data, specifically the CartModel and PromotionGroupModels, is converted into Rule-Aware Objects.
The FactContextFactory creates a FactContext for the type <PROMOTION_ORDER>.
A Spring configuration for <PROMOTION_ORDER> stores the required RAO providers for the evaluation request.
The FactContextFactory maintains a map linking contexts to a list of RAO providers.
RAOs are populated using a loop over the RAO providers, employing the Converter or Populator pattern.
5. Identifying the Rule Engine
The appropriate Rule Engine for promotion evaluation is identified. Evaluating promotion rules in an order management context is not optimal, which is addressed by the AbstractRuleEngineContext.
The Spring configuration for DefaultPromotionEngineService specifies the Rule Engine context for processing promotion evaluation requests.
6. Rule Evaluation Context Creation
Once facts are populated and the rule module identified, the data is placed into a RuleEvaluationContext object. The RuleEngineService is called for evaluation, with DefaultCommerceRuleEngineService enriching the context with additional details.
7. Rule Evaluation Execution
The DefaultPlatformRuleEngineService prepares the DroolsSession and DroolsCommand, triggering the Drools Rule Engine for evaluation.
Rules Evaluation: Drools evaluates the rules. When a rule is fired, it executes actions like applying discounts or adding free products.
The in-memory order calculation is triggered to recalculate the cart, updating or creating CartRAO and other RAOs in working memory.
An ActionRAO is added to the ResultRAO list.
8. Results Compilation
After evaluating all rules, the relevant RAOs are retrieved from working memory and returned in a RuleEvaluationResult. At this stage, nothing is persisted yet; only a list of ActionRAO exists.
9. Persistence of Promotion Results
Promotion results are persisted similarly to legacy promotions. This may involve:
Creating DiscountValues
Updating CartEntryModels
Modifying shipment codes
Creating promotion results based on actions decided by the Rule Engine.
Each ActionRAO is mapped to a strategy that dictates how to process its corresponding action. These strategies, implemented as Java classes, ensure that Rule Engine results are persisted and displayed as needed.
The same ActionRAO can have different processing in various modules. For example, a DisplayMessageRAO may create promotional displays in the Promotion Engine or be used to generate emails for customers.
10. Final Cart Calculation
Once all ActionRAO are processed and applied by their respective strategies, the cart is recalculated.
11. Compatibility and Integration
All promotion results are persisted in a way that ensures compatibility with commercefacades, commerceservices, and the Accelerator extensions, maintaining the integrity of the promotion process across the platform.
Create a custom promotion with conditions and actions that are not available out of the box. we will defining a custom set of "facts" for the Promotion Engine, as well as creating custom conditions and actions. Below steps need to follow :
Creating the custompromotionengine Extension
Defining a New Rule-Aware Object , populators and provider
Implementing a New RAO Action and Strategy
Creating Custom Conditions and Actions
Creating Promotion Rules and Testing
When customers write a review for a product, they are added to a special user group. This special user group is then given an exclusive promotion. In this case, you create two promotions:
Custom Promotion: When customers write a product review, they are added to a special user group, reviewedProductsCustomerGroup.
Out-of-the-box Promotion: If a customer is in the reviewedProductsCustomerGroup, the customer gets 25% off the order.
you will create the new custompromotionengine extension using the yempty template using ant extgen command like below sample data
package: com.experts.hybris
name: custompromotionengine
template : yempty
Once it is created than you need to add the newly created extension to /config/localextension.xml file
<extension name="custompromotionengine"/>
Then import custom extension in IDE(intelliJ, eclise). custompromotionengine extension depends on the promotionengineservices , ruleengineservices extensions. This extension is added to the extensioninfo.xml in the custompromotionengine extension.
<requires-extension name="promotionengineservices"/>
<requires-extension name="ruleengineservices"/>
After that build the platform by running this command: ant clean all.
We need customer reviews to be available in the Rule Engine as facts. To achieve this, we define a new Rule-Aware Object (RAO). we will define the CustomerReviewRAO bean in the new extension's beans.xml
File Path : hybris/bin/custom/custompromotionengine/resources/custompromotionengine-beans.xml
<bean class="com.experts.hybris.rao.CustomerReviewRAO">
<property name="productCode" type="String"/>
</bean>
Now, we need to define customerReviews in existing RAO. We extend the existing UserRAO object to include customerReviews as an additional List attribute.
<bean class="de.hybris.platform.ruleengineservices.rao.UserRAO">
<property name="customerReviews" type="java.util.List<com.experts.hybris.rao.CustomerReviewRAO>"/>
</bean>
For generation RAO files need to run ant all.
For set values of RAO, we need to create or update populators and convertors. The CustomerReviewRaoPopulator populates the CustomerReviewRAO from the CustomerReviewModel.
package com.experts.hybris.converters.populator;
import de.hybris.platform.converters.Populator;
import de.hybris.platform.customerreview.model.CustomerReviewModel;
import de.hybris.platform.servicelayer.dto.converter.ConversionException;
import com.experts.hybris.rao.CustomerReviewRAO;
public class CustomerReviewRaoPopulator implements Populator<CustomerReviewModel, CustomerReviewRAO>
{
@Override
public void populate(final CustomerReviewModel customerReviewModel, final CustomerReviewRAO customerReviewRAO) throws ConversionException
{
customerReviewRAO.setProductCode(customerReviewModel.getProduct().getCode());
}
}
Define a Spring bean for the new CustomerReviewRaoPopulator and the new customerReviewRaoConverter in the extension's spring.xml file:
File Path:\hybris\bin\custom\custompromotionengine\resources\custompromotionengine-spring.xml
<alias name="defaultReviewRaoConverter" alias="customerReviewRaoConverter" />
<bean id="defaultReviewRaoConverter" parent="abstractPopulatingConverter">
<property name="targetClass" value="com.experts.hybris.rao.CustomerReviewRAO" />
<property name="populators">
<list>
<ref bean="customerReviewRaoPopulator" />
</list>
</property>
</bean>
<alias name="defaultCustomerReviewRaoPopulator" alias="customerReviewRaoPopulator"/>
<bean id="defaultCustomerReviewRaoPopulator" class="com.experts.hybris.converters.populator.CustomerReviewRaoPopulator">
</bean>
Now, create populator for adding Customer Reviews to UserRAO.
package com.experts.hybris.converters.populator;
import de.hybris.platform.converters.Converters;
import de.hybris.platform.converters.Populator;
import de.hybris.platform.core.model.user.UserModel;
import de.hybris.platform.customerreview.model.CustomerReviewModel;
import de.hybris.platform.ruleengineservices.rao.UserRAO;
import de.hybris.platform.servicelayer.dto.converter.ConversionException;
import de.hybris.platform.servicelayer.dto.converter.Converter;
import java.util.ArrayList;
import com.experts.hybris.rao.CustomerReviewRAO;
public class CustomUserRaoPopulator implements Populator<UserModel, UserRAO>
{
private Converter<CustomerReviewModel, CustomerReviewRAO> customerReviewConverter;
public Converter<CustomerReviewModel, CustomerReviewRAO> getCustomerReviewConverter()
{
return customerReviewConverter;
}
public void setCustomerReviewConverter(final Converter<CustomerReviewModel, CustomerReviewRAO> customerReviewConverter)
{
this.customerReviewConverter = customerReviewConverter;
}
@Override
public void populate(final UserModel userModel, final UserRAO userRAO) throws ConversionException
{
userRAO.setCustomerReviews(new ArrayList<CustomerReviewRAO>(Converters.convertAll(userModel.getCustomerReviews(),
getCustomerReviewConverter())));
}
}
Same need to define spring configuration for populators in spring xml file.
<alias name="customUserRaoPopulator" alias="customUserRaoPopulator" />
<bean id="customUserRaoPopulator" class="com.experts.hybris.converters.populator.CustomUserRaoPopulator" >
<property name="customerReviewConverter" ref="customerReviewRaoConverter" />
</bean>
<!-- add custom populators in exist list -->
<bean parent="modifyPopulatorList">
<property name="list" ref="userRaoConverter" />
<property name="add" ref="customUserRaoPopulator" />
</bean>
Now, we need to create RAOProvider. The CustomerReviewRaoExtractor overrides expandFact() for add new facts, getTriggeringOption(), and isDefault() methods.
package com.experts.hybris.rao.provider.impl;
import de.hybris.platform.ruleengineservices.rao.CartRAO;
import de.hybris.platform.ruleengineservices.rao.providers.RAOFactsExtractor;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.assertj.core.util.Preconditions;
public class CustomerReviewRaoExtractor implements RAOFactsExtractor
{
public static final String EXPAND_CUSTOMER_REVIEWS = "EXPAND_CUSTOMER_REVIEWS";
@Override
public Set expandFact(final Object fact)
{
Preconditions.checkArgument(fact instanceof CartRAO, "CartRAO type is expected here)");
final Set<Object> facts = new HashSet<>();
final CartRAO cartRAO = (CartRAO) fact;
if (Objects.nonNull(cartRAO.getUser()))
{
facts.addAll(cartRAO.getUser().getCustomerReviews());
}
return facts;
}
@Override
public String getTriggeringOption()
{
return EXPAND_CUSTOMER_REVIEWS;
}
@Override
public boolean isMinOption()
{
return false;
}
@Override
public boolean isDefault()
{
return true;
}
}
Configure in spring xml file .
<alias name="defaultCustomerReviewRaoExtractor" alias="customerReviewRaoExtractor"/>
<bean id="defaultCustomerReviewRaoExtractor" class="com.experts.hybris.rao.provider.impl.CustomerReviewRaoExtractor"/>
<bean id="customCartRAOProviderExtractorsListMergeDirective" depends-on="cartRAOProviderExtractors" parent="listMergeDirective">
<property name="add" ref="customerReviewRaoExtractor"/>
</bean>
The new ChangeUserGroupRAO bean extends AbstractRuleActionRAO and has one attribute for userGroupId. Add this to the custompromotionengine-beans.xml file:
<bean class="com.experts.hybris.rao.ChangeUserGroupRAO" extends="de.hybris.platform.ruleengineservices.rao.AbstractRuleActionRAO">
<property name="userGroupId" type="String" />
</bean>
Creating a New RuleBasedPromotionAction Type for persist value of promotions
<itemtype code="RuleBasedAddUserToUserGroupAction"
extends="AbstractRuleBasedPromotionAction" jaloclass="com.experts.hybris.jalo.RuleBasedAddUserToUserGroupAction"
autocreate="true" generate="true">
<attributes>
<attribute qualifier="userGroup" autocreate="true" type="UserGroup">
<persistence type="property" />
</attribute>
<attribute qualifier="user" autocreate="true" type="User">
<persistence type="property" />
</attribute>
</attributes>
</itemtype>
ant clean all and run ant updatesystem.
create New RAOAction. This method creates a new instance of ChangeUserGroupRAO and ensures that new and changed facts are added to the Rule Engine working memory.
package com.experts.hybris.rule.action.impl;
import de.hybris.platform.ruleengineservices.rao.CartRAO;
import de.hybris.platform.ruleengineservices.rao.RuleEngineResultRAO;
import de.hybris.platform.ruleengineservices.rao.UserGroupRAO;
import de.hybris.platform.ruleengineservices.rao.UserRAO;
import de.hybris.platform.ruleengineservices.rule.evaluation.RuleActionContext;
import de.hybris.platform.ruleengineservices.rule.evaluation.actions.AbstractRuleExecutableSupport;
import de.hybris.platform.ruleengineservices.rule.evaluation.actions.RAOAction;
import de.hybris.platform.ruleengineservices.util.RAOConstants;
import com.experts.hybris.rao.ChangeUserGroupRAO;
public class AddUserToUserGroupRAOAction extends AbstractRuleExecutableSupport implements RAOAction
{
@Override
public boolean performActionInternal(final RuleActionContext context)
{
final String userGroupCode = context.getParameter(RAOConstants.VALUE_PARAM, String.class);
performAction(context, userGroupCode);
return true;
}
protected void performAction(final RuleActionContext context, final String userGroupCode)
{
final CartRAO cartRao = context.getCartRao();
final RuleEngineResultRAO result = context.getRuleEngineResultRao();
final ChangeUserGroupRAO changeUserGroupRAO = new ChangeUserGroupRAO();
getRaoUtils().addAction(cartRao, changeUserGroupRAO);
changeUserGroupRAO.setUserGroupId(userGroupCode);
result.getActions().add(changeUserGroupRAO);
final UserGroupRAO userGroupRAO = new UserGroupRAO();
userGroupRAO.setId(userGroupCode);
final UserRAO user = cartRao.getUser();
user.getGroups().add(userGroupRAO);
setRAOMetaData(context, changeUserGroupRAO);
context.insertFacts(changeUserGroupRAO, userGroupRAO);
context.scheduleForUpdate(user);
}
}
Implement and define the DefaultAddUserToUserGroupActionStrategy. it is implement the following methods:
apply() - responsible for executing our ChangeUserGroupRAO action.
undo() - responsible for undoing what apply() has done.
package com.experts.hybris.action;
import de.hybris.platform.core.model.ItemModel;
import de.hybris.platform.core.model.order.AbstractOrderModel;
import de.hybris.platform.core.model.security.PrincipalModel;
import de.hybris.platform.core.model.user.UserGroupModel;
import de.hybris.platform.core.model.user.UserModel;
import de.hybris.platform.promotionengineservices.action.impl.AbstractRuleActionStrategy;
import de.hybris.platform.promotions.model.PromotionResultModel;
import de.hybris.platform.ruleengineservices.rao.AbstractRuleActionRAO;
import de.hybris.platform.ruleengineservices.rao.CartRAO;
import de.hybris.platform.servicelayer.user.UserService;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.experts.hybris.model.RuleBasedAddUserToUserGroupActionModel;
import com.experts.hybris.rao.ChangeUserGroupRAO;
public class DefaultAddUserToUserGroupActionStrategy extends AbstractRuleActionStrategy<RuleBasedAddUserToUserGroupActionModel>
{
private static final Logger LOG = LoggerFactory.getLogger(DefaultAddUserToUserGroupActionStrategy.class);
private UserService userService;
@Override
public List<? extends ItemModel> apply(final AbstractRuleActionRAO action)
{
if (!(action instanceof ChangeUserGroupRAO))
{
LOG.error("cannot apply {}, action is not of type ChangeUserGroupRAO", this.getClass().getSimpleName());
return Collections.emptyList();
}
final ChangeUserGroupRAO changeUserGroupAction = (ChangeUserGroupRAO) action;
if (!(changeUserGroupAction.getAppliedToObject() instanceof CartRAO))
{
LOG.error("cannot apply {}, appliedToObject is not of type CartRAO, but {}", getClass().getSimpleName(),
action.getAppliedToObject());
return Collections.emptyList();
}
final PromotionResultModel promoResult = getPromotionActionService().createPromotionResult(action);
if (promoResult == null)
{
LOG.error("cannot apply {}, promotionResult could not be created.", this.getClass().getSimpleName());
return Collections.emptyList();
}
final AbstractOrderModel order = promoResult.getOrder();
if (order == null)
{
LOG.error("cannot apply {}, order not found", this.getClass().getSimpleName());
// detach the promotion result if its not saved yet.
if (getModelService().isNew(promoResult))
{
getModelService().detach(promoResult);
}
return Collections.emptyList();
}
final UserGroupModel userGroup = findUserGroup(changeUserGroupAction.getUserGroupId());
if (userGroup == null)
{
LOG.error("User group for id {} not found!", changeUserGroupAction.getUserGroupId());
return Collections.emptyList();
}
final UserModel user = order.getUser();
addUserToUserGroup(userGroup, user);
final RuleBasedAddUserToUserGroupActionModel actionModel = createPromotionAction(promoResult, action);
actionModel.setPromotionResult(promoResult);
actionModel.setUser(user);
actionModel.setUserGroup(userGroup);
getModelService().saveAll(promoResult, actionModel, userGroup);
getModelService().refresh(user);
return Collections.singletonList(promoResult);
}
protected void addUserToUserGroup(final UserGroupModel userGroup, final UserModel user)
{
final Set<PrincipalModel> members = userGroup.getMembers();
final HashSet<PrincipalModel> modifiedMembers = new HashSet<PrincipalModel>(members);
modifiedMembers.add(user);
userGroup.setMembers(modifiedMembers);
}
protected UserGroupModel findUserGroup(final String userGroupId)
{
UserGroupModel userGroup = null;
try
{
userGroup = getUserService().getUserGroupForUID(userGroupId);
}
catch (final Exception e)
{
LOG.error("Problem getting user group with uid=" + userGroupId, e);
return null;
}
return userGroup;
}
@Override
public void undo(final ItemModel item)
{
if (item instanceof RuleBasedAddUserToUserGroupActionModel)
{
final RuleBasedAddUserToUserGroupActionModel action = (RuleBasedAddUserToUserGroupActionModel) item;
final UserGroupModel userGroup = action.getUserGroup();
final UserModel user = action.getUser();
final Set<PrincipalModel> members = userGroup.getMembers();
final HashSet<PrincipalModel> modifiedMembers = new HashSet<PrincipalModel>(members);
modifiedMembers.remove(user);
userGroup.setMembers(modifiedMembers);
undoInternal(action);
getModelService().save(userGroup);
getModelService().refresh(user);
}
}
public UserService getUserService()
{
return userService;
}
public void setUserService(final UserService userService)
{
this.userService = userService;
}
}
Define a Spring bean for Action and Strategy in spring xml file
<alias name="defaultAddUserToUserGroupActionStrategy" alias="addUserToUserGroupActionStrategy"/>
<bean id="defaultAddUserToUserGroupActionStrategy" parent="abstractRuleActionStrategy" class="com.experts.hybris.action.DefaultAddUserToUserGroupActionStrategy" >
<property name="promotionAction" value="com.experts.hybris.model.RuleBasedAddUserToUserGroupActionModel"/>
<property name="userService" ref="userService" />
</bean>
<bean id="customActionStrategies" depends-on="actionStrategies" parent="listMergeDirective">
<property name="add" ref="defaultAddUserToUserGroupActionStrategy" />
</bean>
<bean id="customPromotionActionStrategiesMapping" depends-on="promotionActionStrategiesMapping" parent="mapMergeDirective">
<property name="key" value="defaultAddUserToUserGroupRAOAction" />
<property name="value" ref="defaultAddUserToUserGroupActionStrategy" />
</bean>
<alias alias="addUserToUserGroupRAOAction" name="defaultAddUserToUserGroupRAOAction" />
<bean id="defaultAddUserToUserGroupRAOAction" parent="abstractRuleExecutableSupport" class="com.experts.hybris.rule.action.impl.AddUserToUserGroupRAOAction"/>
<alias alias="addUserToUserGroupAction" name="defaultAddUserToUserGroupAction" />
<bean id="defaultAddUserToUserGroupAction" class="de.hybris.platform.ruledefinitions.actions.DefaultRuleExecutableAction">
<property name="raoAction" ref="addUserToUserGroupRAOAction"/>
</bean>
Create a new condition definition. Define the customer_review condition definition via impex.
$lang=en
INSERT_UPDATE RuleConditionDefinition;id[unique=true];name[lang=$lang];priority;breadcrumb[lang=$lang];allowsChildren;translatorId;translatorParameters;categories(id)
;customer_review;Customer Review;200;Customer wrote a review for a product;false;ruleCustomerReviewTranslator;;customer
INSERT_UPDATE RuleConditionDefinitionRuleTypeMapping;definition(id)[unique=true];ruleType(code)[default=PromotionSourceRule][unique=true]
;customer_review;
Implement RuleCustomerReviewTranslator
package com.experts.hybris.definitions.conditions;
import de.hybris.platform.ruleengineservices.compiler.*;
import de.hybris.platform.ruleengineservices.rao.CartRAO;
import de.hybris.platform.ruleengineservices.rao.OrderEntryRAO;
import de.hybris.platform.ruleengineservices.rao.UserRAO;
import de.hybris.platform.ruleengineservices.rule.data.RuleConditionData;
import de.hybris.platform.ruleengineservices.rule.data.RuleConditionDefinitionData;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.experts.hybris.rao.CustomerReviewRAO;
public class RuleCustomerReviewTranslator implements RuleConditionTranslator
{
public static final String ANONYMOUS_USER = "anonymous";
public static final String CART_RAO_ENTRIES_ATTRIBUTE = "entries";
public static final String CART_RAO_USER_ATTRIBUTE = "user";
public static final String ORDER_ENTRY_RAO_PRODUCT_ATTRIBUTE = "productCode";
public static final String CUSTOMER_REVIEW_RAO_PRODUCT_ATTRIBUTE = "productCode";
public static final String USER_RAO_CUSTOMER_REVIEWS_ATTRIBUTE = "customerReviews";
public static final String USER_RAO_ID_ATTRIBUTE = "id";
@Override
public RuleIrCondition translate(final RuleCompilerContext context, final RuleConditionData condition,
final RuleConditionDefinitionData conditionDefinition) throws RuleCompilerException
{
final String orderEntryRaoVariable = context.generateVariable(OrderEntryRAO.class);
final String cartRaoVariable = context.generateVariable(CartRAO.class);
final String customerReviewRaoVariable = context.generateVariable(CustomerReviewRAO.class);
final String userRaoVariable = context.generateVariable(UserRAO.class);
final List<RuleIrCondition> irConditions = new ArrayList<>();
final RuleIrAttributeRelCondition irCartOrderEntryRel = new RuleIrAttributeRelCondition();
irCartOrderEntryRel.setVariable(cartRaoVariable);
irCartOrderEntryRel.setAttribute(CART_RAO_ENTRIES_ATTRIBUTE);
irCartOrderEntryRel.setOperator(RuleIrAttributeOperator.CONTAINS);
irCartOrderEntryRel.setTargetVariable(orderEntryRaoVariable);
final RuleIrTypeCondition irCustomerReviewProductRel = new RuleIrTypeCondition();
irCustomerReviewProductRel.setVariable(customerReviewRaoVariable);
final RuleIrAttributeRelCondition irOrderEntryProductRel = new RuleIrAttributeRelCondition();
irOrderEntryProductRel.setVariable(orderEntryRaoVariable);
irOrderEntryProductRel.setAttribute(ORDER_ENTRY_RAO_PRODUCT_ATTRIBUTE);
irOrderEntryProductRel.setOperator(RuleIrAttributeOperator.EQUAL);
irOrderEntryProductRel.setTargetVariable(customerReviewRaoVariable);
irOrderEntryProductRel.setTargetAttribute("productCode");
final RuleIrAttributeRelCondition irUserCustomerReviewRel = new RuleIrAttributeRelCondition();
irUserCustomerReviewRel.setVariable(userRaoVariable);
irUserCustomerReviewRel.setAttribute(USER_RAO_CUSTOMER_REVIEWS_ATTRIBUTE);
irUserCustomerReviewRel.setOperator(RuleIrAttributeOperator.CONTAINS);
irUserCustomerReviewRel.setTargetVariable(customerReviewRaoVariable);
final RuleIrAttributeRelCondition irCartUserRel = new RuleIrAttributeRelCondition();
irCartUserRel.setVariable(cartRaoVariable);
irCartUserRel.setAttribute(CART_RAO_USER_ATTRIBUTE);
irCartUserRel.setOperator(RuleIrAttributeOperator.EQUAL);
irCartUserRel.setTargetVariable(userRaoVariable);
final RuleIrAttributeCondition irExcludedCustomersCondition = new RuleIrAttributeCondition();
irExcludedCustomersCondition.setVariable(userRaoVariable);
irExcludedCustomersCondition.setAttribute(USER_RAO_ID_ATTRIBUTE);
irExcludedCustomersCondition.setOperator(RuleIrAttributeOperator.NOT_IN);
irExcludedCustomersCondition.setValue(Collections.singletonList(ANONYMOUS_USER));
irConditions.add(irCartOrderEntryRel);
irConditions.add(irOrderEntryProductRel);
irConditions.add(irCustomerReviewProductRel);
irConditions.add(irUserCustomerReviewRel);
irConditions.add(irCartUserRel);
irConditions.add(irExcludedCustomersCondition);
final RuleIrGroupCondition irCustomerReviewCondition = new RuleIrGroupCondition();
irCustomerReviewCondition.setOperator(RuleIrGroupOperator.AND);
irCustomerReviewCondition.setChildren(irConditions);
return irCustomerReviewCondition;
}
}
Register the Condition Translator bean in spring file.
<alias alias="ruleCustomerReviewTranslator" name="defaultRuleCustomerReviewTranslator" />
<bean id="defaultRuleCustomerReviewTranslator" class="com.experts.hybris.definitions.conditions.RuleCustomerReviewTranslator" />
Creating Action Definition via impex.
$lang=en
INSERT_UPDATE RuleConditionDefinition;id[unique=true];name[lang=$lang];priority;breadcrumb[lang=$lang];allowsChildren;translatorId;translatorParameters;categories(id)
;customer_review;Customer Review;200;Customer wrote a review for a product;false;ruleCustomerReviewTranslator;;customer
INSERT_UPDATE RuleConditionDefinitionRuleTypeMapping;definition(id)[unique=true];ruleType(code)[default=PromotionSourceRule][unique=true]
;customer_review;
$lang=en
INSERT_UPDATE UserGroup;uid[unique=true];groups(uid)
;reviewedProductsCustomerGroup;
INSERT_UPDATE RuleActionDefinitionCategory;id[unique=true];name[lang=$lang];priority
;customer;Customer;700
INSERT_UPDATE RuleActionDefinition;id[unique=true];name[lang=$lang];priority;breadcrumb[lang=$lang];translatorId;translatorParameters;categories(id)
;add_customer_to_group;Add customer to group;200;Add customer to group {customer_group};ruleExecutableActionTranslator;actionId->addUserToUserGroupAction;customer
INSERT_UPDATE RuleActionDefinitionParameter;definition(id)[unique=true];id[unique=true];priority;name[lang=$lang];description[lang=$lang];type;value;required[default=true]
;add_customer_to_group;value;100;Customer group;Customer group;ItemType(UserGroup);;
INSERT_UPDATE RuleActionDefinitionRuleTypeMapping;definition(id)[unique=true];ruleType(code)[default=PromotionSourceRule][unique=true]
;add_customer_to_group;
these impex , you can define in create impex file in same extension or existing project impex file. base on that need to run update with selected extension. Stop the server, and then compile using ant all and start hybris server.
Create 2 promotions and test with storefront.
Promotions 1: reviewed_product_add_customer_to_group create and publish with below condition and action.
Promotions 2: 25_percent_off_orders_for_reviewedProductsCustomerGroup create and publish with below condition and action