Du er her:
Tilpasse prosedyreplaner med Apex Hooks
For å støtte unike prisscenarier legger du til tilpasset Apex i prisprosedyreplanene. Du kan bruke Apex til å bruke tilpasset forretningslogikk som endrer priskonteksten etter at en tilbudslinje har blitt konfigurert. Bruk en Apex prehook til å justere pris basert på produktattributter før den prises, og en Apex posthook til å håndtere prisendringer for grupper og andre Tilbud-objektelementer etter prising. Når en selger konfigurerer et produkt eller endrer en gruppe tilbudslinjer, endrer prisprosedyreplanen prisen basert på instruksjonene i Apex.
Nødvendige utgaver
| Tilgjengelig i Lightning Experience |
| Tilgjengelig i Enterprise, Unlimited og Developer Edition i Revenue Cloud der Salesforce Pricing er aktivert |
| Nødvendige brukertillatelser | |
|---|---|
| For å opprette, oppdatere og slette prisprosedyrer og prosedyreplaner: | Tilgang til Salesforce Prissetting-tidsbruker eller prosedyreplan |
| For å bruke prisprosedyrer: | Salesforce Pricing Run Time-bruker |
| For å definere, redigere, slette, angi sikkerhet og angi versjonsinnstillinger for Apex-klasser: | Forfatter for Apex |
- Når du bruker Revenue Cloud, må eventuell Apex du legger til, være det første eller siste elementet i Prosedyreplan-utførelsessekvensen.
- Eksterne oppkall fra en Apex-krok støttes bare når forespørselen Plasser salgstransaksjon utløses via Salesforce-brukergrensesnittet eller Place Sales Transaction API. De støttes ikke når forespørselen utløses fra Apex eller Flyt.
- Eksterne oppkall i Apex støttes ikke når Double Persist-modus er aktivert. Kontakt Salesforces kundestøtte for å få mer veiledning.
- Eksterne oppkall i Apex kan påvirke ytelsen. Så forutsigbare tjenestenivåmål (SLO-er) kan ikke garanteres.
-
Forsikre deg om at Prosedyreplanorkestrering for prising er slått på.
- Skriv inn Omsetningsinnstillinger i Hurtigsøk-feltet i Oppsett, og velg deretter Omsetningsinnstillinger.
- Finn og aktiver om nødvendig innstillingen Prosedyreplanorkestrering for prising.
- La innstillingen Ekskluder standardpriser og prosedyrer for salgstransaksjonstype være deaktivert.
-
Definer klasser for Apex som skal legges til i prisprosedyrene.
- Skriv inn Apex i Hurtigsøk-feltet i Oppsett, og velg deretter Apex-klasser.
- Velg Ny for å opprette en ny Apex-klasse.
-
Skriv inn klassedefinisjonen i klasseredigeringen.
Denne prehook (ApexDmAttributePreHook) oppdaterer for eksempel verdiene for dynamiske attributter med navnet
Display_Sizebasert på visningsstørrelsen. Flere eksempelklasser vises i Eksempelklasser for Apex Pricing Hooks på slutten av disse trinnene.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; } } - Lagre klassedefinisjonen.
- Skriv inn Prosedyreplan i Hurtigsøk-feltet i Oppsett, og velg deretter Prosedyreplandefinisjoner.
- Velg en prosedyreplandefinisjon som skal redigeres, i kolonnen Definisjonsnavn.
-
Velg Legg til i delen Prosedyreplan i definisjonen av prosedyreplanen for å legge til en ny del.
- Velg Standard.
- Gi delen et navn, for eksempel Pre Apex for en Apex-forhåndshake.
- Velg Apex og deretter Lagre under Avsnittstype.
- Utvid den nye delen.
- Velg Pris for Faser, og velg Standard for Løsningstype.
- Skriv inn Apex-klassen du definerte ovenfor, for eksempel ApexDmlAttributePreHook, i Apex-valgboksen som vises, og velg deretter Lagre.
- Legg eventuelt til flere prehooks og posthooks.
- Velg Behandle deler for å omordne prehooks over Pricing Procedure-delen og posthooks under den.
- Lagre endringene i Prosedyreplan-definisjonen.
Prehook: Oppdater rabattprosenten til 2 % på alle linjer i konteksten (for eksempel tilbudslinjer).
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;
}
}Prehook: Kall opp en ekstern ressurs for å hente en mengdeverdi.
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;
}
}Prehook: Utløs en oppdatering av prisen for et produkt hvis attributtnavnet er Visning og attributtverdien er 1080p Innebygd visning, eller hvis attributtnavnet er Skriver og attributtverdien er 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;
}
}
Prehook: Bruk en tilfeldig rabattprosent for alle linjer i konteksten.
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;
}
}Prehook: Oppdater en dynamisk attributtverdi med en tilfeldig verdi fra et oppkall til en ekstern ressurs.
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 (Posthook): Oppdater beskrivelsen av hver linje i konteksten.
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;
}
}
