Welcome to another “Automate This!” In this live-streamed video series, we cover all things automation, from use cases and best practices to showcasing solutions built by Awesome Admin Trailblazers like you. With automation, you can remove manual tasks, drive efficiency, and eliminate friction and redundancy. In this episode, see how Eric Smith created a subflow to copy files from one object record to another.
The business need: Copy all files automatically from one record to another
There are times when you may want to automate the copying of all the files attached to one record to another record. An example of this might be when closing an opportunity, copy all the files attached to the opportunity record to another record such as a newly created quote or contract.
Salesforce uses a junction object called ContentDocumentLink that includes a lookup to the file (ContentDocument) as well as the record ID of the object record it’s attached to. This subflow references and creates those records to handle the copying of the files.
Subflows are a way to create a separate flow with a series of actions that can be shared and reused by other flows. Values can be passed into the subflow, and other values can be passed back to the calling flow.
The solution #1: A simple subflow to copy files
To handle the steps needed to copy files from one record to another, this subflow gets all of the ContentDocumentLink records pointing to the source record and loops through those to build new ContentDocumentLink records that reference the target record.
The only input attributes needed for the subflow are the record IDs of both the source record and the target record.
Input Attribute
Type
Notes
vSourceObjectId
Text
Record ID of the source record
vTargetObjectId
Text
Record ID of the target record
Because this subflow is designed to be reusable in a number of different ways, it’s important to build in some error checking and processing. To let the calling flow know if there were any errors, the subflow passes back two output attributes. One is a boolean value that’s set to True if there was an error, and the other is a text value with the corresponding error message.
Output Attribute
Type
Notes
vIsError
Boolean
(Optional) True if there was an error in the sub flow
vErrorMessage
Text
• Either or both of the source or target record IDs are blank.
• There are no files attached to the source record.
• There was an error creating the Target Document Links.
Let’s break down the flow to see how this is done.
The first Decision checks for errors by determining if either of the input attributes are null or empty.
If both record IDs are provided, the Get Records element gets all of the ContentDocumentLink records for the source record. The LinkedEntityId field stores the record ID of the Salesforce record that the file is attached to.
The next Decision element checks to make sure that at least one file was attached to the source record by seeing if the result of the Get Records element isn’t empty.
Now we can attach the files to the target record by looping through each of the ContentDocumentLink records from the source record.
The first Assignment element in the Loop changes the value of the Linked Entity Id field from the source record ID to the target record ID and clears the existing record ID from the ContentDocumentLink record. Note: The Create Records element that we use later requires that each of the records does not have a value for the record ID, as that will be inserted automatically when the records are created.
Since we don’t want to create individual records inside of a Loop, we add this new record to a collection variable for ContentDocumentLink records (colContentDocumentLinksNew) using an Assignment element.
After the Loop, we use a Create Records element to create all the records stored in the colContentDocumentLinksNew collection variable.
We do one last error check by adding a Fault path to the Create Records element in case something goes wrong with the record creation.
Each of the three Assignment elements in the error paths in the flow sets the vIsError variable to True and sets the appropriate vErrorMessage text value.
How to call the subflow
To call this process from your primary flow, add a Subflow element and handle any required error processing.
Specify the source and target record IDs in the subflow attributes.
Next, add a Decision element to check if the subflow returned any errors.
This example uses a Screen element to display the error.
The solution #2: An advanced subflow to copy files
The flow outlined above works great when you’re copying files to the target record for the first time. If your needs require that you copy files from one object to another multiple times, you want to make sure you’re not duplicating files that are already attached to the target record.
This advanced version of the copy files subflow adds the additional steps to check the target record first to make sure no files are duplicated.
Advanced subflow to copy files (without nested Loops)
One of the performance drawbacks of the advanced flow shown above is that it requires nested Loops to check each file in the source file collection against every file in the target file collection to see if the source file already exists in the target collection.
The performance of the advanced flow can be improved by calling an invocable Apex action that handles the comparison for you and returns a collection of just the source files that are not already attached to the target record.
Installation links
You can use these links to install the referenced flows in your own orgs. You should always install into a dev or sandbox org and test before you install anything into a production org. Once you click on the link, you’ll be asked to sign in to your dev or sandbox org, and then the flow(s) will be created in that org.
Note: This third-party Apex code has not gone through a Salesforce security review and should be reviewed by a developer to make sure it meets your organization’s coding standards prior to installing in a production org.
Welcome to another “Automate This!” In this live-streamed video series, we cover all things automation, from use cases and best practices to showcasing solutions built by Awesome Admin Trailblazers like you. With automation, you can remove manual tasks, drive efficiency, and eliminate friction and redundancy. In this episode, let’s see how Bradley Condon built the […]
Welcome to another “Automate This!” In this live-streamed video series, we cover all things automation, from use cases and best practices to showcasing solutions built by Awesome Admin Trailblazers like you. With automation, you can remove manual tasks, drive efficiency, and eliminate friction and redundancy. In this episode, let’s see how Ohad Idan vanquishes shared […]
Welcome to another “Automate This!” In this live-streamed video series, we cover all things automation, from use cases and best practices to showcasing solutions built by Awesome Admin Trailblazers like you. With automation, you can remove manual tasks, drive efficiency, and eliminate friction and redundancy. In this episode, learn how Becka Dente leverages a simple […]