+ Start a Discussion
MichelleNMichelleN 

Help with a trigger to count activities on Leads

I am trying to create a trigger that will count activities (tasks) on leads.
My code is below....

When saving I am getting the following error....

Error: Compile Error: unexpected token: '}' at line 30 column 1

But if I remove the curly bracket I get a different error

Error: Compile Error: unexpected token: '<EOF>' at line 30 column 0


trigger TaskUpdateLead on Task (after delete, after insert, after undelete, after update)
{
Set<ID> LeadIds = new Set<ID>();

//We only care about tasks linked to Leads.

String leadPrefix = Lead.SObjectType.getDescribe().getKeyPrefix();

//Add any Lead ids coming from the new data

if (Trigger.new != null) {
    for (Task t : Trigger.new) {
     if (t.WhatId != null && string.valueOf(t.whatId).startsWith(leadprefix) )
         {LeadIds.add(t.whatId);
      }
   }
}
//Also add any Lead ids coming from the old data (deletes, moving an activity from one Lead to another)

if (Trigger.old != null) {
    for (Task t : Trigger.old) {
     if (t.WhatId != null && String.valueOf(t.whatId).startsWith(leadprefix) )
         { LeadIds.add(t.whatId);
      }
   }
}
if (LeadIds.size() > 0)

Lead.Activity_Count__c.updateLeadCount<LeadIds>
}


Any guidance is very much appreciated.
Best Answer chosen by MichelleN
Chidambar ReddyChidambar Reddy
Sorry, Lead will be stored in Who ID of the Task

Try the following.. 

trigger TaskUpdateLead on Task (after delete, after insert, after undelete, after update) {

Set<ID> LeadIds = new Set<ID>();

//We only care about tasks linked to Leads.

String leadPrefix = Lead.SObjectType.getDescribe().getKeyPrefix();

//Add any Lead ids coming from the new data

if(trigger.new!=null){
    for (Task t : Trigger.new) {
     if (t.WhoId!= null && string.valueof(t.WhoId).startsWith(leadPrefix) ) {

if(!LeadIds.contains(t.WhoId)){
//adding unique lead ids since there can be many tasks with single lead
LeadIds.add(t.WhoId);
}
}
      }
}
 
//Also add any Lead ids coming from the old data (deletes, moving an activity from one Lead to another)

if(trigger.old!=null){
    for (Task t2 : Trigger.old) {
     if (t2.WhoId!= null && string.valueof(t2.WhoId).startsWith(leadPrefix) )
         {
if(!LeadIds.contains(t2.WhoId)){
//adding unique lead ids since there can be many tasks with single lead
LeadIds.add(t2.WhoId);
}
}
      }
}

     if (LeadIds.size() > 0){



List<Lead> leadsWithTasks = [select id,Activity_Count__c,(select id from Tasks) from Lead where Id IN : Leadids];

List<Lead> leadsUpdatable = new List<Lead>();

for(Lead L : leadsWithTasks){

L.Activity_Count__c = L.Tasks.size();
leadsUpdatable.add(L);

}

if(leadsUpdatable.size()>0){

update leadsUpdatable;
//update all the leads with activity count

}

    }
}

All Answers

Ramu_SFDCRamu_SFDC
The problem seems to be with the last line "Lead.Activity_Count__c.updateLeadCount<LeadIds>" should there be a semi colon ; ? in simple statements probably the below would work

 Lead.Activity_Count__c = leadids.size(); 
MichelleNMichelleN
Thank you for your responses.  I finally got the trigger to save but my custom field is not updating.

I have the following trigger saved on the Activity object under task triggers. The intention is to update the custom field Activity_Count__c on the Lead object any time a new activity(task) is created, updated, deleted or undeleted.

Any ideas why my custom field is not being updated?

Here's my code....

trigger TaskUpdateLead on Task (after delete, after insert, after undelete, after update) {

Set<ID> LeadIds = new Set<ID>();

//We only care about tasks linked to Leads.

String leadPrefix = Lead.SObjectType.getDescribe().getKeyPrefix();

//Add any Lead ids coming from the new data

if (Trigger.new != null) {
    for (Task t : Trigger.new) {
     if (t.WhatId != null && string.valueOf(t.whatId).startsWith(leadprefix) ) {

if(!LeadIds.contains(t.WhatId)
//adding unique lead ids since there can be many tasks with single lead
)LeadIds.add(t.whatId);
}
      }
   }
//Also add any Lead ids coming from the old data (deletes, moving an activity from one Lead to another)

if (Trigger.old != null) {
    for (Task t : Trigger.old) {
     if (t.WhatId != null && String.valueOf(t.whatId).startsWith(leadprefix) )
         {
if(!LeadIds.contains(t.WhatId)
//adding unique lead ids since there can be many tasks with single lead
)LeadIds.add(t.whatId);
}
      }
   }
  
     if (LeadIds.size() > 0){



List<Lead> leadsWithTasks = [select id,Activity_Count__c,(select id from Tasks) from Lead where Id IN : Leadids];

List<Lead> leadsUpdatable = new List<Lead>();

for(Lead L : leadsWithTasks){

L.Activity_Count__c = L.Tasks.size();
leadsUpdatable.add(L);

}

if(leadsUpdatable.size()>0){

update leadsUpdatable;
//update all the leads with activity count

}

    }
}

Thank you!
MichelleNMichelleN
Activity_Count__c data type is Number.
MichelleNMichelleN
Now I am getting 

Error Error: Compile Error: Method does not exist or incorrect signature: [Id].startsWith(String) at line 13 column 30

13 
if (t.WhatId != null && t.whatId.startsWith(leadprefix) ) {
MichelleNMichelleN
It saves but it the activity count field remains blank
Chidambar ReddyChidambar Reddy
Sorry, Lead will be stored in Who ID of the Task

Try the following.. 

trigger TaskUpdateLead on Task (after delete, after insert, after undelete, after update) {

Set<ID> LeadIds = new Set<ID>();

//We only care about tasks linked to Leads.

String leadPrefix = Lead.SObjectType.getDescribe().getKeyPrefix();

//Add any Lead ids coming from the new data

if(trigger.new!=null){
    for (Task t : Trigger.new) {
     if (t.WhoId!= null && string.valueof(t.WhoId).startsWith(leadPrefix) ) {

if(!LeadIds.contains(t.WhoId)){
//adding unique lead ids since there can be many tasks with single lead
LeadIds.add(t.WhoId);
}
}
      }
}
 
//Also add any Lead ids coming from the old data (deletes, moving an activity from one Lead to another)

if(trigger.old!=null){
    for (Task t2 : Trigger.old) {
     if (t2.WhoId!= null && string.valueof(t2.WhoId).startsWith(leadPrefix) )
         {
if(!LeadIds.contains(t2.WhoId)){
//adding unique lead ids since there can be many tasks with single lead
LeadIds.add(t2.WhoId);
}
}
      }
}

     if (LeadIds.size() > 0){



List<Lead> leadsWithTasks = [select id,Activity_Count__c,(select id from Tasks) from Lead where Id IN : Leadids];

List<Lead> leadsUpdatable = new List<Lead>();

for(Lead L : leadsWithTasks){

L.Activity_Count__c = L.Tasks.size();
leadsUpdatable.add(L);

}

if(leadsUpdatable.size()>0){

update leadsUpdatable;
//update all the leads with activity count

}

    }
}
This was selected as the best answer
MichelleNMichelleN
It works! Thank you so much! Would you know if I will need to create a apex class for this?
Chidambar ReddyChidambar Reddy
I dont think you need a separate class for this. Since the trigger events are 'After' It will not get struck before saving. This trigger will run after saving the record.

you can use a class if you need, by passing list of Tasks


List<Task> alltasks = new List<Task>();
alltasks.addAll(trigger.new);
alltasks.addAll(trigger.old);


pass this alltasks to the method of the class

class.method(alltasks);


Thank you.
MichelleNMichelleN
Thank you again!!
MichelleNMichelleN
So I am now creating the same trigger for Events....I updated the trigger replacing all 'Task' with Event and 't' with 'e'. But it is not working....Is lead stored in the whoid for event too? or do I have to consider something else with events?
Chidambar ReddyChidambar Reddy
It will not work with the same way


because Activity count should be updated on both triggers. It will either contains count of Tasks or Count of Events.


So I suggest you to create two custom number fields (Make them Hidden / visible to admin only)

"All Tasks"(update with trigger on Task)
and "All Events"(update with trigger on Event)



Create a formula field 'Activity Count" 
by summing the above two fields. Use this formula field wherever you need it.
MichelleNMichelleN
Hello Again,

I tried to deploy my change set with my 2 triggers but I am getting a code coverage error. Which I think means I will in fact need an apex class. I am thinking that I can do one class to test both of these triggers. I include the code below....

But when I try to save I get 

Error Error: Compile Error: Variable does not exist: lead.id at line 15 column 52


@isTest

private class TestClassName{

public static testMethod void testCountTask() {

//Setup

Lead l = new Lead(lastname='Test');

insert l;

//Insert our first task

Task t = new Task(subject='Test Activity', whoId = lead.id);

insert t;

//Verify count

lead = [SELECT ID, activity_count__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(1,lead.activity_count__c);

//Disconnect task from the lead

didRun = false; //Reset

t.whoId = null;

update t;

//Verify count = 0

Lead lead = new Lead();

lead = [SELECT ID, activity_count__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(0,lead.activity_count__c);

didRun = false; //Reset

//Add an event

Event e = new Event(subject='Test Event', whoId = lead.id, startDateTime = System.Now(), endDateTime =

System.now());

insert e;

//Verify count = 1

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(1,lead.activity_countE__c);

//Relink the task to the lead

didRun = false; //Reset

t.whoId = lead.id;

update t;

//Verify count = 2

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(2,lead.activity_countE__c);

//Disconnect the event from the lead

didRun = false; //Reset

e.whoId = null;

update e;

//Verify count is back down to 1

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(1,lead.activity_countE__c);

//Delete the task

didRun = false; //reset

delete t;

//Verify count is back down to 0

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(0,lead.activity_countE__c);

}

}
Chidambar ReddyChidambar Reddy
Hi,
You inserted the Lead -> "l" and you are trying to get the Lead ->"Lead"

You can change the initialization instead of changing code.
Check the bold text

@isTest

private class TestClassName{

public static testMethod void testCountTask() {

//Setup

Lead lead1 = new Lead(lastname='Test');

insert lead1;

//Insert our first task

Task t = new Task(subject='Test Activity', whoId = lead1.id);

insert t;

//Verify count

lead1 = [SELECT ID, activity_count__c FROM Lead WHERE ID = :lead1.id];

System.assertEquals(1,lead1.activity_count__c);

//Disconnect task from the lead

didRun = false; //Reset

t.whoId = null;

update t;

//Verify count = 0

Lead lead = new Lead(lastname='lead22');

lead = [SELECT ID, activity_count__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(0,lead.activity_count__c);

didRun = false; //Reset

//Add an event

Event e = new Event(subject='Test Event', whoId = lead.id, startDateTime = System.Now(), endDateTime =

System.now());

insert e;

//Verify count = 1

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(1,lead.activity_countE__c);

//Relink the task to the lead

didRun = false; //Reset

t.whoId = lead.id;

update t;

//Verify count = 2

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(2,lead.activity_countE__c);

//Disconnect the event from the lead

didRun = false; //Reset

e.whoId = null;

update e;

//Verify count is back down to 1

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(1,lead.activity_countE__c);

//Delete the task

didRun = false; //reset

delete t;

//Verify count is back down to 0

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(0,lead.activity_countE__c);

}

}
Bayarea 101Bayarea 101
i am also trying to create same thing. Activity counter on lead. here is y trigger am i missing some thing because when i create a new a ctivity this field remains blank. Any suggestions.
trigger updateLeadCounts on Task (after insert, after update) {

set<ID> LeadIds= new Set<ID>();
for(Task tt:trigger.new)
{
if(tt.whoId!=null && string.valueof(tt.WhoId).startsWith('003'))
{

LeadIDs.add(tt.whoID);
}
}

if(LeadIds.isEmpty())
return;
List<Lead> cnts= new List<Lead>();

Integer number1=1;
for(Lead ct:[select id, name, count1__c from Lead where id in:Leadids])
{

if(ct.count1__c ==null)
ct.count1__c=0;

ct.count1__c=ct.count1__c+number1;


cnts.add(ct);
}

if(cnts.size()>0)
{
update cnts;
}
}

 
Febe NagyFebe Nagy
Hi Chidambar,

I want to create the same trigger to count the number of referrals on a lead, will this work?  I have a master-detail relationship between lead and custom object "Referrer" and my task is to display the count of referrers in a number field.  Will this trigger work in my case? Do I have to consider something else?

 
Febe NagyFebe Nagy
Hi Chidambar,

I want to create the same trigger but I want the trigger to be on Lead and I want to count the number of referrals on a lead, will your approach work for me?  I have a master-detail relationship between lead and a custom object "Referrer" and my task is to display the count of referrers in a number field.  Will this trigger work in my case? Do I have to consider something else?
Chidambar ReddyChidambar Reddy
Hi Febe Nagy,

Use Roll-up summary fields

Create a Roll-up summary field on Lead object to COUNT the children (Referrer)
Febe NagyFebe Nagy
Hi Chidambar,

I got further requirements that I have to call the field from lead and opportunity and I have to limit it to 3 record types.  Is there a better way?
Chidambar ReddyChidambar Reddy
Yes, it will work even when you delete referrers And you can also put filters in it, so that you may count a specific type of referrers Sent from my iPod
Ed SFDCDeveloperEd SFDCDeveloper
Can someone post the code that actually worked?
rmranjith8881.3927046400771116E12rmranjith8881.3927046400771116E12
Hi Chidambar Reddy,

I am implmenting same to get the count of Emails under my Custom Object record.

But, I am getting below error,

Didn't understand relationship 'EmailMessage' in FROM part of query call. If you are attempting to use a custom relationship, be sure to append the '__r' after the custom relationship name. Please reference your WSDL or the describe call for the appropriate names. at line 41 column 32

Can we not get the count fo Emails with trigger?

Here is my code so far,
 
trigger EmailUpdateCases on EmailMessage (after delete, after insert, after undelete, after update) {

Set<ID> caseIds = new Set<ID>();//LeadIds 

//We only care about tasks linked to Cases.

String casePrefix = Case__c.SObjectType.getDescribe().getKeyPrefix();//leadPrefix 

//Add any Case Ids coming from the new data

if(trigger.new!=null){
    for (EmailMessage t : Trigger.new) {
     if (t.RelatedToId!= null && string.valueof(t.RelatedToId).startsWith(casePrefix) ) {

if(!caseIds.contains(t.RelatedToId)){
//adding unique case ids since there can be many tasks with single case
caseIds.add(t.RelatedToId);
}
}
      }
}
 
//Also add any Case Ids coming from the old data (deletes, moving an activity from one Case to another)

if(trigger.old!=null){
    for (EmailMessage t2 : Trigger.old) {
     if (t2.RelatedToId!= null && string.valueof(t2.RelatedToId).startsWith(casePrefix) )
         {
if(!CaseIds.contains(t2.RelatedToId)){
//adding unique lead ids since there can be many tasks with single lead
CaseIds.add(t2.RelatedToId);
}
}
      }
}

     if (CaseIds.size() > 0){



List<Case__c> casesWithTasks = [select id,Tasks_Count__c,(select id from EmailMessage) from Case__c where Id IN : caseIds];//leadsWithTasks 

List<Case__c> casesUpdatable = new List<Case__c>();//leadsUpdatable 

for(Case__c L : casesWithTasks){

L.Tasks_Count__c = L.Tasks.size();
casesUpdatable.add(L);

}

if(casesUpdatable.size()>0){

update casesUpdatable;
//update all the leads with activity count

}

    }
}

Can you please let me know, where I am doing wrong? 

Appreciate for your help.

Thanks in advance.
Liam TimminsLiam Timmins
Can someone let me know which object to use this trigger on?

Lead or Task?

What do I replace and use my Activity counter name? (I assume this is just a field placed on the lead page)

Any help much appreciated!
Liam TimminsLiam Timmins
Hey Chidambar,

Your code worked for me on Sandbox, however when writing I use the test case you provided I receive the following:


Error: Compile Error: Variable does not exist: didRun at line 27 column 1


Here is the test case I am using:

@isTest

private class TestClassName{


public static testMethod void testCountTask() {
//Setup

Lead lead1 = new Lead(lastname='Test');

insert lead1;

//Insert our first task

Task t = new Task(subject='Test Activity', whoId = lead1.id);

insert t;

//Verify count

lead1 = [SELECT ID, activity_count__c FROM Lead WHERE ID = :lead1.id];

System.assertEquals(1,lead1.activity_count__c);

//Disconnect task from the lead

didRun = false; //Reset

t.whoId = null;

update t;

//Verify count = 0

Lead lead = new Lead(lastname='lead22');

lead = [SELECT ID, activity_count__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(0,lead.activity_count__c);

didRun = false; //Reset

//Add an event

Event e = new Event(subject='Test Event', whoId = lead.id, startDateTime = System.Now(), endDateTime =

System.now());

insert e;

//Verify count = 1

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(1,lead.activity_countE__c);

//Relink the task to the lead

didRun = false; //Reset

t.whoId = lead.id;

update t;

//Verify count = 2

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(2,lead.activity_countE__c);

//Disconnect the event from the lead

didRun = false; //Reset

e.whoId = null;

update e;

//Verify count is back down to 1

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(1,lead.activity_countE__c);

//Delete the task

didRun = false; //reset

delete t;

//Verify count is back down to 0

lead = [SELECT ID, activity_countE__c FROM Lead WHERE ID = :lead.id];

System.assertEquals(0,lead.activity_countE__c);

}

}


Thanks in advance!
Akash jena 3Akash jena 3
this code is working perfect for lead standard object. but in my case lead__c , custom is lead , can anybody tell me how to write the same code 
trigger TaskCountLead on Task (after delete, after insert, after undelete, after update) {

Set<ID> LeadIds = new Set<ID>();

//We only care about tasks linked to Leads.

String leadPrefix = Lead.SObjectType.getDescribe().getKeyPrefix();

//Add any Lead ids coming from the new data

if(trigger.new!=null){
    for (Task t : Trigger.new) {
     if (t.WhoId!= null && string.valueof(t.WhoId).startsWith(leadPrefix) ) {

if(!LeadIds.contains(t.WhoId)){
//adding unique lead ids since there can be many tasks with single lead
LeadIds.add(t.WhoId);
}
}
      }
}
 
//Also add any Lead ids coming from the old data (deletes, moving an activity from one Lead to another)

if(trigger.old!=null){
    for (Task t2 : Trigger.old) {
     if (t2.WhoId!= null && string.valueof(t2.WhoId).startsWith(leadPrefix) )
         {
if(!LeadIds.contains(t2.WhoId)){
//adding unique lead ids since there can be many tasks with single lead
LeadIds.add(t2.WhoId);
}
}
      }
}

     if (LeadIds.size() > 0){



List<Lead> leadsWithTasks = [select id,Task_count__c,(select id from Tasks) from Lead where Id IN : Leadids];

List<Lead> leadsUpdatable = new List<Lead>();

for(Lead L : leadsWithTasks){

L.Task_count__c = L.Tasks.size();
leadsUpdatable.add(L);

}

if(leadsUpdatable.size()>0){

update leadsUpdatable;
//update all the leads with activity count

}

    }
}