[SalesForce] Apex Trigger to run lead assignment rules not working when update

I created an APEX trigger to re-assign leads following certain changes to their fields. The trigger only applies to Leads that were assigned to a Queue and not to a User (See code below)

The trigger works correctly when leads are updated manually, and also when updated from the API. But if the lead is updated by a workflow, the Lead Assignment Rules to not run and the Lead remains assigned to the Queue.

Is there anything wrong in the trigger?

trigger RunLeadAassignmentRules on Lead (after update) {
    List<Lead> ls = new List<Lead>();

    for (Lead l : trigger.new) {
        Lead old_lead = trigger.oldMap.get(l.Id);
        // Only run if the lead was assigned to a Queue and not
        // A person. We do not reassign if you are assigned already.
        if ( old_lead.OwnerId.getSobjectType() == Group.SObjectType &&
             (
               old_lead.State != l.State ||
               old_lead.Country != l.Country
             )
            ) {
            ls.add(new Lead(id = l.id));
        }
    }

    if (ls.size() > 0) {
        Database.DMLOptions dmo = new Database.DMLOptions();
        dmo.assignmentRuleHeader.useDefaultRule = true;
        Database.update(ls, dmo);
    }
}

Thanks,
Ariel

Best Answer

I was able to solve this issue, and wanted to share the solution with you. When an "after update" trigger runs in the context of a Workflow, you must run reassignment rules after the whole workflow ended In order to allow the Lead Assignment rules to see the Lead after the transaction of the Workflow ended.

This is the code to achieve this (By Adding an async call to the reassignment rules):

trigger RunLeadAassignmentRules on Lead (after update) {

    Set<ID> ls = new Set<ID>();

    for (Lead l : trigger.new) {
        Lead old_lead = trigger.oldMap.get(l.Id);
        System.Debug(LoggingLevel.DEBUG,l.OwnerId);
        System.Debug(LoggingLevel.DEBUG,old_lead.OwnerId);

        System.Debug(LoggingLevel.DEBUG,l.Status);
        System.Debug(LoggingLevel.DEBUG,old_lead.Status);

        // Only run if the lead was assigned to a Queue and not
        // A person. We do not reassign.
        if ( old_lead.OwnerId.getSobjectType() == Group.SObjectType &&
             (
               old_lead.Number_of_Employees__c != l.Number_of_Employees__c ||
               old_lead.State != l.State ||
               old_lead.Country != l.Country
             )
            )
        {
            ls.add(l.Id);
        }
    }

    if (ls.size() > 0) {
        // This is the Fix
        ReassignLeads.futureLeadReassign(ls);
    }
}

And this is the Async Apex Class

 public with sharing class ReassignLeads {
    @future
    public static void futureLeadReassign(Set<ID> lIdReassignSet) {

      List<Lead> lUpdList = [SELECT Id FROM Lead WHERE Id IN: lIdReassignSet];
      for (Lead l:lUpdList){
        Database.DMLOptions dmo = new Database.DMLOptions();
        dmo.assignmentRuleHeader.useDefaultRule  = true;
        l.setOptions(dmo);
      }

      update(lUpdList);
    }
}

Remember that tests written for this trigger must use Test.startTest(); and Test.stopTest(); in order to wait for the async calls to finish before checking the results of the test.

Related Topic