Extending Calculated Attributes with JavaScript (v.26.2)

Scripting was initially introduced for user business rules in ERP.net and is now supported in calculated attributes.

Calculated attributes can now use JavaScript to compute their values dynamically, going beyond what integrated expressions can reasonably handle.

When to use JavaScript calculated attributes

They are a good fit when:

  • The logic is too complex or verbose for integrated expressions

  • Iteration or looping over related records is required

  • Multiple related records need to be queried and processed

  • Custom, user-defined ordering or grouping logic is needed

The script is evaluated on demand and must return a value. That returned value becomes the calculated attribute's value.

How it works

  1. Create a new calculated attribute.

  2. Set ScriptLanguage to JavaScript

  3. Write your logic in ScriptText

That's it.

The script runs in a sandboxed environment with access to:

  • subject - the entity instance being evaluated

  • The full domain model via the Domain object

If the script returns null or nothing, the calculated attribute value is null.

Why is this useful?

Before scripting, calculated attributes worked best for simple expressions. As soon as you needed iteration, de-duplication, or custom ordering, things became awkward or impossible.

A common example is showing which invoices have covered a sales order.

With integrated expressions, there was no clean way to produce a DISTINCT list of invoice numbers. The usual outcome was workarounds, helper attributes, or giving up.

Now, this logic fits naturally inside a single calculated attribute.

Example: Unique invoice numbers per sales order

Suppose you want to display a readable list of unique invoice numbers related to a sales order:

0001, 0003, 0005…

With JavaScript calculated attributes, this is just a small script that queries the related invoice lines, removes duplicates, and returns the final value.

const lines = Domain.Crm.Invoicing.InvoiceLinesRepository.query({
    SalesOrder: subject
});

const seen = new Set();
const result = [];

lines.forEach(l => {
    const no = l?.Invoice?.DocumentNo;
    if (!no || seen.has(no))
        return;        
    seen.add(no);
    result.push(no);
});

return result.join(', ');

No extra attributes. No workarounds. Just a value that’s always up to date.

Calculated attribute scripting also enables scenarios that were previously out of reach, such as advanced inventory summaries, ATP calculations across stores or lots, and time-based aggregations.

Total ATP across all stores (as-of shipment required date)

ATP by lots (latest per lot as of today)

Performance note

Calculated attributes appear in lists, forms, and reports. JavaScript makes it easy to do expensive work, so restraint is required:

  • Keep queries narrow

  • Limit fetched records when possible

  • Avoid unnecessary loops

Used responsibly, scripted calculated attributes remain fast and readable.

--

Get started

To learn more, see:

Have more questions? Submit a request

0 Comments

Please sign in to leave a comment.
Powered by Zendesk