Skip to content

Write a custom function step

How-to12 minExpert

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.

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.
A Custom function step selected, with the Smart Script box open on the right.
    Write the script in the Smart Script box.
    Insert data adds a field of this workflow. Functions lists the helpers.

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.

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").

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().

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.

Check yourself

A script calls FunctionManager.createRecords for each invoice. What does each call give back?
Show the answer

true when the record was saved, false otherwise. createRecords answers true or false. Count the false answers and write them somewhere you can see.

You loaded invoices into a list called contract_invoices. Which call gives the script that list?
Show the answer

FunctionManager.getListFromContext("contract_invoices"). getListFromContext returns the records of a list an earlier step loaded.

What's next

Last checked