Write a custom function step
Before you start
A Custom function runs a Smart ScriptSmart ScriptBeezr's scripting language (engine name Beezl) used in fields, rules, filters, workflow values and dashboards.Open glossary ↗ inside a workflow. Use it when a job needs a loop, a calculation or a bulk write that the other steps do not offer. This page shows three patterns, each with a check on its own result.
The step is described on Custom function. This page is about what to put in it.
Where does the script get its data?
Section titled “Where does the script get its data?”Three sources are available inside the script.
- Tokens such as
$cm_contracts$.$contract_value$, for the record that started the run. See Tokens and placeholders. - Lists an earlier Load data step made, read with
FunctionManager.getListFromContext("list_name"). - Queries you run yourself with
FunctionManager.loadRecordsByClause.
The script is stored exactly as you type it. To pass a value to later steps, write it to a record with a Record manager step.
How do I create a record for each item of a list?
Section titled “How do I create a record for each item of a list?”This creates a payment reminder for every invoice that a Load data step put in the list contract_invoices.
var invoices = FunctionManager.getListFromContext("contract_invoices");var failed = 0;invoices.forEach(function (invoice) { var values = new java.util.HashMap(); values.put("invoice_number", invoice.getFieldValueMap().get("invoice_number").getCurrentValue()); values.put("note", "Payment reminder"); if (!FunctionManager.createRecords("cm_reminders", values)) { failed = failed + 1; }});failed;getListFromContext always gives a list, empty when the earlier step found nothing, so the loop is safe without a null check. createRecords takes the module’s table name and a map of field names to text values, and answers true or false. The script counts the false answers in failed.
How do I update many records at once?
Section titled “How do I update many records at once?”Change the field on each record in the list, then send them together.
var invoices = FunctionManager.getListFromContext("contract_invoices");var ok = true;if (invoices.size() > 0) { invoices.forEach(function (invoice) { invoice.getFieldValueMap().get("status").setCurrentValue("5"); }); ok = FunctionManager.bulkUpdateRecords("cm_invoices", invoices);}ok;The value "5" is the id of a lookup value, because the status field is a lookup. Get an id from a name with FunctionManager.resolveLookupValue("invoice_status", "Paid").
How do I start another workflow?
Section titled “How do I start another workflow?”runAdhocWorkflow(module, recordKey, workflowId) starts an Adhoc workflow on one record. It takes the module’s table name, the record’s key value and the workflow’s id, and gives back a response you can check.
var result = FunctionManager.runAdhocWorkflow("cm_contracts", "4012", "37");result.getErrorCode() === 1000;The code 1000 means the workflow ran. Any other code comes with a message in result.getErrorMessage().
How do I know it worked?
Section titled “How do I know it worked?”Make the script report on itself, so the run log shows the outcome.
- End the script with a count of what failed, as in the first pattern, or write it to a record.
- Follow the step with a Record manager that stores the outcome, and a Decision that stops the run when it is not what you expect.
- Run the workflow on a test record first, and open the run in the run debugger.