Last Updated on May 8, 2022 by Rakesh Gupta
Big Idea or Enduring Question:
How can you automatically delete open tasks related to opportunity and quote(s) when an opportunity is marked as closed lost?
Objectives:
After reading this blog post, the reader will be able to:
- Understand @InvocableMethod and InvocableVariable Annotation
- Get sObject Type in Apex code
- Pass the list of recordIds to the invocable apex
- Call invocable Apex class that takes a list of ids
- Hard delete records using apex
- Call invocable method from the flow
Business Use case
Arda Turan is working as a System Administrator at Gurukul on Cloud (GoC). He has received a requirement from the management that whenever an opportunity is updated with stage closed lost, then do the following:
- Delete open tasks on the current opportunity
- Delete open tasks from related quotes
Automation Champion Approach (I-do):
- The record-triggered flow doesn’t support IN clause in get element
- The record-triggered flow doesn’t allow us to hard delete record(s)
- and much more
To call an Apex method, add the Call Apex action to your process and select an Apex class with a @invocable method Annotation. It means they allow us to extend the Salesforce Flow by writing Apex code that meets certain criteria and then invoking the Apex from our Flows. If the class contains one or more invocable variables, manually enter values or reference field values from a related record. @InvocableMethod Annotation supports bulk operations.
Before discussing the solution, let me show you a diagram of a Process Flow at a high level. Please spend a few minutes going through the following Flow diagram and understand it.

Guided Practice (We-do):
There are 2 steps to solve Arda’s business requirement using Record-triggered Flow. We must:- Create Apex class & Test class
- Salesforce Flow Steps:
- Define flow properties for record-triggered flow
- Add a text collection variable to store the record Ids
- Add a decision element to validate opportunity stage equals closed lost
- Add an assignment element to add opportunityId to the collection variable (Created in step 1.2)
- Add a get records element to find the related quotes
- Add a decision element to check if quotes was found or not
- Add a loop element to retrieve records from the record collection variable (from step 1.5)
- Add an assignment element to add quoteId to the collection variable (Created in step 1.2)
- Add action – call an Apex class to delete the open tasks for given Ids
Step 1: Create an Apex class and Test class
- Click Setup.
- In the Quick Find box, type Apex Classes.
- Clicks on the New button.
- Copy code from GitHub and paste it into your Apex Class.
- Click Save.

- The getSObjectType method is used to obtain an sObject token from an ID.
- The emptyRecycleBin is used to delete records from the recycle bin immediately.
Step 2.1: Define Flow Properties
- Click Setup.
- In the Quick Find box, type Flows.
- Select Flows then click on the New Flow.
- Select the Record-Triggered Flow option, click on Create
- Object: Opportunity
- Trigger Opportunity Flow When: A record is created or updated
- Set Entry Criteria
- Condition Requirements: None
- Optimize the Flow For Action and Related Records
- Click Done.
Step 2.2: Add a Collection Variable Text to Store Record Ids
- Under Toolbox, select Manager, then click New Resource to store the opportunity or quote(s) ids.
- Input the following information:
- ResourceType: Variable
- API Name: varT_recordIds
- Data Type: Text
- Default Value: {!$GlobalConstant.EmptyString}
- Check Allow multiple values (collection)
- Check Available for Input
- Check Available for Output
- Click Done.

Step 2.3: Using Decision Element to Check if Opportunity is Closed Lost or Not
- On Flow Designer, click on the + icon and select the Decision element.
- Enter a name in the Label field; the API Name will auto-populate.
- Under Outcome Details, enter theLabel theAPI Name will auto-populate.
- Condition Requirements to Execute Outcome: All Conditions Are Met (AND)
- Row 1:
- Resource: {!$Record.StageName}
- Operator: Equals
- Value: Closed Lost
- Row 1:

The reason why we would select the Yes checkbox for the question — Only if the record that triggered the flow to run is updated to meet the condition requirements — is to allow the Flow to execute the actions only if the record meets the criteria now, but the values that the record had immediately before it was saved didn’t meet the criteria. This means that these actions won’t be executed when irrelevant changes are made.
Step 2.4: Adding an Assignment Element to Assign the Opportunity Id to the Collection Variable
- On Flow Designer, below the Closed Lost node, click on the +icon and select the Assignment element.
- Enter a name in the Label the API Name will auto-populate.
- Set Variable Values
- Row 1:
- Field: {!varT_Ids}
- Operator: Add
- Value: {!$Record.Id}
- Row 1:
- Click Done.
Step 2.5: Add a Get Record Element to Find the Related Quotes
The next step is to use the Get Records element to find the related quotes.- On Flow Designer, click on the +icon and select the Get Element element.
- Enter a name in the Label field; the API Name will auto-populate.
- Select the Quote object from the dropdown list.
- Select All Conditions Are Met (AND).
- Set Filter Conditions
- Row 1:
- Field: OpportunityId
- Operator: Equals
- Value: {!$Record.Id}
- Row 1:
- How Many Records to Store:
- select All records
- How to Store Record Data:
- Choose the option to Automatically store all fields
- Click Done.

Step 2.6: Using Decision Element to Check If Quotes Was Found or Not
Now, will use the Decision element to check if the previous Decision element returns quote records or not.
- On Flow Designer, click on the +icon and select the Decision element.
- Enter a name in the Label field; the API Name will auto-populate.
- Under Outcome Details, enter the Label the API Name will auto-populate.
- Condition Requirements to Execute Outcome: All Conditions Are Met (AND)
- Row 1:
- Resource: {!Get_Quotes}
- Operator: Is Null
- Value: {!$GlobalConstant.False}
- Row 1:
- When to Execute Outcome: If the condition requirements are met.
- Click Done.

Step 2.7: Add a Loop Element to Retrieve Records from Record Collection Variable
- On Flow Designer, below the Yes node, click on the +icon and select the Loop element.
- Enter a name in the Label field; the API Name will auto-populate.
- For Collection Variable select {!Get_Quotes}.
- For Specify Direction for Iterating Over Collection select the option First item to last item.
- Click Done.
Step 2.8: Adding an Assignment Element to Assign the Quote Id to the Collection Variable
- On Flow Designer, click on the +icon and select the Assignment element.
- Enter a name in the Label the API Name will auto-populate.
- Set Variable Values
- Row 1:
- Field: {!varT_Ids}
- Operator: Add
- Value: {!Loop_through.Id}
- Row 1:
- Click Done.

Step 2.9: Add Action – Call an Apex Class
- On Flow Designer, click on the +icon and select the Action element.
- Search and select the DeleteOpenTasks apex class from the dropdown menu
- Enter a name in the Label field; the API Name will auto-populate.
- Set Input Values:
- Field: Record Ids
- Value: {!varT_Ids}
- Click Done.
In the end, Arda’s Flow will look like the following screenshot:
Once everything looks good, perform the steps below:
- Click Save.
- EnterFlow LabeltheAPI Name will auto-populate.
- Click Show Advanced.
- API Version for Running the Flow: 55
- Interview Label: Query Records by List of Ids in Flow {!$Flow.CurrentDateTime}
- Click Save.
Almost there! Once everything looks good, click the Activate button.
Proof of Concept
Now onwards, if a business user updates the Opportunity Stage to Closed Lost, Record-Trigger will automatically delete all open tasks from Opportunity and related quotes.
- Currently, there are two Quotes attached to the Opportunity West Mountain Sign. Each of them has one open task, as shown in the following screenshot:
- Now, we update the Opportunity Stage to Closed Lost.
- Navigate back to the Opportunity and Quote activity-related list available on the detailed page.
Formative Assessment:
I want to hear from you!
What is one thing you learned from this post? How do you envision applying this new knowledge in the real world? Feel free to share in the comments below.
Hi Rakesh,
I have a requirement detailed in below link, I would like to achieve this by Salesforce flow but am not getting any idea.
Please could you explain me in steps how can I deal with it.
Objects :
Opportunity
CW Products
CW Product Groups
Opportunity Product Association
Opp Product Group Assoc
Relationship
Opp Product Group Assoc (MDR to CW Product Groups)
Opp Product Group Assoc (MDR to Opportunity)
Opportunity Product Association (MDR to CW Products) junction obj
Opportunity Product Association (MDR to Opportunity) junction obj
When I add/create New Opp Product Group Assoc record – flow need to trigger and get all the products from the selected CW Product Group and create Opportunity Product Association record for each product from the group and associate with Opportunity.
https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000HjZ63SAF
Many Thanks
Prema
Thanks for the post, is this can be handled completely in flow without the apex action?
No
Thanx for the post
Very helpful post. Thanks Rakesh.
So kind of you 🙂