You are here:
Customize B2B Store Pricing with Apex Hooks
To support unique pricing scenarios, add custom Apex logic to your pricing procedure plans. You can use Apex hooks to apply custom business logic that modifies the pricing context before or after your pricing procedure runs. Apex hooks are custom code that run at specific points in the pricing procedure plan.
Required Editions
-
From Setup, in the Quick Find box, enter
Apex, and select Apex Classes. - Select New to create an Apex class.
- In the class editor, enter the class definition. See the sample classes for Apex hooks provided in this topic.
-
After you create your Apex class, add it as an Apex section in your procedure
plan definition. From Setup, in the Quick Find box, enter
Procedure Plan Definitions, and select Procedure Plan Definitions. - Select the procedure plan that you want to modify.
- In the Procedure Plan Sections area, click Add.
- Select Standard type.
- Enter a name for your section.
- For Section Type, select Apex.
- In the section details, set Phases to Pricing, Resolution Type to Default, and select the Apex class you created.
- Click Save.
- If you added multiple sections, click Manage Sections. Drag the sections to set their exact execution order relative to your pricing procedure.
Sample Classes for Apex Hooks
Apex prehook: This example demonstrates an Apex prehook for attribute-driven pricing at the SalesTransactionItem node.
global class ApexDmlAttributePreHook implements RevSignaling.SignalingApexProcessor {
public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
System.debug('Executing PREHOOK');
String contextId = request.ctxInstanceId;
Context.IndustriesContext industriesContext = new Context.IndustriesContext();
// STEP 1 - Query SalesTransactionItem nodes
Map<String, Object> inputQueryItem = new Map<String, Object>{
'contextId' => contextId,
'tags' => new List<String>{ 'SalesTransactionItem' }
};
Map<String, Object> itemQueryOutput = industriesContext.queryTags(inputQueryItem);
Map<String, Object> itemQueryResult = (Map<String, Object>) itemQueryOutput.get('queryResult');
List<Object> itemData = (List<Object>) itemQueryResult.get('SalesTransactionItem');
// STEP 2 - Build update list for items with ProductName = 'Home Office Starter'
List<Map<String, Object>> itemNodeUpdates = new List<Map<String, Object>>();
for (Object itemObj : itemData) {
Map<String, Object> itemNode = (Map<String, Object>) itemObj;
Map<String, Object> tagMap = (Map<String, Object>) itemNode.get('tagValue');
List<Object> dataPath = (List<Object>) itemNode.get('dataPath');
String productName = null;
if (tagMap != null && tagMap.containsKey('ProductName')) {
productName = (String) ((Map<String, Object>) tagMap.get('ProductName')).get('tagValue');
}
if (productName == 'Home Office Starter') {
System.debug('Matched Home Office Starter item: ' + JSON.serialize(dataPath));
// Remove root contextId from dataPath
dataPath.remove(0);
itemNodeUpdates.add(new Map<String, Object>{
'nodePath' => new Map<String, Object>{
'dataPath' => dataPath
},
'attributes' => new List<Object>{
new Map<String, Object>{
'attributeName' => 'ProductCustom__c',
'attributeValue' => 'DISCOUNTAPPLICABLE'
}
}
});
}
}
// STEP 3 - Submit context update
if (!itemNodeUpdates.isEmpty()) {
Map<String, Object> updateInput = new Map<String, Object>{
'contextId' => contextId,
'nodePathAndAttributes' => itemNodeUpdates
};
System.debug('--- PREHOOK: SUBMITTING CONTEXT UPDATE ---');
System.debug(JSON.serializePretty(updateInput));
industriesContext.updateContextAttributes(updateInput);
}
RevSignaling.TransactionResponse response = new RevSignaling.TransactionResponse();
response.status = RevSignaling.TransactionStatus.SUCCESS;
return response;
}
}
Apex posthook: This example demonstrates an Apex posthook to validate and selectively override pricing attributes.
global class ApexDmlListPricePostHook implements RevSignaling.SignalingApexProcessor {
public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
System.debug('Executing POSTHOOK - Update ListPrice');
String contextId = request.ctxInstanceId;
Context.IndustriesContext industriesContext = new Context.IndustriesContext();
// STEP 1 - Query SalesTransactionItem nodes
Map<String, Object> inputQueryItem = new Map<String, Object>{
'contextId' => contextId,
'tags' => new List<String>{ 'SalesTransactionItem' }
};
Map<String, Object> itemQueryOutput = industriesContext.queryTags(inputQueryItem);
Map<String, Object> itemQueryResult = (Map<String, Object>) itemQueryOutput.get('queryResult');
List<Object> itemData = (List<Object>) itemQueryResult.get('SalesTransactionItem');
// STEP 2 - Build update list
List<Map<String, Object>> itemNodeUpdates = new List<Map<String, Object>>();
for (Object itemObj : itemData) {
Map<String, Object> itemNode = (Map<String, Object>) itemObj;
List<Object> dataPath = (List<Object>) itemNode.get('dataPath');
// Remove root contextId as required by updateContextAttributes
dataPath.remove(0);
itemNodeUpdates.add(new Map<String, Object>{
'nodePath' => new Map<String, Object>{
'dataPath' => dataPath
},
'attributes' => new List<Object>{
new Map<String, Object>{
'attributeName' => 'ListPrice',
'attributeValue' => 20.0
}
}
});
}
// STEP 3 - Submit context update
if (!itemNodeUpdates.isEmpty()) {
Map<String, Object> updateInput = new Map<String, Object>{
'contextId' => contextId,
'nodePathAndAttributes' => itemNodeUpdates
};
System.debug('--- POSTHOOK: SUBMITTING CONTEXT UPDATE ---');
System.debug(JSON.serializePretty(updateInput));
industriesContext.updateContextAttributes(updateInput);
}
RevSignaling.TransactionResponse response = new RevSignaling.TransactionResponse();
response.status = RevSignaling.TransactionStatus.SUCCESS;
return response;
}
}
Did this article solve your issue?
Let us know so we can improve!

