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
- The trigger runs
after updateand passes the Opportunities to the handler. - The handler queries
OpportunityContactRolerecords whereIsPrimary = trueto find each Opportunity primary Contact. - For each one it builds a Task.
WhatIdlinks the Task to the Opportunity andWhoIdlinks it to the Contact. The Task is due 12 days from today. - 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 Progresswith a space.InProgresswill fail unless you created that value yourself. - Trigger.old: the trigger passes
trigger.old. It works because the Ids are the same, buttrigger.newis 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
- Create an Opportunity and add a Contact as the primary Contact Role.
- Edit and save the Opportunity.
- 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.