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
Elliot32Elliot32 

Help With Apex Code

Hi All,

 

I am an administrator and have not much apex experience. Having a bit of an issue with my trigger. The purpose of the trigger is to count the number of Activity Records associated to a Lead and then drop it into a field called Activity_Count__c on the Lead. The code all works as intended, but I wanted to add another parameter. I would like to be able to only have that field contain the number of Activity Records that are 'Created By' a certain User (i.e. User ID = '12345'). How would I add that contraint into the Trigger, Class and Test Class? See below.

 

Thanks,

Elliot

 

 

Class:

 

 

public with sharing class LeadActivityCount {

 

    public static Boolean didRun = false;

    public static String ledsPrefix =  Lead.sObjectType.getDescribe().getKeyPrefix();

 

    /*

    * Takes a set of lead IDs, queries those leads, and updates the activity count if appropriate

    */

    public static void updateLeadCounts(Set<ID> ledsIds) {

 

        if (didRun == false) { //We only want this operation to run once per transaction.

            didRun = true;

 

            //Query all the leads, including the tasks child relationships

            List<Lead> leds = [SELECT ID, activity_count__c, (SELECT ID FROM Tasks), (SELECT ID FROM Events) FROM Lead WHERE ID IN :ledsIds];

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

 

            for (Lead l : leds) {

                Integer count = l.tasks.size() + l.events.size();

 

                if (l.activity_count__c != count) {

                    l.activity_count__c = count;

                    updateLeds.add(l); //we're only doing updates to leads that have changed...no need to modify the others

                }

            }

 

            //Update the appropriate leads

            try {

                update updateLeds;

            } catch (Exception e) {

                //This is controversial. Anything could happen when updating the opportunity..validation rule, security, etc. The key is we don't

                //want the event update to fail...so we put a try catch around the opp update to make sure we don't stop that from happening.

            }

        }

    }

}

 

 

Test Class:

 

 

@isTest
private class LeadsTestClassName{

public static Boolean didRun = false;
public static String ledsPrefix =  Lead.sObjectType.getDescribe().getKeyPrefix();
   
    /*
    * Test method for this class and TaskUpdateLead and EventUpdateLead
    */
    public static testMethod void testCountTask() {
        //Setup

        Lead leds = new Lead(lastname='Test', email='1@2.com', company='Test');
        insert leds;

        //Insert our first task
        Task t = new Task(subject='Test Activity', whoId = leds.id);
        insert t;

        //Verify count
        leds = [SELECT ID, activity_count__c FROM Lead WHERE ID = :leds.id];
        System.assertEquals(1,leds.activity_count__c);

        //Disconnect task from the lead
        didRun = false; //Reset
        t.whoId = null;
        update t;
        //Verify count = 0
        leds = [SELECT ID, activity_count__c FROM Lead WHERE ID = :leds.id];
        System.assertEquals(0,leds.activity_count__c);

        didRun = false; //Reset
        //Add an event
        Event e = new Event(subject='Test Event', whoId = leds.id, startDateTime = System.Now(), endDateTime = System.now());
        insert e;

        //Verify count = 1
        leds = [SELECT ID, activity_count__c FROM Lead WHERE ID = :leds.id];
        System.assertEquals(1,leds.activity_count__c);

        //Relink the task to the lead
        didRun = false; //Reset
        t.whoId = leds.id;
        update t;

        //Verify count = 2
        leds = [SELECT ID, activity_count__c FROM Lead WHERE ID = :leds.id];
        System.assertEquals(2,leds.activity_count__c);

        //Disconnect the event from the lead
        didRun = false; //Reset
        e.whoId = null;
        update e;

        //Verify count is back down to 1
        leds = [SELECT ID, activity_count__c FROM Lead WHERE ID = :leds.id];
        System.assertEquals(1,leds.activity_count__c);

        //Delete the task
        didRun = false; //reset
        delete t;
        //Verify count is back down to 0
        leds = [SELECT ID, activity_count__c FROM Lead WHERE ID = :leds.id];
        System.assertEquals(0,leds.activity_count__c);

    }
}

 

 

Trigger:

 

 

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

    Set<ID> ledsIds = new Set<ID>();
    //We only care about tasks linked to leads.
    String prefix =  LeadActivityCount.ledsPrefix;

    //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(prefix) ) {
                ledsIds.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 t : Trigger.old) {
            if (t.WhoId != null && String.valueOf(t.whoId).startsWith(prefix) ) {
                ledsIds.add(t.whoId);
            }
        }
    }

    if (ledsIds.size() > 0)
        LeadActivityCount.updateLeadCounts(ledsIds);

}

Best Answer chosen by Admin (Salesforce Developers) 
JohnSchultzJohnSchultz

You could add the user id to your SOQL query, like so:

List<Lead> leds = [SELECT ID, activity_count__c, (SELECT ID FROM Tasks where CreatedById='12345'), (SELECT ID FROM Events where CreatedById='12345') FROM Lead WHERE ID IN :ledsIds];

 

You wouldn't need to update your trigger since it is just handing off the lead ids to your class and allowing the class to do the logic (as it should be).

 

As for updating your class, you'll need to create test tasks and events by first getting the user record that should be the creator, and then using the System.runAs(user) functionality to create those tasks and events.

User u = [select Id from User where Id='12345'];

System.runAs(u) {
	//Insert our first task
	Task t = new Task(subject='Test Activity', whoId = leds.id);
	insert t;
}

 

All Answers

JohnSchultzJohnSchultz

You could add the user id to your SOQL query, like so:

List<Lead> leds = [SELECT ID, activity_count__c, (SELECT ID FROM Tasks where CreatedById='12345'), (SELECT ID FROM Events where CreatedById='12345') FROM Lead WHERE ID IN :ledsIds];

 

You wouldn't need to update your trigger since it is just handing off the lead ids to your class and allowing the class to do the logic (as it should be).

 

As for updating your class, you'll need to create test tasks and events by first getting the user record that should be the creator, and then using the System.runAs(user) functionality to create those tasks and events.

User u = [select Id from User where Id='12345'];

System.runAs(u) {
	//Insert our first task
	Task t = new Task(subject='Test Activity', whoId = leds.id);
	insert t;
}

 

This was selected as the best answer
Elliot2642Elliot2642

Hi John,

 

Thanks very much, that did it. One more question for you. I created a field on the Lead Object (Last_Owner_Change_Date__c) that tracks when the last time the Owner of the Lead was changed via a Workflow that drops the date of the change into the field. I would like to add the constraint in that the Due Date of the Task/Events that is being queried must be greater than the Last_Owner_Change_Date__c field. Basically, I am doing this to reset the counter each time the Owner changes. How would I go about accomplishing this in the query?

 

Thanks again,

Elliot

JohnSchultzJohnSchultz

Unfortunately, to the best of my knowledge, you can't compare two date fields in a SOQL query. You could add those fields to the query and then compare then in your class, though.

Elliot2642Elliot2642

Hi John,

 

Okay. Thanks for letting me know. Would you be able to direct me to some documentation and/or give me the name of the topic I could use to accomplish this? As I said, I am an APEX newbie so I'm not sure where to start.

 

Elliot

JohnSchultzJohnSchultz

Try adding something like this to your class:

List<Lead> leds = [SELECT ID, activity_count__c, Last_Owner_Change_Date__c, (SELECT ID, ActivityDate FROM Tasks where CreatedById='12345'), (SELECT ID, ActivityDate FROM Events where CreatedById='12345') FROM Lead WHERE ID IN :ledsIds];

for (Lead l : leds) {
    List<Task> goodTasks = new List<Task>();
    List<Event> goodEvents = new List<Event>();
    
    for (Task t : l.Tasks) {
        if (t.ActivityDate > l.Last_Owner_Change_Date__c) {
            goodTasks.add(t);
        }
    }
    
    for (Event e : l.Events) {
        if (e.ActivityDate > l.Last_Owner_Change_Date__c) {
            goodEvents.add(e);
        }
    }
    
    Integer count = goodTasks.size() + goodEvents.size();

    if (l.activity_count__c != count) {
        l.activity_count__c = count;
        updateLeds.add(l); //we're only doing updates to leads that have changed...no need to modify the others
    }
}

 

Elliot2642Elliot2642

John - This works great. Thanks so much for the help!

Luke RobertosLuke Robertos
To add the constraint to only count Activity Records that are 'Created By' a certain User (i.e. User ID = '12345'), you can modify the SOQL query in the updateLeadCounts method of the LeadActivityCount class. Here's how you can modify the query:

sql
Copy code
List<Lead> leds = [SELECT ID, activity_count__c, (SELECT ID FROM Tasks WHERE CreatedById = '12345'), (SELECT ID FROM Events WHERE CreatedById = '12345') FROM Lead WHERE ID IN :ledsIds];
This modified query will only count the Tasks and Events that were created by the User with the ID '12345'. If you want to make the User ID dynamic, you can pass it as a parameter to the updateLeadCounts method and use it in the query.

Once you've made this change, you can also update the comments in the updateLeadCounts method to reflect the new constraint.

Besides, usually when I have to make an application and in order not to make a mistake and not to make this counterversion, I prefer to get information from these guys https://phdessay.com/essay-type/controversial/ because I have already had this problem several times and I don't like to redo what I have worked on for more than a week. How do you avoid this?

To modify the Test Class, you can simply update the testCountTask method to create Tasks and Events that are 'Created By' the User with the ID '12345'. For example:

sql
Copy code
//Insert our first task, created by User with ID '12345'
Task t = new Task(subject='Test Activity', whoId = leds.id, CreatedById = '12345');
insert t;

//Add an event, created by User with ID '12345'
Event e = new Event(subject='Test Event', whoId = leds.id, startDateTime = System.Now(), endDateTime = System.now(), CreatedById = '12345');
insert e;
Finally, you don't need to modify the TaskUpdateLead trigger because it already includes the WhoId filter that limits the trigger to only Tasks associated with Leads.