Wizard News is going to answer our first “Letter to the Developer.” This column was originally intended for developers, but, as I mentioned in last weeks post, we’re expanding it to Salesforce & Wizard questions in general.
For our first column, we hear from David with a flow question.
Hi, I've been playing around with headless flows and love them. I still need to get my head around collections, because they're not quite clicking for me (needing to populate a second collection based on assignments based on the first collection, in order to do a Fast Update). So.. the question I have is, is it possible using the Loop function or some other way within a flow to loop through a set of dates and create records based on them. Say I have a start and end date on object A. I want to loop through all days from the start to the end date and create records (1 / day) on record B. Is that possible, and if so...how? Thanks, David
After some forethought and some experimenting, this is something you definitely can do with flow! First let’s clarify what Loops, Collections, and sObject Variables are with Flow.
sObject Variable in flow represents 1 record of 1 specific object type. For example, it can be a single record of an Opportunity. Once defined we can set field values or create, update, and delete that record from Salesforce.
sObject Collection in flow represents multiple records of a single object. So it could be 5 opportunity records. Once defined we can create, update and delete all the records within that collection. We can also use an element to loop and do something with each record
Loop in flow represents an element that will take a sObject Collection and pass each individual record – one at a time – to the next element. Once all records have been “looped” through, it’ll go to the “end of loop” element. This is useful when you do a Fast Lookup and have multiple records that you want to review.
In the flow I’ll use today we’re going to create multiple records based on two date fields. I’m going to find multiple Opportunity records and look at each opportunity. Based on the Created Date and Close Date of each opportunity we’ll create a new task – one for each day between Created Date and Close Date. I’m not going to use this as a headless flow. Instead, I’m going to add screens to the flow so you can each see the major steps.
Here’s what we need in the flow:
- ThisDate – Variable using the date format
- NewTask – sObject Variable for a Task Object
- ThisOpportunity – sObject Variable for a single Opportunity
- ListInboundOpty – sObject Collection variable that will contain a list of all our Opportunities
- ListNewTasks – sObject Collection variable that will contain all the Tasks we’ll create
- OpportunityName – This is a screen input for this flow, but could be a variable if using Headless flow. This so we can query which Opportunities we want to include
I’ve also added a few extras for the “screens” that will show you the number of tasks that will be created for each iteration of the loop and the total number of tasks.
The flow elements, excluding screens, will be:
- Fast Lookup – to query for all the Opportunities. The flow will find any Opportunities where the name starts our ‘OpportunityName” input. This could also be a variable set by a flow trigger if using Headless flows
- Loop – Loops through the sObject Collection ‘ListInboundOpty”
- Assignment: Sets the “ThisDate” variable to the Created Date of “ThisOpportunity” which is the Opportunity record we’re currently looking at in the loop
- Decision: Compares “ThisDate” with the Close Date. If the “ThisDate” is less than or equal to the Close Date it goes into the task create elements. Otherwise, it’ll return us to our loop
- Assignment: Sets the values for the fields in the “NewTask”
- Assignment: Adds the “NewTask” to the sObject Collection “ListNewTasks”
- Fast Create: Creates all the Tasks in the sObject Collection “ListNewTasks”
The above overview includes some extra assignments and screens for demo purposes.
We start with the Fast Lookup. This can return one record or many records depending on what is specified in the filters. There are three very important parts of a fast lookup.
- Filters – The filters control which records will be returned. In this situation I’m doing a Name Starts With filter. I can add additional filters to make sure only the records I want to return go into the flow. This could be an ID of a record and often is if you’re using Headless flow
- Variable assignment – this is where the record(s) will be stored in the flow. It can be either a single sObject Variable (one record) or a sObject Collection (many records). To be safe, I recommend always doing an sObject collection unless there is NO POSSIBLE WAY of getting more than one record, for example, your filtering by record ID
- Fields – this will be the fields and values stored in your collection or sObject variable. Make sure to include only what you need, but include what you need. In my flow, I’m capturing the ID, CreatedDate, CloseDate and Name. I’m using the last 3 items within the flow and I like to capture the ID for any debugging purposes.
The loop variable does something very simple and very important. It lets you take all the records within a sObject collection and review each individual record one at a time. There are two important components to the loop:
- sObject Collection – what are you looping through
- sObject Variable – What variable will hold the individual record you’re currently looking at within the loop
This is an important distinction. The Loop doesn’t loop through anything other than sObjects. Think of the Loop as a digital PEZ dispenser. It holds multiple pieces of candy (records) but only gives you one at a time. The loop lets you draw two lines, one for the “Next Element” which passes 1 record over and the second line for when you’re out of candy.
If you’ve been using Flow for a while, you’re probably familiar with the decision element. This is basically a big “If this then that” step. You define the “That” through “Outcomes” and then you define the “if this” as the criteria for each outcome. In my flow there’s two outcomes: “Still More Dates,” and “No more Dates”
My criteria for “Still More Dates” is simply “ThisDate” is less than or equal two ThisOpportuniy’s close date. This outcome means I have more tasks to create. The other, or default outcome, means there are no more tasks to create.
You MUST have at least 2 outcomes for a decision, but you can have multiple outcomes – each with their own criteria.
Assignment defining Field values
Assignment elements are wonderful things. They can be used to set variables within your flow and recently you can use them to specify field values for sObject Variables and add them to a sObject Collection. In this element, I’m setting the value for the Subject, ActivityDate and WhatID (related record) for “NewTask.” That’s it. I could also use this same element to add to a sObject Collection, but I like to keep this neat and use a second assignment element to do that.
I’m also using the Assignment element to add 1 day to “ThisDate” each time I go through the decision path. Each time I go to the Decision element I’m re-comparing to see if “ThisDate” is now greater than my Close Date. I keep adding 1 day to “ThisDate” until the Decision takes us to the “No More Dates” outcome.
Finally, our Fast Create element. This can create a single record from a sObject variable or create multiple records that are within a sObject Collection. I’m doing the latter in this flow. I’m creating all the records at once within the collection. I consider this a best practice and it prevents me from creating the records within the loop which may cause an error if I have too many records.
You need to keep your validation rules in mind when using Fast Create. Flows run under the same restrictions a user as if they were manually creating the records. If you have a validation rule that requires a field and you do not fill that field in – your flow will cause an error. Keep that in mind.
So there’s our flow. We start by querying our Opportunities and then we loop through each record. For each record, we compare our dates using a Decision element. If we need to create a record, we add 1 day to our date variable, assign values to our Task record (sObject Variable) and then add that Task to our collection. We then go back to the decision and compare the updated “ThisDate” to our Close Date. Repeat as necessary. Once we’ve created tasks for all the days between the Created and Close date we go to the next record in the loop. Finally, once we’ve looped through all the records, added all the tasks to the collection, we create the actual tasks.
Want to see what the finished result looks like? You can see a video of it here http://youtu.be/2PYHIY6zk18 Sorry there’s no audio to walk you through it. I haven’t quite figured out how to record audio and video without causing my computer to go on strike.
There are some considerations to this flow. A fast update element is limited to 200 records at a time. Plan accordingly, if your flow has a chance to create more than 200 records you’ll want to do a decision tree to do a fast create when you hit 200 records, then empty your collection and start adding new records. Rinse and repeat. This method also has an upper limit. You can only have 150 DML elements (Create, Update, and Delete) with a maximum of 10,000 records created from DML statements. Consider using asynchronous APEX if you have to create that many records.
You can find information on the limits of Flow here: https://help.salesforce.com/HTViewHelpDoc?id=vpm_admin_flow_limits.htm&language=en_US
David – and everyone else reading this – I hope you find this helpful.
The Developer aka The Salesforce Wizard
Want more information about Loops and flow? Check out my video Wizard’s Apprentice Lightning Experience – sObject Variables, Collections & Loops Revisted
A Note From The Editor
A little secret about WizardNews posts. I hate writing Post Titles. I struggle with trying to write titles that are informative, accurate, and grab your attention. One of the more difficult parts is not to interject my sense of humor into the title – too much. For example, alternative titles for today’s post included:
- Yay! Someone used the Letters to Developer form!
- Once again into the flow dear friends!
- Loopy for Loops
- Want to come to my office and see my sObject Collection?
What other titles can you come up with for this week’s blog post?