You need to sign in to do that
Don't have an account?

Trigger on Task to Update Opportunity and Account
I've created a trigger on a Task to update a custom Opportunity field (Last_Contact_Date__c). The field gets updated based on the most recent task Activity Date. The trigger is seen below and works as desired:
However, then I tried to modify this trigger to also update a custom Accounts variable (In_Touch_Date__c) but I cannot get it to function properly.
Here is the modified code:
trigger UpdateOppLastContactDate on Task (after insert, after update) { Set<String> whatIDs = new Set<String>(); for (Task t : Trigger.new) { whatIDs.add(t.whatID); } List<Opportunity> opps = [SELECT Id, Last_Contact_Date__c FROM Opportunity WHERE Id =: whatIDs]; Map<String, Task> taskMap = new Map<String, Task>(); for (Task t : Trigger.new){ if (!(t.Type.equals('Eloqua Activity'))) { if (t.Status.equals('Completed')) { taskMap.put(t.whatID, t); } } } for (Opportunity o : opps) { if (taskMap.containsKey(o.Id)) { o.Last_Contact_Date__c = taskMap.get(o.Id).ActivityDate; } } update opps; }
However, then I tried to modify this trigger to also update a custom Accounts variable (In_Touch_Date__c) but I cannot get it to function properly.
Here is the modified code:
trigger UpdateOppLastContactDate on Task (after insert, after update) { Set<String> whatIDs = new Set<String>(); for (Task t : Trigger.new) { whatIDs.add(t.whatID); } List<Opportunity> opps = [SELECT Id, Last_Contact_Date__c FROM Opportunity WHERE Id =: whatIDs]; Map<Id, Account> accts = new Map<Id, Account>(); Map<String, Task> taskMap = new Map<String, Task>(); for (Task t : Trigger.new){ if (!(t.Type.equals('Eloqua Activity'))) { if (t.Status.equals('Completed')) { taskMap.put(t.whatID, t); } } } for (Opportunity o : opps) { if (taskMap.containsKey(o.Id)) { o.Last_Contact_Date__c = taskMap.get(o.Id).ActivityDate; Account a = accts.get(o.AccountId); if (a.In_Touch_Date__c != null) { if (taskMap.get(o.Id).ActivityDate.daysBetween(a.In_Touch_Date__c) < 0) { a.In_Touch_Date__c = taskMap.get(o.Id).ActivityDate; } } } } update opps; }I've bolded the updated code, any advice on why this doesn't work is much apprecaited.
The exception is getting thrown because the equals() String method does not like null values; that's the Null in NullPointerException, so you have to test for null first before you can even evaluate the Type field. If it's null, you don't want the equals() method to get called at all.
I also noted that the Account__r is unnecessary, we can simply use Account.In_Touch_Date__c
Although it's not a problem, the trigger does a lot of unnecessary processing when the Task is not related to an Opportunity. A few if(opps.size() > 0){} conditions around anything checking the opps List will keep things running efficiently.
I commented the few changes I made below.
(and I just noticed that Safari doesn't seem to generate that nice Code block! Back to Firefox for Forum work I guess!)
All Answers
There's a couple things missing here. The Account map is not populated with any records, so you will need to add a query to do that, or modify your existing Opportunity query to populate it with the Accounts for the Opportunities you're referencing. After you have the Account records in the map, your for loop should put the update values back into the accts map. And finally, don't forget the all-important update accts DML call.
I'm winging this while sprint-planning but will check it out later if it doesn't get you further:
add AccountId and Account__r.In_Touch_Date__c into your query and then after declaring your Account map populate it:
for(Opportunity o : opps){
accts.put(o.AccountId, o.Account__r.In_Touch_Date__c);
}
that would allow your accts.get() to acquire the related Account, check its In_Touch_Date__c field value and update it.
From there you'll need to update the map again: accts.put(o.AccountId, o.Account__r.In_Touch_Date__c);
Finally, you'll need to do the DML update:
update accts;
There are definitely more efficient ways to organize & error-proof all this (and probably a few typos in my psuedo code above), so let me know how far that gets you and I'll check back in a few hours for further improvements.
So I've updated the code:
But now I receive the following error:
DML requires SObject or SObject list type: MAP<Id, Account>
Any suggestions?
Cheers
You can "cast" the Map to a List by using update accts.values(); which will give the update DML the list of sObjects it wants.
One hazard to consider is that the accts Map has all of the Accounts for all the Opportunities returned by your query, not just the ones that you filtered in line 39. You could create a second Map to hold the ones you actually want to update. You could also just use an Account List, but if you ever need to expand the trigger in the future to handle other updates to Accounts, the Map allows you to do that more easily.
Nice work accounting for my haphazard advice and getting the put() correct with the inclusion of the sObject itself and not just the field.
Apex trigger UpdateOppLastContactDate caused an unexpected exception, contact your administrator: UpdateOppLastContactDate: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.UpdateOppLastContactDate: line 23, column 1
Here is the updated code:
And thanks for all the help! Very helpful.
The exception is getting thrown because the equals() String method does not like null values; that's the Null in NullPointerException, so you have to test for null first before you can even evaluate the Type field. If it's null, you don't want the equals() method to get called at all.
I also noted that the Account__r is unnecessary, we can simply use Account.In_Touch_Date__c
Although it's not a problem, the trigger does a lot of unnecessary processing when the Task is not related to an Opportunity. A few if(opps.size() > 0){} conditions around anything checking the opps List will keep things running efficiently.
I commented the few changes I made below.
(and I just noticed that Safari doesn't seem to generate that nice Code block! Back to Firefox for Forum work I guess!)
Any ideas?
Cheers