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
  • 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. – Thomas Taylor Aug 20 '19 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 '19 at 21:56
  • Can someone help with this issue? – mike Aug 27 '19 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. – Thomas Taylor Aug 27 '19 at 16:27
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;
|improve this answer|||||
  • Adrian, I tried your solution and it says Variable Tasks does not exist. Please check the original post. – mike Aug 14 '19 at 20:10
  • @mike Just a typo. Pretty easy one to spot. ;) I fixed it in my answer now. – Adrian Larson Aug 14 '19 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 '19 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 '19 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.

|improve this answer|||||
  • Thanks, dphil. Let me try this :) – mike Aug 14 '19 at 19:37
  • 2
    Actually that is perfectly valid. – Adrian Larson Aug 14 '19 at 19:40
  • @AdrianLarson Huh, the more you know! – dphil Aug 14 '19 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;
}
|improve this answer|||||
  • 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 '19 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 '19 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 '19 at 13:15

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.