Loading
Aprender
Índice de materias
Seleccionar filtros

          No hay resultados
          No hay resultados
          Estas son algunas sugerencias de búsqueda

          Compruebe la ortografía de sus palabras clave.
          Utilice términos de búsqueda más generales.
          Seleccione menos filtros para ampliar su búsqueda.

          Buscar en toda la Ayuda de Salesforce
          Personalizar sus planes de procedimientos con ganchos Apex

          Personalizar sus planes de procedimientos con ganchos Apex

          Para admitir escenarios de precios exclusivos, agregue lógica Apex personalizada a sus planes de procedimientos de precios. Puede utilizar ganchos Apex para aplicar lógica de negocio personalizada que modifica el contexto de precios después de configurar una partida de presupuesto. Utilice un preenganche Apex para ajustar los precios en función de los atributos del producto antes de que se aplique el precio, y un postenganche Apex para gestionar los cambios de precios para grupos y otros elementos del objeto Presupuesto después de aplicar el precio. Cuando un representante de ventas configura un producto o cambia un grupo de partidas de presupuesto, el plan de procedimiento de precios cambia el precio basándose en las instrucciones en Apex.

          Ediciones necesarias

          Disponible en: Lightning Experience
          Disponible en: Ediciones Enterprise, Unlimited y Developer de Revenue Cloud donde Precios de Salesforce está activada
          Permisos de usuario necesarios
          Para crear, actualizar y eliminar procedimientos de precios y planes de procedimientos: Acceso de usuario de tiempo de diseño de precios de Salesforce o plan de procedimiento
          Para utilizar procedimientos de precios: Usuario de tiempo de ejecución de precios de Salesforce
          Para definir, modificar , eliminar, definir seguridad y establecer la configuración de la versión para clases de Apex: Apex de autor
          Importante
          Importante
          • Cuando utilice el tipo de proceso Revenue Cloud, cualquier lógica Apex que agregue debe ser el primer o último elemento en la secuencia de ejecución del Plan de procedimiento.
          • Las llamadas externas desde un gancho Apex solo se admiten cuando la solicitud Realizar transacción de ventas se desencadena a través de la interfaz de usuario de Salesforce o la API de Realizar transacción de ventas. No se admiten cuando la solicitud se desencadena desde Apex o Flow.
          • Las llamadas externas en ganchos Apex no son compatibles cuando el modo Persistir doble está activado. Para obtener orientación adicional, haga contacto con el Servicio de atención al cliente de Salesforce.
          • Las llamadas externas en ganchos Apex pueden afectar al desempeño. Por lo tanto, no se pueden garantizar los Objetivos de nivel de servicio (SLO) predecibles.
          1. Asegúrese de que Orquestación de planes de procedimientos para precios está activada.
            1. Desde Configuración, en el cuadro Búsqueda rápida, ingrese Configuración de ingresos y, a continuación, seleccione Configuración de ingresos.
            2. Busque y, si es necesario, active el parámetro Orquestación de plan de procedimiento para precios.
            3. Deje el parámetro Excluir procedimientos de precios de tipo transacción de ventas y predeterminado desactivado.
          2. Defina clases para los ganchos de Apex para agregar a sus procedimientos de precios.
            1. Desde Configuración, en el cuadro Búsqueda rápida, ingrese Apex y, a continuación, seleccione Clases Apex.
            2. Seleccione Nuevo para crear una nueva clase Apex.
            3. En el editor de clases, ingrese la definición de clase.

              Por ejemplo, este pregancho (ApexDmAttributePreHook) actualiza los valores de atributos dinámicos con el nombre Display_Size en base a su tamaño de visualización. Se muestran más clases de muestra en Clases de muestra para ganchos de precios Apex al final de estos pasos.

              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. Guarde la definición de clase.
          3. Desde Configuración, en el cuadro Búsqueda rápida, ingrese Plan de procedimiento y, a continuación, seleccione Definiciones de plan de procedimiento.
          4. En la columna Nombres de definición, seleccione una definición de plan de procedimiento para modificar.
          5. Desde la definición del plan de procedimiento, en Secciones de plan de procedimiento, seleccione Agregar para agregar una nueva sección.
            1. Seleccione Estándar.
            2. Asigne un nombre a la sección, por ejemplo Pre Apex para un preenganche de Apex.
            3. En Tipo de sección, seleccione Apex y Guardar.
            4. Amplíe la nueva sección.
            5. Para Fases, seleccione Precios y para Tipo de resolución seleccione Predeterminado.
            6. En el cuadro de selección Apex que aparece, ingrese la clase Apex que definió anteriormente, por ejemplo ApexDmlAttributePreHook, luego seleccione Guardar.
            7. Agregue ganchos previos y ganchos posteriores adicionales según sea necesario.
          6. Seleccione Gestionar secciones para reorganizar los preganchos por encima de la sección Procedimiento de precios y los postganchos por debajo de ella.
          7. Guarde sus cambios en la definición de Plan de procedimiento.
          Ejemplo
          Ejemplo Clases de muestra para ganchos de precios Apex

          Preenganche: Actualice el porcentaje de descuento al 2% en todas las partidas en el contexto (por ejemplo, partidas de presupuesto).

          
          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;
              }
          }

          Preenganche: Llame a un recurso externo para obtener un valor de cantidad.

          
          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;
              }
          }

          Preenganche: Desencadene una actualización del precio de un producto si su Nombre de atributo es Visualización y su Valor de atributo es Visualización integrada 1080p, o si su Nombre de atributo es Impresora y su Valor de atributo es Láser.

          
          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;
              }
              
          }
          
          

          Preenganche: Aplique un porcentaje de descuento aleatorio para todas las partidas en el contexto.

          
          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;
              }
          
          }

          Preenganche: Actualice un valor de atributo dinámico con valor aleatorio desde una llamada a un recurso externo.

          
          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;
              }
          }

          Posthook: Actualice la descripción de cada partida en el contexto.

          
          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;
              }
          }
           
          Cargando
          Salesforce Help | Article