Loading
Salesforce B2B Commerce
Table of Contents
Select Filters

          No results
          No results
          Here are some search tips

          Check the spelling of your keywords.
          Use more general search terms.
          Select fewer filters to broaden your search.

          Search all of Salesforce Help
          Customize B2B Store Pricing with Apex Hooks

          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

          1. From Setup, in the Quick Find box, enter Apex, and select Apex Classes.
          2. Select New to create an Apex class.
          3. In the class editor, enter the class definition. See the sample classes for Apex hooks provided in this topic.
          4. 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.
          5. Select the procedure plan that you want to modify.
          6. In the Procedure Plan Sections area, click Add.
          7. Select Standard type.
          8. Enter a name for your section.
          9. For Section Type, select Apex.
          10. In the section details, set Phases to Pricing, Resolution Type to Default, and select the Apex class you created.
          11. Click Save.
          12. 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
          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;
              }
          }
           
          Loading
          Salesforce Help | Article