+ Start a Discussion
SFDCDevQASFDCDevQA 

Creating Auto Approval Process Trigger

I've created an automatic approval process trigger, which works, but I'm running into a snag in that it will throw up errors later when the Opportunity is edited after approval and maybe at other points in time.  The trigger is supposed to run if the opportunity is updated and the field Risk Build is changed to "Yes".  That works but it should only run if the field Risk Build is actually changed to yes from either being blank or from No.  It should not run if it is already at Yes and the user simply edits a different part of the opportunity (such as the stage).  Is there some kind of "ischanged" function like you can use for workflows and formulas? Ideally I need it to say that Risk Build is changed AND changed to "yes".  The code (see below) is pretty simple thus far so hopefully the answer is something simple too.

Thanks,

Amanda

 

 

trigger Risk_Build_Approval on Opportunity (after update) 
{
  for(Opportunity o: trigger.new){ 
  if(o.risk_build__c == 'Yes')
  {
    O = [ select ID from Opportunity where id in :Trigger.new ];
  Approval.ProcessSubmitRequest req1 = new Approval.ProcessSubmitRequest();
  req1.setComments('Submitting request for approval.');
  req1.setObjectId(o.id);
   Approval.ProcessResult result = Approval.process(req1); 
   System.assert(result.isSuccess());        


  }
  }
  }
Best Answer chosen by Admin (Salesforce Developers) 
JimRaeJimRae

That should be pretty easy to do by leveraging the Trigger.Old map in combination with the trigger.new.

 

Here is a possible refactoring of your code that would include both:

 

 

trigger Risk_Build_Approval on Opportunity (after update) 
{
  for(Opportunity o: trigger.new){ 
     Opportunity oldOpp = trigger.oldMap.get(o.Id);
     if(o.risk_build__c == 'Yes' && oldOpp.risk_build__c <> 'Yes')
     {
    
         Approval.ProcessSubmitRequest req1 = new Approval.ProcessSubmitRequest();
         req1.setComments('Submitting request for approval.');
         req1.setObjectId(o.id);
         Approval.ProcessResult result = Approval.process(req1); 
         System.assert(result.isSuccess());        
     }
  }
}

 

 

All Answers

JimRaeJimRae

That should be pretty easy to do by leveraging the Trigger.Old map in combination with the trigger.new.

 

Here is a possible refactoring of your code that would include both:

 

 

trigger Risk_Build_Approval on Opportunity (after update) 
{
  for(Opportunity o: trigger.new){ 
     Opportunity oldOpp = trigger.oldMap.get(o.Id);
     if(o.risk_build__c == 'Yes' && oldOpp.risk_build__c <> 'Yes')
     {
    
         Approval.ProcessSubmitRequest req1 = new Approval.ProcessSubmitRequest();
         req1.setComments('Submitting request for approval.');
         req1.setObjectId(o.id);
         Approval.ProcessResult result = Approval.process(req1); 
         System.assert(result.isSuccess());        
     }
  }
}

 

 

This was selected as the best answer
SFDCDevQASFDCDevQA

That worked perfectly.  You are awesome!  Thanks.

SFDCDevQASFDCDevQA

Jim,

Thanks so much for your help with this.  One other question.  I didn't think about the fact that when sales reps initially make the opportunity they might go ahead and set it to Risk build status....right now the trigger is only for an updated opp and not a new opp.  When I tried to add after insert to the beginning of the trigger I got an error due to there not being a risk build prior value when the opportunity is brand new.  Is there a way to tell it to run IF the opp is brand new and risk build is set to Yes OR if opp is updated and risk build is set to yes but was not yes in the prior value?

 

Thanks again,

Amanda

JimRaeJimRae

Yes, that is possible.  You need the trigger to execute after both insert and update, and a little checking for each.

 

 

trigger Risk_Build_Approval on Opportunity (after insert, after update) 
{
  for(Opportunity o: trigger.new){ 
     if(Trigger.isInsert && o.risk_build__c == 'Yes')
     {
          genRequest(o);
     }else if(Trigger.isUpdate)
     {
          Opportunity oldOpp = trigger.oldMap.get(o.Id);
          if(o.risk_build__c == 'Yes' && oldOpp.risk_build__c <> 'Yes')
          {
                genRequest(o);
          }
     }
  }
  //moved approval submission to a method to allow reusability
  public void genRequest(Opportunity o){
       Approval.ProcessSubmitRequest req1 = new Approval.ProcessSubmitRequest();
       req1.setComments('Submitting request for approval.');
       req1.setObjectId(o.id);
       Approval.ProcessResult result = Approval.process(req1); 
       System.assert(result.isSuccess());        
  
  }
}

 

 

SFDCDevQASFDCDevQA

That worked perfectly!  Thank you so much.  For some reason I seem to be okay with taking existing classes and visualforce pages and rewriting them to do what i want but the triggers I have more trouble with.

 

Thanks again,

Amanda

mtbclimbermtbclimber

The process verb counts as a dml statement so it's best to avoid embedding it in loops to avoid the governor limit. Here's the bulkification of Jim's sample. I didn't compile this so apologies for typos:

 

 

trigger Risk_Build_Approval on Opportunity (after insert, after update)  {
	List<Approval.ProcessSubmitRequest> reqList = new List<Approval.ProcessSubmitRequest>();
	for(Opportunity o: trigger.new){ 
		if(Trigger.isInsert && o.risk_build__c == 'Yes') {
			reqList.add(genRequest(o));
			
		} else if(Trigger.isUpdate) {
			Opportunity oldOpp = trigger.oldMap.get(o.Id);
			if(o.risk_build__c == 'Yes' && oldOpp.risk_build__c <> 'Yes') {
                        	reqList.add(genRequest(o));
               		} 
     	    	}
	}
	
	if(resultList.size() > 0) {
		//process in one bulk, all-or-nothing request
		List<Approval.ProcessResult> resultList = Approval.process(reqList, true); 
		System.assert(resultList.get(0).isSuccess());
	}
	//moved approval submission to a method to allow reusability
	public Approval.ProcessSubmitRequest genRequest(Opportunity o){
		Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
		req.setComments('Submitting request for approval.');
		req.setObjectId(o.id); 
		return req;
	}
}