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
tgk1tgk1 

Trigger / Test Class Help - updating a field on an account from a child task record

Hi everyone.  I have a trigger that currently works fine through the user interface.  However I need to bulk update 85,000 task records and the trigger is causing failures.

 

Intended trigger purpose:  Update the Last_SW_Activity__c field (date time field) on the account object with the last modified date of the record when a task record meets the following criteria:

  1. The Subject Line starts with "sw".
  2. The task is marked as completed.
trigger LastSWDate on Task (after insert, after update) {
 
  //To do - If the subject of a completed task contains "SW", put the date of the completed task in the 
  //the "Last_SW_Activity__c" field on the account object

//Create a set of related account ID's
Set <ID> acctIDs = new Set <ID> ();
//Create a list to hold the Updated Accounts
List<Account> updAccts = new List<Account>();

//For every task, add it's related to account ID to the set
  for (Task t: Trigger.new){
    acctIDs.add(t.accountID);
//Create a map to match the task related to ID's with their corresponding account ID's
    Map<ID, Account> acctMap = new Map<ID, Account> ([Select ID, Last_SW_Activity__c from Account where ID in :acctIDs]);
//Create the account object
      Account acctRec = acctMap.get(t.accountID);

//If the account ID isn't null, the subject line starts with "sw", and the task has been marked as completed    
  If ((t.accountID != null) &&(t.subject.indexOf('sw')==0) && (t.Status == 'Completed'))
//Check to see if the Last_SW_Activity__c field is current compared with the latest completed activity
      If (acctMap.get(t.accountID).Last_SW_Activity__c < t.LastModifiedDate || acctMap.get(t.accountID).Last_SW_Activity__c ==null){
//Update the Last_SW_Activity__c field on the account object with the task's end date  
        acctrec.Last_SW_Activity__c = t.LastModifiedDate;
        updAccts.add(acctrec);
    }
  }
  update updAccts;
}

 Can somebody please help make the trigger code more efficient (bulkifying it) and help with creating a test class?  I'm not a developer and could use some serious help here.  Thanks!!

 

 

Best Answer chosen by Admin (Salesforce Developers) 
SLockardSLockard

Okay, I guess the WhoId has to be for a contact, so change your test like this:

@isTest
private class TestSW
{
    static testMethod void testSW() 
    {
		Integer num = 5;
        String aName = 'Test-acc-';
        List<Account> accList = new List<Account>();
        for (Integer i = 0; i < num; i++)
        {
            aName = aName + String.valueof(i);
            accList.add(new Account(Name = aName, Last_SW_Activity__c = date.today()-1));
            aName = 'Test-acc-';
        }
        insert accList;
		
		String cName = 'Test-con-';
        List<Contact> conList = new List<Contact>();
        for (Integer i = 0; i < num; i++)
        {
            cName = cName + String.valueof(i);
            conList.add(new Contact(AccountId = accList[i].Id, LastName = 'Test-con-lastname'));
            cName = 'Test-con-';
        }
        insert conList;
		
        String tName = 'Test-task-';
        List<Task> tList = new List<Task>();
        for (Integer i = 0; i < num; i++)
        {
            tName = tName + String.valueof(i);
            tList.add(new Task(Subject = 'sw', WhoId = conList[i].Id, ActivityDate = date.today()-100, Status = 'Completed', LastModifiedDate = date.today()));
            tName = 'Test-task-';
        }
        
        Test.startTest();
        
        insert tList;
		
		Test.stopTest();
		
		// assert here
		Account a = [SELECT Last_SW_Activity__c FROM Account WHERE Name = 'Test-acc-1'];
		system.assertequals(date.today(), a.Last_SW_Activity__c);
	}
}

 

All Answers

SLockardSLockard

To bulkify the trigger, just move the SOQL query out of the for loop like this:

trigger LastSWDate on Task (after insert, after update) 
{
 
	//To do - If the subject of a completed task contains "SW", put the date of the completed task in the 
	//the "Last_SW_Activity__c" field on the account object

	//Create a set of related account ID's
	Set <ID> acctIDs = new Set <ID> ();
	//Create a list to hold the Updated Accounts
	List<Account> updAccts = new List<Account>();

	//For every task, add it's related to account ID to the set
	for (Task t: Trigger.new)
	{
		acctIDs.add(t.accountID);
	}
	//Create a map to match the task related to ID's with their corresponding account ID's
    Map<ID, Account> acctMap = new Map<ID, Account> ([Select ID, Last_SW_Activity__c from Account where ID in :acctIDs]);
	for (Task t: Trigger.new)
	{
		//Create the account object
		Account acctRec = acctMap.get(t.accountID);

		//If the account ID isn't null, the subject line starts with "sw", and the task has been marked as completed    
		if ((t.accountID != null) &&(t.subject.indexOf('sw')==0) && (t.Status == 'Completed'))
		{
			//Check to see if the Last_SW_Activity__c field is current compared with the latest completed activity
			if (acctMap.get(t.accountID).Last_SW_Activity__c < t.LastModifiedDate || acctMap.get(t.accountID).Last_SW_Activity__c ==null)
			{
				//Update the Last_SW_Activity__c field on the account object with the task's end date  
				acctrec.Last_SW_Activity__c = t.LastModifiedDate;
				updAccts.add(acctrec);
			}
		}
	}
	update updAccts;
}

 And your test class could be something like this :

@isTest
private class TestSW
{
    static testMethod void testSW() 
    {
		Integer num = 5;
        String aName = 'Test-acc-';
        List<Account> accList = new List<Account>();
        for (Integer i = 0; i < num; i++)
        {
            aName = aName + String.valueof(i);
            accList.add(new Account(Name = aName, Last_SW_Activity__c = date.today()-1));
            aName = 'Test-acc-';
        }
        insert accList;
        String tName = 'Test-task-';
        List<Task> tList = new List<Task>();
        for (Integer i = 0; i < num; i++)
        {
            tName = tName + String.valueof(i);
            tList.add(new Task(Subject = 'sw', WhoId = accList[i].Id, ActivityDate = date.today()-100, Status = 'Completed', LastModifiedDate = date.today()));
            tName = 'Test-task-';
        }
        
        Test.startTest();
        
        insert tList;
		
		Test.stopTest();
		
		// assert here
		Account a = [SELECT Last_SW_Activity__c FROM Account WHERE Name = 'Test-acc-1'];
		system.assertequals(date.today(), a.Last_SW_Activity__c);
	}
}

 I may have missed a few fields, but that is most of it I believe.

If you want to test 85000, just change num to 85000, but that may still cause an error because you may need to do a batch job instead.

tgk1tgk1

Thanks for your help SLockard - I really appreciate it.  The trigger appears to work fine but the test class is resulting in a failure with the following error:

 

System.DmlException: Insert failed. First exception on row 0; first error: FIELD_INTEGRITY_EXCEPTION, Contact/Lead ID: id value of incorrect type: 001P000000Z4U1sIAF: [WhoId]

SLockardSLockard

Okay, I guess the WhoId has to be for a contact, so change your test like this:

@isTest
private class TestSW
{
    static testMethod void testSW() 
    {
		Integer num = 5;
        String aName = 'Test-acc-';
        List<Account> accList = new List<Account>();
        for (Integer i = 0; i < num; i++)
        {
            aName = aName + String.valueof(i);
            accList.add(new Account(Name = aName, Last_SW_Activity__c = date.today()-1));
            aName = 'Test-acc-';
        }
        insert accList;
		
		String cName = 'Test-con-';
        List<Contact> conList = new List<Contact>();
        for (Integer i = 0; i < num; i++)
        {
            cName = cName + String.valueof(i);
            conList.add(new Contact(AccountId = accList[i].Id, LastName = 'Test-con-lastname'));
            cName = 'Test-con-';
        }
        insert conList;
		
        String tName = 'Test-task-';
        List<Task> tList = new List<Task>();
        for (Integer i = 0; i < num; i++)
        {
            tName = tName + String.valueof(i);
            tList.add(new Task(Subject = 'sw', WhoId = conList[i].Id, ActivityDate = date.today()-100, Status = 'Completed', LastModifiedDate = date.today()));
            tName = 'Test-task-';
        }
        
        Test.startTest();
        
        insert tList;
		
		Test.stopTest();
		
		// assert here
		Account a = [SELECT Last_SW_Activity__c FROM Account WHERE Name = 'Test-acc-1'];
		system.assertequals(date.today(), a.Last_SW_Activity__c);
	}
}

 

This was selected as the best answer
tgk1tgk1

Worked perfectly, thank you so much!

SLockardSLockard

No problem, I'm glad I could help!