1

I have this trigger on Task which should take the first record of tasks and update on their contact id. But, when I tried updating the big file through data loader, It doesn't take the first record. How do I make sure that when I bulk upload, every contact id gets updated with their first record of the task? Thank you in advance!

trigger contactActivityTrigger on Task (after insert, after update) {
if (Trigger.isafter && Trigger.isInsert){
              contactActivityHandler.insertContact(Trigger.New);

     } 
     if(Trigger.isafter && Trigger.isUpdate){
         contactActivityHandler.updateOldContact(Trigger.New ,Trigger.Old);

     }
}


public class contactActivityHandler {

public static void insertContact(List<Task> tks){ // Trigger.New comes as List here
    Set <Id> ContactIds = new Set<Id>();
    List <Contact> ContactList = new List<Contact>();

    for(Task t :tks) 
    {
        if(t.whoId!=null)
        {
            Schema.SObjectType tType= t.whoId.getSObjectType();
            if(tType == Contact.Schema.SObjectType)
            {
                ContactIds.add(t.WhoId);
            }
        }
    }
    //Querying the related Contacts based on whoId on Task
    Map<Id,Contact> ContactMap =  new Map<Id,Contact>([select id, Last_Contact_Date__c,Name,
                                                       Last_Activity_TypeOfInteraction__c, 
                                                       LastActivityDate, Last_Activity_Subject__c,
                                                       Last_Activity_Date__c, Last_Activity_Name__c 
                                                       from Contact where id in:ContactIds]);
    for(Task t :tks)
    {

            for(Contact l : ContactMap.Values())
            {  
              If(t.ActivityDate >=l.Last_Contact_Date__c)
                {
                l.Last_Activity_Subject__c = t.subject;
                l.Last_Activity_Date__c = t.ActivityDate;
                l.Last_Activity_Name__c = l.Name;
                l.Last_Activity_TypeOfInteraction__c = t.Type_of_Interaction__c;
                l.Last_Activity_Assigned_to__c = t.Owner.Name;
                ContactList.add(l);
                     System.debug('Printining that INSERTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT ran');  
                }
             } 

    }  

    map<id,Contact> conMap = new map<id,Contact>();
    conMap.putAll(ContactList);

    // updating the Lead

    if(conMap.size()>0)
    {


        update conMap.Values();
    }
}//End of insert Contact



public static void updateOldContact(List<Task> tks, List<Task>tksOld){ // Trigger.New comes as List here

    Set<Id> ContactIds = new Set<Id>();
    Set<Id> OldContactIds = new Set<Id>(); //to get old contact ids
    List<Contact> ContactList = new List<Contact>();
    List<Contact> OldContactList = new List<Contact>();
    List<Contact> AllUpdateContactList = new List<Contact>();

    for(Task ot :tks)
    {
        if(ot.whoId!=null)
        {
            Schema.SObjectType otType= ot.whoId.getSObjectType();
            if(otType == Contact.Schema.SObjectType)
            {       
                ContactIds.add(ot.WhoId); //Get new contact Id
            }
        }
    }//End of Second loop         

            List<Contact> relatedContacts = [select id,Last_Contact_Date__c,
                                                                  Name, Last_Activity_TypeOfInteraction__c, 
                                                                  LastActivityDate, Last_Activity_Subject__c,
                                                                  Last_Activity_Date__c, Last_Activity_Name__c,
                                             (select id,Subject,ActivityDate,Owner.Name, Type_of_Interaction__c  from Tasks Order By ActivityDate DESC LIMIT 1)
                                                                  from Contact where id in:ContactIds];


            for (Contact relatedContact : relatedContacts)
                {
                    relatedContact.Last_Activity_Subject__c = relatedContact.Tasks[0].Subject;
                    relatedContact.Last_Activity_Assigned_to__c=relatedContact.Tasks[0].Owner.Name;
                    relatedContact.Last_Activity_Date__c = relatedContact.Tasks[0].ActivityDate;
                    relatedContact.Last_Activity_Name__c =  relatedContact.Name;
                    relatedContact.Last_Activity_TypeOfInteraction__c = relatedContact.Tasks[0].Type_of_Interaction__c;

                     System.debug('Printining that UPDATEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ran'); 


                    // etc.
                }
                update relatedContacts;


}//End of Update Old Contact

}//End of Class
4
  • Can you edit your question to show your current code? Also, are you using the Bulk API option with Dataloader? In your comment below on Adrian's answer you write, "Do you think because one task id is connected to multiple contacts?" That could absolutely be the issue - both your original code and the subquery that Adrian guided you to will only get Tasks related to the contact directly by the WhoId, and not any that are related indirectly via TaskRelation records. Aug 20, 2019 at 19:40
  • Thanks, Thomas. I have added full code. It has two parts to it. One for insert and one for the update. I tried updating with record Id and activity Id and where I saw the problem. So how do you think I should get all contact updated with this code correctly?
    – mike
    Aug 20, 2019 at 21:56
  • Can someone help with this issue?
    – mike
    Aug 27, 2019 at 15:24
  • You need to switch to using the TaskRelation object. There is a TaskRelation object for every Contact associated with a Task, including the one directly associated through the WhoId. Aug 27, 2019 at 16:27

3 Answers 3

2

Use a subquery to get the related Task records. Right now you are only pulling one Task, no matter how many Contact records are passed through. You want one per.

[
    SELECT ...
        (SELECT ... FROM Tasks ORDER BY ActivityDate DESC LIMIT 1)
    FROM Contact WHERE ...
]

Please note you will not even need a Map anywhere here, and there is no benefit to checking for empty collections before DML. So you can roughly simplify to the following:

Set<Id> contactIds = new Set<Id>();
// populate the same

List<Contact> relatedContacts = [/*same query as I mention above*/];
for (Contact relatedContact : relatedContacts)
{
    relatedContact.Last_Activity_Subject__c = relatedContact.Tasks[0].Subject;
    // etc.
}
update relatedContacts;
4
  • Adrian, I tried your solution and it says Variable Tasks does not exist. Please check the original post.
    – mike
    Aug 14, 2019 at 20:10
  • @mike Just a typo. Pretty easy one to spot. ;) I fixed it in my answer now.
    – Adrian Larson
    Aug 14, 2019 at 20:20
  • Omg that you so much !! It is working for 25 records as of now. I will be testing tomorrow for 40k records and I am very excited (crossed finger, hope it won't crash on me when I mass update). I did not get a chance to try everyone solution but wanted to say thank you to everyone for helping out here.. God bless you all !!
    – mike
    Aug 14, 2019 at 20:26
  • Hi Adrian, I tried updating 600 records and I did get a few problems here with this. Some contacts are still not getting updated to their first task instead they get updated for 5th or 6th task instead. I wonder why? Do you think because one task id is connected to multiple contacts ? I hope you read this message.
    – mike
    Aug 20, 2019 at 16:26
0

I'm not sure if this is the only problem, but you are trying to use = instead of IN:

task where WhoId =: ContactIds

->

task where WhoId IN: ContactIds

NOTE: Not an error but you already have the Contacts in a map. Use that instead of having a loop within a loop.

3
  • Thanks, dphil. Let me try this :)
    – mike
    Aug 14, 2019 at 19:37
  • 2
    Actually that is perfectly valid.
    – Adrian Larson
    Aug 14, 2019 at 19:40
  • @AdrianLarson Huh, the more you know!
    – dphil
    Aug 14, 2019 at 19:42
0

From what I can tell you want to identify when the contact on a task changes. When this happens, you want to update the new contact with the most recent task's information?

I would do it in the contact trigger.

public class contactService {
    // Should be in before update trigger
    // a contact cannot have tasks on insert
    public static void getRecentTaskInformation(List<Contact> contacts) {
        List<Contact> contactsWithLastTasks = [
            SELECT Id, Last_Activity_Subject__c, Last_Activity_Date__c,
                Last_Activity_Name__c , Last_Activity_Assigned_to__c ,
                Last_Activity_TypeOfInteraction__c , Name, (
                    SELECT Subject, ActivityDate, Owner.Name, 
                        Type_of_Interaction__c
                    FROM Tasks
                    ORDER BY ActivityDate DESC 
                    LIMIT 1
                )
            FROM Contact WHERE Id IN :contacts
        ];

        for (Contact c : contactsWithLastTasks) {
            if (!c.tasks.isEmpty()) {
                Task lastTask = c.tasks[0];

                c.Last_Activity_Subject__c = lastTask.subject;
                c.Last_Activity_Date__c = lastTask.activityDate;
                c.Last_Activity_Assigned_to__c = lastTask.Owner.Name;
                c.Last_Activity_Name__c  = c.Name;
                c.Last_Activity_TypeOfInteraction__c  = lastTask.Type_of_Interaction__c;
            }
        }
    }
}

Then in your task trigger you just need to update the contacts that you want to re-calculate:

trigger TaskTrigger on Task (after insert, after update) {
    List<Contact> contactsToRecalc = new List<Contact>();

    for (Task t : Trigger.New) {
        if (trigger.oldMap == null || t.WhoId != trigger.oldMap.get(t.Id).whoId) {
            contactsToRecalc.add(new Contact(Id=t.whoId));
            contactsToRecalc.add(new Contact(Id=trigger.oldMap.get(t.Id).Id));
        }
    }

    update contactsToRecalc;
}
3
  • I am not sure you will read this but I am thinking to use this trigger. I am confused about the part where you wrote "// Should be in before update trigger" & "// a contact cannot have tasks on insert" Also, shouldn't be trigger TaskTrigger on Contact? Thanks!
    – mike
    Sep 18, 2019 at 20:52
  • The only thing the task trigger does is fire the contact trigger. You are correct that there should be a contact trigger as well. The contact trigger will fire the code above in the contact service. There is no point putting the contact service code in the before insert trigger because there will never be any tasks on insert, not sure how else to explain that.
    – gNerb
    Sep 18, 2019 at 22:00
  • Sorry, but can you explain why do I need the TaskTrigger because you have it for Task. From your first reply, it sounds like you want me to run on Contact which I understood.
    – mike
    Sep 19, 2019 at 13:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .