Loading
Ongoing maintenance for Salesforce HelpRead More
Table of Contents
Select Filters

          No results
          No results
          Here are some search tips

          Check the spelling of your keywords.
          Use more general search terms.
          Select fewer filters to broaden your search.

          Search all of Salesforce Help
          Create Custom Field and Define Apex Triggers

          Create Custom Field and Define Apex Triggers

          Create the necessary custom fields and define Apex triggers on the Quote Line Item and Order Product (OrderItem) objects.

          Required Editions

          Available in: Lightning Experience
          Available in: Enterprise, Performance, Unlimited, and Developer Editions of Revenue Cloud with the Revenue Cloud Growth license or the Revenue Cloud Advanced license

          Create the ConstraintEngineNodeStatus Custom Field

          Create a custom field on the Quote Line Item, Order Product, and Asset Action Source objects to store data that Constraint Rules Engine uses for internal processing.

          Go to the object management settings of these objects, and create a custom field with these values:

          1. Select Text Area (Long) as the data type.
          2. Enter Constraint Engine Node Status as the field label.
          3. Enter 131072 as the length.
          4. Enter ConstraintEngineNodeStatus as the field name.
          5. Select Visible access and deselect Read-Only access for the profiles of the users who'll use Constraint Rules Engine, and Customer Community and Partner Community users.
          6. Deselect the page layouts.

          Define Apex Triggers for Quote and Order Line Items

          Define triggers for the Quote Line Item and Order Product (OrderItem) objects by using Apex code.

          Use this Apex code for the Quote Line Item object.

          trigger QuoteItemTrigger on QuoteLineItem (before insert) {
             //collect QuoteActionIds 
             Set<Id> quoteActionIds = new Set<Id>();
             
             for (QuoteLineItem qi : Trigger.new) {
             if (qi.QuoteActionId != null && qi.ConstraintEngineNodeStatus__c == null) {
             quoteActionIds.add(qi.QuoteActionId);
             }
             }
             
             if (!quoteActionIds.isEmpty()) {
             // Step 1: Get QuoteAction → SourceAsset
             Map<Id, Id> quoteActionToAssetId = new Map<Id, Id>();
             for (QuoteAction qAction : [
             SELECT Id, SourceAssetId 
             FROM QuoteAction 
             WHERE SourceAssetId != null 
             AND Id IN :quoteActionIds
             ]) {
             quoteActionToAssetId.put(qAction.Id, qAction.SourceAssetId);
             }
             
             // Step 2: Get AssetActions
             List<AssetAction> assetActions = [
             SELECT Id, AssetId, ActionDate 
             FROM AssetAction 
             WHERE AssetId IN :quoteActionToAssetId.values()
             ];
             
             // Step 3: Get latest AssetAction per Asset
             Map<Id, AssetAction> assetIdToLatestAction = new Map<Id, AssetAction>();
             for (AssetAction aAction : assetActions) {
             AssetAction existing = assetIdToLatestAction.get(aAction.AssetId);
             if (existing == null || aAction.ActionDate > existing.ActionDate) {
             assetIdToLatestAction.put(aAction.AssetId, aAction);
             }
             }
             
             // Step 4: Get related AssetActionSource records
             Map<Id, Id> assetIdToActionId = new Map<Id, Id>();
             for (Id assetId : assetIdToLatestAction.keySet()) {
             assetIdToActionId.put(assetId, assetIdToLatestAction.get(assetId).Id);
             }
             
             List<AssetActionSource> assetActionSources = [
             SELECT ConstraintEngineNodeStatus__c, AssetAction.AssetId 
             FROM AssetActionSource 
             WHERE AssetActionId IN :assetIdToActionId.values() ORDER BY CreatedDate DESC
             ];
             // Step 5: Map AssetId → Status
             Map<Id, String> assetIdToStatus = new Map<Id, String>();
             for (AssetActionSource actionSource : assetActionSources) {
             if (!assetIdToStatus.containsKey(actionSource.AssetAction.AssetId) && 
             actionSource.ConstraintEngineNodeStatus__c != null) {
             assetIdToStatus.put(
             actionSource.AssetAction.AssetId, 
             actionSource.ConstraintEngineNodeStatus__c
             );
             }
             }
             List<QuoteLineItem> toUpdate = new List<QuoteLineItem>();
             // Step 6: Set ConstraintEngineNodeStatus__c directly on Trigger.new records
             for (QuoteLineItem qi : Trigger.new) {            
             if (qi.QuoteActionId != null && qi.ConstraintEngineNodeStatus__c == null) {
             Id assetId = quoteActionToAssetId != null ? quoteActionToAssetId.get(qi.QuoteActionId) : null;
             if (assetId != null && assetIdToStatus != null) {
             String status = assetIdToStatus.get(assetId);
             if (status != null) {
             qi.ConstraintEngineNodeStatus__c = status;
             }
             }
             }
             }
             }
             }

          Use this Apex code for the Order Product (OrderItem) object.

          trigger OrderItemTrigger on OrderItem  (before insert) {
            //collect orderActionIds
            Set<Id> orderActionIds = new Set<Id>();
           
            for (OrderItem oi : Trigger.new) {
            if (oi.OrderActionId != null && oi.ConstraintEngineNodeStatus__c == null) {
            orderActionIds.add(oi.OrderActionId);
            }
            }
           
            if (!orderActionIds.isEmpty()) {
            // Step 1: Get OrderAction → SourceAsset
            Map<Id, Id> orderActionToAssetId = new Map<Id, Id>();
            for (OrderAction oAction : [
            SELECT Id, SourceAssetId
            FROM OrderAction
            WHERE SourceAssetId != null
            AND Id IN :orderActionIds
            ]) {
            orderActionToAssetId.put(oAction.Id, oAction.SourceAssetId);
            }
           
            // Step 2: Get AssetActions
            List<AssetAction> assetActions = [
            SELECT Id, AssetId, ActionDate
            FROM AssetAction
            WHERE AssetId IN :orderActionToAssetId.values()
            ];
           
            // Step 3: Get latest AssetAction per Asset
            Map<Id, AssetAction> assetIdToLatestAction = new Map<Id, AssetAction>();
            for (AssetAction aAction : assetActions) {
            AssetAction existing = assetIdToLatestAction.get(aAction.AssetId);
            if (existing == null || aAction.ActionDate > existing.ActionDate) {
            assetIdToLatestAction.put(aAction.AssetId, aAction);
            }
            }
           
            // Step 4: Get related AssetActionSource records
            Map<Id, Id> assetIdToActionId = new Map<Id, Id>();
            for (Id assetId : assetIdToLatestAction.keySet()) {
            assetIdToActionId.put(assetId, assetIdToLatestAction.get(assetId).Id);
            }
           
            List<AssetActionSource> assetActionSources = [
            SELECT ConstraintEngineNodeStatus__c, AssetAction.AssetId
            FROM AssetActionSource
            WHERE AssetActionId IN :assetIdToActionId.values() ORDER BY CreatedDate DESC
            ];
            // Step 5: Map AssetId → Status
            Map<Id, String> assetIdToStatus = new Map<Id, String>();
            for (AssetActionSource actionSource : assetActionSources) {
            if (!assetIdToStatus.containsKey(actionSource.AssetAction.AssetId) &&
            actionSource.ConstraintEngineNodeStatus__c != null) {
            assetIdToStatus.put(
            actionSource.AssetAction.AssetId,
            actionSource.ConstraintEngineNodeStatus__c
            );
            }
            }
            List<OrderItem> toUpdate = new List<OrderItem>();
            // Step 6: Set ConstraintEngineNodeStatus__c directly on Trigger.new records
            for (OrderItem oi : Trigger.new) {           
            if (oi.OrderActionId != null && oi.ConstraintEngineNodeStatus__c == null) {
            Id assetId = orderActionToAssetId != null ? orderActionToAssetId.get(oi.OrderActionId) : null;
            if (assetId != null && assetIdToStatus != null) {
            String status = assetIdToStatus.get(assetId);
            if (status != null) {
            oi.ConstraintEngineNodeStatus__c = status;
            }
            }
            }
            }
            }
            }
          

          See Define Apex Triggers.

          After you define the Apex triggers, set up constraint rules engine.

           
          Loading
          Salesforce Help | Article