Loading
Salesforce에서 이메일을 보내기 위해서는 도메인 인증이 필요합니다.더 많이 읽기

How to assign a custom field’s value from quote line group to its related quote line items

게시 일자: Mar 11, 2026
상세 설명

In Revenue Cloud Advanced, when a quote line group is created on a quote, then it is a common use case to assign the value of a custom field from the quote line group to its related quote line items.

솔루션

This use case can be achieved in 2 ways - Pricing Procedure and Apex Hook.

Method 1 - Pricing Procedure

Step 1 - Create custom fields on the QuoteLineGroup and the QuoteLineItem objects (for eg., GroupPriority__c (text field) and ItemPriority__c (text field)).

Step 2 - Create custom attributes under the SalesTransactionGroup and the SalesTransactionItem nodes within the currently used extended sales transaction context definition (for eg., GroupPriority__c (input output, string attribute) and ItemPriority__c (input output, string attribute)). Make sure that the Transient checkbox is set to false for these attributes.

Step 3 - Give tags to the custom attributes (for eg., GroupPriority__c and ItemPriority__c) and map those to the custom fields within QuoteEntitiesMapping.

Step 4 - Create a custom attribute under the SalesTransactionItem node within the currently used extended sales transaction context definition (for eg., ItemGroupPriority__c (input output, string attribute)). Make sure that the Transient checkbox is set to false for this attribute.

Step 5 - Give the custom attribute a tag (for eg., ItemGroupPriority__c) and map it to the quote line group’s custom field via the QuoteLineItem object within QuoteEntitiesMapping.

Step 6 - Add a conditional assignment element within the currently used pricing procedure.

Step 7 - Add products to a quote and group them.

Step 8 - Update the group’s field and click on Save.

Step 9 - Click on Reprice All.

Note - This method requires the user to recalculate the quote (for eg., by clicking on Reprice All) because when the group’s field is populated from the editor, it is saved to the database after that pricing run is completed. Then, when the next pricing run is performed, the group’s field’s value is loaded from the database into the context.

Method 2 - Apex Hook

The following sample Apex prehook can be used to achieve this use case -

global class ApexPricingPrehook implements RevSignaling.SignalingApexProcessor {
public virtual class BaseException extends Exception {}
public class OtherException extends BaseException {}

public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
String ctxInstanceId = request.ctxInstanceId;
Context.IndustriesContext industriesContext = new Context.IndustriesContext();

//----------------------------------------------------------------------

List<String> tags = new List<String>();
tags.add('SalesTransactionItem');
tags.add('SalesTransactionGroup');

Map<String, Object> queryInput = new Map<String, Object>();
queryInput.put('contextId', ctxInstanceId);
queryInput.put('tags', tags);

Map<String, Object> queryOutput = industriesContext.queryTags(queryInput);
System.debug('queryOutput = ' + JSON.serializePretty(queryOutput));

Map<String, Object> queryResult = (Map<String, Object>) queryOutput.get('queryResult');

//----------------------------------------------------------------------

Map<String, String> groupsToPriorities = new Map<String, String>();

List<Object> groupData = (List<Object>) queryResult.get('SalesTransactionGroup');

for (Object groupObj : groupData) {
Map<String, Object> groupNode = (Map<String, Object>) groupObj;
Map<String, Object> groupTagMap = (Map<String, Object>) groupNode.get('tagValue');

String currentGroup = (String) ((Map<String, Object>) groupTagMap.get('GroupSource')).get('tagValue');
String currentGroupPriority = (String) ((Map<String, Object>) groupTagMap.get('GroupPriority__c')).get('tagValue');

groupsToPriorities.put(currentGroup, currentGroupPriority);
}

//----------------------------------------------------------------------

List<Map<String, Object>> nodePathAndAttributes = new List<Map<String, Object>>();

List<Object> itemData = (List<Object>) queryResult.get('SalesTransactionItem');

for (Object itemObj : itemData) {
Map<String, Object> itemNode = (Map<String, Object>) itemObj;
Map<String, Object> itemTagMap = (Map<String, Object>) itemNode.get('tagValue');

Object dmlStatus = ((Map<String, Object>) itemTagMap.get('LineItem')).get('dmlStatus');

if ((dmlStatus == null) || (String.valueOf(dmlStatus).equals('DELETED'))) {
continue;
}

String currentItem = (String) ((Map<String, Object>) itemTagMap.get('LineItem')).get('tagValue');
String currentItemGroup = (String) ((Map<String, Object>) itemTagMap.get('SalesTransactionItemGroup')).get('tagValue');

if (currentItemGroup != null) {
List<Map<String, Object>> attributes = new List<Map<String, Object>>();

Map<String, Object> priorityUpdate = new Map<String, Object>();
priorityUpdate.put('attributeName', 'ItemPriority__c');
priorityUpdate.put('attributeValue', groupsToPriorities.get(currentItemGroup));
attributes.add(priorityUpdate);

List<Object> dataPath = (List<Object>) itemNode.get('dataPath');
dataPath.remove(0);

Map<String, Object> contextDataPathInputRepresentation = new Map<String, Object>();
contextDataPathInputRepresentation.put('dataPath', dataPath);

Map<String, Object> nodePathAndAttributesInputRepresentation = new Map<String, Object>();
nodePathAndAttributesInputRepresentation.put('nodePath', contextDataPathInputRepresentation);
nodePathAndAttributesInputRepresentation.put('attributes', attributes);

nodePathAndAttributes.add(nodePathAndAttributesInputRepresentation);
}
}

//----------------------------------------------------------------------

Map<String, Object> input = new Map<String, Object>();

input.put('contextId', ctxInstanceId);
input.put('nodePathAndAttributes', nodePathAndAttributes);

Map<String, Object> res = industriesContext.updateContextAttributes(input);

//----------------------------------------------------------------------

RevSignaling.TransactionResponse response = new RevSignaling.TransactionResponse();
response.status = RevSignaling.TransactionStatus.SUCCESS;

return response;
}
}

Note - This method does NOT require the user to recalculate the quote (for eg., by clicking on Reprice All). This method works during the initial pricing run as well.

Additional note for both methods - If the user updates the group’s field outside of the sales transaction line editor, for eg., from the record detail page, then the quote will not be recalculated automatically, i.e. the line items’ field’s value will not be updated automatically. The user will need to recalculate the quote (for eg., by clicking on Reprice All, or via an automation).

Knowledge 기사 번호

005239173

 
로드 중
Salesforce Help | Article