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
MicrobeMicrobe 

Copy data from Task to Opportunity upon event trigger

I'm trying to cause data to be copied when a trigger occurs. When a task attached to an opportunity is created with a subject of "Week In Review", I want it to update two custom fields in the parent opportunity. One of the fields will be updated with the task's description, and the other field will be updated with the current date and time.

 

I've tried a few different things, and this is close to what I want - but it's not right, syntactically or functionally.

 

Please be gentle, this is the very first piece of Apex code I have ever written.

 

 

 

trigger ReviewActivity on Task (after update) {

List<Task> taskIds = [SELECT Id, WhatId FROM Task WHERE Id IN :Trigger.new AND What.Type='Opportunity' AND Subject='Week In Review'];

    Map<Id, Task> taskMap = New Map<ID, Task>([SELECT WhatId, Description FROM Task Where Id IN :taskIds]);

List<Opportunity> opps = [SELECT Id, Last_Week_In_Review__c, Last_Week_In_Review_Date_Time__c From Opportunity WHERE Id IN taskIds.WhatId];

for(Opportunity opp : opps)
{
opp.Last_Week_In_Review__c = taskMap(opp.Id).Description;
opp.Last_Week_In_Review_Date_Time__c = System.now();
}

update opps;
}

 

 

 

Best Answer chosen by Admin (Salesforce Developers) 
bob_buzzardbob_buzzard

I think the following should give you what you want - I've tried to mark the important changes in red.  You already have the tasks in the trigger, so there's no need to fetch those you are interested in again, simply iterate the trigger.new list and examine each element.  There's now a map keyed by opportunity id with a value of task id, thus when you are processing the opportunities, you can retrieve the id of the task associated with it and then extract that from the trigger.newMap() based on the task id.  Note that I haven't compiled this, but it should be there or thereabouts.

 

A couple of things you may wish to enhance:

 

(1) This will cause the opportunity to be updated when a task is updated regardless of the change - it might be better to compare the old and new tasks to see if the fields you care about have changed.

(2) You'll need something similar for inserts.

(3) If there are multiple tasks added for the same opportunity, only the final task will impact the opportunity.

 

 

 

 

trigger ReviewActivity on Task (after update) {
    Map<Id, Id> taskIdByOppId=new Map<Id, Id>();
    for (Task tsk : trigger.new)
    {
       if (tsk.What.Type='Opportunity') && (Subject='Week In Review') )
       {
          taskIdByOppId.put(tsk.WhatId, tsk.id);
       }
    }
   
    List<Opportunity> opps = [SELECT Id, Last_Week_In_Review__c, Last_Week_In_Review_Date_Time__c From Opportunity WHERE Id IN :taskIdByOppId.keySet()];
    
    for(Opportunity opp : opps)
    {
        opp.Last_Week_In_Review__c = trigger.newMap(taskIdByOppId.get(opp.Id)).Description;
        opp.Last_Week_In_Review_Date_Time__c = System.now();
    }
    
    update opps;
}

 

 

All Answers

bob_buzzardbob_buzzard

I think the following should give you what you want - I've tried to mark the important changes in red.  You already have the tasks in the trigger, so there's no need to fetch those you are interested in again, simply iterate the trigger.new list and examine each element.  There's now a map keyed by opportunity id with a value of task id, thus when you are processing the opportunities, you can retrieve the id of the task associated with it and then extract that from the trigger.newMap() based on the task id.  Note that I haven't compiled this, but it should be there or thereabouts.

 

A couple of things you may wish to enhance:

 

(1) This will cause the opportunity to be updated when a task is updated regardless of the change - it might be better to compare the old and new tasks to see if the fields you care about have changed.

(2) You'll need something similar for inserts.

(3) If there are multiple tasks added for the same opportunity, only the final task will impact the opportunity.

 

 

 

 

trigger ReviewActivity on Task (after update) {
    Map<Id, Id> taskIdByOppId=new Map<Id, Id>();
    for (Task tsk : trigger.new)
    {
       if (tsk.What.Type='Opportunity') && (Subject='Week In Review') )
       {
          taskIdByOppId.put(tsk.WhatId, tsk.id);
       }
    }
   
    List<Opportunity> opps = [SELECT Id, Last_Week_In_Review__c, Last_Week_In_Review_Date_Time__c From Opportunity WHERE Id IN :taskIdByOppId.keySet()];
    
    for(Opportunity opp : opps)
    {
        opp.Last_Week_In_Review__c = trigger.newMap(taskIdByOppId.get(opp.Id)).Description;
        opp.Last_Week_In_Review_Date_Time__c = System.now();
    }
    
    update opps;
}

 

 

This was selected as the best answer
MicrobeMicrobe

Thanks, that's just what I was looking for. I started down the path of using maps previously, but it was the idea of querying the opporunities from the map that I missed.

 

I modified the event to be after an insert, as this would be called normally only when a new task with that subject was created, which addresses 1) and 2). As for 3) - that is precisely the functionality called for - they want the most recent task information updated into the opportunity.

 

There were a couple small errors in your code that I worked out. I'll post my corrected, working version here for anyone who wants to refer to it in future:

 

 

trigger HandleWeekInReviewActivity on Task (after insert) {
   
    Map<Id, Id> taskIdByOppId=new Map<Id, Id>();

    for (Task tsk : trigger.new)
    {
       if (tsk.What.Type=='Opportunity' && tsk.Subject=='Week In Review') taskIdByOppId.put(tsk.WhatId, tsk.id);
    }
   
    List<Opportunity> opps = [SELECT Id, Last_Week_In_Review__c, Last_Week_In_Review_Date_Time__c From Opportunity WHERE Id IN :taskIdByOppId.keySet()];
    
    for(Opportunity opp : opps)
    {
        opp.Last_Week_In_Review__c = trigger.newMap.get(taskIdByOppId.get(opp.Id)).Description;
        opp.Last_Week_In_Review_Date_Time__c = System.now();
    }
    
    update opps;
}

 

 

MicrobeMicrobe

A follow up to this - the code as written didn't work, for what seems like an obscure reason. Apparently, the What.Type property of the trigger.new task list is not yet populated when the after insert trigger occurs - its value is null. However, if the task table is queried using the task list contained in trigger.new, THAT resultset has the What.Type property populated. So the following code works (changes in red):

 

 

trigger HandleWeekInReviewActivity on Task (after insert) {

List<Task> taskList = [SELECT Id, Subject, What.Type, Description FROM Task WHERE Id in :trigger.new];
Map<Id, Id> taskIdByOppId=new Map<Id, Id>();

for (Task tsk : taskList)
{
if (tsk.What.Type=='Opportunity' && tsk.Subject=='Week In Review') taskIdByOppId.put(tsk.WhatId, tsk.id);
}

List<Opportunity> opps = [SELECT Id, Last_Week_In_Review__c, Last_Week_In_Review_Date_Time__c From Opportunity WHERE Id IN :taskIdByOppId.keySet()];

for(Opportunity opp : opps)
{
opp.Last_Week_In_Review__c = trigger.newMap.get(taskIdByOppId.get(opp.Id)).Description;
opp.Last_Week_In_Review_Date_Time__c = System.now();
}

update opps;
}