How and when calculations run

Calculations are JavaScript that runs in the background to compute variable values, change task settings or call external systems. You write them on the Calculations tab in the task editor (see the article Task calculations) and in shared scripts in the administration. This article describes the order and context in which calculations run, how shared scripts are attached to them, where their errors are logged and what happens when a calculation fails. The specific interface available in a calculation (vars, proc, task, lib, dt...) is described in other articles in this section.

When a section runs

The Calculations tab contains one or more code sections. Each section has the moments when it runs selected:

MomentWhen exactly
On startThe task is activated – for a user task after the solver is determined, for an email notification before it is sent, for a Smart Event only after it has been executed, for a subprocess before the child case is created.
On endThe task is completed, for all task types including automatic ones.
On recalculationThe solver selects Recalculate in the task menu. The form is saved first.
ManuallyA user opens a pending task of type Event in the Event window, before the variables are displayed.
Before takeoverThe task becomes a task to be taken over, just before it is offered to users.

If a task has several sections with the same moment, they run in the order in which they are arranged on the tab – reorder them with the order icon if they depend on each other. A disabled section (the Active toggle) and a section with no moment selected never run.

Task vs. process
Calculations on the Calculations tab always run in the context of a single task (they have access to task, snaps, storage, excel, jwt, identity, axios, ai, ftp, vault as well as proc, lib, dt, dr, html, zip). There is no separate tab for a “whole-process calculation” – if something needs to be computed independently of a specific task, put it in an automatic task or in a shared script of type Calculations.

Attached scripts

The Scripts field on the Calculations tab offers active shared scripts of type Calculations from Administration → Scripts (see the article Global scripts and React scripts). The code of the selected scripts is inserted before the section code, so their functions are directly available in the section – you do not need to import anything:

// Skript "ExchangeRates" vybraný v poli Skripty definuje:
function getEurRate() {
    return lib.getExchangeRate('EUR');
}

// Kód sekce ho může rovnou zavolat:
const rate = getEurRate();
vars['totalPriceEur'].setValue(vars['totalPrice'].getValue() / rate);

If you select several scripts, they are inserted in the order in which they are selected in the field. If you disable or delete a script in the administration, it also disappears from the calculations that used it, and the next time the template is saved this results in an error if the code references its functions.

Source and ES6 syntax

You write code on the Source tab. After saving, the server translates (transpiles) it into the form shown on the ES6 syntax tab, which is what actually runs – among other things, await is added there after every API method call, because methods such as setValue or getDynTable are asynchronous. That is why you usually do not write await in the source, and notation without function/arrow syntax, used by older templates, is also fine.

How values are saved

Every call to vars['x'].setValue(...), vars['x'].setAttribute(...), task.setAttribute(...) or proc.setAttribute(...) writes a row to the database immediately, not at the end of the calculation. The calculation therefore does not run in a single all-or-nothing transaction: if it fails halfway through, the values set before the error remain saved, but the action that triggered the calculation (e.g. completing the task) is not finished and the user gets an error message.

vars['approved'].setValue(true); // tato hodnota zůstane uložená i při chybě níž
const supplier = vars['supplier'].getValue();
vars['supplierEmail'].setValue(supplier.email); // TypeError, pokud je supplier null – úkol se nesplní
Test on a test case
Because partial writes remain in the database even after an error, debugging a calculation on a live case can leave variables in an intermediate state. Therefore, debug on a test case, not on a real order or request.

Logging and debugging

The debug object writes to a log that the admin can find in Administration → Logs → Calculation Logs (see the article Logs):

MethodPurpose
debug.log(message)Writes a message to the Calculation Log. Converts a non-text value to JSON.
debug.dump()Writes the values of all task variables to the log as JSON – even if the calculation ends with an exception, so you can see the state that was not saved because of the error.
debug.error(message, languages)Ends the calculation with an error with the given message; languages is an object with translations, e.g. {cs: '...', en: '...'}.
debug.sleep(seconds)Pauses the calculation for the given number of seconds – for testing timing.
debug.enable() / debug.disable()Turns on/off writing every line of the calculation to the log.
debug.on() / debug.off()Turns off/on wrapping the calculation in a try-catch; use off() only briefly while debugging, because it lets unhandled exceptions pass through.
debug.log({ step: 'before-approval', total: vars['totalPrice'].getValue() });

if (!vars['supplier'].getValue()) {
    debug.dump();
    throw new Error('Supplier is empty, cannot continue.');
}

An entry in the Calculation Log contains the case, the task and the trace ID, so you can easily track down an error even retrospectively.

Related: Task calculations, Logs, Calculation API reference, Global scripts and React scripts.

Calculations API reference: the lib library

Syca (opens in a new tab)

Powered by HelpDocs (opens in a new tab)