Olet tässä:
Toimenpidesuunnitelmiesi mukauttaminen Apex
Jos haluat tukea yksilöllisiä hinnoittelukenaarioita, lisää hinnoittelutoimenpidesuunnitelmiisi mukautettua Apex. Voit käyttää Apex käyttääksesi mukautettua liiketoimintalogiikkaa, joka muokkaa hinnoittelun kontekstia, kun tarjousrivi on määritetty. Käytä Apex säätääksesi hinnoittelua tuoteattribuuttien perusteella ennen hinnoittelua ja Apex käsitelläksesi ryhmien ja muiden Tarjous-objektin elementtien hintojen muutokset hinnoittelun jälkeen. Kun myyntiedustaja määrittää tuotteen tai muuttaa tarjouksen rivikohteiden ryhmää, hinnoittelutoimenpidesuunnitelma muuttaa hinnoittelua Apexin ohjeiden perusteella.
Vaaditut versiot
| Käytettävissä: Lightning Experiencessa |
| Käytettävissä: Revenue Cloudin Enterprise-, Unlimited- ja Developer Edition -versioissa, joissa on Salesforce Pricing käytössä |
| Tarvittavat käyttöoikeudet | |
|---|---|
| Hinnoittelutoimenpiteiden ja toimintasuunnitelmien luominen, päivittäminen ja poistaminen: | Salesforce Pricing Design Time -käyttäjän tai toimintasuunnitelman käyttöoikeus |
| Hinnoittelutoimenpiteiden käyttäminen: | Salesforce Pricing Run Time -käyttäjä |
| Apex-luokkien määrittäminen, muokkaaminen, poistaminen, suojauksen määrittäminen ja versioasetusten määrittäminen: | Apex-laadintaoikeus |
- Kun käytät Revenue Cloud -prosessityyppiä, kaikki lisäämäsi Apex täytyy olla toimintasuunnitelman suoritusjärjestyksen ensimmäinen tai viimeinen elementti.
- Ulkoisia callout-kutsuja tuetaan vain, kun Paikanna myyntitapahtuma -pyyntö käynnistyy Salesforce-käyttöliittymän tai Place Sales Transaction API:n kautta. Niitä ei tueta, kun pyyntö käynnistetään Apexista tai kulusta.
- Apex ulkoisia kutsuja ei tueta, kun Kaksinkertainen pysyvä -tila on käytössä. Saat lisätietoja ottamalla yhteyttä Salesforce-asiakastukeen.
- Ulkoiset Apex voivat vaikuttaa suorituskykyyn. Ennustettavia palvelutasojen tavoitteita (SLO) ei siis voida taata.
-
Varmista, että Toimenpidesuunnitelman orkestrointi hinnoittelulle on käytössä.
- Kirjoita Määritykset-valikon Pikahaku-kenttään Tuottoasetukset ja valitse Tuottoasetukset.
- Etsi ja ota tarvittaessa käyttöön Toimenpidesuunnitelman orkestrointi hinnoittelua varten -asetus.
- Jätä Poista oletusarvoiset ja myyntitapahtumatyyppien hinnoittelutoimenpiteet pois käytöstä -asetus pois käytöstä.
-
Määritä hinnoittelutoimenpiteisiisi lisättävät Apex.
- Kirjoita Määritykset-valikon Pikahaku-kenttään Apex ja valitse Apex-luokat.
- Valitse Luo uusi Apex-luokka valitsemalla Uusi.
-
Syötä luokan määritelmä luokkaeditoriin.
Esimerkiksi tämä etuliite (ApexDmAttributePreHook) päivittää dynaamisten attribuuttien arvot nimellä
Display_Sizeniiden näyttön koon perusteella. Muita esimerkkiluokkia näytetään näiden vaiheiden lopussa olevissa Apex esimerkkiluokissa.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; } } - Tallenna luokan määritelmä.
- Kirjoita Määritykset-valikon Pikahaku-kenttään Toimenpidesuunnitelma ja valitse Toimenpidesuunnitelman määritelmät.
- Valitse määritelmän nimet -sarakkeesta toimintasuunnitelman määritelmä, jota haluat muokata.
-
Valitse toimintasuunnitelman määritelmästä Toimintasuunnitelman osiot -osiosta Lisää lisätäksesi uuden osion.
- Valitse Vakio.
- Anna osiolle nimi, esimerkiksi Apex-esikatselun nimeksi Apex.
- Valitse Osion tyyppi -osiosta Apex ja sitten Tallenna.
- Laajenna uusi osio.
- Valitse Vaiheet-asetukseksi Hinnasto ja Ratkaisutyyppi-asetukseksi Oletus.
- Kirjoita avautuvassa Apex-valintaruudussa yllä määrittämäsi Apex-luokka, esimerkiksi ApexDmlAttributePreHook, ja valitse sitten Tallenna.
- Lisää enemmän etuliitoksia ja jälkiliitoksia tarvittaessa.
- Valitse Osioiden hallinta muuttaaksesi hinnoittelutoimenpide-osion yläpuolella ja sen alapuolella olevien kohteiden järjestystä.
- Tallenna toimintasuunnitelman määritelmään tekemäsi muutokset.
Prehook: Päivitä alennusprosenttiksi 2 % kaikille asiayhteydessä oleville riveille (esimerkiksi tarjousriville).
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: Kutsu ulkoista resurssia noutaaksesi määrän arvon.
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: Käynnistä tuotteen hintaan päivitys, jos sen attribuutin nimi on Näytä ja sen attribuutin arvo on 1080p sisäänrakennettu näyttö tai jos sen attribuutin nimi on Tulostin ja sen attribuutin arvo on Laseri.
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: Käytä satunnaista alennusprosenttia kaikille riville asiayhteydessä.
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: Päivitä dynaaminen attribuutin arvo satunnaisella arvolla callout-kutsusta ulkoiseen resurssiin.
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: Päivitä kunkin rivin kuvaus asiayhteydessä.
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;
}
}
