As a Salesforce Admin, you are requested to copy all the Files attached to an Opportunity to its parent Account whenever the Opportunity is Closed-Won. This way, the Account record will have each file added to any of the Opportunities of the Account.
A little bit of background:
To tackle this requirement, we should first understand the data model behind Files and how they are attached to records in Salesforce.
The Data model for Content Document is:
The key objects to understand
- ContentDocument: Represents a document that has been uploaded to a library in Salesforce CRM Content or Salesforce Files
- ContentDocumentLink: Represents the link between a Salesforce CRM Content document or Salesforce file and where it’s shared. A file can be shared with other users, groups, records, and Salesforce CRM Content libraries. Fields of this object:
- ContentDocumentId: is the Id of the ContentDocument
- LinkedEntityId: ID of the linked object. Can include Chatter users, groups, records (any that support Chatter feed tracking including custom objects), and Salesforce CRM Content libraries.
- Visibility: picklist with 3 values. ‘V’ for Viewer permission – the user can explicitly view but not edit the shared file. ‘C’ for Collaborator permission – the user can explicitly view and edit the shared file. ‘I’ for Inferred permission. The user’s permission is determined by the related record.
- ShareType: picklist with 3 values. AllUsers – the file is available to all users who have permission to see the file. InternalUsers – the file is available only to internal users who have permission to see the file. SharedUsers – the file is available to all users who can see the feed to which the file is posted.
So, to simplify, anytime you upload a File via the Files related list, you create a ContentDocument and a ContentDocumentLink that links the ContentDocument to the record! Simple.
To tackle this requirement, we’re going to use Lightning Flow (Process + Flow). The process will be simply used to call the Flow when the Opportunity is Closed-Won, and to pass the Id of the Opportunity to the Flow. The process will be created AFTER the flow.
The Flow will be used to:
- Get the Opportunity details (mainly the AccoundIt field)
- Get all ContentDocumentLinks that are associated to the Opportunity and put them all in a single sObject Collection Variable
- Loop through these ContentDocumentLink records
- On each pass, add a new ContentDocumentLink record to a Collection Variable – but specify that the LinkedEntityId is the AccountId
- Finally, create the collection of ContentDocumentLink. This way, the links will be available on the Account
Here’s the final flow:
To begin, let’s create the Autolaunched Flow:
The first thing to do is to create the recordId variable. This variable will be used by the process to pass the Id of the Opportunity. Make sure you make it “Available for Input” as the process will pass the Opportunity Id to this variable.
Now, we’ll use recordId to the the Opportunity record and store it in sov_Opportunity. Field to include is AccountId.
Next, let’s get the ContentDocumentLink records that reference the Opportunity via the LinkedEntityId field. We store all these records in the variable socv_CDL_Opty.
We’ll now loop hrough this list of ContentDocumentLink records, and on each pass, we’ll assign a new record of ContentDocumentLink, then add it to the collection. The variable socv_CDL_Opty_Single is a single ContentDocumentLink record that will be used on each pass. Make sure to define it.
On each pass, 2 assignments will happen. The first is to assign a new ContentDocumentLink record, while specifyign the LinkedEntityId field to be the AccountId field retrieved from the first step.
The second assignment is to assign this single record to a collection of records.
And finally, we should create the ContentDocumentLink collection variable using the Record Create element:
The flow is done, we’ll now create the process that will simply call the Flow when an Opportunity is in the Closed-Won stage:
Here’s the Unmanaged Package that contains both the Flowand the Process. You can use it and modify it as needed, you can also use the same logic to apply for other objects and requirements.
For Production/Dev Edition:
Thanks for providing this guide with the package. Really helpful.
Thumbs up sir
Can this be used on any object?
Hi, yes, you can change it to any other 2 related objects. I picked Account and Opportunity just to show the example. Once you get the unmanaged package, modify the flow to follow the 2 other objects.
Hope this helps.
thank you for the step by step
Thank you for sharing this! Very useful, especially with the screenshots of every Flow screen.
I successfully shared Quote PDF Files from Quote object to Opportunity object.
can we check before linking the file to the account if the same file is already linked with the account ?
This flow is not working when i installed it and created Account and linked Opportunity to it in which the Files are present under Files related list.
Is it a one time activity? where i have to manually enter the Inputs in the flow? When i entered the Opportunity Id under Input variables, and run again it moved all files from Opportunity to Account , not copied. It this the usual behaviour?
Thanks for detailed process. It was really helpful for me.
I used get record element in a flow to get ContentDocumentLink records but in debug log it shows “|FLOW_BULK_ELEMENT_NOT_SUPPORTED|FlowRecordLookup|Get_Related_Object_All_Attachments|ContentDocumentLink” and due to this my flow do not run for bulk records.
Is there any solution for it?
Is it possible to only have this done for the last attached file? Instead of looping it for every file on the opportunity, can it be set to only do the latest attached file?