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
mms16mms16 

trigger that re-runs assignment rules for leads in a queue?

We have a trigger that automatically re-runs assignment rules for any leads that meet certain critereon and and put into a specific queue. It's a trigger on the lead object, and it works great when I assign a lead to the queue in the UI, or it I do it in batches of 9 or smaller via demandtools etc. However, any time leads are bulk updated by Marketo (scoring etc) or if I try and perform bulk updates via DemandTools or DataLoader I get the error:

"Developer script exception from TRUSTe : reassignAutoQueue : reassignAutoQueue: execution of AfterUpdate caused by: System.AsyncException: Future method cannot be called from a future or batch method: AssignLeads.assign(LIST<Id>) Trigger.reassignAutoQueue: line 31, column 1"

Here is the fulltext of the error email:
Apex script unhandled trigger exception by user/organization: 005E000000XXXX/00DE0000000XXXX
reassignAutoQueue: execution of AfterUpdate
caused by: System.AsyncException: Future method cannot be called from a future or batch method: AssignLeads.assign(LIST<Id>)
Trigger.reassignAutoQueue: line 31, column 1


My trigger is below (it's primative, but I am a beginner and only starting to learn APEX so please forgive the poor coding). I can easily do small batch updates via demandtools, but I can't via Marketo. Is there any way I can prevent this trigger from running if the active user is Marketo (we don't want it to run for Marketo updates anyway)? Any help is greatly appreciated, thank in advance.

-Matt Stryker

trigger reassignAutoQueue on Lead (after update){

List<Id> lIds=new List<id>();

For (lead l:trigger.new){

Decimal checkrun=0;

if(l.Round_Robin_East_ID__c<>NULL)
checkrun=(checkrun+1);

if(l.Round_Robin_West_ID__c<>NULL)
checkrun=(checkrun+1);

if(l.Round_Robin_APAC_ID__c<>NULL)
checkrun=(checkrun+1);

if(l.Round_Robin_EMEA_ID__c<>NULL)
checkrun=(checkrun+1);

if (l.IsConverted==True)
checkrun=0;

if (l.OwnerID<>'00GE0000001buSm')
checkrun=0;

if (checkrun>0){
lIds.add(l.Id);
}
}
if (AssignLeads.assignAlreadyCalled()==FALSE){
system.debug('Assign already called? '+AssignLeads.assignAlreadyCalled());
AssignLeads.Assign(lIds);
}
}

sfdcfoxsfdcfox

Presumably, your future method is calling an update after re-assigning owners. This would cause even single updates to fail, because you can't recursively call future methods.

 

I'm guessing that AssignLeads.assignAlreadyCalled is supposed to return a flag in the event that this function has already run. I'm also guessing that you've coded that part wrong, because if you hadn't, you wouldn't be getting this specific error.

 

I've cleaned up your trigger for you, and I also added the three lines of code you're missing. You can probably safely remove "assignAlreadyCalled", based on an educated guess of what your utility class is doing.

 

trigger reassignAutoQueue on Lead (after update){
	// Can't run from a future invocation
	if(System.isFuture()) {
		return;
	}
	List<Id> leadIds = new List<Id>();
	for(Lead record: Trigger.new) {
		if(!record.IsConverted && 
			record.OwnerId != '00GE0000001buSm' &&
			(record.Round_Robin_East_Id__c != null ||
			 record.Round_Robin_West_Id__c != null ||
			 record.Round_Robin_APAC_Id__c != null ||
			 record.Round_Robin_EMEA_Id__c != null)
		) {
			leadIds.add(record.Id);
		}
	}
	// Don't call future method if there's nothing to do.
	if(!leadIds.isEmpty()) {
		AssignLeads.assign(leadIds);
	}
}

 

mms16mms16

I complete forgot to post the helper class, I think it only runs @future?

 

public class AssignLeads{

  public static Boolean assignAlreadyCalled=FALSE;

    public static boolean assignAlreadyCalled(){
        return assignAlreadyCalled;
    }

  @future
  public static void assign(List<Id> lIds){
    assignAlreadyCalled=TRUE;
    List<Lead> leads=[SELECT Id FROM Lead WHERE Id IN: lIds];
    For (lead l:leads){
      Database.DMLOptions dmo = new Database.DMLOptions();
      dmo.assignmentRuleHeader.useDefaultRule= true;
       l.setOptions(dmo);

    }
    update(leads);
  }

}

sfdcfoxsfdcfox
That's about what I expected. Try my code and see if it's close to what you need.