Write your first Smart Scripts
Before you start
You will write three scripts, each in a different place, on a contracts app: a dashboard count, a check before a contract is saved, and a filter that loads a contract’s invoices. By the end you have used tokens, FunctionManager, the editor’s suggestions and Run test, and you know why each rule exists.
The names below (cm_contracts, contract_status, contract_value) are examples. Yours will differ. Open Modules and the module’s Fields page to read the real ones: the table name starts with cm_, and each field has a system name.
Script 1: count the active contracts
Section titled “Script 1: count the active contracts”A metric block is the best place to start, because it has a Run test button.
- Open Dashboards, choose a dashboard and open it in the Page builder.
- Drag Metric into a section. In the right panel, type the Label
Active contracts. - Click inside Value and type the script below. Press Ctrl + Space after
FunctionManager.to see the helpers. - Click Run test.
var activeId = FunctionManager.resolveLookupValue("contract_status", "Active");var count = parseInt(FunctionManager.evaluateCount("cm_contracts", "WHERE cm_contracts.status = " + activeId), 10);isNaN(count) ? 0 : count;Read it line by line.
resolveLookupValueturns the wordActiveinto the lookup’s id. Status is a lookup field, so theWHEREclause compares it with an id, not a word.evaluateCountreturns the number of matches as text.parseInt(..., 10)makes it a number.- The last line is the result. There is no
return. If anything went wrong,isNaNcatches it and the block shows0instead of an error.
The test result reads “Returned 12 in 140 ms”. If it says the script “didn’t run and would show as text”, a module or lookup name is misspelled. The metric blocks page lists every message.
Script 2: block a contract with no value
Section titled “Script 2: block a contract with no value”A Rule Book rule runs before a record is saved and can stop it. Its script must be one expression that gives true to pass.
- Open Forms, choose the contract form and click Form rules. The Form Settings panel opens.
- In Rule Book, click Add Rule.
- Set Rule Code to
CON-001and Rule Name toContract value above zero. - Set Severity to Block (hard stop).
- Type the Decision Message:
Enter a contract value above zero. - In Script, type the line below and click Save Rule.
- Click Save on the form builder.
parseFloat($cm_contracts$.$contract_value$) > 0Now the token. $cm_contracts$.$contract_value$ is replaced with the field’s value before the script runs. A number arrives as it is, so you can hand it straight to parseFloat. If the field is empty, the result is NaN, NaN > 0 is false, and the rule blocks the save. That is the behaviour you want here.
Beezr wraps your script as one expression, so write a single expression, not a list of statements. For more than one line, wrap the work in a function and call it: (function () { ... return x > 0; })().
Script 3: load a contract’s invoices
Section titled “Script 3: load a contract’s invoices”In a workflow, Load data gets the records a later step will use. Its filter is a Smart Script too.
- Open Automation for the Contracts module and open a workflow, or create one with New workflow.
- Click + and choose Load data.
- Under Load from, choose the module, for example Invoices, and name the list
contract_invoices. - Under Which records?, open the Smart Script tab.
- Type the filter below and click Save.
WHERE cm_invoices.vendor_name = $cm_contracts$.$vendor_name$Three habits show up here.
- The clause starts with
WHERE. Each column carries its module’s table name:cm_invoices.vendor_name, notvendor_name. - The token stands for the record that started the workflow. Beezr replaces it with the contract’s vendor name, already in quotes, because it is text. Numbers and dates arrive without quotes, so quote a date yourself.
- Always give the step a filter. To load every record, write
WHERE 1 = 1.
Steps after this one read the first record as contract_invoices, and a Loop goes through all of them. When nothing matches, the list is empty, and a Decision with has no records can branch on that.
What should I carry away?
Section titled “What should I carry away?”You wrote scripts in three places, and the same rules held in all of them.
- Tokens are replaced first, then the script runs.
- Values you read from records are text until you parse them.
- Lookups are compared by id.
resolveLookupValuefinds the id, andresolveLookupIdValuefinds the name from an id. - Guard the empty case, so a missing record shows
0and not an error.
Keep Tokens and placeholders open while you write, and read Smart Script functions for the rest of the helpers.