This blog post is a continuation of the loop basics. The original post showed you how to update the record in the loop. This blog post will focus on how to update a record related to the record in your loop.
Here are a few lessons learned from implementing this use case:
- Learn how to create a loop, set values via assignments, add another record to a collection and handle DML (database actions) outside of the 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.
What’s a loop? Think of it as an assembly line. Every item going down the assembly line has the same actions taken on it. In the Salesforce world, if you have a group of records that you need to perform the same actions on for every record in this grouping would go through a loop. Each record, when it is its turn to go down the assembly line will be placed into a record variable, let’s call it a loop variable. After it’s done with its turn, then that record is removed from loop variable and the next record in the collection is placed into the loop variable. This continues to happen until we are done with the last record in the collection and therefore, ends the loop.
A collection variable is a list of records you wish to take action on. A loop uses a loop variable to store the values for the current record in the collection. When the loop completes taking action on the one loop record, Salesforce then places the next record into the loop variable. If you want any database action to be taken on any record or record related to the record in the loop, you place it into a collection, to be handled outside the loop.
One very important note: Avoid the bad Apex development practice of making a DML operation within a loop. You do not want to hit Salesforce-imposed ‘governor’ limits on how many database operations you can do in a single transaction. This same limit applies to flows as well.
Business Use Case: Addison Dogster is the system administrator at Universal Containers. Mary Markle is the Director of Operations. She would like to take all tasks that were marked completed today and if the task is associated with a contact, she wanted the Last Completed Task Date to be updated on the contact record.
Solution: This blog post will just cover solution of getting the group of tasks that have been marked completed today and taking action on any associated contact records.
The outcome looks like this:
This flow does the following: (1) gets the tasks that were marked closed today and store the records in a collection, (2) put each record in a loop record variable, (3) determine whether there is a contact associated to the task, aka loop record, (4) set the Task Completed Date to today and set a contactId of a variable called varContact to the contact associated to the task, (5) add the varContact variable into a new collection of records that will be updated and after the last record in the collection is completed, (6) update the contact records in the new collection.
Steps:
1. Create a custom formula field on the Task object called “Completed Date.” This is so we can track the completed date, not date/time, of the task. The standard CompletedDateTime is in the date/time format. For our purposes, we only care about today’s date, not the time so we need the formula to only take the date portion of the CompletedDateTime field.
Formula: DATEVALUE(CompletedDateTime)
Best practice tip: Provide a description so you and other/future admins know what this custom field is used for.
2. Create a custom date field on the Contact object called “Last Completed Task.” This will track the last completed task date.
Best practice tip: Provide a description so you and other/future admins know what this custom field is used for.
3. 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 “varContact” that will store the the information for the contact record variable, where Record is the Data Type and Contact is the Object.
Create a record collection variable resource called “ContactsToBeUpdatedCollection” that has a Record data type, Contact as the object and is set to allow multiple values (collection).
Create a formula resource called “TodayFormula” that has a Date data type and the Formula: Today().
B. Next, we will use Get Records flow element to query the Task object to get all the records with a completed date of today and is marked closed.
Object: Task
Filter the Task Records by Completed_Date__c Equals {!TodayFormula} and IsClosed Equals {!$GlobalConstant.True}.
How many records to store: All records
For the “How to Store the Data” option, I chose to use “Automatically store all fields.”
Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.
Configure to match the below:
C. We now need a Loop flow element where we will take each task record in the Get Task record collection variable to iterate through. Configure it as follows:
Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.
Collection Variable :{!Get_All_Tasks_Closed_Today}
[Note: The Loop Variable is {!Current Item from Loop_Loop}]
D. We will a Decision flow element to determine whether the task is associated to a contact.
Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.
For the “Yes” outcome, we need to check that the task whoId is associated to a contact. Set the conditions to the following:
{!Loop.WhoId} Started With 003 (003 is the three characters that signify a contact).
The default outcome: No
E. For a loop record variable, we need an Assignment flow element to assign values to fields that we will update in this flow. We will assign today’s date as the last completed task date field on the contact record and the id of the contact record to the whoId of the Loop record variable. Configure it as follows:
Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.
Set the variable values to:
{!varContact.Last_Completed_Task__c} Equals {!TodayFormula}
{!varContact.Id} Equals {!Loop.WhoId}
F. We need another Assignment flow element to assign the contact record variable {!varContact} to a new collection {!ContactsToBeUpdatedCollection} that will be updated after the loop ends.
I have to admit, this configuration trips me up. It reads backwards AND you don’t need to specify the Id of the loop record variable, just specify the loop record variable. Here we are added the {!varContact} to the collection {!ContactsToBeUpdatedCollection}.
Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.
Set the variable values to:
{!ContactsToBeUpdatedCollection} Add {!varContact}
As noted earlier, but worth noting again, please avoid database actions within a loop. Close the loop and make your DML action outside the loop to avoid hitting Salesforce governor limit for the number of DML actions within a transaction.
G. We need one more Decision flow element to determine whether there are records in the collection to be updated. If we do not do this check and just go to update the collection and there weren’t any records, the flow will fault.
Best practice tip: Provide a description so you and other/future admins know what this flow element is used for.
For the “Has Contacts” outcome, we need to check that the collection is not blank (i.e. {!ContactsToBeUpdatedCollection} Is Null {!$GlobalConstant.False}.
The default outcome: No Contacts
H. Now that we’ve closed the loop, we want to update all the contact records in the collection {!ContactsToBeUpdatedCollection} with an Update Records flow element. This will update the Last Completed Task date to today for all contact records in the collection.
Configure it as follows:
How to Find Records to Update and Set Their Values: Use the IDs and all field values from a record or record collection
Record or Record Collection: {!ContactsToBeUpdatedCollection}
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. Set your flow starting point. And connect the flow elements, fault connectors and outcome connectors to match the below…
J. Save/Save As the flow.
K. Click the “Activate” button.
Reminder: You need to complete the automation that triggers this process – whether it is a process, scheduled flow or a button. That was not covered in this blog post.
Now, before you deploy the changes to Production, don’t forget to test your configuration changes.
- Create a few tasks, some associated to contacts. Others not. Mark some completed.
- After the flow runs, verify the tasks were updated as expected (Completed Task Date is set to today for any completed tasks associated to a contact. The Completed Task Date is blank for any completed tasks not associated to a contact).
Deployment Notes/Tips:
- Flow can be deployed to Production in a change set (or can be deployed using a tool such as Metazoa’s Snapshot).
- You will find flow in a change set under the Flow Definition component type.
- Activate the flow post deployment as flows deploy inactive in Production, unless 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.
I was playing around with the flow and inadvertently took a screenshot of it where I did not connect the end of the loop with the Update Records flow element. Updated now.
LikeLike