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
Drew Gehman 18Drew Gehman 18 

Trigger to update a custom activity field with information from the account associated with a task

Thanks to help from this forum, I created a trigger to populate task records with information from the associated account object. Because of this trigger, I now have the "account number" of the account tied to the task (via WHATID) included in the record as field "AccountBannerID". I can now export those tasks into another system, and relate them back to the account via the account number.  Thank you to @RatherGeeky, @thecrmninja and @EDLJames for assistance.

Open to suggestions, and any optimizations!

First the trigger:
trigger TaskRelatedToAcc on Task (before insert, before update)
{ 
// Created by DLG 3-31-16 
// Goal: Find the 'Account Number' of the account that a task is related to 
// and update the activity custom field 'AccountBannerID' with that value 
// If the task is related to an Account, query to find out the unique Account ID 
// Relation to an account is determined by the first three digits of the WhatID being 001
// Create collection of tasks that are related to an account (where the account is listed only once) 
Set<Id> AccIds = new Set<Id>(); 
for(Task t : trigger.new)
    {String wId = t.WhatId; 
        if(wId!=null && wId.startsWith('001') && !AccIds.contains(t.WhatId))
            {AccIds.add(t.WhatId);}
    } 
// Pull in account ids and related fields to populate task record 
List<Account> taskAccs = [Select Id, AccountNumber from Account where Id in :AccIds]; 
Map<Id, Account> accMap = new Map<Id, Account>(); 
for(Account o : taskAccs)
    {accMap.put(o.Id,o);} 
// Update the custom activity field 'Banner ID of Account' with the 'Account Number' field from Accounts object 
for(Task t : trigger.new)
    {String wId = t.WhatId; 
        if(wId!=null && wId.startswith('001'))
            { Account thisAcc = accMap.get(t.WhatId); 
                if(thisAcc!=null)
                    {t.AccountBannerID__c = thisAcc.AccountNumber;
                        if(t.AccountBannerID__c==null){t.AccountBannerID__c='BannerID Not Available';} /*if BannerID is not in Account Number let it be known */
                    }
            }
    }
}

Now the test 
@isTest
private class TaskRelatedToACCTriggerTestClass { 
static testMethod void myUnitTest() {
// Run test of code
//HERE, WE CREATE AN ACCOUNT 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 ACCOUNT
Account aDS = new Account(name='SomeAccount', AccountNumber='123 or text');
insert aDS; 
//NOW, CREATE A TASK ASSIGNED TO THE ACCOUNT
Task t1 = new Task(subject='test', WhatId = aDS.id, description = 'test description'); 
insert t1; 
//NOW, RUN AN ASSERT CALL TO MAKE SURE THE CUSTOM FIELD ON THE TASK HAS THE VALUE FROM THE ACCOUNT
//THIS IS WHAT TESTS THE FUNCTIONALITY OF THE TRIGGER
Task t = [Select AccountBannerID__c from Task where id = :t1.id];
system.AssertEquals('123 or text', t.AccountBannerID__c);
}
}


 
Shashikant SharmaShashikant Sharma
Hi Drew,

Looks fine both trigger and test class.

Only one suggestion, your trigger works on before insert and before update.

You are using following code to add to account id set which is used further
 
if(wId!=null && wId.startsWith('001') && !AccIds.contains(t.WhatId))
          {AccIds.add(t.WhatId);}

This will make your code getting eccecuted every time record is updated regardless there is any change in relevant field. Means on update it will only need to be executed when WhatId is changed.

If you want to include that criteria then just update this code to
if(wId!=null && wId.startsWith('001') && !AccIds.contains(t.WhatId)) {

// when task is inserted or account is updated or  t.AccountBannerID__c == null
if( trigger.isInsert || wId != trigger.OldMap(t.Id).WhatId ||  t.AccountBannerID__c == null ) {
     AccIds.add(t.WhatId);
}

}

Other than What ID change i have added criteria for  t.AccountBannerID__c == null so that if any record does not get populated earlier for any reason that is accepted by criteria.

Thanks
Shashikant
Mahesh DMahesh D
Hi Drew,

First of all I would like to appreciate that you have written the code very nicely by adding lot of comments and logic.

Below is my code which I did few changes on top of your code:

Here I considered:

(1) Alignment.
(2) Naming Convention.
(3) Modified the logic to capture the valid Tasks into a taskList variable, so that I don't need to check all conditions again in the second for loop.
(4) Added null / empty checks.
// Created by DLG 3-31-16 
// Goal: Find the 'Account Number' of the account that a task is related to 
// and update the activity custom field 'AccountBannerID' with that value 
// If the task is related to an Account, query to find out the unique Account ID 
// Relation to an account is determined by the first three digits of the WhatID being 001
// Create collection of tasks that are related to an account (where the account is listed only once)
trigger TaskRelatedToAcc on Task (before insert, before update) { 
     
    Set<Id> accIdSet = new Set<Id>();
    List<Task> taskList = new List<Task>();
    
    for(Task t : trigger.new) {
        String wId = t.WhatId; 
        if(wId != null && wId.startsWith('001') && !accIdSet.contains(t.WhatId)) {
            // when task is inserted or account is updated or  t.AccountBannerID__c == null
            if( trigger.isInsert || wId != trigger.OldMap.get(t.Id).WhatId ||  t.AccountBannerID__c == null ) {
                accIdSet.add(t.WhatId);
                taskList.add(t);
            }
        }
    }
    
    if(!accIdSet.isEmpty()) {
    
        // Pull in account ids and related fields to populate task record 
        Map<Id, Account> accMap = new Map<Id, Account>([Select Id, AccountNumber from Account where Id IN :accIdSet]);
        
        // Update the custom activity field 'Banner ID of Account' with the 'Account Number' field from Accounts object 
        for(Task t : taskList) {
            Account thisAcc = accMap.get(t.WhatId); 
            if(thisAcc!=null) {
                t.AccountBannerID__c = thisAcc.AccountNumber;
                if(t.AccountBannerID__c==null){
                    t.AccountBannerID__c='BannerID Not Available'; /*if BannerID is not in Account Number let it be known */
                }
            }
        }
    }
}

Below is the Test Class:

Here I considered:
(1) Only alignment, otherwise everything looks good and the code coverage is 93%.
@isTest
private class TaskRelatedToACCTriggerTestClass { 
    static testMethod void myUnitTest() {
        // Run test of code
        //HERE, WE CREATE AN ACCOUNT 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 ACCOUNT
        Account aDS = new Account(name='SomeAccount', AccountNumber='123 or text');
        insert aDS; 
        //NOW, CREATE A TASK ASSIGNED TO THE ACCOUNT
        Task t1 = new Task(subject='test', WhatId = aDS.id, description = 'test description'); 
        insert t1; 
        //NOW, RUN AN ASSERT CALL TO MAKE SURE THE CUSTOM FIELD ON THE TASK HAS THE VALUE FROM THE ACCOUNT
        //THIS IS WHAT TESTS THE FUNCTIONALITY OF THE TRIGGER
        Task t = [Select AccountBannerID__c from Task where id = :t1.id];
        system.AssertEquals('123 or text', t.AccountBannerID__c);
    }
}

Please do let me know if it helps you.

Regards,
Mahesh