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
salesforce_hoonigansalesforce_hoonigan 

Help with my Apex Class and Trigger

Hi,

I am currently building an Task Counter and I was able to achieve this by counting the Activity History and Open Activity using the current code. My new requirement is to count the number of Activities whether an Activity is a Call or an Email, I will base the criteria by Task Type (ex. Emai, Call - Connected, Call - Not Connected). So basically, I will have a total of 4 fields. 
1. Completed Activities - Call, 
2. Open Activities - Call, 
3. Completed Activities - Email, 
4. Open Activities - Email

I hope you could assist me on modifying my code please.

Class: 
public class ActivityUtils {
     
    //config
     
    String fieldToUpdate = 'Activity_Logs__c'; //this field must be added to each object we're updating
    String fieldOpenToUpdate = 'Open_Activities__c'; //this field must be added to each object we're updating
     
    //state
    set<id> leadIds;
     
    public ActivityUtils(sObject[] records) {
        leadIds = new set<id>();
        captureWhatAndWhoIds(records);
    }
     
    public void updateLeadActivityCount() {
        if(leadIds.size() == 0) return;
        updateActivityCount('Lead','WhoId', getStringFromIdSet(leadIds));
                updateActivityHistory('Lead','WhoId', getStringFromIdSet(leadIds));
 
    }

    private void updateActivityCount(String objToUpdate, String queryFld, String updateIds) {
        string strQuery = 'SELECT Id, (SELECT Id FROM OpenActivities) FROM ' + objToUpdate + ' WHERE Id IN (' + updateIds + ')';
        sObject[] sobjects = new list<sobject>();
        for(sObject so : database.query(strQuery)) {
            OpenActivity[] oActivities = so.getSObjects('OpenActivities');
            Integer openActivityCount = oActivities == null ? 0 : oActivities.size();
            sObject obj = createObject(objToUpdate, so.Id);
            obj.put(fieldOpenToUpdate, openActivityCount);
            sobjects.add(obj);
            system.debug('openActivityCount: ' + openActivityCount);
        }
        update sobjects;
    }
      
    private void updateActivityHistory(String objToUpdate, String queryFld, String updateIds) {
        string strQuery = 'SELECT Id, (SELECT Id FROM ActivityHistories) FROM ' + objToUpdate + ' WHERE Id IN (' + updateIds + ')';       
System.debug(strQuery);
        sObject[] sobjects = new list<sobject>();
        for(sObject so : database.query(strQuery)) {
            ActivityHistory[] oActivities = so.getSObjects('ActivityHistories');
            Integer closedActivityCount = oActivities == null ? 0 : oActivities.size();
            sObject obj = createObject(objToUpdate, so.Id);
            obj.put(fieldToUpdate, closedActivityCount);
            sobjects.add(obj);
            system.debug('ActivityHistoryCount: ' + closedActivityCount);
        }
        update sobjects;
    }
     
    private void captureWhatAndWhoIds(sObject[] objects) {
        for(sObject o : objects) {
            Id whoId = (Id)o.get('WhoId');
            if(whoId != null) {
                String objectName = getObjectNameFromId(whoId);
                if(objectName == 'lead') leadIds.add(whoId);
            }
        }
    }
     
    private String getObjectNameFromId(Id objId) {
        String preFix = String.valueOf(objId).left(3).toLowercase();
        if(prefix == '00q') return 'lead';
        return '';
    }
     
    private String getStringFromIdSet(set<id> idSet) {
        string idString = '';
        for(Id i : idSet) idString+= '\'' + i + '\',';
        return idString == '' ? idString : idString.left(idString.length()-1); //If idString contains some ids we want to ensure we strip out the last comma
    }
     
    //The main part of the method below was taken from //Taken from http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_dynamic_dml.htm
    //However we've modified this to accept an object id
    private sObject createObject(String typeName, Id objId) {
        Schema.SObjectType targetType = Schema.getGlobalDescribe().get(typeName);
        if (targetType == null) {
            // throw an exception
        }
         
        // Instantiate an sObject with the type passed in as an argument
        //  at run time.
        return targetType.newSObject(objId);
    }
     
}

Trigger:
trigger ActivityCounterTrigger on Task (after insert, after update, after delete, after undelete) {
     
    sObject[] triggerRecords;
    if(!trigger.isDelete) triggerRecords = trigger.new;
    else triggerRecords = trigger.old;
     
    //Update Open Activity Count
    ActivityUtils au = new ActivityUtils(triggerRecords);
    au.updateLeadActivityCount();

}




 
LakshmanLakshman
You can do a query on Task instead of ActivityHistories, something like this:
Pseudo logic-
Task[] lstTask = [select Id, IsClosed, Subject from Task Order by IsClosed, Subject where whatId in: updateIds];
//iterate over task
for(Task t:  lstTask) {
 if(t.isClosed) {
  countClosed ++; 
}
if(t.isClosed && t.Subject =='Call') {
 countCall++;
}
.
.
.
}
The above logic can be made dynamic easily and you wont have to do double queries, a single query should solve the purpose. 
Let me know if it helps.
 
salesforce_hoonigansalesforce_hoonigan
Hi Lakshman,

Can you help me out where will I be placing the logic you indicated? Sorry, I am a noob on apex.

Thank you.
LakshmanLakshman
You need to include the logic in your updateActivityCount and there wont be any need of updateActivityHistory method as we will be counting everything at one place.