- 1. Four concepts that get you started
- 2. Your first process in 10 minutes (without a single line of code)
- 3. What a calculation is and when it runs
- 4. Your first calculation (three lines)
- 5. Five patterns that cover 90 % of your start
- 6. Three rules you must not break
- 7. Cheat sheet
- 8. Form validation, dynamic condition, calculation, script
- 9. How to debug when it does not work
- 10. Most common beginner mistakes
- 11. What next
🚀 Quick Start
- 1. Four concepts that get you started
- 2. Your first process in 10 minutes (without a single line of code)
- 3. What a calculation is and when it runs
- 4. Your first calculation (three lines)
- 5. Five patterns that cover 90 % of your start
- 6. Three rules you must not break
- 7. Cheat sheet
- 8. Form validation, dynamic condition, calculation, script
- 9. How to debug when it does not work
- 10. Most common beginner mistakes
- 11. What next
This is not a reference guide. It is the shortest path to having something that actually runs within an hour. Once it runs, then it makes sense to read the rest of the documentation.
1. Four concepts that get you started
Concept | What it is |
Template | The blueprint of a process. This is where you configure everything: steps, forms, rules, code. |
Case | One run of a template. One specific request, invoice or contract. |
Task | One step of a case. It has a solver and a form. |
Variable | A field that stores a value. You define it on the template, its value lives in the case. |
One sentence worth remembering: the template holds the rules, the case holds the data.
The technical name of a variable is sacred
Every variable has a label (what the user sees, in any language) and a technical name (what you use in code). In code you work exclusively with the technical name, and it is case-sensitive.
vars['amount'] // correct - technical name
vars['Amount '] // wrong - label or a typo, will not work
Write technical names in English, without diacritics, in camelCase. Keep a list of the variables for each template. In three months it will save you an hour.
2. Your first process in 10 minutes (without a single line of code)
Goal: a simple purchase request. Someone submits it, someone approves it.
Step 1 - Create a template. Templates > new template. Name: Purchase request.
Step 2 - Create three variables. As of version 5.19 you have two options and both lead to the same result:
- Manually - variable by variable, full control over the type and the technical name.
- AI builder mode - you describe what the process needs and the builder proposes and creates the variables for you.
For your first template, do it manually at least once. The AI builder is faster, but until you know what a variable type and a technical name look like, you cannot tell whether it gave you what you asked for. Once you do know, switch to the builder. It saves a lot of clicking.
No matter how you create them, check the technical names afterwards. Those are what you will use in code.
Label | Technical name | Type |
Amount excl. VAT |
| Number |
Purchase reason |
| Text |
Approver note |
| Text |
Step 3 - Draw the process graph. Two tasks and a link between them:
[ Submit request ] ------> [ Approval ]
Submit request- solver: the case ownerApproval- solver: a specific user or a role (for testing, use yourself)
Step 4 - Assign the variables to the tasks and set the permissions. This is the most common place where beginners get stuck: a variable will not appear on the form until you assign it to the task.
Task | amount | reason | approvalNote |
Submit request | W + M | W + M | - |
Approval | R | R | W |
- R (Read) - visible, not editable
- W (Write) - editable
- M (Mandatory) - the task cannot be completed without it
Step 5 - Start a case and click it through. Create a case, fill it in, complete the task, complete the second task.
3. What a calculation is and when it runs
A calculation is a piece of JavaScript stored in the template that TAS runs on its own at a moment you choose. It runs on the server, it has no UI and the user sees nothing of it.
When it runs
Trigger | When it fires | Typical use |
Case start | when the case is created | pre-filling values, assigning a number from a sequence |
Task start | right before the user receives the task | preparing and fetching data for the form |
Task end | after the user clicks Complete | recalculations, status changes, calls to other systems |
Scheduled task / cron | on a schedule | bulk operations, integrations, notifications |
What a calculation can and cannot do
Can: read and write variables, read and populate dynamic tables, call external REST APIs, generate documents, write to the log.
Cannot: change the form at runtime, which means hiding fields, marking something as required or recalculating a value while the user types. That is what form validation and dynamic conditions are for, both running in the browser.
Where you write a calculation
A calculation is not a separate object. It lives inside the template, on the task and trigger you pick. The trigger is therefore not something you configure in the code, you choose it when you create the calculation.
4. Your first calculation (three lines)
Add a variable amountWithVat (Number) to the template and put this on task end of Submit request:
const amount = vars['amount'].getValue();
vars['amountWithVat'].setValue(amount * 1.21);
proc.warn('VAT recalculated', { caseId: lib.iprocId(), amount });
Line by line:
vars['amount'].getValue()- read the value of a variable from the current case.vars['amountWithVat'].setValue(...)- write the result back into the case.proc.warn(...)- log what happened. Do this from day one, otherwise you will be guessing when something breaks. Whywarnand notinfois explained in Logging.
Start a new case, fill in the amount, complete the task. In the second task, or in the case detail, you will see amountWithVat filled in. That is it, you can write calculations.
5. Five patterns that cover 90 % of your start
5.1 Reading and writing a variable
const amount = vars['amount'].getValue();
vars['result'].setValue(amount * 2);
5.2 Input validation belongs on the form, not in a calculation
When a user is about to fill something in incorrectly, do not let them find out only after clicking Complete. Since version 5.17 validation is configured directly on the form in the builder, so the user sees the error immediately, next to the field it concerns.
Only put in a calculation what cannot be checked on the form, typically a check against an external system or against data the user cannot see.
5.3 Logging, and why proc.warn is your friend
proc.warn('VAT recalculated', { caseId: lib.iprocId(), amount });
proc.warn('Supplier not found', { supplierId });
proc.error('External call failed', { err: err.message });Three levels are available, but in practice you will mostly use one:
Level | When to use it |
| Things you care about. They stand out in the log immediately and do not get buried among other records. This is your default choice during development and debugging. |
| Something actually went wrong: a call to an external system failed, mandatory data is missing. |
| Detailed operational records. Easily lost in the volume of entries, so not much use for debugging. |
In practice: when you want to see what a calculation is doing, write it to proc.warn. Write messages in English. The second parameter is an object with context, whatever helps you trace the specific case. console.log does not exist in the TAS backend, see Three rules you must not break.
5.4 Working with dates
const today = moment();
const due = moment(vars['dueDate'].getValue());
const daysLeft = due.diff(today, 'days');
vars['daysLeft'].setValue(daysLeft);
proc.warn('Days left calculated', { caseId: lib.iprocId(), daysLeft });
moment is available in the sandbox, no import is needed.
5.5 Looking up a row in a dynamic table
A dynamic table is a global lookup table at environment level: price lists, suppliers, mappings. Its columns are named COL_1, COL_2 and so on.
const row = dt
.from('PRICE_TABLE', ['COL_1', 'COL_2']) // always list the columns you need
.whereCol('COL_1', vars['contractType'].getValue())
.getFirst(); // returns object or null
if (!row) {
proc.warn('No matching row in PRICE_TABLE', { caseId: lib.iprocId() });
return;
}
vars['price'].setValue(row['COL_2']);
proc.warn('Price resolved', { price: row['COL_2'] });
from(), the list of columns. Without it TAS logs a warning and pulls unnecessary data.6. Three rules you must not break
6.1 No async, await, Promise, .then(), .catch()
TAS transpiles your code itself and handles asynchronous calls for you. Everything in TAS calculations is written synchronously.
// FORBIDDEN
const data = await client.get('/orders/1');
dt.from('TBL').whereCol('COL_1', x).getFirst().then(row => { ... });
// CORRECT
const data = client.get('/orders/1');
const row = dt.from('TBL', ['COL_1']).whereCol('COL_1', x).getFirst();
Yes, HTTP calls are written synchronously too. No, you do not need await. If you find an example with await somewhere online, rewrite it.
6.2 No console.log
The backend only has TAS logging: proc.warn, proc.error, proc.info. See Logging.
console.log belongs to the frontend (dynamic conditions, Case Overview), where proc.* does not exist.
6.3 The case ID is always lib.iprocId()
const caseId = lib.iprocId(); // correct
// not proc.IPROC_ID, not proc.IPROC_INST_ID
7. Cheat sheet
Variables
I want to | Code |
Read a value |
|
Write a value |
|
Get the text form (title for a DT or list variable) |
|
Get a JSON variable as an object |
|
Write a JSON variable |
|
Access variables on a multi-instance task |
|
getValue() returns the index (a number) and getTitle() returns the text. In calculations compare by index, it does not depend on translations.Case and task
I want to | Code |
Get the case ID |
|
Read or write the case status |
|
Get the case owner's name |
|
Get a link to the case |
|
Get the task solver's name |
|
Get a link to the task |
|
Get the next number from a sequence |
|
Read variables of another case |
|
Other
I want to | Code |
Get a row from a dynamic table |
|
Get multiple rows |
|
Log something I want to see |
|
Work with dates |
|
Make an HTTP call |
|
Get a secret or password (Vault, 5.17+) |
|
Validate user input | Does not belong in a calculation. Use the builder, see Input validation. |
8. Form validation, dynamic condition, calculation, script
Four different things. Mixing them up means solving a problem on the wrong layer.
Tool | Where it runs | What it is for | Where you configure it |
Form validation | browser (frontend) | checking what the user is filling in | builder, on the variable or form (no code) |
Dynamic condition | browser (frontend) | form behaviour at runtime: hiding fields, requiredness, reacting to other values | in the template, on the task |
Calculation | server (backend) | business logic, data, integrations | in the template, on a specific task or trigger |
Script | depends on type | reusable code shared across templates | Administration > Scripts |
Quick test:
- "The user must not enter a negative number." - form validation in the builder
- "I want this field hidden when the user ticks X." - dynamic condition
- "I want to calculate and store this when the task is completed." - calculation
- "I will need this function in three other templates as well." - script
9. How to debug when it does not work
- Log from the very beginning. Put
proc.warn('Step 1 done', { amount })at key points. Without logs you are guessing, andwarnshows up in the log immediately. - Check the three rules. Roughly half of all mysteriously broken calculations contain an
awaitor aconsole.log. See Three rules you must not break. - Check the technical name of the variable. A typo or one extra capital letter gives you
undefinedwith no error. - Verify that the variable is assigned to the task and has the right permissions. A missing field on the form is usually not a code problem.
- Use
debug.dump()to write all variables to the log. Useful when you do not know what the calculation is actually working with. - Simplify. Comment out half of the calculation and try again.
10. Most common beginner mistakes
Mistake | Symptom | Fix |
| nothing happens, no error | rewrite synchronously |
| nothing in the log | use |
Logging into | the record gets lost among the rest | put what you want to see into |
Label instead of the technical name |
| check the variable name |
Variable not assigned to the task | the field is not on the form | assign it and set permissions |
Input validation handled in a calculation | the user learns about the error only after clicking Complete | configure validation on the form in the builder |
Form logic in a calculation | the field hides only after the task is completed | use dynamic conditions |
Hardcoded token or password in the code | security issue | use the Vault: |
An invented function name that sounds right | the function does not exist | check the documentation or ask |
11. What next
Once your first process is done, take it in roughly this order:
- Form validation in the builder - the fastest way to raise data quality without a line of code
- Case statuses (
proc.setCaseStatus) - so overviews show where each case stands - Dynamic conditions - hiding fields and making them required based on other values
- Dynamic tables - lookup tables, price lists, mappings
- Dynamic Rows (DR) - a table of items the user adds rows to
- AI builder for a whole template - once you know what a good template looks like, let it prepare one for you
- Print templates and Case Overview - PDF outputs and the case detail page
- Integrations via
axiosand the Vault - calls to external systems
Updated
by Frantisek Brych