function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
LEI ZHOU 23LEI ZHOU 23 

trigger recursion stops processing the same record with changed value

Hello,
I work in a company that our salesforce platform's architect follows SalesForce's trigger best practice to have a recursion check on Opportunity to stop the execution on each event independently. So the ExecuteAfterUpdate will run exactly once for each opportunity record. 
Here is my requirement:
1.  Apex class to have an API call to import Opportunity and OpportunityLineItems from another systme to Salesforce
2. Rollup OpportunityLineItems value to corresponding Opportunity value
3. Calculate OpportunityLineItems' value percentage= OpportunityLineItem Value/ Opportunity value.
Here is the implementation:
1. Apex class1 insert/update Opportunities
2. Opportunity Trigger is executed 1st time
3. Same Apex class1 then insert/update OpportunityLineItems
4. OpportunityLineItem trigger is exeucted 1st time and calls Apex class2 to rollup OpportunityLineItems value to Opportunity value, Opportunity is updated
5. Opportunity trigger is executed 2nd time and calls Apex class3 to calculate OpportunityLineItems' value percentage= OpportunityLineItem Value/ Opportunity value.
I am blocked in step#5, because Opportunity trigger is executed 2nd time, our company's trigger recusion check finds this Opportunity is already processed in step#2, it does not pass this Opportunity record to Apex class3.
My questions:
1. Is my implementation correct? 
2. Is company's trigger recursion implementation correct, because the same Opportunity record's value in step #2 and step #5 is not the same?
3. What should I do to bypass it?

thank you for the help.
Lei
AnudeepAnudeep (Salesforce Developers) 
Hi Lei,

If you haven't checked already, I recommend looking at the 
Apex Trigger Best practices to avoid recursion for best practices and implement your apex class accordingly

Let me know if it helps
LEI ZHOU 23LEI ZHOU 23
Hi Anudeep,

Thanks for the reply, but it does not really help my question. We have trigger recursion implemented as following, it compares the opportunity in Trigger.new and recursionCheck set, if recrusion check contains this Id, don't pass down. But the problem is : Trigger.new and recusionCheck have same opportunity Id, but for that opportunity's value in Trigger.new is different from that opportunity already processed in recusionCheck.

  if(Trigger.new != null && Trigger.new.size() > 0)
            {                  
                for(Opportunity opp : (Opportunity[])Trigger.new)
                {                   
                    if(!recursionCheck.contains(opp.ID))
                    {                                                                       
                        newRecordIdsToProcess.add(opp.ID);
                    }                    
                }
            }
thanks
Joe AlianJoe Alian
Howdy Lei, 

On the off chance that you haven't checked as of now, I suggest taking a gander at the 

Peak Trigger Best practices to stay away from recursion (https://help.salesforce.com/articleView?id=000332407&type=1&mode=1) for best practices and execute your zenith class (https://waterfilterly.com/water-softener-shower-heads/) likewise 

Inform me as to whether it makes a difference
Ashvin JAshvin J
Hey Lei, 

Can you please confirm which object you are updating at step no 5 ? Is it Opportunity or OpportunityLineItem ?

If you are updating Opportunity then can you perform same activity in step no 4 ? Since you are already fetching OpportunityLineItem details in step 4, where you will also logic written in step 5.

Thanks,
Ashvin
LEI ZHOU 23LEI ZHOU 23
Hi Ashvin,

In step #5, I update OpportunityLineItem, 
OpportunityLineItem.percentage = (OpportunityLineItem.Value / Opportunity.Value)
Opportunity.Value: - comes from step #4
But trigger recursion check flag checks this opportunity Id, finds it is already processed in step #2, it stops processing this opportunity.
                                  Opportunity.Id        Opportunity.Value
step #2 Vs step #5      same                     different

thanks
Lei
Malika Pathak 9Malika Pathak 9
Hi 
LEI ZHOU 23

Please refer to this link https://jayakrishnasfdc.wordpress.com/2020/02/23/recursive-trigger-in-salesforce/ 
Thanks
Ashvin JAshvin J
Hi Lei,
Considering below steps that you are performing 

1. Apex class1 insert/update Opportunities
2. Opportunity Trigger is executed 1st time
3. Same Apex class1 then insert/update OpportunityLineItems
4. OpportunityLineItem trigger is exeucted 1st time and calls Apex class2 to rollup OpportunityLineItems value to Opportunity value, Opportunity is updated
5. Opportunity trigger is executed 2nd time and calls Apex class3 to calculate OpportunityLineItems' value percentage= OpportunityLineItem Value/ Opportunity value.


Below is psedo code, refer solution.
-----------------------------------------------------------------------------------------------------
Current behaviour : 

Step 1 when Opportunity is inserted, Opportunity trigger is fired - 

public class class1{
    
    public static void insertOpportunityLineItem(){ //Step1,2,3
        
        //logic to insert/update OpportunityLineItem
    }

}


Step 4

OpportunityLineItem trigger is executed 

public class class2{

    public static void updateOpportunity(){
        //fetch Opportunity
        OpportunityValue = OpportunityLineItem.value;
    
    }
    update Opportunity
}


Step 5
Opportunity trigger is fired again

public class class3{
    //update OpportunityLineItem
    OpportunityLineItems' value percentage= OpportunityLineItem Value/ Opportunity value
}

---------------------------------------------------------------------------------------------------------------------------------------------------------------


Solution : 

Step 1 when Opportunity is inserted, Opportunity trigger is fired - 

public class class1{
    
    public static void insertOpportunityLineItem(){ //Step1,2,3
        
        //logic to insert/update OpportunityLineItem
    }

}

Step 4

OpportunityLineItem trigger is executed 

public class class2{
    
    //populate below map as
    //Opportunity 1 - record ID -> OLT1(value=5),OLT2(value=10),OLT3(value=15) = Total value = 30
    //mapofOpportunityId_OpportunityLineItemValue will contain (opp1recordId, 30)
    
    map<Id,Decimal> mapofOpportunityId_OpportunityLineItemValue = new map<Id, Decimal>(); 
    
    public static void updateOpportunity(trigger.new){
        list<Opportunity> opptylstToupdate = new list<Opportunity>();
        Decimal totalvalue = 0;
        for(Integer i = 0 i<=trigger.new.size()){
            
        }
        for(OpportunityLineItem olt : trigger.new ){
            //populate mapofOpportunityId_OpportunityLineItemValue map, e.g. old.OpportunityId(opp1) -> OLT1(value=5),OLT2(value=10),OLT3(value=15) = Total value = 30
            //so map will be {opp1,30}
            
        }
        
        //get the opportunity
        for(Opportunity opp : [Select Id,OpportunityValue from Opportunity where ID IN : mapofOpportunityId_OpportunityLineItemValue.keyset()]){
            opp.opportunityvalue = mapofOpportunityId_OpportunityLineItemValue.get(opp.Id) ; //here for opp1, 30 will be returned
            opptylstToupdate.add(opp);
        }
        
        if(opptylstToupdate.size() > 0){
            update opptylstToupdate; //step 4
        }
        
        //step 5
        for(OpportunityLineItem olt : trigger.new){
            OpportunityLineItems' value percentage= OpportunityLineItem Value (olt.value)/ Opportunity value (mapofOpportunityId_OpportunityLineItemValue.get(olt.OpportunityId))
        }
        
    }
    
}

Regards,
Ashvin
errol allenerrol allen
To avoid recursive triggers you can create a class with a static Boolean variable with default value true. In the trigger, before executing your code keep a check that the variable is true or not. Once you check make (https://errolallenconsulting.com/) the variable false.