How To · Salesforce Release

Update Multiple Contacts Associated to a Task

This blog post is in response to an inquiry from Ryan Scheibert. Thank you, Ryan.

Ryan.GIF

Activities are different beast in Salesforce. There is the Task and Event object. Then, there is a junction object called Task Relation or Event Relation, respectively, which holds the primary contact on the task or event and all the other people (whoId) or items (whatId) associated with the activity. Additionally, there is another junction object called Task Who Relation, which only contains the people who are associated to a task.

Task Object:

The below Salesforce extract shows the task id (ID), associated person to the task (WHOID), associated item to the object (WHATID), how many people are associated with the task (WHOCOUNT). In this example, this task has three people associated to it.

Task.GIF

Task Relation Object:

The below Salesforce extract shows the Task Relation Id (ID), the associated person to the task (RELATIONID), the associated task (TASKID) and whether there is a thing associated to the task (ISWHAT). In this example, for the task ID, there are three people associated to it.

TaskRelation.GIF

Task Who Relation Object:

The below Salesforce extract shows the Task Who Relation Id (ID), the associated person to the task (RELATIONID), the associated task (TASKID). This object does not show records that are items associated to the task. In this example, it shows the three people records associated to the same task.

TaskWhoRelation.GIF

In this situation, for our automation, we will interact with the task and task who relation objects so we know we are excluding any task relation ids associated to a thing.

Here are a few lessons learned from implementing this use case:

  • Learn how to invoke flow from a process.
  • Do not perform database commits within a loop.
  • Provide descriptions, where provided, in Salesforce. This may be tedious step, I know, but your future self will thank you when you are trying to remember what you configured or assist other/future admins when troubleshooting or enhancing what was built. This includes variables, the purpose of a flow, what each flow element does, etc.

Business Use Case:  Addison Dogster is the system administrator at Universal Containers. Mary Markle is the Director of Operations. She would like to automatically populate a field on the contact record for each contact associated to a completed meeting task.

Screen-TaskDemo.GIF

View image full screen

Solution: Being the #AwesomeAdmin that Addison is, she was able to solution this declaratively using Lightning Flow. She builds the first part of the process using Process Builder run on the Task Object when a task record is updated to a Status = ‘Completed’ and Type = ‘Meeting.’ and the latter part of the process in Flow Builder by creating a flow to handle the more complex part of the automation.

The outcome looks like this:

Process created in Process Builder on the Task object that runs when a task record is updated to a Status = ‘Completed’ and Type = ‘Meeting,’ then invoke the flow as an intermediate step.

Process-TakeActiononNewExistingTask.GIF

This flow does the following: (1) looks up all contact records associated with the task, (2) determine if there are records in the collection, (3) if there are records in the collection, then take each record and do the following: (3a) assign today’s date to the Last Completed Task field on the contact record and (3b) add the contact record to the collection to update and finally, outside the loop, update all contact records in the collection.

Note: The update action is performed OUTSIDE the loop, not inside it. Similar to apex, when DML statements (insert, update, delete, undelete) are placed inside a for loop, database operations are invoked once per iteration of the loop making it very easy to reach these governor limits. Instead, move any database operations outside of for loop. The same applies to flow (remember, Salesforce translates flow into code behind the scenes).

UpdateContactLastCompletedTask-Flow.GIF

Quick Steps:

1. We are going to create a custom field to hold the Last Completed Task Date on the contact object and set the FLS accordingly.

LastTaskCompletionDate.GIF

2. Now, let’s create the flow. For those using Salesforce Classic, flow can be found in Create | Workflows & Approvals | Flows. In Lightning Experience, it is found under Process Automation | Flows.

A. Let’s create our flow resources.

Best practice tip: Provide a description so you and other/future admins know what this flow resource is used for.

Let’s create a text variable called “varTaskId” that is available for input so that the taskId can be passed from process builder into flow.

varTaskId.GIF

Create a formula resource called “TodayFormula” with the date data type. This will set the date to today using the syntax today().

TodayFormula.GIF

This record variable called “varLoopRecord” holds the Task Who Relation record going through the loop. Note: Data Type = Record and Object = Task Who Relation.

varLoopRecord.GIF

This Record Collection Variable called “CollectionofContacts” will hold the contact record that matches the Task Who Relation Id.

CollectionofContacts.GIF

This Record Collection Variable called “CollectionForContactUpdate” holds the contacts that will have the Last Completed Task Date updated to today.

CollectionForContactUpdate.GIF

B. First, we need to perform a lookup to pull all the task who relation records associated with the task. We are using the Get Records resource because we are pulling a collection of Salesforce records. We are looking up the Task Who Relation where the TaskId equals the variable varTaskId. Once found, we will store the records in the Record Collection Variable created in the previous step {!CollectionofContacts}.”

Note: Select “Manually assign variables.” instead of having Salesforce create the variable. We want to select the option “When no records are found, set specified variables to null.” We don’t see this option when auto-created.

We will store the Id, TaskId and the RelationId.

Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.

LookupContactsAssociatedToaTask.GIF

C. Next, we will a Decision flow element to determine whether the Get Record in the previous step yielded in any task who relation records. The “Records Found” outcome looks at the items in the {!CollectionofContacts} Record Collection Variable is null false. Two negatives equal a positive, which means the collection has at least one or more task who relation records. The default outcome is named “No Records.”

Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.

RecordFoundDecision.GIF

View image full screen

D. We now need to create a Loop flow element so that we can go through each task who relation record in the collection. It looks at the Record Collection Variable {!CollectionofContacts} and put each task who relation record into a loop variable {!varLoopRecord}.

Loop.GIF

E. For each loop record, we use a Get Records flow element to look up a contact record that matches the loop record (i.e. task who relation). It will lookup on the Contact object where the Id equals {!varLoopRecord.RelationId} and only retrieve the first record found. It will store the Id and the Last Completed Task Date (JWLee__Last_Task_Completion_Date__c).

LookupContactGetRecords.GIF

F. Next, for each loop record, in the Assignment flow element, we will set (or assign) the Last Completed Task Date to today.  Variable is {!Look_up_contact.JWLee__Last_Task_Completion_Date__c} equals {!TodayFormula}.

Best practice tip: Provide a description so you and other/future admins know what this flow is used for.

UpdateContactFieldAssignment.GIF

G. For each loop record, in the Assignment flow element, we will add the loop record to a new collection that will be updated.

{!CollectionForContactUpdate} Add {!Look_up_contact}.

Note: {!Look_up_contact} is the dynamically created variable from the Get Records from Step E.

Best practice tip: Provide a description so you and other/future admins know what this flow is used for.

AddtoCollectionAssignment.GIF

H. Next, we need to create the Update Records flow element to update all the contacts in the sObject Collection Variable {!CollectionForContactUpdate}. This step will occur after we exit the loop.

Best practice tip: Provide a description so you and other/future admins know what this flow is used for.

UpdateCollectionUpdateRecords.GIF

View image full screen

I. Add the subflow Send Flow Fault Email. For instructions on how to create this, go to Step 2 of blog post: Maximize Maintainability With Process Builder and Componentized Visual Workflow.

FlowFault.GIF

J. Set your flow starting point. And connect the flow elements, outcome connector, loop connector and the fault connectors to match the below…

FlowConnectors.GIF

K. Save/Save As and provide the following properties.

Best practice tip: Provide a description so you and other/future admins know what this flow is used for.

UpdateContactLastCompletedTask-FlowProperties.GIF

L. Before you activate your flow, test this by using the Debug button. Create a task associated with multiple contacts, Status = Completed and Type = Meeting. Then copy and paste the id of the newly created task into the varTaskId field. Verify that this runs successfully. Check the contact records to see that the Last Completed Task Date field on the contact records are updated to today’s date.

Note: Only use the Debug feature in a sandbox as it will update records. Because of this, NEVER use the flow debug function in Production.

M. Click the “Activate” button.

3. Now, create a new process using process builder. In setup, go to Create | Workflows & Approvals | Process Builder in Salesforce Classic or Process Automation | Process Builder in Lightning Experience.

A. Click on the New button to create our new process. Complete the information below and select “A record changes.”

Best practice tip: Provide a description so you and other/future admins know what this process is used for.

Process-TakeActiononNewExistingTask-Properties.GIF

B. Specify Task as the object, when a record is created or edited.

Process-TakeActiononNewExistingTask-Object.GIF

C. Specify the Criteria Node. This needs to evaluate to true for it to execute. We will call the criteria “Completed Today.” The criteria is when the status is “Completed” and the type is “Meeting.”

[Task].Status Equals Picklist Completed

[Task].Type Equals Picklist Meeting

Process-TakeActiononNewExistingTask-CriteriaNode

View image full screen

D. For the immediate action, we are invoking the flow we created in Step 2.

Select Flow as the action, select “Update Contact Last Completed Date” flow. Specify the flow variable varTaskId and pass in the field reference [Task].Id onto the flow.

Process-TakeActiononNewExistingTask-ImmediateAction

View image full screen

E.  Click on the Activate button to activate the process builder.

Now, before you deploy the changes to Production, don’t forget to test your configuration changes.

  1. Create a task associated to multiple several contact records with the Type = Meeting.
  2. Update the task to status = Completed.
  3. Verify that the Last Completed Task Date is updated to today’s date for all the contacts associated to the task.

Deployment Notes/Tips:

  • The process builder, flow, the custom field (along with the FLS on the profiles) can be deployed to Production in a change set (or can be deployed using a tool such as Metazoa’s Snapshot).
  • You will find the process builder and flow in a change set under the Flow Definition component type.
  • Activate the process builder and flow post deployment as they deploy inactive in Production, unless with Winter ’19, you have opted in on the Process Automation Settings screen, to “Deploy processes and flows as active.” NOTE: With this change, in order to successfully deploy a process or flow, your org’s Apex tests must launch at least 75% of the total number of active processes and active autolaunched flows in your org.