Undeleting Records with Flow

Created by Yumi Ibrahimzade


ABOUT

You can perform insert, update and delete operations in Salesforce Flow. Most of the time, they are enough but what if you want to undelete records from the recycle bin? There isn’t undelete records operation in Flow. However, you can achieve this using this Invocable Apex Action.

See this post for the main discussion of this new Flow capability.

INSTALLATION

Production or Developer Edition

Sandbox

PARAMETERS

recordIds – Enter a text collection of record Ids to undelete.

CONSIDERATIONS

This Invocable Apex Action undeletes the records from the Recycle Bin. If the record is permanently deleted, which means that it is not in the Recycle Bin anymore, you cannot undelete it.

HOW TO USE

Add an Action element from the Toolbox and search for FlowUndeleteRecords. Pass the text collection of the record Ids to the input parameter called recordIds. Even if you want to pass a single record Id, you still need to create a text collection and pass it as the input value.

undelete records action and parameters

Read this post to learn how to find the deleted record Ids and see an example of undeleting records using this Invocable Apex Action.

DEMO

Sneak Preview: The New ‘Collection Filter’ Element

Collection Filter Overview

A new out of the box collection processor element joins the fray! With the new Collection Filter element you will be able to pass in a collection of records and filter it down. But that’s not all. This element has a few superpowers:

  • Simplified Flows: It allows the removal of loops, enabling simpler flows
  • Very Large Record Sets: It works with very large sets of records, extending the upward limits of Flow
  • Enhanced Condition Specification: It allows direct inline formulas with the ability to traverse to parents

1. Simplifying flows by replacing loops

Here’s an example of how filtering is typically done today (on the left) and how it can be done in Spring ’22 (on the right):

Finding records in a collection with loops

Finding records with the new Filter element

2. Much higher processing limits

In the above three element loop example above, there’s a limit of 2,000 element ‘iterations’ or ‘hits’ in a single flow, which effectively caps the number of records you can process to about 700. Go beyond that and you get the ‘ITERATION_LIMIT_EXCEEDED’ error.

With the new Collection Filter, however, you’ll no longer be bound by this limit. We’ve been able to filter collections of upwards of 50,000 records within seconds! Win.

3. Enhanced condition specification

Let’s first look at how conditions are specified. This will be quite familiar. Suppose you want to filter out all of the members of a collection of Accounts that have AnnualRevenue < 100,000. You can do that easily by setting conditions:

However, you can also choose to filter using an inline formula. Take for example an extension of the above scenario where you need to filter a collection of 12,000 accounts with complex criteria not currently supported by ‘Get Records’. Imagine in this fictitious scenario you need to filter by a combination of RecordType, Account Owner criteria, and Parent Account details.

Using the Formula Expression capabilities of the new Filter element you can now do that:

Additional Usage Notes

Filter Collection Saves a New Collection Instead of Overwriting the Existing One

While the ‘Sort Collection’ element overwrites the collection you pass in, the new Filter Collection creates a new one. We did this so you could have the flexibility to create multiple collections from a source collection of records, giving you more flexibility in how you control how your data ‘flows’.

The CurrentItem Variable Persists After Collection Filter is Removed

When the new Filter Collection element is inserted into a flow, a record variable called CurrentItem_FilterElementName is automatically generated and added to the flow to provide a way to use formulas and expressions for filtration.

If the Collection Filter element is deleted from the flow, the CurrentItem variable will be left as a resource in the flow and will need to be deleted manually.

Formula Performance Impact

Note that complex formulas with large amounts of records will impact performance, but by and large it will still be faster than your standard flow looping.

If you can use Conditions instead of a Formula Evaluation to drive your filter logic, you should always use Conditions due to the performance gains. The performance impact is relatively minimal for <500 records but you may start seeing a difference when you exceed 5,000 to 10,000 records.

Advanced Use Case: Avoid ‘Getting’ in Your Loops

For you intermediate to Jedi level Flownatics out there, this one’s for you! One powerful use case of Filter is that you’ll be able to achieve more efficient looping within your Flows. Note the below example could be solved a million ways, we just wanted to show you a creative way to utilize this new element.

Suppose you have a Flow that updates the Sales Price on a Product Line Item based on a discount determined in a set of Product Discount records. Your discount values are stored as records in Salesforce and you already have the discount records in your flow available to you. You just need to apply the discount for that particular product to the Product Line Item.

When the Opportunity is changed to a stage of ‘Proposal/Price Quote’ you want all of the Product Line Items to get the max discount possible applied. For each of the products tied to the opportunity, you do not want to do a a ‘Get’ inside of your loop to retrieve the relevant Product Discount records because you want to be a good ‘Governor Limit Citizen’.

The two big pieces here are the Collection Filter and Collection Sort elements. Here we are ‘Filtering’ the Discount records we grabbed in the beginning and finding discounts that are related to the product in our line item, then we are sorting it by the biggest Discount Percentage and reducing/limiting the collection to 1 record. In this fictitious scenario we had 2 possible discount records, but we only wanted the one with the biggest discount, hence the ‘LIMIT 1’. We then grab the single record stored in the results of the sort by using a quick loop.

The assignment here is: {!Loop_Over_Line_Items.UnitPrice} Equals {!numDiscountPercentage} * {!Loop_Over_Line_Items.UnitPrice}

The possibilities are endless! We’d love to hear how you’re using the new element when this starts rolling out.

Co-Authored by Adam White and Alex Edelstein

Using Flow to Process Approval Requests Automatically

There’s a bug in Approval Process involving a feature that’s designed to auto-approve an approval request if a specified step entry criteria is not met. This post describes a way to work around that bug.

This feature is normally activated here:

When this feature works properly, you can see it displayed here:

In certain situations, as described here, you can follow the steps but you won’t see the ‘else Approve’. One combination is when the previous step has an Auto-Skip pathway, as shown below. The first step has โ€˜else Next Stepโ€™ and the second step fails to show the โ€˜else Approveโ€™:

Workaround

The workaround for this bug involves creating an special User account that automatically approves every approval requests it receives, and adding a step that calls that ‘autoapprover’ if the conditions warrant.

Hereโ€™s the general flow:

Preparing Your Approval Process For AutoApproval

Let’s go back to our example from above. We have a step that we want to enter if the industry is not Agricultural. If it is Agricultural we want an automatic approval: However, the bug in approval processes prevents the auto approval:

For our workaround, we need to add a step that causes immediate approval if the step gets executed. We’ll do this by adding a new step 2 called Autoapprove Agricultural Accounts that executes immediately before our malfunctioning step. Note that 1) its criteria is set up to be the exact opposite of the original step 2, and it uses ‘go to next step’:

Importantly, We also modify our original step 2 so that it also uses ‘go to next step’. If we leave it on ‘approve record’ it will actually reject the record, which may not be what we want. Basically, since โ€˜Approve Recordโ€™ is broken, you donโ€™t want it in any part of your process.

Assigning the Step to a Special AutoApproval User

We assign our new Autoapprove Agricultural Account step to the newly created User called Autoapprover User:

This is just a normal User, but it has a special email address: 

Weโ€™ll touch on that in a moment. First, let’s review what we’ve done so far. After Step 1, our new Step 2 gets evaluated. If the industry is Agricultural, Step 2 will execute as normal and send an email notification to the AutoApprover User’s email account. Otherwise, the approval process will carry on to the original Step 2.

Adding an AutoApproval Capability to your Org

If our new Step 2 gets entered, we want it to cause the request to immediately be approved. To do this, our AutoApprover User uses as its email address a special Salesforce Apex Email Service Address that youโ€™ll generate by setting up an Apex Email Service. This service provides an email address and will auto-process email received at that address. 

Normally, you give each Email Service the name of an Apex Class that youโ€™ve coded up to handle the incoming email. But we donโ€™t want users to need to write code, so weโ€™re going to use a Flow extension that provides Email Services with an Apex Class that knows how to take the incoming email and pass it to a flow. 

Below, you’ll see instructions to create a flow called Auto Approve Request that is designed to be passed an email body by an Email Service. The flow then uses the Find Text action to extract the id of the Approval Process and then uses a new Resolve Approval Process action to approve the request. Hereโ€™s what Resolve Approval Process looks like:ย (UPDATE: this action now also has the input fields ‘objectName’ and ‘recordId’, and you can pass those values in instead of an approvalRequestId, if you wish. This improvement is courtesy of Adityaonmove)

When this action executes, the request will be approved.

Installing the AutoApprover Extensions

Step 1: First, install the EmailToFlow Extension.

This enables any Salesforce inbound Email Service you create to pass incoming emails to a flow.

Step 2: Install Find Text Extension

This is needed to extract the recordId from the email notification that approval processes send out. Here, you can see the id that we need to extract:

Step 3: Generate the โ€˜Resolve Approval Processโ€™ Invocable Action

Follow the instructions here to generate a Resolve Approval Process action that can be used when the AutoApprover User is assigned a step.

Step 4: Create an autolaunched flow that will autoapprove an approval request

This flow uses the Find Text and Resolve Approval Process actions from the steps above:

To create this flow, do the following:

4.1 – create the following input variable to receive the body of the email notifications:

4.2 – configure the Find Text action to extract the 15 character ID of the approval process from the email notification

4.3 Configure the Resolve Approval Process to carry out an automatic approval

Note the the โ€˜foundStringโ€™ output from the Find Text action is mapped into the โ€˜approvalRequestIdโ€™ input here.

4.4 Donโ€™t forget to activate the flow. 

You might want to test it out at this point by passing it an email body and verifying that it approves the specified approval request. 

Step 5 Update the the Email2Flow apex class to point to your newly created autoapproval flow

When you installed  EmailToFlow in Step 1 above, the package included an apex class called EmailToFlow that gets called by the Email Service and invokes a specified flow. As installed, that class attempts to call a test flow called โ€˜EmailControllerโ€™. You need to hand-edit the Apex class in two places to point it at the flow you created above in Step 4. Hereโ€™s an example of a class that has been modified to point to a flow called Auto_Approve_Request:

At this point, you can carry out final testing.

Appendix – Troubleshooting

It can be a little tricky to assign an Email Service generated email address to a Salesforce User because of the various confirmation emails that can get sent out. You often need to look at error messages or debug text to find important links or codes. In the following image, when an existing user had their email address changed to be an Email Service address, a confirmation message was sent which generated an error email. Clicking the debug link made it possible to find the necessary confirmation link:

If you have too much difficulty getting this to work, an alternative is to give the auto approver User a free public email address or a corporate email address and then have that account auto forward emails to the Email Service account.

Use Flow to Approve, Reject and Cancel Approval Processes

You can create a Resolve Approval Request action that allows your flows to approve, reject or remove Salesforce approval processes. The action looks like this:

Input Attributes

actionSupported values: Approve, Reject, and Removed (See this for more info).
approvalRequestIdThis can be extracted from email notifications. See this.
commentsText provided here will be saved in Approval Activity History
nextApproverIds (See this for more info).

Usage

This action is used to work around a bug in Approval Processes.

Installation

Instead of installing a package, you’ll need to copy this apex code and add it to your org as a new Apex class ( Itโ€™s not currently possible to package actions that use Approval Process apis.) You can create the class using Developer Console or Setup -> Custom Code -> Apex Classes. After creating the action, you can create a flow like this:

In the example flow above, the first action is the Find Text action . It’s used in this specific example to extract the id of the approval process from an email notification. In other use cases, you’ll be able to get the approval process id in other ways.

Creating a Test Class

Andy Haas has added a nice test class to this project called ResolveApprovalRequestsTest.cls. As he explains:

This test class will help pass the Resolve Approval Requests to production. Unfortunately, a lot of hardcoding had to be done as Process Instances, and Process Definitions can not have a DML insert function. So you’ll need to inspect this test class and replace various strings to match them up with your org.

When using this test class, you will need to create the following:

  • An Account with the name “Acme (Sample).”
  • An Approval Process on the Account object with a Developer Name “Test_Process_Definition.”
  • Activate the Approval Process
  • Submit for Approval the Acme (Sample) account. Leave it as pending, as that is what the code looks for.

If you want, you could make these changes within the test class to fit your orgs’ test records, but this will need to be done for this class to run. You then will get a 93% code coverage.

Easily Extract Substrings & Tap the Power of Regex with FindText

Suppose you have a message like this, generated from an email you’ve received…

“User User has requested your approval for the following item: https://ruby-force-1213-dev-ed.cs97.my.salesforce.com/p/process/ProcessInstanceWorkitemWizardStageManager?id=04i0U000000e9je

Please click this link to approve or reject this record.

Thank you,
Salesforce”

…and you need to extract that recordId. In the scenario that inspired FindText, the goal was to use Flow to auto-approve the approval request represented by that recordId.

If you’re comfortable with formula functions, you can use them to pull the string out. We wanted to make it a little easier, so we created FindText. This initial version of FindText is quite limited as it will only find a string of a specified length that follows a specified prefix string. So in our example, we’re able to pass in the string along with these specific values:

This action, when passed the above email body, returns ’04i0U000000e9je.

The action outputs two values:

  • foundString &
  • foundStringCollection

foundString will contain the first hit and is useful if you’re only expecting a single hit. foundStringCollection will contain all of the hits.

See this action in action in this Approval Process example.

Also, here’s info on processing inbound email.

Future Development

Searching by length and prefix is only one of hundreds of ways you might want to extract substrings. Feel free to request other modes of query in the comments here.

Developer Notes

This action uses Salesforce Apex regex. Ideally, it will become the friendly way for flow creators to tap into the power of regex

Install

v1.0 11-26

Source

source

Connect Powerful Einstein Discovery AI To Your Flows

Two recent articles highlight new tools to connect AI predictions to Flow. This one is by Salesforce Director of Product Manager Bobby Brill:

This one by Salesforce engineer Alex Rich focuses on the use of the PREDICT formula function. His example shows PREDICT being used in Validation Rules, but the same use case is pertinent to the use of formulas in Flow:

From Jessie Rymph: How to display or upload a contact photo using Flow

Jessie Rymph over at her blog on Unhandled Sunshine posted a nice tutorial on how you can create a flow that lets users upload a contact photo or display their existing photo in a nice, clean, code free way utilizing Narender Singh’s File Preview component.

Check it out

From Tamar Erlich – Submit an orchestration from a button

Currently there are two ways you can launch a flow orchestration: using a record trigger, or auto launch from Apex, But what if I want to be able to launch an orchestration from a button and mimic the good old “Submit for Approval” button?
I looked at alternative ways to start orchestrations, and this is what I found:
1. Launching an orchestration from a URL button was not user friendly as the user was presented with a blank auto launched flow screen and was not redirected back to the record when finished even if the the return URL was part of the button definition. Overall, while this may work, the user experience was not smooth
2. Trying to include the submit flow as an interactive step assigned to the current user, resulted in a warning when saving the flow and an error during execution saying that no assigned user was found

I ended up with the following solution that worked well and gave a smooth user experience:

1. An action button to launch the submit flow on the record page
2. A submit screen flow that will update a field on the record to indicate the record was submitted and who the approver is
3. An orchestration that will listen to the field updated by the submit flow and will run the approval flow, routing to the approver that was updated on the record by the submit flow
4. The approval flow will update the record again with the final approval status

Here is an illustration of the overall process:

Both the submit and approve flows are very simple and only have one screen followed by an update records step

Submit Flow

Launch the submit flow from an action button added to the page layout

Action Button
Approval Flow

The flow orchestration only has one stage and one step

Orchestration Flow

It starts when the record’s approval status is updated to submitted

And routes the approval to the username that was updated on the record by the submit flow

Here is a short video demonstrating the complete process

Some notes about the flows:

1. The submit flow clears any previous approval status and rejection notes
2. The approval flow only displays rejection notes if the user selects to reject, using a visibility rule
3. In both flows, I’m using a record input variable and this saves having a get records element in the flow as the whole record gets passed in from the button or from the orchestration step

Possible enhancements:

1. The approval request flow can include a message with approval details to the approval request flow by using a display text with merge fields from the record and related records information
2. The submit flow can select the approver automatically by using criteria from the record or an approval matrix stored in custom metadata
3. The submit flow can also be used to recall or not allow to submit an approval by displaying another screen based on the approval status

Launching an orchestration from a button opens up a lot of possibilities, please share if you come up with other use cases.

From Ryan Mercer: Yet More File Upload Improvements

From Ryan Mercer: โ€œIโ€™m excited to release my next sprint of File Upload Improved. Thank you to everyone for your feature suggestions, I really enjoy working through your great ideas! Please continue to keep them coming.โ€

This releaseโ€™s features includeโ€ฆ

Show files below the component

By default, the files will show above the File Upload Component. If you’d prefer they be shown below the component, set this to TRUE.

Restrict users from uploading multiple files

Allow the user to upload multiple files. If this is not TRUE, then once the user uploads one file, the file upload component will not allow any additional files to be uploaded.

Control whether uploaded files are visible to all users

By default, when an internal user uploads a file, the file is only visible to other internal users (meaning community users can’t see it). If you’d like to make the uploaded file visible to all users, set this to TRUE. When a community user uploads a file, the file is already visible to all users.

From a technical perspective, this sets ContentDocumentLink.Visibilty = AllUsers.

Modify or Enhance The Names of Uploaded Files

The file name of the uploaded files defaults to the actual name of the file. If you’d prefer to override the default file name, you can specify the new file name here.

You can do funky things here like using a Text Template (remember to View as Plain Text) or even using a Flow Formula

Show Existing Files Related to Record Id

If you’d like to show the existing files associated with the Related Record Id (in addition to the ones that the user may upload), set this to TRUE. Be aware that sharing rules are NOT enforced, so the user could see files that they wouldn’t normally have access to.

Plus other general performance and architectural improvements

Install here.

From Tom Hoffman and Automation Hour: Manage Enterprise Territory Management with Salesforce Flow

It’s always great to see someone like Tom go deep on the use of Flow for a particular corner of Salesforce. Enterprise Territory Management is a core element of Sales Cloud, and this Automation Hour shows how to automate easily.

Check it out!