Loading
Salesforce から送信されるメールは、承認済ドメインからのみとなります続きを読む
学習
目次
絞り込み条件を選択

          結果がありません
          結果がありません
          検索のヒントをいくつかご紹介します

          キーワードの入力ミスがないか確認する。
          より一般的な検索語を使用する。
          絞り込み条件を減らして、検索範囲を広げる。

          Salesforce ヘルプ全体を検索
          Apex フックを使用した処置計画のカスタマイズ

          Apex フックを使用した処置計画のカスタマイズ

          独自の価格設定シナリオをサポートするには、カスタムApexロジックを価格設定手順プランに追加します。Apex フックを使用して、見積品目の設定後に価格設定コンテキストを変更するカスタムビジネスロジックを適用できます。Apex 事前フックを使用して、価格設定前の商品属性に基づいて価格設定を調整し、Apex 後フックを使用して、価格設定後のグループおよびその他の見積オブジェクト要素の価格設定の変更を処理します。営業担当が商品を設定するか、見積品目のグループを変更すると、価格設定手順プランにより Apex の手順に基づいて価格が変更されます。

          必要なエディション

          使用可能なインターフェース: Lightning Experience
          使用可能なエディション: Revenue Cloud の Enterprise Edition、Unlimited Edition、および Developer Edition (Salesforce 価格設定が有効)
          必要なユーザー権限
          価格設定手順および手順プランを作成、更新、削除する Salesforce 価格設定設計時ユーザーまたは手順プランアクセス権
          価格設定手順を使用する Salesforce 価格設定ランタイムユーザー
          Apex クラスの定義、編集、削除、セキュリティの設定、およびバージョンの設定を行う 「Apex 開発」
          重要
          重要
          • Revenue Cloud プロセス種別を使用する場合、追加する Apex ロジックは、プロシージャプラン実行シーケンスの最初または最後の要素である必要があります。
          • Apex フックからの外部コールアウトは、Salesforce ユーザー インターフェイスまたは Place Sales Transaction API を介して Place Sales Transaction 要求がトリガーされる場合にのみサポートされます。要求が Apex またはフローからトリガーされた場合はサポートされていません。
          • 二重保持モードが有効になっている場合、Apexフックの外部コールアウトはサポートされません。詳細は、Salesforce カスタマーサポートにお問い合わせください。
          • Apex フックの外部コールアウトは、パフォーマンスに影響する可能性があります。そのため、予測可能なサービスレベル目標 (SLO) を保証することはできません。
          1. [Procedure Plan Orchestration for Pricing (価格設定の手順プランオーケストレーション)] が有効になっていることを確認します。
            1. [設定] から、[クイック検索] ボックスに「収益設定」と入力し、[収益設定] を選択します。
            2. [Procedure Plan Orchestration for Pricing (価格設定の手順プランオーケストレーション)] を見つけて、必要に応じて有効にします。
            3. [デフォルトと販売トランザクション種別の価格設定手順を除外] の設定は無効のままにします。
          2. 価格設定手順に追加する Apex フックのクラスを定義します。
            1. [設定] から、[クイック検索] ボックスに「Apex」と入力し、[Apex クラス] を選択します。
            2. [新規] を選択して、新しい Apex クラスを作成します。
            3. クラスエディターで、クラス定義を入力します。

              たとえば、次の事前フック(ApexDmAttributePreHook)は、表示サイズに基づいて名前 Display_Size を持つ動的属性の値を更新します。その他のサンプル クラスについては、この手順の最後にある「Apex 価格設定フックのサンプル クラス」を参照してください。

              global class ApexDmlAttributePreHook implements RevSignaling.SignalingApexProcessor {
              
                  public virtual class BaseException extends Exception {}
                  public class OtherException extends BaseException {}
                  public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
                      System.debug('Executing PREHOOK');
                      
                      String contextId = request.ctxInstanceId;
                      Context.IndustriesContext industriesContext = new Context.IndustriesContext();
                      
                      // STEP 1 - Query SalesTransactionItemAttribute and extract Display_Size values
                      Map<String, Object> inputQueryItemAttr = new Map<String, Object>{
                          'contextId' => contextId,
                          'tags' => new List<String>{ 'SalesTransactionItemAttribute' }
                      };
                      Map<String, Object> itemAttrQueryOutput = industriesContext.queryTags(inputQueryItemAttr);
                      Map<String, Object> itemAttrQueryResult = (Map<String, Object>) itemAttrQueryOutput.get('queryResult');
                      List<Object> itemAttrData = (List<Object>) itemAttrQueryResult.get('SalesTransactionItemAttribute');
              
                      Map<String, Decimal> parentCtxIdToDisplaySize = new Map<String, Decimal>();
              
                      for (Object attrObj : itemAttrData) {
                          Map<String, Object> attrNode = (Map<String, Object>) attrObj;
                          Map<String, Object> tagMap = (Map<String, Object>) attrNode.get('tagValue');
              
                          String attributeName = null;
                          String attributeValueStr = null;
                          String parentCtxId = null;
              
                          if (tagMap.containsKey('Attribute')) {
                              attributeName = (String)((Map<String, Object>) tagMap.get('Attribute')).get('tagValue');
                          }
                          if (tagMap.containsKey('AttributeValue')) {
                              attributeValueStr = (String)((Map<String, Object>) tagMap.get('AttributeValue')).get('tagValue');
                          }
                          if (tagMap.containsKey('SalesTransactionItemAttrParent')) {
                              parentCtxId = (String)((Map<String, Object>) tagMap.get('SalesTransactionItemAttrParent')).get('tagValue');
                          }
              
                          if (attributeName == 'Display_Size' && attributeValueStr != null && parentCtxId != null) {
                              Decimal sizeValue = Decimal.valueOf(attributeValueStr.split(' ')[0]);
                              parentCtxIdToDisplaySize.put(parentCtxId, sizeValue);
                              System.debug('DisplaySize=' + sizeValue);
                              System.debug('Matched itemCtxId=' + parentCtxId);
                          }
                      }
              
                      // STEP 2 - 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 3 - 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');
                          System.debug('Full item dataPath: ' + JSON.serialize(dataPath));
              
                          Boolean matched = false;
                          for (String ctxKey : parentCtxIdToDisplaySize.keySet()) {
                              if (dataPath.contains(ctxKey)) {
                                  Decimal newPrice = parentCtxIdToDisplaySize.get(ctxKey);
                                  System.debug('DisplaySize match found for item ' + ctxKey);
                                  dataPath.remove(0); // Remove contextId
              
                                  itemNodeUpdates.add(new Map<String, Object>{
                                      'nodePath' => new Map<String, Object>{ 'dataPath' => dataPath },
                                      'attributes' => new List<Object>{
                                          new Map<String, Object>{
                                              'attributeName' => 'UnitPrice',
                                              'attributeValue' => newPrice
                                          }
                                      }
                                  });
                                  matched = true;
                                  break;
                              }
                          }
              
                          if (!matched) {
                              String itemCtxId = dataPath.size() > 1 ? String.valueOf(dataPath[1]) : 'UNKNOWN';
                              System.debug('No DisplaySize match found for item ' + itemCtxId);
                          }
                      }
              
                      // STEP 4 - 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;
                      //response.status = RevSignaling.TransactionStatus.FAILED;
                      //response.message = 'An error occurred during the processing...';
                      return response;
                  }
                  
              }
            4. クラス定義を保存します。
          3. [設定] から、[クイック検索] ボックスに「処置プラン」と入力し、[処置プラン定義] を選択します。
          4. [定義名] 列で、編集する処置プラン定義を選択します。
          5. 処置プラン定義の [処置プランセクション] で、[追加] を選択して新しいセクションを追加します。
            1. [標準] を選択します。
            2. セクションに「 PreApex for an Apex 」 (Apex 事前フックの Apex など) という名前を付けます。
            3. [セクション種別] で、[Apex]、[保存] の順に選択します。
            4. 新しいセクションを展開します。
            5. [フェーズ] で [価格設定] を選択し、[解決種別] で [デフォルト] を選択します。
            6. 表示される Apex 選択ボックスに、前に定義した Apex クラス (ApexDmlAttributePreHook など) を入力し、[保存] を選択します。
            7. 必要に応じて、追加の事前フックと事後フックを追加します。
          6. [Pricing Procedure (価格設定手順)] セクションの上に事前フックを、その下に後フックを並び替えるには、[セクションを管理] を選択します。
          7. 処置プラン定義への変更を保存します。
          例
          Apex 価格設定フックのサンプルクラス

          事前フック: コンテキストのすべての品目 (見積品目など) で割引率を 2% に更新します。

          
          global class ApexDmlDiscountUpdatePreHook implements RevSignaling.SignalingApexProcessor {
          
              public virtual class BaseException extends Exception {}
              public class OtherException extends BaseException {}
              
              public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
                  System.debug('Executing PREHOOK');
                  
                  String contextId = request.ctxInstanceId;
                  Context.IndustriesContext industriesContext = new Context.IndustriesContext();
                  
                  Integer randomDiscountPercentage = 2;
          
                  // STEP 2 - 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');
          
                  System.debug('QLI itemData=' + itemData);
          
                  // STEP 3 - 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');
                      System.debug('Full item dataPath: ' + JSON.serialize(dataPath));
          
                      Boolean matched = false;
                      dataPath.remove(0); // Remove contextId
          
                      itemNodeUpdates.add(new Map<String, Object>{
                          'nodePath' => new Map<String, Object>{ 'dataPath' => dataPath },
                          'attributes' => new List<Object>{
                              new Map<String, Object>{
                                  'attributeName' => 'Discount',
                                  'attributeValue' => randomDiscountPercentage
                              }
                          }
                      });
                      matched = true;
          
                      if (!matched) {
                          String itemCtxId = dataPath.size() > 1 ? String.valueOf(dataPath[1]) : 'UNKNOWN';
                          System.debug('No DisplaySize match found for item ' + itemCtxId);
                      }
                  }
          
                  // STEP 4 - 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;
                  //response.status = RevSignaling.TransactionStatus.FAILED;
                  //response.message = 'An error occurred during the processing...';
                  return response;
              }
          }

          事前フック: 外部リソースをコールして数量値を取得します。

          
          global class ApexDmlQuantityCalloutPreHook implements RevSignaling.SignalingApexProcessor {
          
              public virtual class BaseException extends Exception {}
              public class OtherException extends BaseException {}
              
              public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
                  System.debug('Executing PREHOOK');
                  
                  String contextId = request.ctxInstanceId;
                  Context.IndustriesContext industriesContext = new Context.IndustriesContext();
                  
                  // STEP 1 - External Callout Test
                  Integer randomNumber = getRandomNumber();
                  System.debug(' Random Number from API: ' + randomNumber);
          
                  // STEP 2 - 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');
          
                  System.debug('QLI itemData=' + itemData);
          
                  // STEP 3 - 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');
                      System.debug('Full item dataPath: ' + JSON.serialize(dataPath));
          
                      Boolean matched = false;
                      dataPath.remove(0); // Remove contextId
              
                      itemNodeUpdates.add(new Map<String, Object>{
                          'nodePath' => new Map<String, Object>{ 'dataPath' => dataPath },
                          'attributes' => new List<Object>{
                              new Map<String, Object>{
                                  'attributeName' => 'Quantity',
                                  'attributeValue' => randomNumber
                              }
                          }
                      });
                      matched = true;
          
                      if (!matched) {
                          String itemCtxId = dataPath.size() > 1 ? String.valueOf(dataPath[1]) : 'UNKNOWN';
                          System.debug('No DisplaySize match found for item ' + itemCtxId);
                      }
                  }
          
                  // STEP 4 - 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;
                  //response.status = RevSignaling.TransactionStatus.FAILED;
                  //response.message = 'An error occurred during the processing...';
                  return response;
              }
              
              // External callout
              private Integer getRandomNumber() {
                  String endpoint = 'https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain&rnd=new';
                  Http http = new Http();
                  HttpRequest req = new HttpRequest();
                  req.setEndpoint(endpoint);
                  req.setMethod('GET');
                  req.setTimeout(5000);
          
                  try {
                      HttpResponse res = http.send(req);
                      if (res.getStatusCode() == 200) {
                          System.debug('Fetched prices from external service');
                          return Integer.valueOf(res.getBody().trim());
                      } else {
                          System.debug(' Callout failed: ' + res.getStatus());
                      }
                  } catch (Exception ex) {
                      System.debug(' Exception during callout: ' + ex.getMessage());
                  }
                  return 10;
              }
          }

          事前フック: [属性名] が [Display] で [属性値] が [1080p Built-in Display] の場合、または [属性名] が [Printer] で [属性値] が [Laser] の場合、商品の価格の更新をトリガーします。

          
          global class ApexDmlMultiAttributePreHook implements RevSignaling.SignalingApexProcessor {
          
              public virtual class BaseException extends Exception {}
              public class OtherException extends BaseException {}
              public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
                  System.debug('Executing PREHOOK');
                  
                  String contextId = request.ctxInstanceId;
                  Context.IndustriesContext industriesContext = new Context.IndustriesContext();
                  
                  // STEP 1 - Query SalesTransactionItemAttribute and extract Display_Size values
                  Map<String, Object> inputQueryItemAttr = new Map<String, Object>{
                      'contextId' => contextId,
                      'tags' => new List<String>{ 'SalesTransactionItemAttribute' }
                  };
                  Map<String, Object> itemAttrQueryOutput = industriesContext.queryTags(inputQueryItemAttr);
                  Map<String, Object> itemAttrQueryResult = (Map<String, Object>) itemAttrQueryOutput.get('queryResult');
                  List<Object> itemAttrData = (List<Object>) itemAttrQueryResult.get('SalesTransactionItemAttribute');
          
                  Map<String, Decimal> parentCtxIdToAttribute = new Map<String, Decimal>();
          
                  for (Object attrObj : itemAttrData) {
                      Map<String, Object> attrNode = (Map<String, Object>) attrObj;
                      Map<String, Object> tagMap = (Map<String, Object>) attrNode.get('tagValue');
          
                      String attributeName = null;
                      String attributeValueStr = null;
                      String parentCtxId = null;
          
                      System.debug('TagMap ' + tagMap);
                      if (tagMap.containsKey('Attribute')) {
                          attributeName = (String)((Map<String, Object>) tagMap.get('Attribute')).get('tagValue');
                      }
                      if (tagMap.containsKey('AttributeValue')) {
                          attributeValueStr = (String)((Map<String, Object>) tagMap.get('AttributeValue')).get('tagValue');
                      }
                      if (tagMap.containsKey('SalesTransactionItemAttrParent')) {
                          parentCtxId = (String)((Map<String, Object>) tagMap.get('SalesTransactionItemAttrParent')).get('tagValue');
                      }
                      
                      if (attributeName == 'Display' && attributeValueStr == '1080p Built-in Display' && parentCtxId != null) {
                         Decimal defaultDisplayCost = 1000.00;
                         parentCtxIdToAttribute.put(parentCtxId, defaultDisplayCost);
                         System.debug('Display=' + defaultDisplayCost);
                         System.debug('Matched itemCtxId=' + parentCtxId);
                      }
                      
                      if (attributeName == 'Printer' && attributeValueStr == 'Laser' && parentCtxId != null) {
                         Decimal defaultLaserPrinterCost = 500.00;
                         parentCtxIdToAttribute.put(parentCtxId, defaultLaserPrinterCost);
                         System.debug('Printer=' + defaultLaserPrinterCost);
                         System.debug('Matched itemCtxId=' + parentCtxId);
                      }
                  }
          
                  // STEP 2 - 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 3 - 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');
                      System.debug('Full item dataPath: ' + JSON.serialize(dataPath));
          
                      Boolean matched = false;
                      for (String ctxKey : parentCtxIdToAttribute.keySet()) {
                          if (dataPath.contains(ctxKey)) {
                              Decimal newPrice = parentCtxIdToAttribute.get(ctxKey);
                              System.debug('Attribute match found for item ' + ctxKey);
                              System.debug('Attribue with new price ' + newPrice);
                              dataPath.remove(0); // Remove contextId
          
                              itemNodeUpdates.add(new Map<String, Object>{
                                  'nodePath' => new Map<String, Object>{ 'dataPath' => dataPath },
                                  'attributes' => new List<Object>{
                                      new Map<String, Object>{
                                          'attributeName' => 'UnitPrice',
                                          'attributeValue' => newPrice
                                      }
                                  }
                              });
                              matched = true;
                              break;
                          }
                      }
          
                      if (!matched) {
                          String itemCtxId = dataPath.size() > 1 ? String.valueOf(dataPath[1]) : 'UNKNOWN';
                          System.debug('No DisplaySize match found for item ' + itemCtxId);
                      }
                  }
          
                  // STEP 4 - 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;
                  //response.status = RevSignaling.TransactionStatus.FAILED;
                  //response.message = 'An error occurred during the processing...';
                  return response;
              }
              
          }
          
          

          事前フック: コンテキストのすべての品目にランダムな割引率を適用します。

          
          global class ApexDmlRandomDiscountPreHook implements RevSignaling.SignalingApexProcessor {
          
              public virtual class BaseException extends Exception {}
              public class OtherException extends BaseException {}
              
              public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
                  System.debug('Executing PREHOOK');
                  
                  String contextId = request.ctxInstanceId;
                  Context.IndustriesContext industriesContext = new Context.IndustriesContext();
                  
                  Integer randomDiscountPercentage = getRandomNumber();
          
                  // STEP 2 - 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');
          
                  System.debug('QLI itemData=' + itemData);
          
                  // STEP 3 - 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');
                      System.debug('Full item dataPath: ' + JSON.serialize(dataPath));
          
                      Boolean matched = false;
                      dataPath.remove(0); // Remove contextId
          
                      itemNodeUpdates.add(new Map<String, Object>{
                          'nodePath' => new Map<String, Object>{ 'dataPath' => dataPath },
                          'attributes' => new List<Object>{
                              new Map<String, Object>{
                                  'attributeName' => 'Discount',
                                  'attributeValue' => randomDiscountPercentage
                              }
                          }
                      });
                      matched = true;
          
                      if (!matched) {
                          String itemCtxId = dataPath.size() > 1 ? String.valueOf(dataPath[1]) : 'UNKNOWN';
                          System.debug('No DisplaySize match found for item ' + itemCtxId);
                      }
                  }
          
                  // STEP 4 - 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;
                  //response.status = RevSignaling.TransactionStatus.FAILED;
                  //response.message = 'An error occurred during the processing...';
                  return response;
              }
                  // External callout
              public static Integer getRandomNumber() {
                  String endpoint = 'https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain&rnd=new';
                  Http http = new Http();
                  HttpRequest req = new HttpRequest();
                  req.setEndpoint(endpoint);
                  req.setMethod('GET');
                  req.setTimeout(5000);
          
                  try {
                      HttpResponse res = http.send(req);
                      if (res.getStatusCode() == 200) {
                          System.debug('Fetched prices from external service');
                          return Integer.valueOf(res.getBody().trim());
                      } else {
                          System.debug(' Callout failed: ' + res.getStatus());
                      }
                  } catch (Exception ex) {
                      System.debug(' Exception during callout: ' + ex.getMessage());
                  }
                  return 10;
              }
          
          }

          事前フック: 外部リソースへのコールアウトからランダムな値を使用して動的属性値を更新します。

          
          global class ApexDmlAttributeExternalCalloutPreHook implements RevSignaling.SignalingApexProcessor {
          
              public virtual class BaseException extends Exception {}
              public class OtherException extends BaseException {}
              public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
                  System.debug('Executing PREHOOK');
                  
                  String contextId = request.ctxInstanceId;
                  Context.IndustriesContext industriesContext = new Context.IndustriesContext();
                  
                  // STEP 1 - Query SalesTransactionItemAttribute and extract Display_Size values
                  Map<String, Object> inputQueryItemAttr = new Map<String, Object>{
                      'contextId' => contextId,
                      'tags' => new List<String>{ 'SalesTransactionItemAttribute' }
                  };
                  Map<String, Object> itemAttrQueryOutput = industriesContext.queryTags(inputQueryItemAttr);
                  Map<String, Object> itemAttrQueryResult = (Map<String, Object>) itemAttrQueryOutput.get('queryResult');
                  List<Object> itemAttrData = (List<Object>) itemAttrQueryResult.get('SalesTransactionItemAttribute');
          
                  Map<String, Decimal> parentCtxIdToDisplaySize = new Map<String, Decimal>();
          
                  for (Object attrObj : itemAttrData) {
                      Map<String, Object> attrNode = (Map<String, Object>) attrObj;
                      Map<String, Object> tagMap = (Map<String, Object>) attrNode.get('tagValue');
          
                      String attributeName = null;
                      String attributeValueStr = null;
                      String parentCtxId = null;
          
                      if (tagMap.containsKey('Attribute')) {
                          attributeName = (String)((Map<String, Object>) tagMap.get('Attribute')).get('tagValue');
                      }
                      if (tagMap.containsKey('AttributeValue')) {
                          attributeValueStr = (String)((Map<String, Object>) tagMap.get('AttributeValue')).get('tagValue');
                      }
                      if (tagMap.containsKey('SalesTransactionItemAttrParent')) {
                          parentCtxId = (String)((Map<String, Object>) tagMap.get('SalesTransactionItemAttrParent')).get('tagValue');
                      }
          
                      if (attributeName == 'Display_Size' && attributeValueStr != null && parentCtxId != null) {
                          Decimal sizeValue = getRandomNumber();
                          parentCtxIdToDisplaySize.put(parentCtxId, sizeValue);
                          System.debug('DisplaySize=' + sizeValue);
                          System.debug('Matched itemCtxId=' + parentCtxId);
                      }
                  }
          
                  // STEP 2 - 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 3 - 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');
                      System.debug('Full item dataPath: ' + JSON.serialize(dataPath));
          
                      Boolean matched = false;
                      for (String ctxKey : parentCtxIdToDisplaySize.keySet()) {
                          if (dataPath.contains(ctxKey)) {
                              Decimal newPrice = parentCtxIdToDisplaySize.get(ctxKey);
                              System.debug('DisplaySize match found for item ' + ctxKey);
                              dataPath.remove(0); // Remove contextId
          
                              itemNodeUpdates.add(new Map<String, Object>{
                                  'nodePath' => new Map<String, Object>{ 'dataPath' => dataPath },
                                  'attributes' => new List<Object>{
                                      new Map<String, Object>{
                                          'attributeName' => 'UnitPrice',
                                          'attributeValue' => newPrice
                                      }
                                  }
                              });
                              matched = true;
                              break;
                          }
                      }
          
                      if (!matched) {
                          String itemCtxId = dataPath.size() > 1 ? String.valueOf(dataPath[1]) : 'UNKNOWN';
                          System.debug('No DisplaySize match found for item ' + itemCtxId);
                      }
                  }
          
                  // STEP 4 - 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;
                  //response.status = RevSignaling.TransactionStatus.FAILED;
                  //response.message = 'An error occurred during the processing...';
                  return response;
              }
              
                  // External callout
              private Integer getRandomNumber() {
                  String endpoint = 'https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain&rnd=new';
                  Http http = new Http();
                  HttpRequest req = new HttpRequest();
                  req.setEndpoint(endpoint);
                  req.setMethod('GET');
                  req.setTimeout(5000);
          
                  try {
                      HttpResponse res = http.send(req);
                      if (res.getStatusCode() == 200) {
                          System.debug('Fetched prices from external service');
                          return Integer.valueOf(res.getBody().trim());
                      } else {
                          System.debug(' Callout failed: ' + res.getStatus());
                      }
                  } catch (Exception ex) {
                      System.debug(' Exception during callout: ' + ex.getMessage());
                  }
                  return 10;
              }
          }

          ポストフック: コンテキスト内の各行の説明を更新します。

          
          global class ApexDmlDescriptionPostHook implements RevSignaling.SignalingApexProcessor {
          
              public virtual class BaseException extends Exception {}
              public class OtherException extends BaseException {}
              
              public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
                  System.debug('Executing POSTHOOK');
                  
                  String contextId = request.ctxInstanceId;
                  Context.IndustriesContext industriesContext = new Context.IndustriesContext();
                  
                  String randomDescription = 'via Post Apex Pricing Hook';
          
                  // STEP 2 - 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');
          
                  System.debug('QLI itemData=' + itemData);
          
                  // STEP 3 - 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');
                      System.debug('Full item dataPath: ' + JSON.serialize(dataPath));
          
                      Boolean matched = false;
                      dataPath.remove(0); // Remove contextId
          
                      itemNodeUpdates.add(new Map<String, Object>{
                          'nodePath' => new Map<String, Object>{ 'dataPath' => dataPath },
                          'attributes' => new List<Object>{
                              new Map<String, Object>{
                                  'attributeName' => 'SalesTrxnItemDescription',
                                  'attributeValue' => randomDescription
                              }
                          }
                      });
                      matched = true;
          
                      if (!matched) {
                          String itemCtxId = dataPath.size() > 1 ? String.valueOf(dataPath[1]) : 'UNKNOWN';
                          System.debug('No DisplaySize match found for item ' + itemCtxId);
                      }
                  }
          
                  // STEP 4 - 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;
                  //response.status = RevSignaling.TransactionStatus.FAILED;
                  //response.message = 'An error occurred during the processing...';
                  return response;
              }
          }
           
          読み込み中
          Salesforce Help | Article