Visual Workflow
As we already learned in Chapter 1, Salesforce Fundamentals, Visual Workflow is the product that lets you design, manage, and run flows. You create and manage your flows through a tool with a graphical interface, previously called the Cloud Flow Designer (now called Flow Builder). Each flow is actually an application that automates a business process by collecting, updating, editing, and creating Salesforce data. Flows can execute actions based upon criteria you set, interact with records in your database, call Apex classes, and they can even guide your users to wizard-like screens to collect and/or update information.
At the time of writing (Spring 2019), the Cloud Flow Designer just got a major revamp and got a new name: Flow Builder! So, I'll be showing you the latest version in our examples.
The following screenshot shows the new Flow Builder in all its glory:
The Flow Builder interface has two parts:
- The Toolbox: This is the sidebar, which contains two tabs—Elements and Manager. Firstly, the Elements tab: This contains all elements that you can drag and drop onto the canvas and connect together to build out your flow. Then, the Manager tab gives an overview of all elements in use within your flow.
- The canvas: This is your actual flow. You chain elements together and configure each element so that they perform a certain action.
Use the more powerful Visual Flows to perform even more actions than Process Builder or workflow rules! With Visual Flow, you can perform the following tasks:
- Accept user input
- Call Apex (can be used to send outbound messages too)
- Create records
- Delete records
- Post to chatter
- Send emails
- Submit for approval
- Update fields on any record
- Quick actions
- Query records
- Loop through records
- Make multiple decisions
Tips, before you start creating your flows, include the following:
- Draw your business process out before you try to automate it.
- My principle is always that you must be able to do each action sequentially through the user interface before you can start automating it. Automation is all about automating actions that a user would otherwise perform manually and removing the burden.
- Be aware of required fields when creating records from within your flow.
- Give your actions, variables, decisions, and screens meaningful names so that you keep a clear overview of your flow.
In the previous chapter, I promised you that we would create a flow that provides the user with a little wizard to create a new movie, director, and review in one go. We'll do that right now.
- To create our flow, navigate to Setup | Process Automation | Flows and click the New Flow button:
- You'll see a big blank canvas with only a start element on it. In the sidebar, you'll find your Toolbox containing elements you can choose from to build out your flow. The first thing we'll need is an input screen for our users to fill in some details, which we will use to create our movie, (possibly) a person, and a review.
- So, drag the Screen element onto the canvas and it will open the element configurator, as shown in the following screenshot:
Start by filling in the Label with Fast Create New Movie. The API name should get filled in automatically based upon the label. Leave all other settings as default. Perform the following steps very carefully:
- Drag a Display Text component as the next component and fill in DisplayNewMovie as the API Name. In the white box underneath the API name, copy/paste the following text: Fill in the necessary fields to create a new movie record.
- Next, drag a Text component into the screen part (not a Long Text Area!). As the label, fill in the Movie Title. The API name should be Movie_Title. Check the Require checkbox.
- Drag a Date component onto the screen, and call the label Release Date. The API name becomes Release_Date. Leave the rest as default.
- Next, drag a Multi-Select Picklist into the screen. As the label, put Genre. As the API Name, overwrite the default to GenrePick (this is because an API name must be unique and we will select our real Genre picklist field from the Movie object to provide us with values). The data type is Text. Don't set a default value.
- In the Select Choices section, put your cursor in the first choice box and click New Resource. A new window will pop open with a search box for Resource Type. Select Picklist Choice Set. As the API Name, fill in Genre, for Object, select Movie, as Data Type, select Multi-Select Picklist, and as Field, select our Genre__c field. Then, click Done:
- After clicking Done, you will see that the Choice field is still empty, so click in it again. But now, you will be able to select the Genre picklist choice set we just created. Select this, as shown in the following screenshot:
- Drag a Number component into the screen and set Label as Runtime, the API Name as Runtime, and decimal places equal to 0.
- Drag a Currency component into the screen and set Label as Budget, the API Name as Budget, and decimal places equal to 0.
- Drag a Text component into the screen and set Label as Cover URL, and the API Name as Cover_URL.
- Drag a Long Text Area component into the screen and set Label as Description and the API Name as Description.
- Drag a Display Text component into the screen and set the API name as DisplayDirector and copy/paste the following sentence into the big white box: Fill in First Name and Last Name of the Director. If the Director already exists, it will be linked automatically. If not you'll be asked to enter some more details in the next step.
- Drag a Text component into the screen, set its Label to Director Full Name and the API name as Director_Full_Name, and then check the Require checkbox.
- Drag a Display Text component into the screen, set the API name as DisplayNewReview, and copy/paste the following sentence in the big white box: Please enter a first review for this movie. It will be automatically sent for approval after successful creation.
- Drag a Long Text Area component into the screen and set its Label to Review Description, the API name to Review_Description, and check the Require checkbox.
- Drag a Picklist component into the screen and set its Label to Review Rating, and the API name to Review_Rating. Check the Require checkbox and choose Data Type as Text. Under the Select Choices section, put your cursor in the choice box and click New Resource. Select Picklist Choice Set as Resource Type, set the API name to ReviewRating, choose Review as Object, choose Picklist as Data Type, and choose Rating__c as Field. Then, click Done:
- Just as with our previous picklist choice, the Choice is again blank. Click on it and you'll find your newly created ReviewRating picklist choice set. Select this option.
- Your screen element is now finished and should appear as follows (I can't get all the fields on one screen, so this is the bottom part):
If your screen looks the same and you have paid attention to very carefully create all the components with the exact labels, names, and settings as I've instructed (if you're not sure, go over every step one more time), you can click the Done button to save your screen element and go back to the Flow Builder canvas. It should look like this:
- Now that we have our first element, we need to connect it with the Start element. To do that, click and hold the little white circle of the Start element and drag the connecting line onto our Fast Create New Movie Screen element. This will connect both elements, as follows:
What we've actually created right now is an input screen for our users with fields that are required to create a movie, a person (as director), and a review. By marking some fields as mandatory, we are sure we have a minimum of data required to create a record of each type. But for now, all we would have is that data in memory, in variables within our flow, but not in the database!
And what we also want to do is check, based upon the director's full name, whether this person already exists in our BIM DB. If so, we won't create a second person with the same name, but relate the movie to the existing one. If the person doesn't exist, we'll provide the user with a second screen asking for some more details (a biography and a birthdate).
Let's continue. We've got a lot of steps ahead, so keep paying attention and follow the next steps very carefully:
- Drag a Get Records element onto the canvas. This opens the element configurator screen. Fill in Fetch Persons as Label, and the API Name as Fetch_Persons.
- In the Get Records of This Object section, select the Person object.
- In the Filter Person Records section, select Conditions are Met and choose the Name as a field, Equals as operator, and select Director_Full_Name (under the screen components section) as the value.
- In the Sort Person Records section, choose Ascending as Sort Order and select the Name as Sort By value. Now, for How Many Records to Store, choose Only the first record and for Where to Store Field Values, select the Together in a record variable radio button, and also check the When no records are returned, set specified variables to null. checkbox!
- In the Select Variable to Store Person section, put your cursor in the Record Variable search box and click New Resource. A new screen opens. Choose Variable as the resource type, set the API name to FoundPerson, select Record as the data type, and Person as the object. Check the Available for output checkbox, and then hit Done.
- Just like before, our Record Variable is still empty, but click in it and now you can select our new FoundPerson record variable. Lastly, in the Select Person Fields To Store in Variable, the ID is already set for you and marked as read-only. Add the Name field also. If your screen looks like the following screenshot, you can hit the Done button at the bottom:
What we did here was to create a Get Records element. This is basically a query we will perform to find person records in the database with the same name as what the user fills in the director full name screen element. We don't care if we find multiple records. We only store the first one found in a record variable called FoundPerson, so our FoundPerson variable will contain the record ID and the name of that record.
If no match is found, our FoundPerson variable will be null and, as a result, not set. We will use this query to make a decision if we need to create a new Person record and ask for more details, or if we can relate an existing Person record as the director for this new movie. That's actually our next step.
- Drag a Decision element onto the canvas. This opens the element configurator screen. Enter FoundPersonOrNot as Label and the API name.
- In the Outcome Details section, fill in PersonFound as Label and the API name, select All Conditions Are Met for when to execute the outcome, and, from the resource box, select FoundPerson under the Record Variables section and select its ID field. Then, as the operator, choose Was Set and, as the value, select GlobalConstant.True. Then, hit Done:
What we did here was create an IF/ELSE decision. Each decision element always has a default outcome, and as we did not set that, it will act as our person not found outcome. We also created a PersonFound outcome that checks whether, in a previous step, our FoundPerson variable has been set (this means that we found at least one person record with the exact same name as the director's full name, filled in by the user).
- Drag an assignment element onto the canvas. The element configurator will open. Set the Label to AssignPersonIdFound, and the API name as AssignPersonIdFound.
- In the Set Variable Values section, click in the Variable box and select New Resource. Select Variable as the resource type, the API name as PersonIdToUse, and the data type as Text. Select the Available for output checkbox, and then click Done.
- As always, you need to select the newly created variable now as the variable, so select PersonIdToUse and set the operator as Add, As the value, select our existing FoundPerson as its ID field, and hit Done. Your assignment element should look like the following screenshot:
What we did here was to create an assignment element that we will use to assign the ID of the Person record that we found through our query to a text variable called PersonIdToUse. We will connect this assignment element to our decision element for the outcome when a Person has been found!
- So, before we continue creating other elements, let's first connect the elements we already have. Click and hold the white circle of the Fast Create New Movie screen element and connect it to the Fetch Persons Get records element.
- Then connect the Fetch Persons element to our Decision element. Now, connect our Decision element to our Assignment element.
- A popup will open in which you need to choose the outcome for which you want this assignment action to be executed. Choose the outcome PersonFound and click Done:
Your flow should now look like the following screenshot:
It should become clear to you that we are now following the path (decision) where we found an existing Person record that has the exact same full name as the director's full name value that the user would have entered in our wizard, right? So, let's continue first finishing this path; afterward, we will build out the path where the director does not yet exist in our database.
- Drag a Create Records element onto the canvas. The element configurator opens. Fill in the Label with InsertTheMovie and the API name with InsertTheMovie. Choose One record to create and Use separate variables, resources, and literal values for how to set the record fields. In the object, choose Movie, and then map the following fields (of our Movie object) to values we have in memory:
- Field: Budget__c; Value: Budget (under the screen components section)
- Field: Cover_URL__c; Value: Cover URL (under the screen components section)
- Field: Description__c; Value: Description (under the screen components section)
- Field: Director__c; Value: PersonIdToUse (under the variables section)
- Field: Genre__c; Value: GenrePick (under the screen components section)
- Field: Name; Value: Movie title (under the screen components section)
- Field: Release_Date__c; Value: Release date (under the screen components section)
- Field: Runtime__c; Value: Runtime (under the screen components section)
- Now, in the Store Movie ID in Variable section of the configurator, click New Resource. Select Variable as the resource type, as the API name, fill in NewlyCreatedMovieId, as the data type, choose Record, and, as the object, choose Movie. Select the Available for output checkbox, and then click Done:
Let's first create the last element of this path and then we'll recap what we have done so far. I appreciate that it's a lot!
- Drag a Create Records element onto the canvas. The element configurator pops open. Set the Label to CreateNewReview and the API Name to CreateNewReview. Select One record to create and Use separate variables, resources, and literals for how to set the record fields option. Choose the Review object as the record to create and map the following fields and values:
- Field: Description__c; Value: Review Description (under the screen components section)
- Field: Movie_Title__c; Value: NewlyCreatedMovieId (under the Record variables section)
- Field: Rating__c; Value: Review Rating (under the screen components section)
- Field: Status__c; Value: Pending Review (under the picklist values section)
- Now, in the Store Review ID in Variable section of the configurator, click New Resource. Select Variable as the resource type, as the API Name, fill in NewlyCreatedReview, as the data type, choose Record, and, as the object, choose Review. Select the Available for output checkbox, and then click Done. Don't forget that you have to set the variable now to your NewlyCreatedReview, its ID field, and then hit Done again to save your element.
It should now look like this:
- To complete our path for when we found an already existing director, connect our Assignment element to the InsertTheMovie record create element, and then connect the InsertTheMovie record create element to our CreateNewReview record create element. Our whole flow now looks like this (you may want to move your elements a bit on the canvas, so you get a clear flow):
The first part of our flow is done! Let's recap what we have now.
Our goal was to create a wizard-like screen that lets a user create a new movie, related to a director with at least one review, in one go. So when our flow starts, the first thing that happens is a screen that opens up to the user, so that he can input the necessary data to create a movie record, at least a name for the director, and the necessary fields to create a review.
We know about our data model, so we know that the Director field on the Movie object is a lookup. We will need the ID of a Person record and we also know that a review needs to be related to the movie, so we will need the movie record ID before we can create the review record. This proves that you need to draw your flow and the order in which things need to happen beforehand! So, our user fills in all the necessary details in our screen element, which has saved all this data in memory into screen component variables.
The first thing we do, after the user has filled in our form, is to query our database to see whether we can find a person with the exact same name as our director's full name. This can give us two results: either we find at least one, or we don't find any. This is where our decision comes into play because, based on the outcome, we either can use the record ID of the person we found, or we will first need to create this new person (the second part of our flow, which we still need to build).
We now create the next steps that need to happen in case we find an existing person, so we assign the ID of the person found in a variable called PersonIdToUse. At this point, we have all the necessary data to create our records. We first create our new movie record, set the fields to the values provided by the user, and then we fill the lookup relation with the ID value stored in our PersonIdToUse variable.
Once the movie has been created, Salesforce gives us back the Salesforce record ID of that movie and we store that in a record variable called NewlyCreatedMovieId. In the last step, we create our review with the values provided by the user, and fill the relation to the movie with the NewlyCreatedMovieId ID value.
Now, let's continue with the second part of our flow. This is the part where we couldn't find any existing Person record with the same name as the director, which is the default outcome of our decision element!
- Drag a Screen element onto the canvas. The element configurator will pop open.
- In the screen properties section, fill in the Label with Create New Director and the API name with Create_New_Director. Now, drag a Text component onto the page, set the Label to New Director Full Name, and the API name to New_Director_Full_Name. Check the Require checkbox and, as the default value, select Director Full Name (under the screen components).
We don't want our user to have to type the name twice, right? So, we can already prefill the name with the value the user entered when they started the flow.
- Now, drag a Long Text Area onto the page, set its Label to New Director Biography, and the API name to New_Director_Biography. And, lastly, drag a Date component onto the page and set its Label to New Director Birthdate, and the API name to New_Director_Birthdate. Then, click Done.
- Now, connect our decision element to this Create New Director screen element and it will automatically map as Default outcome. This is because we only had two outcomes, and PersonFound has already been used.
- Drag a Create Records element onto the canvas. The element configurator will pop open. Enter CreateNewPersonAsDirector as the Label and API name. Choose to create only One record and the Use separate variables, resources, and literal values for how to set the record fields section. Choose Person as the object and map the following field to the variables:
- Field: Biography__c; Value: New Director Biography (under the screen components section)
- Field: Birthdate__c; Value: New Director Birthdate (under the screen components section)
- Field: Name; Value: New Director Full Name (under the screen components section)
- Now, in the Store Person ID in Variable section of the configurator, click New Resource. Select Variable as the resource type, as the API name fill in NewlyCreatedPerson, as the data type, choose Record, and, as the object, choose Person. Select the Available for output checkbox, and then click Done. Don't forget that you have to set the variable now to your NewlyCreatedPerson, its ID field, and then hit Done again to save your element. It should now appear as follows:
We are almost there. There is one more element to create and that's an assignment to assign the ID of our NewlyCreatedPerson to our PersonIdToUse variable.
- Drag an Assignment element onto the canvas. The element configurator pops open. As the Label, fill in AssignNewlyCreatedPersonId and the API name, AssignNewlyCreatedPersonId. As the variable, select our PersonIdToUse variable, the operator should be Add, and, as the value, select our NewlyCreatedPerson record variable, its ID field, and then click Done. Refer to the following screenshot:
- To finish everything off, connect our Create New Director screen element to the CreateNewPersonAsDirector create records element. Afterward, connect this one to the AssignNewlyCreatedPerson assignment. Lastly, connect this assignment to our already existing InsertTheMovie create records element. Your finished flow should now look like this:
- Now, save your flow by hitting the Save button in the top-right corner of the Flow Builder, give it the name FastCreateMovieWizard, and choose Screen Flow as the type. Then, hit Save, as follows:
However, your flow is still inactive. You'll need to activate it first by clicking the Activate link next to your flow in the Flows screen:
Now, you're done and you probably, just like me, can't wait to test this out, right?