Developer Note: Flow Combo Box Now Supports Automatic Output References

Here’s what Flow Combo Box displayed previously:

As of FlowScreenComponentsBasePack version 2.3.7 and higher, Flow Combobox also makes automatic references available:

Use Salesforce Flow to Make No-Code Web Callouts

The new DataMapper package of actions provides a way to easily create web callouts and powerful new data mapping solution that allows data to be extracted easily from JSON text. This post introduces the Make HTTP Action that is included in DataMapper.

Easy HTTP Calls

We’re going to start by retrieving exchange rates via an api call. Here’s the api:

The property editor of this action looks like this:

You can click Test Callout right there in the custom property editor to try things out. Keep in mind that for every site you connect to, your org must have a corresponding Remote Site Setting.

Here’s what happens when we click Test Callout:

To make effective use of that big blob of JSON that’s returned by the call, we’ll need a way to do some data mapping. That will be handled by the Extract JSON Data action and Map JSON Array action.

Special appreciation to Munawirrahman, who published original work on this 6 months ago.

Install

Install as part of DataMapper.

Use DataMapper to Convert Web JSON to Salesforce Flow Objects

The DataMapper package provides two Flow Actions that can be combined in different ways to achieve powerful transformations between Salesforce objects and JSON. We’ll demonstrate this using the JSON created in the example in the Make HTTP Call. In that example, a call is made to a foreign exchange web service and it returns the exchange rates for ALL the traded currencies. But we only need a single exchange rate.

Extract JSON Data

Here’s what the JSON returned by the call looks like in a test callout:

Let’s look at it with a little bit of formatting:

In our example, we want to extract the exchange rate of the US Dollar against the Australian Dollar. We can see that at the moment the above call was made, that rate was 1.2945. Let’s extract that with Extract JSON Data, the first of the two Datamapper actions:

As you can see above, we pass the Body JSON in from the HTTP response and then reference the AUD rate by giving the dot-notation path to it. When you use this action, you provide keys and assign their values to 1 of 20 available outputs. These static outputs are labeled ‘value1’, ‘value2’, etc… and they’re strings. You can use those values downstream in the flow or you can assign them to more memorable variables.

This test output shows the successful extractions:

Map JSON Array: Handling groups of JSON objects

Extract JSON Data is powerful but it has a flaw: you can’t practically use it against arrays. And arrays show up all over the place. Here’s an example from a Slack API that can return 1 or more attachments:

The most practical way to manipulate arrays of JSON data is to map them to a corresponding collection of Salesforce SObjects. That’s the function of the second DataMapper action: Map JSON Array. When you configure this action, you first need to isolate the array JSON that you want to map. Here’s what an isolated array json string looks like:

In our example, we’ll use this json data to create records of type ‘CustomAttachment__c’:

Here’s what the Map JSON Array looks like:

This action will output a collection of the selected Target Object Type, which you can use to create a new set of records or do futher processing:

The keys on the right will be looked for in the individual json array members, and their respective values will be set to the specified output fields.

  • Developer Note: The underlying action uses a generic SObject output. The CPE makes sure that a concrete type (in this case, CustomAttachment__c) is provided.
  • Developer Note: The variable List Builder mechanism used here has been implemented so that it can be reused easily in unrelated CPE’s.

This action doesn’t currently support the ability to edit/update existing records, but that could be added in the future. It also doesn’t convert strings to dates yet. That will get fixed soon.

Here’s a view of the resulting Custom Attachment records created using the record collection variable output by the Map JSON Array:

Install

Version 1.0.0.0 Unmanaged 6/13/21

View Source

source

Webhook2flow – Released

Webhooks2Flow

– Need to integrate an external system with your SalesForce Instance using its out of the box webhooks  without programming? Webhook2Flow may be your answer. You can build webhook service endpoints in your Salesforce instance completely in Flow; 1) declaring the the interface with Flow Resources (“Available for Input” and “Available for Output”), 2) service the requests with Flow Logic, then 3) define the connection securely using metadata.

Demonstration and Introduction Video(Part 1)

Datatable – Latest Release Notes (v3.2.2 & v3.2.3)

Today, I’ve released a new version of the Datatable component. I’ve fixed a few minor issues and added a few new enhancements. The key changes are that pre-selected records are showing again, edited date fields should display the correct day (not the prior day) and there is a new Table Behavior option to hide the Clear Selection button on Datatables with radio button selection.

Updates: 3.2.3

  • When the running User doesn’t have Read access to the Datatable’s SObject, Record Type Id for Picklist Values is ignored and all picklist values will be available when editing a picklist field
  • Fields that are Read Only to the running User can still be edited when the Flow is running in System Mode

Updates: 3.2.2

  • Editable picklist fields now show a pencil icon when editable (Same behavior as all other field edits) – Thanks to Jerry Poon
  • Icon Pickers in the CPE and Configure Column Wizard have been updated to the latest version
  • Added a new attribute to optionaly hide the Clear Selection button that appears on a table with radio button selection

Bug Fixes

  • Fixed alignment of picklist fields when selecting Center or Right alignment
  • Adjust edited Date fields by the running User’s timezone offset to keep the correct day
  • Enforced no edits on fields such as Rollups and Formulas
  • Fixed occasional error message about the not_suppressNameFieldLink attribute
  • Fixed v3.2.1 bug where pre-selected rows did not display as selected

From Ralph Braun: Using the ‘Edit Quip Document’ Action

The Quip team has provided some powerful Flow Actions that allow flow to drive the creation of new Quip documents from Quip templates. Ralph Braun’s new wiki page builds out the Quip section of the UnofficialSF wiki:

Keep in mind that EVERYONE is invited to create new wiki articles and submit edits to existing ones. Just click the Edit Article button. The wiki has tremendous potential to become the ultimate source of Flow knowledge.

Check it out!

7 Things Architects Should Know About Flow

Check out my recent post on the official Salesforce Architect Medium blog channel around Flow! Thank you to the Salesforce Architect Relations team for the help in getting this out the door!

https://medium.com/salesforce-architects/7-things-architects-should-know-about-flow-8173ddeeae28

May 2021 Community Flowcast Video

Like the previous month I highlight a bunch of components, articles, and actions featured here on UnofficialSF – check it out in the link below!

See below the video for links to each of the articles mentioned – enjoy!

Developer Notebook: Robert Fay shows how to make LWC-embedded screen flows resize properly

We previously published an LWC screen component called Screen Flow that allows flows to be embedded in Lightning Web Components.However, it doesn’t resize automatically. Rob Fay extended it to do this elegantly and then posted about it.

Check it out!

Note: Salesforce has an LWC version of the lightning:flow component under construction. Look for it in the next 12 months.

Best Practices for Creating Invocable Actions: Using Inner Classes and Invocable Variables

I’ve long been a fan of using invocable methods with flows. Today I’ll use a real-life scenario to explain the importance of using invocable variables as well. We’ll start by looking at the anti-pattern of a standalone invocable method, then we’ll follow best practices and refactor the solution into an invocable method plus invocable variables.

The use case comes from a pro bono project for Playworks. Playworks is the leading national nonprofit leveraging the power of play to transform children’s social and emotional health. They’re a great organization, and they could definitely use some support.

Playworks tracks each school partnership with an opportunity record. A school might purchase 5 trainings, represented by opportunity product records. For financial purposes, the service completion date is tracked for each training, so each training needs its own opportunity product record. Manual entry can get cumbersome, with some opportunity records having 10 or more opportunity products associated with them.

To address this need, we created the Add Products Wizard. Built using flow, the wizard starts by presenting a user with a list of products to select from.

Note: The handy table above is made possible by a free LWC called the Welkin Data Table for Flows.

The user selects the products they want, then enters the quantity and sales price of each product they selected.

So far, so good, but things get tricky if you build an invocable method without invocable variables. Let’s take a look at what not to do, then we’ll refactor our solution to follow best practices.

First up, the anti-pattern. Here’s what the flow loop element looks like behind the scenes, designed for a standalone invocable method. After the user selects their products, the loop begins. The loop runs once for each product selected. The pattern is as follows:

  1. Get the quantity and sales price for each product from the user.
  2. Gather up all needed inputs for the invocable method into a flow text collection variable.
  3. Pass the flow text collection variable into the invocable method.
  4. The invocable method then creates the desired number of opportunity product records.
  5. Clear the values of the text collection variable so the loop can start over.

Then comes the messy part. The text collection variable holds 4 values.

The four values are added to the text collection variable in the following order:

  • First: Product Id
  • Second: Opportunity Id
  • Third: Sales Price
  • Fourth: Quantity

Imagine having to come in and explain what the opportunityProductInputs variable is holding. There is no way to know, without explicitly inspecting the assignment element that populates the opportunityProductInputs variable. Frustrating, to say the least. The code gets even more wonky. Take a look at the invocable method.

@InvocableMethod(label='Create New Opportunity Products')
public static void createNewOpportunityProducts(List<List<String>> inputs){

List<OpportunityLineItem> oppProds = new List<OpportunityLineItem>();

PriceBook2 stdPriceBook = [SELECT Id
FROM Pricebook2
WHERE isStandard = True
LIMIT 1];

PriceBookEntry pbe = [SELECT Id
FROM PriceBookEntry
WHERE Product2Id =: inputs.get(0).get(0)
AND Pricebook2Id =: stdPriceBook.Id
LIMIT 1];

for(Integer i = 0; i < Integer.valueOf(inputs.get(0).get(3)); i++){
OpportunityLineItem oppProd = new OpportunityLineItem();
oppProd.Product2Id = inputs.get(0).get(0);
oppProd.PricebookEntryId = pbe.Id;
oppProd.OpportunityId = inputs.get(0).get(1);
oppProd.UnitPrice = Integer.valueOf(inputs.get(0).get(2));
oppProd.Quantity = 1;
oppProds.add(oppProd);
}
insert oppProds;
}

Notice that the data type of the input parameter is a nested list of strings. A standalone invocable method requires that the input parameter be a list. A single string becomes a list of strings, and a list of strings becomes a nested list of strings. Not to mention, you have to use nondescript indexes to reference the inputs within the method. The whole thing gets unwieldy fast. This has major downstream implications for code readability.

Now for a best practice. Let’s refactor this code by pivoting away from a standalone invocable method, and adding some invocable variables to hold the inputs. The invocable variables are defined in an inner class called Requests.

public class Requests{

@invocableVariable(label='Product Id, requests[0]' required=true)
public String productId;

@invocableVariable(label='Opportunity Id, requests[1]' required=true)
public String opportunityId;

@invocableVariable(label='Sales Price, requests[2]' required=true)
public Double salesPrice;

@invocableVariable(label='Quantity, requests[3]' required=true)
public Integer quantity;
}

Next, let’s change the input parameter of the invocable method to accept the data type of the inner class.

@InvocableMethod(label='Create New Opportunity Products')
public static void createNewOpportunityProducts(List<Requests> requests)

Here’s what the refactored method looks like, using the new input parameter.

@InvocableMethod(label='Create New Opportunity Products')
public static void createNewOpportunityProducts(List<Requests> requests){

List<OpportunityLineItem> oppProds = new List<OpportunityLineItem>();
PriceBook2 stdPriceBook = [SELECT Id
FROM Pricebook2
WHERE isStandard = True
LIMIT 1];

PriceBookEntry pbe = [SELECT Id
FROM PriceBookEntry
WHERE Product2Id =: requests[0].productId
AND Pricebook2Id =: stdPriceBook.Id
LIMIT 1];

for(Integer i = 0; i < requests[3].quantity ; i++){
OpportunityLineItem oppProd = new OpportunityLineItem();
oppProd.Product2Id = requests[0].productId;
oppProd.PricebookEntryId = pbe.Id;
oppProd.OpportunityId = requests[1].opportunityId;
oppProd.UnitPrice = requests[2].salesPrice;
oppProd.Quantity = 1;
oppProds.add(oppProd);
}
insert oppProds;
}

Notice how much more readable the Apex is. Gone are the nondescript indexes, replaced by logical variable names. The Apex action element is also much more readable inside the flow. It is no longer necessary to gather up the inputs with an assignment element. The invocable variable values are set and the invocable method is called in the same place, creating a much more intuitive flow.

When comparing a standalone invocable method to an invocable method plus invocable variables, the difference is clear. The code becomes much more readable, and the flow is much easier to understand in the latter.

There is one more advantage of using an invocable method plus invocable variables, not shown in this example. While a standalone invocable method can only accept a collection of primitive data types, an invocable variable makes it possible to indirectly pass sObjects into the invocable method. An inner class with variables to hold accounts and opportunities would look something like this.

public class Requests{

@invocableVariable(label='Accounts', requests[0] required=true)
public List<Account> accountsToProcess;

@invocableVariable(label='Opportunities', requests[1] required=true)
public List<Opportunity> opportunitiesToProcess;
}

Hopefully this post has convinced you not to build a standalone invocable method again, opting instead for an invocable method plus invocable variables. Thanks for reading, and feel free to send me any questions or feedback.