I'd like to share a solution for a problem that I've worked on and found some similar scenarios online but not quite exactly the same.

So what are we trying to accomplish here?

Every time an Opportunity inserts or updates an Opportunity Product(OpportunityLineItems) with a Product it should copy the value selected in a picklist from it and update Practice field under Opportunity, yep you guessed it - both fields are named the same. It's expected that All products added under a specific OLIS will share the same Practice(i.e: Salesforce, Microsoft, Apple) value, it's a business requirement, so no need to go over the list just pick the first Product item.

PS: Opportunity has a custom text area field called Practice while Product has a picklist called Practice with values defined as Salesforce, Microsoft, Apple.

1 Answer 1


TriggerToUpdatePracticeOnOpp is the trigger called once OpportunityLineItems is updated or a Product is added to it. It should be created under triggers folder then deployed to your org, if you're doing from Salesforce Dev Console just make sure you hit ctrl+s/cmd+s to save your code.

//This trigger should be fired every time there's an insert/update in Opportunity Product
trigger TriggerToUpdatePracticeOnOpp on OpportunityLineItem (after insert, after update) {
    //Get all the Opportunity related to the product 
    map<Id, Opportunity> opportunityIdToOpportunity = new map<Id, Opportunity>();

    /*In this loop it populates opportunityProduct based on the query getting info from 
    OpportunityLineItem as well Product2 Practice
    Trigger.New contains all the records that were inserted in insert or update triggers, 
    context variables, such as Trigger.New, can contain only one record or multiple records. 
    You can iterate over Trigger.New to get each individual sObject.
    for (OpportunityLineItem opportunityProduct : [ SELECT Id,
                                                    FROM OpportunityLineItem
                                                    WHERE ID IN: trigger.new]){

        // Show Opportunity Practice value
        // Show Product2 Practice value

        // Gets the practice from Product and pass it to Opportunity thru Opportunity Product
        opportunityProduct.Opportunity.Practice__c = opportunityProduct.Product2.Practice__c;

        // Adds Id and Opportunity to this map
    // Updates Opportunity value accordint to its ID and Opportunity Info
    update opportunityIdToOpportunity.values();


In order to test your trigger you should deploy the code above to your org then go to Opportunities > Open an Opportunity > Product > Add Products > Select your product with a Practice > Fulfill req fields > Save. If you don't see the update under Opportunity Practice try to refresh your page and/or make sure you've Deployed the code to the right Org. If everything worked as expected, voilà!

In case you're working from Visual Code and would like to take a more programmatically approach you can also include TriggerToUpdatePracticeOnOppTest Apex Class to your project under classes to test your trigger - basically this class will simulate a user Creating an Account, Opportunity, Product, Price Book Entry then glue Opp and Prod stuff using OpportunityLineItem. Make sure you've deployed this class to your org or saved it if you're on Salesforce Dev Console.

public with sharing class TriggerToUpdatePracticeOnOppTest {

        static void test_setup() {
        Account testAccount = new Account(Name = 'Test');
        Insert testAccount;

        Opportunity testOpportunity = new Opportunity(  Name = 'Test',
                                                        AccountId = testAccount.Id,
                                                        CloseDate = Date.today(),
                                                        StageName = 'Closed Won'

        insert testOpportunity;

        Product2 testProduct = new Product2();
        testProduct.Name = 'Some Product';
        testProduct.Practice__c = 'Salesforce';
        insert testProduct;

        PriceBookEntry testPriceBookEntry = new PriceBookEntry();
        testPriceBookEntry.Product2Id = testProduct.Id;
        testPriceBookEntry.PriceBook2Id =  Test.getStandardPricebookId();
        testPriceBookEntry.UnitPrice = 1.0;
        testPriceBookEntry.IsActive = true;
        Insert testPriceBookEntry;

    static void should_update_opportunity() {
        Opportunity testOpportunity = getOpportunity().get(0);
        PriceBookEntry testPriceBookEntry = getPriceBookEntries().get(0);
        Insert new OpportunityLineItem(OpportunityId = testOpportunity.Id, 
                                      PriceBookEntryId = testPriceBookEntry.Id, 
                                      Quantity = 1,
                                      TotalPrice = 1000.0 );
        testOpportunity = getOpportunity().get(0);

      System.assertEquals('Salesforce', testOpportunity.Practice__c);

    private static List<PriceBookEntry> getPriceBookEntries(){
        return [SELECT Id from PriceBookEntry];

private static List<Opportunity> getOpportunity(){
    return [SELECT Id, Practice__c from Opportunity];


I'd love to share my Apex Class logs, however it's a long file so it's easier if you get your own and go over the info there to make sure it worked like expected.

Well, this is my second post here so my first one was on how to see SOQL query results in Apex code while debugging it using Visual Code. For that scenario I got to know that it's not possible(unfortunately), feel free to check it out: Query via Apex returns null, however the same query via SOQL shows results


Update Opportunity with Product custom fields

SOQL to update a field of an OpportunityLineItem in the opportunity in use

Kudos to Anup Prakash who assisted me on getting the code straighten up.

LinkedIn: https://www.linkedin.com/in/anupprakash/ Websit: https://anupprakash.com/

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .