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
Ti Saunders 8Ti Saunders 8 

Task Trigger to Change Open Tasks "Assigned to" to New Contact Owner

I am wanting to change the "assigned to" value in open (i.e. not closed) activities whenever the parent record owner changes. Our marketing automation system is automatically creating a bulk of tasks and assigning them to the current contact owner, but a few hours later a mass contact reassignment is happening and these tasks are not getting assigned to the new contact owner.

Desired functionality:
1. Contact Owner changes
2. Related open activities (tasks) are reassigned to new contact owner
-end-

Thanks in advance for your help.
Ravi Dutt SharmaRavi Dutt Sharma
This is standard functionality. Whenever the contact owner changes, any tasks present under that contact gets automatically re-assigned to the new contact owner.
Ti Saunders 8Ti Saunders 8
Ravi,

Thank you for your response. This is true when manually changing the record owner, but not when doing bulk entry (e.g. data loader).
Ravi Dutt SharmaRavi Dutt Sharma
Hi Ti Saunders,

Ok, I got your point. Please use the below code and let me know if it works for your use case.

I have written an after update trigger on contact which checks 2 things:
1) Whether the process is running in bulk
2) If the owner of contact is changed

If both the conditions are met, it updates the owner of all the tasks present under that contact. You may need to add more conditions in the query in the batch class to satisfy your business use case.
 
trigger ContactTrigger on Contact (after update) {
	
    if(Trigger.isAfter && Trigger.isUpdate){
        if(ContactTriggerHandler.executeHandleAfterUpdate){
            ContactTriggerHandler.handleAfterUpdate(Trigger.new, Trigger.oldMap);
        }
    }
}
public class ContactTriggerHandler {
    
    public static void handleAfterUpdate(List<Contact> newList, Map<Id,Contact> oldMap){
        // check if trigger is running in bulk mode because for a single record updated through UI,
        // the owner of task is updated automatically
        if(newList.size() > 1){
            Map<Id,Id> contactIdToOwnerIdMap = new Map<Id,Id>();        
            // check if owner has been changed
            for(Contact con: newList){
                if(con.OwnerId != oldMap.get(con.Id).OwnerId){
                    contactIdToOwnerIdMap.put(con.Id, con.OwnerId);
                }
            }
            // There can be large number of tasks under these contacts, so its always a good idea to 
            // process them in a batch
            Database.executeBatch(new TaskOwnerUpdateBatch(contactIdToOwnerIdMap), 200);
        }
    }
}
 
public class TaskOwnerUpdateBatch implements Database.Batchable<sObject>{

    public Map<Id,Id> contactIdToOwnerIdMap;
    
    public TaskOwnerUpdateBatch(Map<Id,Id> contactIdToOwnerIdMap){
        this.contactIdToOwnerIdMap = contactIdToOwnerIdMap;
    }
    
    public Database.QueryLocator start(Database.BatchableContext bc){
        Set<Id> contactIds = contactIdToOwnerIdMap.keySet();
        return Database.getQueryLocator('SELECT OwnerId,WhoId FROM Task WHERE WhoId IN:contactIds');
    }
    
    public void execute(Database.BatchableContext bc, List<Task> taskList){
        for(Task tsk: taskList){
            tsk.OwnerId = contactIdToOwnerIdMap.get(tsk.WhoId);
        }
        update taskList;
    }
    
    public void finish(Database.BatchableContext bc){
        
    }
}

Thanks,
Ravi​​​​​​​
 
Ti Saunders 8Ti Saunders 8
Thanks, Ravi! This is incredibly helpful.

Management is now telling me they would like to have this restricted to only tasks that begin with "TPP". Is there a way to add that condition in here. Sorry for the late reply here. Things have been a little crazy over here this week.
Ravi Dutt SharmaRavi Dutt Sharma
Hey Ti Saunders,

Sorry for the late reply. If you want to restrict to only tasks that begin with "TPP", you can add a condition in the SOQL query to get only matching records.
 
public class TaskOwnerUpdateBatch implements Database.Batchable<sObject>{

    public Map<Id,Id> contactIdToOwnerIdMap;
    
    public TaskOwnerUpdateBatch(Map<Id,Id> contactIdToOwnerIdMap){
        this.contactIdToOwnerIdMap = contactIdToOwnerIdMap;
    }
    
    public Database.QueryLocator start(Database.BatchableContext bc){
        Set<Id> contactIds = contactIdToOwnerIdMap.keySet();
        return Database.getQueryLocator('SELECT OwnerId,WhoId FROM Task WHERE WhoId IN:contactIds AND Subject LIKE \'TPP%\'');
    }
    
    public void execute(Database.BatchableContext bc, List<Task> taskList){
        for(Task tsk: taskList){
            tsk.OwnerId = contactIdToOwnerIdMap.get(tsk.WhoId);
        }
        update taskList;
    }
    
    public void finish(Database.BatchableContext bc){
        
    }
}

Please mark it as the best answer if it solves your problem. Thanks.
 
Ti Saunders 8Ti Saunders 8
Thanks a lot, Ravi.

Last question. Would I make 3 separate contact triggers for this, or combine eveything into a single one?
Ti Saunders 8Ti Saunders 8
I may have figured this out.

The first is a Contact trigger.

The second and third would be put under Apex Classes.

I am running into a problem though. The Apex classes went in fine, but I am getting this error when adding the Contact Trigger: "Error: Compile Error: Variable does not exist: executeHandleAfterUpdate at line 4 column 34"
Ravi Dutt SharmaRavi Dutt Sharma
hey,

Please use below code for Contact trigger:
 
trigger ContactTrigger on Contact (after update) {
	
    if(Trigger.isAfter && Trigger.isUpdate){
            ContactTriggerHandler.handleAfterUpdate(Trigger.new, Trigger.oldMap);
    }
}

 
Ti Saunders 8Ti Saunders 8
Hi Ravi,

I have all of this in here and it does not appear to be working.

I have this in my sandbox and did a bulk record update and none of the tasks are transferring when the owner changes.