Allows you to update your SOQL statements in the DataSources before the data is retrieved by PDF Butler.
This is achieved by creating an APEX class that implements interface “cadmus_core.AbstractDataSourceActionable”
Config: #
- The DocConfig (or the Pack if you are running a Pack) has an Actionable.

- Create the Actionable with following settings:
- Record Type: has to be “Run Class”, only APEX classes are supported for this Actionable type
- Class: the custom APEX class you have created. More information will follow
- When: only option “DATA_SOURCE” is possible for this Record Type (If this option is not visible, just add it via the (Object Manager => Object Actionable => Field When)
- Active: make sure your Actionable is Activated!

APEX class: #
The Actionable will have to be an APEX class that implements the interface “cadmus_core.AbstractDataSourceActionable”.
Here an example:
global class Actionable_DataSourceUpdater implements cadmus_core.AbstractDataSourceActionable {
global void execute(cadmus_core__Actionable__c actionable, Id docConfig, Id objectId, Map<String, Object> inputMap,
cadmus_core.ConvertController.ConvertDataModel cdm, cadmus_core.UtilClasses.DataSourceActionableData dataSourceData) {
//Get sort Order from parameter:
String order = (String)inputMap.get('sortOrder');
if(String.isEmpty(order)) {
Opportunity opp = [SELECT Product_Ordering__c FROM Opportunity WHERE Id = :objectId];
order = opp.Product_Ordering__c;
}
//loop the data sources and replace the ordering placeholders identified via '::ORDERING'
for(cadmus_core__Data_Source__c ds : dataSourceData.dataSourceList) {
String soql = ds.cadmus_core__SOQL__c;
soql = soql.replace('::ORDERING', order);
ds.cadmus_core__SOQL__c = soql;
}
}
}
The above example will:
- Get the “order” from a parameter that was set via eg a Flow or APEX.
- If the parameter was not set, it will get the default order from a record field
- Loop over all DataSources from variable dataSourceData and replace the placeholder “::ORDERING” with the selected order. Variable “dataSourceData” has following methods:
- “dataSourceData.dataSourceList” will have the list of DSs => Map<Id, cadmus_core__Data_Source__c>
- “dataSourceData.dataSourceMap” Map of DSs with there SFDC Id => List<cadmus_core__Data_Source__c>
The above is just an example that you can change according to your use-case and requirements.
The DataSource: #
You can replace and rewrite your entire SOQL in the DataSource as you whish but make sure it is still a correct SOQL, that is your responsibility.
Here an example of the DataSource:
- It is not SOQL Builder managed as these placeholders cannot be introduced by the SOQL Builder
- The placeholder is added to the SOQL. The naming convention used here is that the placeholder starts with 2 “:” and then the name in uppercase. Feel free to select your own convention or re-use what is proposed here

Introducing a parameter via Flow: #
In this example, we let the user select an order and pass this on via the parameters. In our APEX class, all parameters added via the Flow will be available in the “inputMap” variable (see example above).

- Select Order: for the demo, we just added a Visual Picker

- Create variables
- Create variable
- Name: parameters
- Data Type: Apex-Defined
- Apex Class: cadmus_core__CadmusParameters

- Create variable:
- Name: orderKeyVal
- Data Type: Apex-Defined
- Apex Class: cadmus_core__CadmusKeyValue

- Create further variables of type “cadmus_core__CadmusKeyValue” for each placeholder you need replaced or that fit your requirement
- Create variable
- Assign the variables
- Choose a unique name for the key (this is the name) of the parameter. With this key, the parameter can be easily retrieved from the inputMap in your APEX class.
- Set the value
- Add the parameter to the list of parameters

- Pass on the parameters to PDF Butler
- Create a PDF Butler Flow Action (minimal setup is that it requires DocConfig Id and Record Id). I used Flow Action “Call PDF Butler And Get Return Variables”
- Assign the parameters variable

- Document is created:Â This shows a small text and I used the ContentDocument Id to create a link to open the document








