Skip to content

Write your first Smart Scripts

Tutorial25 minPractitioner

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.

A metric block is the best place to start, because it has a Run test button.

  1. Open Dashboards, choose a dashboard and open it in the Page builder.
  2. Drag Metric into a section. In the right panel, type the Label Active contracts.
  3. Click inside Value and type the script below. Press Ctrl + Space after FunctionManager. to see the helpers.
  4. 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;
The Spend under contract metric block selected in the Page builder, with the Value script editor and the Run test button in the right panel.
    Value holds the script. The last expression is what the block shows.
    Run test runs it now and says what it returned and how long it took.
    The Label is plain text, or a label key.

Read it line by line.

  • resolveLookupValue turns the word Active into the lookup’s id. Status is a lookup field, so the WHERE clause compares it with an id, not a word.
  • evaluateCount returns 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, isNaN catches it and the block shows 0 instead 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.

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.

  1. Open Forms, choose the contract form and click Form rules. The Form Settings panel opens.
  2. In Rule Book, click Add Rule.
  3. Set Rule Code to CON-001 and Rule Name to Contract value above zero.
  4. Set Severity to Block (hard stop).
  5. Type the Decision Message: Enter a contract value above zero.
  6. In Script, type the line below and click Save Rule.
  7. Click Save on the form builder.
parseFloat($cm_contracts$.$contract_value$) > 0

Now 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; })().

In a workflow, Load data gets the records a later step will use. Its filter is a Smart Script too.

  1. Open Automation for the Contracts module and open a workflow, or create one with New workflow.
  2. Click + and choose Load data.
  3. Under Load from, choose the module, for example Invoices, and name the list contract_invoices.
  4. Under Which records?, open the Smart Script tab.
  5. 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, not vendor_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.

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. resolveLookupValue finds the id, and resolveLookupIdValue finds the name from an id.
  • Guard the empty case, so a missing record shows 0 and not an error.

Keep Tokens and placeholders open while you write, and read Smart Script functions for the rest of the helpers.

Check yourself

Your Rule Book script is `parseFloat($cm_contracts$.$contract_value$) > 0` and the value field is empty. What happens?
Show the answer

The rule fails, because an empty value gives NaN and NaN > 0 is false. parseFloat of an empty value is NaN, and NaN is not greater than 0. The rule gives false, so Beezr shows your Decision Message.

In a Load data filter you write `cm_invoices.vendor_name = $cm_contracts$.$vendor_name$`. Do you add quotes round the token?
Show the answer

No, a text token arrives already quoted. Beezr quotes text values when it fills the token. Numbers and dates arrive without quotes.

Which function turns the lookup value name "Active" into the id you compare with in a WHERE clause?
Show the answer

resolveLookupValue. resolveLookupValue takes the lookup table and a name and returns the id. resolveLookupIdValue goes the other way, from an id to the name.

What's next

Last checked