I'm trying to build a bulkified version of Flow's Fast Lookup element so that I can safely trigger bulkified flows from process builder.
I've written an InvocableMethod which allows me to pass in a list of Ids and return a list of SObjects with the appropriate fields queried. These work perfectly with the test class I've written with them, but when invoked from a flow they fail:
public class UserFastLookup {
@InvocableMethod(label='Retrieve User' description='Returns the User requested, acts as a bulkified version of Fast Lookup')
public static list<User> getUsers(list<Id> requestIds) {
//query for user Ids requested
map<Id,User> recordMap = new map<Id,User>([SELECT Id, Name FROM User WHERE Id IN :requestIds]);
list<User> userResults = new list<User>();
//return Users in same order as request to Flow
for (Id request : requestIds) {
userResults.add(recordMap.get(request));
}
return userResults;
}
}
I've created a very simple flow, which invokes the Apex InvocableMethod with an Id passed into it, captures the User object output into an SObject variable, and dumps it to the screen (as a simplification to the headless flow using a record update, which exhibits the same errors).
<?xml version="1.0" encoding="UTF-8"?>
<Flow xmlns="http://soap.sforce.com/2006/04/metadata">
<actionCalls>
<name>Lookup_User</name>
<label>Lookup User</label>
<locationX>196</locationX>
<locationY>237</locationY>
<actionName>UserFastLookup</actionName>
<actionType>apex</actionType>
<connector>
<targetReference>Display</targetReference>
</connector>
<inputParameters>
<name>requests</name>
<value>
<elementReference>userId</elementReference>
</value>
</inputParameters>
<outputParameters>
<assignToReference>usr</assignToReference>
<name>output</name>
</outputParameters>
</actionCalls>
<interviewLabel>User Lookup Test {!$Flow.CurrentDateTime}</interviewLabel>
<label>User Lookup Test</label>
<processType>Flow</processType>
<screens>
<name>Display</name>
<label>Display</label>
<locationX>507</locationX>
<locationY>242</locationY>
<allowBack>true</allowBack>
<allowFinish>true</allowFinish>
<allowPause>false</allowPause>
<fields>
<name>Output</name>
<fieldText>{!usr.Name}</fieldText>
<fieldType>DisplayText</fieldType>
</fields>
</screens>
<startElementReference>Lookup_User</startElementReference>
<variables>
<name>userId</name>
<dataType>String</dataType>
<isCollection>false</isCollection>
<isInput>true</isInput>
<isOutput>false</isOutput>
</variables>
<variables>
<name>usr</name>
<dataType>SObject</dataType>
<isCollection>false</isCollection>
<isInput>false</isInput>
<isOutput>false</isOutput>
<objectType>User</objectType>
</variables>
</Flow>
This fails with the following error:
FLOW_ELEMENT_ERROR The flow failed to access the value for usr.Name because it hasn't been set or assigned.|FlowScreen|Display
If I rewrite the code to return a list of strings it works perfectly (and plugs into process builder and works perfectly for bulk operations, as described here).
@InvocableMethod
public static list<String> getUsers(list<Id> requestIds) {}
I've also attempted to define the SObject within an InvocableVariable for the return type, again no luck
@InvocableMethod
public static list<Result> getUsers(list<Id> requestIds) {}
public class Result {
@InvocableVariable(label='User' description='Retrieved User Object')
public User usr;
}
Can anyone see where I'm going wrong with this, or has anyone successfully passed SObject from an Apex Invocable Method to a Flow?