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
SpunkySpunky 

Tracking first completed activity on an opportunity

We have a business requirement to track the # of days between an opportunity being created and the first completed task against that opp.

 

I've created 2 triggers and 1 apex class to achive this. The triggers work as desired but i'm having trouble with the apex class. Since I don't have enough test coverage, I can't migrate this to production but i just can't figure out what needs to be corrected on the test class. Can someone please help me with this?

 

1) Store an activity completed date

 

 

trigger Task_Completed_Date on Task (before insert, before update) {
   Task[] checkTasks = Trigger.new;
   for(Task t : checkTasks){
      if(t.Status=='Completed'){
         t.DateTimeCompleted__c = System.now();
      }
   }
}

 

2) Update a custom field on the opp called "First_Activity_Completed_date__c" with that date

 

trigger Update_FirstCompletedActivity_onOpp on Task (after insert, after update){  
    List<Opportunity> Opp = new List<Opportunity>();  
    for (Task t: Trigger.new)  {   
    if(t.Type=='Call Back'&&t.Status=='Completed'){   
        Opp = [select Id,First_Completed_Activity__c from Opportunity where Id=:t.WhatId];     
        Opp[0].First_Completed_Activity__c = t.DateTimeCompleted__c;   
        update Opp;
        }
}
}

 Test Class

 

public class testTask_Completed_Date{

    static testmethod void testme(){
 
     Opportunity opp = [select First_Completed_Activity__c from Opportunity where recordtypeid = '012300000000lqDAAQ' limit 1];
                System.debug('[[[[[[[[[[[[[[[[[[[[[[ start '+opp.Id);
    System.assert(opp.First_Completed_Activity__c == null );  
    System.assert(opp.NextStep != 'xx' );  
    Task tk = new Task(OwnerId = opp.OwnerId,Status='Not Started',Subject = 'test', Type = 'Test', ActivityDate = Date.newInstance(2026,10,10),WhatId = opp.Id);
    insert tk;
    opp = [select First_Completed_Activity__c from Opportunity where Id = :opp.Id ];

    tk.ActivityDate = Date.newInstance(2026,11,10);
    update tk;
    opp = [select First_Completed_Activity__c from Opportunity where ownerid = '00530000000ybdAAAQ' limit 1 ];

    
    //Events

    Schema.DescribeFieldResult f = Event.Type.getDescribe();
    List <Schema.PicklistEntry> typevalues = f.getPicklistValues();
    List<Event> events = new List<Event>();
    for (Schema.PicklistEntry avalue :typevalues) {
      events.add(new Event(OwnerId = opp.OwnerId, Subject = 'test', ActivityDateTime= Datetime.now()+5 ,DurationInMinutes=60, WhatId = opp.Id, Type = avalue.getValue()));
    }
    insert events;          
      }
}

 

 

 

Jeremy_nJeremy_n

If you are using Eclipse IDE, you should have a list of the un-covered lines of code. This is a good place to start. For each line, figure out what would be the test case that would trigger that logic, and code it.

 

If you have specific lines that you are having trouble covering, please post them.

 

Jeremy

sfdcfoxsfdcfox

There's one small issue: your code doesn't support bulk processing, which means that a synchronization against Salesforce might fail. Your SOQL query should be moved outside of the loop.

 

 

trigger Update_FirstCompletedActivity_onOpp on Task (after insert, after update) {
  // Map tasks to the related opportunity.
  Map<Id,Task>oppTaskMap = new Map<Id,Task>();
  // Opportunities to update.
  List<Opportunity> opps = new List<Opportunity>();
  // Build the mapping for closed tasks.
  for(Task t:Trigger.new)
   if(t.whatid<>null && t.Status=='Completed')
     oppTaskMap.put(t.whatid,t);
  // Find opportunities that will be updated, and add them to the list.
  for(Opportunity o:[select id,first_completed_activity__c from opportunity where id in :oppTaskMap.keySet() and first_completed_activity__c=null])
    opps.add(new opportunity(id=o.id,first_completed_activity__c=oppTaskMap.get(o.id).DateTimeCompleted__c));
  // If we have any updates, do so now.
  if(!opps.isEmpty())
    update opps;
}

 

In regards to code coverage, you should probably take the path of least resistance. I would write a class as follows:

 

 

@isTest
public class testTriggers {
  public static testMethod void testTaskTriggers()
  {
    Opportunity o = new Opportunity(Name='Test',CloseDate=System.Today(),StageName='Won');
    insert o;
    Task t1 = new Task(Status='Not Started',Subject='Test',WhatId=o.id,Type='Test',ActivityDate=System.Today().addDays(10));
    insert t1;
    o = [select id,First_Completed_Activity__c from opportunity where id = :o.id];
    System.AssertEquals(null,o.First_Completed_Activity__c,'This date should be a null value.');
    t1 = [select id,whatid,activitydate,status,datetimecompleted__c from task where id = :t1.id];
    t1.Status='Completed';
    update t1;
    System.AssertEquals(t1.DateTimeCompleted__c,o.First_Completed_Activity__c,'This date should be set to the Task date.');
    Task t2 = new Task(Status='Completed',Subject='Test',WhatId=o.id,Type='Test',ActivityDate=System.Today().addDays(5));
    insert t2;
    o = [select id,First_Completed_Activity__c from opportunity where id = :o.id];
    System.assertEquals(t1.ActivityDate,o.First_Completed_Activity__c,'This date should be set to the first Task, not the second.');
  }
}

 

 

We test the system by confirming that the date field is null at first, then set to the first task's date, and then remains so for the second insert. This is generally how a test method should go. Your trigger should have 100% coverage with this simple class method. The idea of testing is to make sure that each part of the code is covered.

 

You can use Run All Tests in Sandbox, then click on the Percent Complete column to see which lines of code were missed. Please let us know if you need further help with the code.

SpunkySpunky

You rock! This works perfectly in the sandbox. The only issue I'm having now is that I cant deploy it to production because the apex test coverage is only 68% in production and it needs to be 75 . ugh!

 

 

Thank you!