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
RatherGeekyRatherGeeky 

Trigger: Update Custom Field on Task Based on Related WhatID Record

Goal: use a trigger to update a custom field on the Task (OppNumber) with a field on the Opportunity that is selected in the WhatID field (if an Opp is selected)

 

I thought this would be easy to do using a lookup and just passing the value, but you apparently cannot create a lookup on the Activity/Task object. 

 

I know I can pull in the record ID for the opp related via the WhatID field, but how can I refer to a specific field on that record? (Such as the Opportunity Number).

 

Open to suggestions.

 

 

Best Answer chosen by Admin (Salesforce Developers) 
RatherGeekyRatherGeeky

Resolved this with a trigger, created step by step with a referral from my customer success rep (amazing support! I am very pleased).

 

Here's the code:

 

trigger TaskRelatedToOpp on Task (before insert, before update) { // Goal: Find the opp ID of the opportunity that a task is related to // and update the Opportunity_Number field on the task object with the value // If related to an Opportunity, query to find out the Opportunity number // Create collection of tasks that are related to an opp (where the opp is listed only once) Set<Id> opIds = new Set<Id>(); for(Task t : trigger.new){ String wId = t.WhatId; if(wId!=null && wId.startsWith('006') && !opIds.contains(t.WhatId)){ opIds.add(t.WhatId); } } // Pull in opp ids and related field to populate task record List<Opportunity> taskOps = [Select Id, Opportunity_Number__c from Opportunity where Id in :opIds]; Map<Id, Opportunity> opMap = new Map<Id, Opportunity>(); for(Opportunity o : taskOps){ opMap.put(o.Id,o); } // Update custom task field with custom opp field for(Task t : trigger.new){ String wId = t.WhatId; if(wId!=null && wId.startswith('006')){ Opportunity thisOp = opMap.get(t.WhatId); if(thisOp!=null){t.Opportunity_Number__c = thisOp.Opportunity_Number__c;} } } }

 

 Awesome! Works perfectly.

 

 

 

All Answers

RatherGeekyRatherGeeky

Well, I at least determined that I can figure out based on the id if a related record is an opp or not. (I just discovered that there is a standard opp id prefix of "006". Duh)

 

I added a field ("myWhatId)to my activity object that shows the id of the WhatID record selected in the lookup. I also a field to my activty object for "IsOpp", which looks at the first three characters of the id and returns "True" if it starts with "006." 

 

So, now I just need help with some sort of a trigger that does something like "If IsOpp = true, Task.OppNumber = Opp.OppNumber where Opp.Id = task.myWhatId"

 

Going to test out on my own. I'm not very familiar with syntax, so if anyone has a tip that would be great.

RatherGeekyRatherGeeky
This is what I have so far. Triggers still don't make much sense to me and I've been looking for a simple example of something similar to refer to.

trigger TaskRelatedToOpp on Task (after insert, after update) {

// Goal: Find the opp ID of the opportunity that a task is related to
// and update the Opportunity_Number field on the task object with the value

// If related to an Opportunity, query to find out the Opportunity number

If(IsOpp__c=='True') {

Opportunity Opp = [SELECT Id, Opportunity_Number__c FROM Opportunity WHERE Id = myWhatID__c]

Opp_Number__c = Opp.Opportunity_Number__c

}

}

 (Obviously, this doesn't work.)


Message Edited by J Baze on 09-28-2009 04:38 PM
McAdminMcAdmin
I had a similar problem two weeks ago, and I was able to fix it with access rights. I wish I had the solution documented, but maybe this could help point you in the right direction. I apologize for the vague response, hope that brings some ideas to mind. 
RatherGeekyRatherGeeky
Thanks for the information. I will do some research about access rights and see what I can find.
RatherGeekyRatherGeeky

Resolved this with a trigger, created step by step with a referral from my customer success rep (amazing support! I am very pleased).

 

Here's the code:

 

trigger TaskRelatedToOpp on Task (before insert, before update) { // Goal: Find the opp ID of the opportunity that a task is related to // and update the Opportunity_Number field on the task object with the value // If related to an Opportunity, query to find out the Opportunity number // Create collection of tasks that are related to an opp (where the opp is listed only once) Set<Id> opIds = new Set<Id>(); for(Task t : trigger.new){ String wId = t.WhatId; if(wId!=null && wId.startsWith('006') && !opIds.contains(t.WhatId)){ opIds.add(t.WhatId); } } // Pull in opp ids and related field to populate task record List<Opportunity> taskOps = [Select Id, Opportunity_Number__c from Opportunity where Id in :opIds]; Map<Id, Opportunity> opMap = new Map<Id, Opportunity>(); for(Opportunity o : taskOps){ opMap.put(o.Id,o); } // Update custom task field with custom opp field for(Task t : trigger.new){ String wId = t.WhatId; if(wId!=null && wId.startswith('006')){ Opportunity thisOp = opMap.get(t.WhatId); if(thisOp!=null){t.Opportunity_Number__c = thisOp.Opportunity_Number__c;} } } }

 

 Awesome! Works perfectly.

 

 

 

This was selected as the best answer
jvolkovjvolkov

Thanks for posting this J Blaze, switching out opportunity with account works perfectly to update the task object with account custom fields as well.

 

What does your test class look like?

RatherGeekyRatherGeeky

Here's my test class:

 

@isTest private class TaskRelatedToOppTriggerTestClass { static testMethod void myUnitTest() { // Run test of code Opportunity o = [select Id from opportunity limit 1]; Task t1 = new Task(subject='test', WhatId = o.id, description = 'test description'); insert t1; } }

 

 

 

symantecAPsymantecAP

Hi I have a same kind of issue . I am sure you may find  a easy solution for this ..

 

"If an activity/task is associated with an opportunity, a territory field on the task should reflect that opportunity."

Write a trigger on Tasks/Event to populate a custom field "Opportuity Territory" on Activities object.

 

 

If i can get a bit help on this..

 

Thanks

thecrmninjathecrmninja

You can use the code above making a few minor changes (to get your fields covered)

 

 

trigger TaskRelatedToOpp on Task (before insert, before update) { // Goal: Find the opp ID of the opportunity that a task is related to // and update the Opportunity_Number field on the task object with the value // If related to an Opportunity, query to find out the Opportunity number // Create collection of tasks that are related to an opp (where the opp is listed only once) Set<Id> opIds = new Set<Id>(); for(Task t : trigger.new){ String wId = t.WhatId; if(wId!=null && wId.startsWith('006') && !opIds.contains(t.WhatId)){ opIds.add(t.WhatId); } } // Pull in opp ids and related field to populate task record List<Opportunity> taskOps = [Select Id, Opportunity_Number__c from Opportunity where Id in :opIds]; Map<Id, Opportunity> opMap = new Map<Id, Opportunity>(); for(Opportunity o : taskOps){ opMap.put(o.Id,o); } // Update custom task field with custom opp field for(Task t : trigger.new){ String wId = t.WhatId; if(wId!=null && wId.startswith('006')){ Opportunity thisOp = opMap.get(t.WhatId); if(thisOp!=null){t.PUT YOUR TASK FIELD NAME HERE__c = thisOp.PUT YOUR OPPORTUNITY FIELD NAME HERE;} } } }

 

 Replace "PUT YOUR TASK FIELD NAME HERE__c" with your task field name (Ex: Custom_Task_Field__c) and then Replace "PUT YOUR OPPORTUNITY FIELD NAME HERE__c" with your task field name (Ex: Custom_Opportunity_Field__c).  Then, use the test class above.

 

thecrmninjathecrmninja

J Baze wrote:

Here's my test class:

 

@isTest

private class TaskRelatedToOppTriggerTestClass {

static testMethod void myUnitTest() {

// Run test of code

Opportunity o = [select Id from opportunity limit 1];

Task t1 = new Task(subject='test', WhatId = o.id, description = 'test description');

insert t1;

}

}

 

 

Hey, Jbaze, how much coverage do you get on this test class?  When I look at this, it seems like it could be optimized to follow best practices and get higher coverage (not that I'm any sort of testing guru).

 

 


 

Message Edited by thecrmninja on 02-10-2010 12:34 PM
RatherGeekyRatherGeeky

thecrmninja:

 

I'm sure it could be optimized. My knowledge about code and test classes is pretty minimal. So, feel free to have at it!

RatherGeekyRatherGeeky

thecrmninja: By the way, thanks for responding to symantecAP with the suggestion to modify my code. It's been awhile since I revisited this, so your response was appreciated.

thecrmninjathecrmninja

Ok, i've thrown together something quickly that you could try.  I'd love to hear if this improves your results. 

 

Because your trigger was very straightforward (and has only a few lines) it's not going to make a signficant difference.  However, this is a great way for you to learn a bit more about test classes so that you can advance your ambitions and create more throroughly vetted code in the future

 

!!!EDITOR'S NOTE!!! I have made the assumption that your custom field is a Text Field. If it is a number field, this test class will fail.  Please let me know if it is and I can adapt the Test Class easily.  All that would need to change is removal of quotes from around 123 (in two parts of the code) and to have "STRING t" changed to "INTEGER T"

 

I've laced this class with comments to try to explain why I made the changes that I did.  I just want to make sure that anybody that comes across your great trigger example learns a little about Testing via classes.  

 

Let me know if this works. (I did it quickly, so I might have overlooked something)

 

 

@isTest

private class TaskRelatedToOppTriggerTestClass {

static testMethod void myUnitTest() {

// Run test of code

//I'VE REMOVED THIS LINE IN FAVOR OF CREATING AN OPP RECORD IN THIS TEST CLASS THAT IS CATERED TOWARDS THIS TEST CLASS
//Opportunity o = [select Id from opportunity limit 1];

//HERE, WE CREATE AN OPP RECORD PUTTING A VALUE IN THE FIELD THAT YOU CALL IN YOUR TRIGGER
//WE WANT TO TEST THE COMPLETE FUNCTIONALITY OF YOUR TRIGGER SO IT IS IMPORTANT TO VALIDATE, VIA THE TEST CLASS
//THAT YOUR TRIGGER ACHIEVES THE DESIRED RESULTS.. ...UPDATING A FIELD ON A TASK WITH A VALUE FROM AN OPP

//SOME SFDC ORGS HAVE ACCOUNTS AS REQUIRED FIELDS ON OPPS, SO I'M CREATING ONE JUST TO BE SAFE
Account aDS = new Account(name='jbaze');
insert aDS;

//NOW I'M CREATING AN OPP AND PUTTING A VALUE IN THE FIELD THAT YOUR TRIGGER CALLS
Opportunity opTASK = new Opportunity(name='test value to task', Account=aDS, closedate=system.today(), stagename='Prospect',Opportunity_Number__c = '123');
insert opTASK;

//IMPORTANT NOTE!!!!!!!! I'VE MADE AN ASSUMPTION THAT YOUR CUSTOM FIELD IS A TEXT FIELD,
//IF IT IS NOT, REMOVE THE QUOTES AROUND '123'

//NOW, AS IN YOUR ORIGINAL, WE ARE CREATING A TASK ASSIGNED TO THE OPP
Task t1 = new Task(subject='test', WhatId = opTASK.id, description = 'test description');

insert t1;

//NOW, THE CRITICAL PART, WE WILL RUN AN ASSERT CALL TO MAKE SURE THAT THE CUSTOM FIELD ON THE TASK HAS THE VALUE FROM THE OPP
//THIS IS WHAT TESTS THE FUNCTIONALITY OF YOUR TRIGGER

STRING t = [Select Opportunity_Number__c from Task where id = :t1.id];

system.AssertEquals('123', t);

//BEFORE, THE TEST CLASS WAS MERELY CAUSING YOUR TRIGGER TO FIRE, NOT CONFIRMING THAT IT WORKS AS EXPECTED
//NOW, YOU SHOULD SEE AN INCREASE IN YOUR CODE COVERAGE

}

}

 

 

 

Message Edited by thecrmninja on 02-12-2010 06:43 AM
DDSDDS

I tried using this code to update the field on the related object but it doesnt seem to work. Instead of updating the field on the Task, I want to update the field on my related custom object "Store__c"

 

Basically, I have a task with several Date fields, and each time I update a date on the task, it should update the date on the Store page as well.

 

I thought that just reversing that last statement would do the trick...but nothing seems to happen on the Store record:

 

// Update custom Store field with custom task field
for(Task t : trigger.new){
String wId = t.WhatId;
if(wId!=null && wId.startswith('a0I')){
Store__c thisStore = storeMap.get(t.WhatId);
if(thisStore!=null){thisStore.DSL_Install_Date__c = t.DSL_Install_Date__c;}
}

 

Let me know if I'm not making sense.

TheresaAndersonTheresaAnderson

Can you provide the code that will take a custom field from opportunities and update the standard task field called comment?

aaronderanaaronderan

Bringing it back from the dead but...

 

One thing to add to this reply on customizing the code though...

 

You need to change Opportunity_Number__c in line 17 as well.