Trigger: On Update Create new Task on Primary Contact of Opportunity

Example: When Opportunity get updated. Create new Task on Primary Contact of that Opportunity.

Solution

OpportunityTrigger
trigger OpportunityTrigger on Opportunity (after update) {
    OpportunityTriggerHandler handler = new OpportunityTriggerHandler();
	if(trigger.isAfter && Trigger.isUpdate) {
        handler.createTaskOnPrimaryContact(trigger.old);
    }
}
OpportunityTriggerHandler
public class OpportunityTriggerHandler {
    public void createTaskOnPrimaryContact(List<Opportunity> lstOppor) { 
        List<OpportunityContactRole> contactRoles = [Select Id, ContactId,OpportunityId From OpportunityContactRole Where IsPrimary = True and OpportunityId in: lstOppor];
        List<Task> lstTask = new List<Task>();
        for(OpportunityContactRole oppContactRole: contactRoles) { 
            List<Opportunity> oppr = [Select Id, OwnerId  From Opportunity Where Id=: oppContactRole.OpportunityId limit 1];
            Task task = new Task(Subject='Email', 
            ActivityDate = System.Today() + 12,               
            Status = 'InProgress', 
            OwnerId = oppr[0].OwnerId ,                 
            WhatId = oppContactRole.OpportunityId, // Related to does not support Contact                     
            WhoId = oppContactRole.ContactId               
        	);      
            lstTask.add(task);
        }     
        System.debug(lstTask);
    	insert lstTask; 
    }
}

Scenario

When an Opportunity is updated, create a follow-up Task for its primary Contact so the sales team does not miss the next step.

How the code works

  1. The trigger runs after update and passes the Opportunities to the handler.
  2. The handler queries OpportunityContactRole records where IsPrimary = true to find each Opportunity primary Contact.
  3. For each one it builds a Task. WhatId links the Task to the Opportunity and WhoId links it to the Contact. The Task is due 12 days from today.
  4. All Tasks are inserted together.

Problems in this version

  • Query inside a loop: the Opportunity owner is queried for every contact role. With many records this hits the limit of 100 SOQL queries.
  • Status value: the standard Task status is In Progress with a space. InProgress will fail unless you created that value yourself.
  • Trigger.old: the trigger passes trigger.old. It works because the Ids are the same, but trigger.new is the usual choice.
  • Runs on every update: a Task is created each time the Opportunity is saved. In real projects, create it only when a field such as StageName changes.

Improved handler (bulk-safe)

public class OpportunityTriggerHandler {
    public void createTaskOnPrimaryContact(List<Opportunity> lstOppor) {
        List<Task> lstTask = new List<Task>();
        for (OpportunityContactRole role : [
            SELECT ContactId, OpportunityId, Opportunity.OwnerId
            FROM OpportunityContactRole
            WHERE IsPrimary = true AND OpportunityId IN :lstOppor
        ]) {
            lstTask.add(new Task(
                Subject = 'Email',
                ActivityDate = System.today().addDays(12),
                Status = 'In Progress',
                OwnerId = role.Opportunity.OwnerId,
                WhatId = role.OpportunityId,
                WhoId = role.ContactId
            ));
        }
        if (!lstTask.isEmpty()) {
            insert lstTask;
        }
    }
}

This version reads the owner in the same query, so there is only one query no matter how many records are updated.

How to test

  1. Create an Opportunity and add a Contact as the primary Contact Role.
  2. Edit and save the Opportunity.
  3. Open the Contact. A new Task with subject Email should appear.

FAQ

What is the difference between WhoId and WhatId?
WhoId points to a person (Contact or Lead). WhatId points to a record such as an Opportunity or Account.

Why not use Trigger.new in the loop for the owner?
You can. The improved version reads the owner through the contact role query, which keeps the code simple.

Leave a Reply