0

I need to write a trigger on task in which I have to map its 3 fields Subject, Priority, ActivityDate to contact. Lets say I have 5 tasks related to contact, I insert the 6th task then the (Subject, Priority, ActivityDate) fields should be mapped in contacts fields. Now if I insert the 7th task then its values should come in contacts fields, and now here comes the tricky part If I delete the 7th task now the values of 6th task should come on contacts fields as it was 2nd last recently modified.

public class UpdateRecentlyUsedTaskDetailsHandler 
{
public static void updateTaskDetailOnContact(List<Task> taskList)
{
    List<Contact> conList = new List<Contact>();
    Set<Id> taskIdSet = new Set<Id>();
    for(Task task : taskList)
    {
        taskIdSet.add(task.whoId);
    }

    Map<Id, Contact> contactsMap = new Map<Id, Contact>([Select id, Priority__c, Due_Date__c, Subject__c, lastname, 
                                                          (Select id, whoId, Subject, Priority, ActivityDate From Tasks)
                                                             From Contact Where Id IN : taskIdSet]);
    for(Task task : taskList)
    {
        Contact con = contactsMap.get(task.whoId);
        con.Priority__c = task.Priority;
        con.Due_Date__c = task.ActivityDate;
        con.Subject__c = task.Subject;
        conList.add(con);
    }
    update conList;
}
}

trigger UpdateRecentlyUsedTaskDetails on Task (after insert, after update, after delete, after undelete) 
{
if(Trigger.isInsert || Trigger.isUpdate || Trigger.isUndelete)
{
    UpdateRecentlyUsedTaskDetailsHandler.updateTaskDetailOnContact(Trigger.new);
}

if(Trigger.isDelete)
{
    UpdateRecentlyUsedTaskDetailsHandler.deleteTaskOnContact(Trigger.old);
}
}
  • Where is your deleteTaskOnContact code? You should be able to query the newest Task where ID isn't in the deletion trigger and WhatId = to the WhatId of the records in the deletion trigger. – Stephen Sep 21 '16 at 12:03
0

It looks like your query is pretty close. It's just missing a little something.

The key here is to realize that you only need the most recent Task related to a given Contact. We can achieve this by using ORDER BY and LIMIT like so

[
 SELECT id, Priority__c, Due_Date__c, Subject__c, lastname, 
    (
     SELECT Id, whoId, Subject, Priority, ActivityDate 
     From Tasks
     ORDER BY CreatedDate DESC
     LIMIT 1
    )
 FROM Contact 
 WHERE Id IN : taskIdSet 
]

This will work even when a Task is deleted because by the time that the after events run, the insert/update/delete/undelete has been saved to the database (but not yet committed).

Queries that are run in the same transaction are issued against this saved database state. This guarantees that the query will pull a newly inserted record after insert, the most recently created record after update, the most recently created non-deleted record after delete and after undelete

The only other thing you might need to worry about is what happens when a Contact has no Task that meets the criteria.

To handle this, I'd re-work your loop to iterate over Contact instead of Task.

// This variable can be declared inside the loop if you want.
// Keeping it outside the loop saves a little CPU time per iteration of the loop.
// Probably insignificant in your situation, but can help if you end up dealing 
//   with thousands of records in one shot.
Task mostRecentTask;

for(Contact con :contactsMap.values())
{
    if(con.Tasks.isEmpty())
    {
        // This task won't be inserted
        // It allows you to set default values in cases where a Contact doesn't
        //   have a Task that we can use.
        // As is, this should cause the fields on the Contact to be nulled out.
        mostRecentTask = new Task();
    }
    else
    {
        mostRecentTask = con.Tasks[0];
    }

    // Since the if/else above guarantees that we'll always have a Task
    //   in the mostRecentTask variable, we can keep these 3 lines outside
    //   of the if/else.
    con.Priority__c = mostRecentTask.Priority;
    con.Due_Date__c = mostRecentTask.ActivityDate;
    con.Subject__c = mostRecentTask.Subject;

    conList.add(con);
}

With that, you should be able to call updateTaskDetailOnContact() in all of your trigger events (just be sure to keep passing Trigger.old in the case where a Task is being deleted).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.