Dec 3, 2012

Shared Activity for more than 10 Contacts


One of the major use of custom pages, classes are for extending the standard functions. I have recently come across one of such requirements. The requirement was:
  • Client meets, say 15 contacts out of 25 people in an Company (or Account)
  • User comes back and needs to record the call in one shot. i.e. instead of going to each contact and clicking on 'Log A Call' button 5 times they wanted an easier way of doing this
Solution that was proposed (and accepted after demo):
  • Have a button in Account details page - Create Mass Tasks (or Create Mass Calls)
  • This opens up a page which will show list of Contacts of that Account
  • User selects the required contacts - clicks on 'Create Call' button
  • This opens up Task/Event edit page
  • User enters details and clicks on Save
  • This should create tasks/events for each of the selected contacts
Now you might be wondering why we did not suggest Shared Activities, but if you note it clearly says that upto 10 Contacts can be related. But here we needed more than 10 contacts at a time (most of the time).

So now let us jump to the technical stuff. Created a VF page which shows all contacts of an account. For selection, I created a checkbox - Log A Call. The UI would be something similar to a list view.

VF page code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<apex:page extensions="MassLogACallController_Contacts" standardcontroller="Account">
    <apex:form>
        <apex:pageblock id="Customlist" title="Contacts ">
            <apex:pageblockbuttons>
                <apex:commandbutton action="{!CreateCall}" value="Create Call">
                <apex:commandbutton action="{!cancel}" value="Cancel">
            </apex:commandbutton></apex:commandbutton></apex:pageblockbuttons>
            
            <apex:pageblocktable value="{!lstContacts}" var="lst">
                <apex:column>
                    <apex:inputfield value="{!lst.Log_a_Call__c}">
                </apex:inputfield></apex:column> 
                <apex:column headervalue="Contact Name">
                    <apex:outputfield value="{!lst.Name}">
                </apex:outputfield></apex:column>
            </apex:pageblocktable>
        </apex:pageblock>
    </apex:form>
</apex:page>

Now the controller code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class MassLogACallController_Contacts {
    public List<contact> lstContacts {get; set;}
    public String accountId {get; set; }
    
    public MassLogACallController_Contacts(ApexPages.StandardController controller) {
        accountId = ApexPages.CurrentPage().getParameters().get('id');
        lstContacts = [select Name, Log_a_call__c from Contact where AccountId =: accountId];
    }
    
    public PageReference createCall() {
        update lstContacts;
        PageReference pg=new PageReference('/apex/MassCreateCall?accId=' + accountId);
        pg.setRedirect(true);
        return pg;
    }
}

So note that 'Create Call' method calls a VF page (MassCreateCall) by passing the Account ID. This page would replicate the detail page of task. It is simple and straight forward, so I will not include it's code. What's not simple is the 'Save' method. On click of Save, the code should create tasks (Activity History or Events - as per your requirement) for all those selected contacts.

Here is the constructor and 'save()' method code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public MassCreateCallController_Events(ApexPages.StandardController controller) {
        this.evt = (Event)controller.getRecord();
        // more initialization
}

public PageReference createCalls() {
        try {
            if(lstContacts.size() &gt; 0) {
                // lstContacts is the list of Contacts of this Account whose Log_A_Call__c = true
                for(Contact c : lstContacts) {
                    newEvent = new Event();
                    newEvent.Call_Type__c = evt.Call_Type__c;
                    newEvent.Subject = evt.Subject;
                    newEvent.WhatId = accountId;
                    newEvent.IsAllDayEvent = evt.IsAllDayEvent;
                    newEvent.StartDateTime = evt.StartDateTime;
                    newEvent.EndDateTime = evt.EndDateTime;
                    newEvent.OwnerId = userId;
                    newEvent.RecordTypeId = evt.RecordTypeId;
                    newEvent.Description = evt.Description;
                    newEvent.WhoId = c.Id;
                    lstEvents.add(newEvent);
                    // Clear the checkbox of each contact
                    c.Log_a_call__c = false;
                }
                insert lstEvents;
                update lstContacts;
            }
        }
        catch(Exception e) {
            ApexPages.addMessage(new ApexPages.Message(ApexPAges.Severity.FATAL, e.getMessage()));
        }
        PageReference pg = new PageReference('/' + accountId);
        pg.setRedirect(true);
        return pg;
    }

As you can see I am looping through the list of contacts and inserting the task (Event in this case). 'evt' contains the values that are filled in the UI. So I am copying it to the new records while adding to list. Whenever a new record is added to list, I am clearing the checkbox (Log A Call) in each Contacts.

Works well with many use cases.

As always I am keen to know if any easier method was implemented/available.

3 comments:

  1. Unfortanetly the solution above as you call out is creating multiple tasks and events. How would you handle an update the the Task? I assume it would need to be updated on all the mirror Task records? How do you keep them in sync if you can't relate them via a lookup to one another?

    Standard Activites in SFDC are always painful for my clients. One of the more painful decisions I've had to make is how to link one task to multiple records. Out of the box you can't do this, AND Shared Activities is a step in the right direction, but at this time only supports 10 contacts. My clients typically want to link to multiple objects (A client, multiple contacts, multiple products, etc) to a single task (show me all the products we talked about for example).

    Depending on how critical the request, we will either modify the Task and Events objects with VF / Apex as much as possible similar to what you are doing above, or we will completely dump SFDC Task and Events and use our own custom Task / Event objects. Its not an easy decision to make to give up SFDC Tasks and Events and isn't to be taken lightly. However depending on how critical it is to link them and customize them sometimes it makes sense to give up the standard SFDC features of Activities and roll your own.

    As I've gone down that road, and as Shared Activities has been released, I've made sure to use a CustomTaskRelation and CustomEventRelation object which mirrors the new TaskRelation and EventRelation objects in standard SFDC. That way we can easily roll our data model onto the Shared Activities if and when SFDC decides to improve on it by allowing more objects and more records.

    ReplyDelete
    Replies
    1. Good question Cory. I did not think this way becasue client did not require this particular thing - updating these tasks. I believe there will be easier methods available soon and there will be better enhancements to Shared Activities.

      However one point on using custom objects instead of Std Tasks/Events - replicating recurring tasks/events, calendar sync, pop-up notification would be time consuming (or painful). But yeah, you cannot have everything you want :)

      Delete
  2. I did this kind of implementation ...Need to share one task to more that 50 people..so for that

    1. Created a filed on task object
    2. When ever the process was initiated i created a random number using math.random and storing the same in the task object field...with in the instance we will get the same random number for all the tasks..so that we can maintain a unique value between all the tasks...

    3. Finally created a trigger on task to get in sync using that earlier created random number when ever any one of the user changes the value on the task page layout...

    ReplyDelete

Featured Post

I am Salesforce Certified System Architect

By passing Identity & Access Management Designer, I earned System Architect. The journey of Application Architect & System Architec...

Popular Posts