Search This Blog

Sunday, September 28, 2014

Currency Specific Promotion Websphere commerce Using CustomConditions


   WCS OOB gives option of currency as purchase condition while creating new promotion in management center. From MC Create promotion UI it looks like its a purchase condition but its not !

WCS OOB use this currency option as currency of adjustment value you entered while creating promotion. At the time of promotion evaluation promotion will applied even customer order currency is different. Promotion engine convert adjustment currency and apply promotion. So in nutshell this currency option specifies discount value currency.

To test it, create two promotions in two different currencies (fox exp: USD and GBP) using same promo code (for exp: 12345). Now apply this promo code on store front you will observe that both promotions are applied on order with two adjustments.

Here are the steps to make this currency option as part of purchase condition. This article also explains how to use CustomConditions in Promotion Runtime XML. WCS Infocenter doesn't give enough information on CustomConditions.

1. First lets understand Promotion component configuration

 WC\xml\config\com.ibm.commerce.promotion\com.ibm.commerce.promotion.facade.server.config.PromotionComponentConfigurationImpl.xml

This configuration file holds Promotion Run-time Configuration templates. Those are used by promotion engine while creating new promotion. Lets pick one example from this file.

<promotionComponentRegistry>
<promotionTypeConfiguration name="OrderLevelPercentDiscount" >
<param key="purchaseConditionTemplate" value="OrderPercentOffPurchaseConditionTemplate.xsl"/>
<param key="basePromotionTemplate" value="DefaultBasePromotionTemplate.xsl"/>
<param key="customConditionTemplate" value="DefaultCustomConditionsTemplate.xsl"/>
<param key="targetingConditionTemplate" value="DefaultTargetingConditionTemplate.xsl"/>
<param key="promotionGroup" value="OrderLevelPromotion"/>
<param key="calculationCodeDisplayLevel" value="1"/>
</promotionTypeConfiguration>

Above snippet from PromotionComponentConfigurationImpl.xml depicts what all templates will be used while creating OrderLevelPercentDiscount promotion. As we can see first template is main template OrderPercentOffPurchaseConditionTemplate.xsl. This template defines all OOB OrderLevelPercentDiscount promotion configuration. Every promotion has separate main config template. Incase you want to customize any specific promotion customize this template and save it under

 WC\xml\config\com.ibm.commerce.promotion-ext\template

and create entry in

 WC\xml\config\com.ibm.commerce.promotion-ext\com.ibm.commerce.promotion.facade.server.config.PromotionComponentConfigurationImpl.xml

Second parameter is for OOB base template.  Better not to touch it otherwise while upgrading platform your changes will be overwritten.

Third parameter customConditionTemplate gives placeholder for custom condition.

But here we want to add this custom config to all promotions rather a specific promotion. So  customConditionTemplate  is perfect place because its included in all promotion configs and once we add these custom config template changes, it will be reflected in all promotions.

2. Create DefaultCustomConditionsTemplate.xsl under

 WC\xml\config\com.ibm.commerce.promotion-ext\template

here is sample xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- ================================================================= Licensed
Materials - Property of IBM WebSphere Commerce (C) Copyright IBM Corp. 2008
All Rights Reserved. US Government Users Restricted Rights - Use, duplication
or disclosure restricted by GSA ADP Schedule Contract with IBM Corp. ================================================================= -->
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template name="DefaultCustomConditionsTemplate" match="/">
<!-- handle custom conditions -->
<CustomConditions>
<Condition impl="com.mycompany.commerce.marketing.promotion.condition.ExtCurrencyPurchaseCondition">
<Currency><xsl:value-of select="PromotionData/Elements/PurchaseCondition/Data/Currency" /></Currency>
</Condition>
</CustomConditions>
</xsl:template>
</xsl:transform>


3. Create Custom condition class. ExtCurrencyPurchaseCondition

For example here is sample code


package com.mycompany.commerce.marketing.promotion.condition;

import org.w3c.dom.Node;

import com.ibm.commerce.marketing.promotion.runtime.PromotionContext;
import com.ibm.commerce.marketing.promotion.xml.DeXMLizationException;
import com.ibm.commerce.marketing.promotion.xml.XMLizationException;
import com.ibm.commerce.foundation.common.util.logging.LoggingHelper;
import com.ibm.commerce.marketing.util.XMLHelper;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.w3c.dom.NodeList;

public class ExtCurrencyPurchaseCondition implements Condition {

private static final Logger LOGGER = LoggingHelper
.getLogger(ExtCurrencyPurchaseCondition.class);
private static final String CLASSNAME = ExtCurrencyPurchaseCondition.class.getName();
private String currency = null;

@Override
public void fromXML(Node anXMLNode) throws DeXMLizationException {
String methodName = "fromXML";
if (LoggingHelper.isEntryExitTraceEnabled(LOGGER)) {
LOGGER.entering(CLASSNAME, "fromXML()");
}
boolean bTraceEnabled = LoggingHelper.isTraceEnabled(LOGGER);
try {
if (anXMLNode == null) {
throw new DeXMLizationException("The node passed in is empty!");
}
if (getClass() != Class.forName(XMLHelper.getAttributeValue(
anXMLNode, "impl"))) {
if (bTraceEnabled) {
LOGGER.logp(Level.FINEST, CLASSNAME, "fromXML()",
"Wrong implementation");
}
throw new DeXMLizationException("Wrong implementation");
}

NodeList childNodes = anXMLNode.getChildNodes();
if ((childNodes != null) && (childNodes.getLength() > 0)) {
for (int i = 0; i < childNodes.getLength(); i++) {
if (childNodes.item(i).getNodeName().compareTo("Currency") == 0) {
if (childNodes.item(i).hasChildNodes()) {
this.currency = childNodes.item(i).getFirstChild()
.getNodeValue().trim();
}
}
}
}
} catch (Exception e) {
throw new DeXMLizationException(e.getMessage());
}
if (LoggingHelper.isEntryExitTraceEnabled(LOGGER)) {
LOGGER.exiting(CLASSNAME, "fromXML()");
}
}

@Override
public String toXML() throws XMLizationException {
String METHODNAME = "toXML()";
boolean bTraceEnabled = LoggingHelper.isTraceEnabled(LOGGER);
if (LoggingHelper.isEntryExitTraceEnabled(LOGGER))
LOGGER.entering(CLASSNAME, "toXML()");

StringBuffer buffer = new StringBuffer(3072);
buffer.append("<Condition impl=\"").append(getClass().getName())
.append("\">").append("<Currency>"+this.currency+"</Currency>")
.append("</Condition>");
String sTemp = buffer.toString().trim();
if (bTraceEnabled)
LOGGER.logp(Level.FINEST, CLASSNAME, "toXML()", (new StringBuilder(
"Result=")).append(sTemp).toString());

if (LoggingHelper.isEntryExitTraceEnabled(LOGGER))
LOGGER.exiting(CLASSNAME, "toXML()");

return sTemp;
}

@Override
public boolean evaluate(PromotionContext promotioncontext)
throws PromotionConditionEvaluationException {
boolean evalResult = false;
boolean bTraceEnabled = LoggingHelper.isTraceEnabled(LOGGER);

String ordercurrency = promotioncontext.getOrderCurrency();

if (promotioncontext.isUnderSimulatedPromotionEvaluationMode()) {
String simulatedCurrency = (String) promotioncontext.getSimulatedPromotionEvaluationConfigurations().get("Currency");
if (bTraceEnabled) {
LOGGER.logp(Level.FINEST, CLASSNAME, "filter()", "Simulated Payment Type: " + simulatedCurrency);
}
if (simulatedCurrency != null) {
if ((simulatedCurrency.equalsIgnoreCase(ordercurrency))) {
evalResult = true;
}
}
}
else
{
if(this.currency!=null && this.currency.equalsIgnoreCase(ordercurrency)){
evalResult = true;
}
}

return evalResult;
}

}


Please make usre toXML is very important method, If this method is not implemented properly, Promtion engine wont create Custom Condition in Promotion Runtime Xml and hence custom condition wont be saved in px_promotion. So ensure this method returns complete custom condition xml.



Now you can target promotion to specific order currency.  You need to create new promotion, It wont effect already created promotions.

This approach can be used to add any other custom filters as well.

Hope it helps!