Parsware
Todos los artículos

Parsware Platform

Shared logic: solution scripts

When a plugin step and a Custom API need the same rule, write it once as a solution script and import it into both. We used the Shared Server Logic sample, where an approval limit decides both whether an order saves and what an API tells a partner, then changed the limit in one line and watched both follow. Here is how import and export work, and which scripts can import.

Este artículo solo está disponible en inglés.

The Order rules script in the BS editor, with approvalLimit returning 2000 and needsApproval exported, next to the title "Shared logic: solution scripts"

Sooner or later, two scripts need the same rule. A plugin step refuses an order over a limit, and a Custom API tells a partner system whether an order will need approval. Both have to use the same limit. If you paste the number into each, they agree on the day you write them, and stop agreeing the first time somebody changes one and forgets the other.

A solution script fixes that. It holds the rule once, and the step and the API each import it. We used the Shared Server Logic sample; import it from samples/solutions/business-rules-shared-server-logic to follow along.

The script

Open the solution and choose Scripts. There's one, Order rules:

The Scripts list in the Shared Server Logic solution, with one script: Order rules, module path par_order_rules. The subtitle reads: Shared BS Lang code: write a helper once, and import it from any business rule, command, plugin step or Custom API in this environment

Its code is short:

func approvalLimit(): number {
  return 1000;
}

func needsApproval(amount: number): bool {
  return amount > approvalLimit();
}

export needsApproval;

Two functions, and one line that matters more than it looks: export needsApproval;. A script that imports this one gets only what it exports. So other scripts can ask does this amount need approval?, but they can't read the number itself. If the limit changes, only this line changes.

The module path, par_order_rules, is the name other scripts use to import it.

Two scripts that import it

The plugin step, Require an approval note over the limit, runs when an order is created:

The plugin step's script: import 'par_order_rules'; then if needsApproval(getValue('par_total')) and the approval note is empty, throwValidationError('An order over the approval limit needs an approval note.')

The Custom API, Will this order need approval?, answers POST /api/par/v1/orders/needs-approval:

The Custom API's script: import 'par_order_rules'; then setOutput('needsApproval', needsApproval(getInput('total')));

Both start with the same line, import 'par_order_rules';, and both call needsApproval. Neither one has the number 1000 in it.

Trying it

In the Platform Shell, open Orders — Shared Server Logic and add orders:

  • 500, no note: saved.
  • 1500, no note: refused.

The New Order form with SO-1002 and a total of 1500, an empty approval note, and the message An order over the approval limit needs an approval note.

  • 1500 with a note: saved.

Then we called the API with the same two totals:

{ "total": 500 }   →  { "needsApproval": false }
{ "total": 1500 }  →  { "needsApproval": true }

The step and the API agree, because they're asking the same function.

Change it in one place

Now the part the sample is for. Back in Scripts, we opened Order rules, changed return 1000; to return 2000; and saved:

The Order rules script in the editor with approvalLimit returning 2000. Above the code: Call it from a rule, a command, a plugin step or a Custom API with: import 'par_order_rules';

We didn't touch the step or the API. An order of 1500 with no note now saves:

A new order SO-1003 with a total of 1500 and no approval note, saved

And the API answered { "needsApproval": false } for 1500. Both changed at once, because the rule was only ever written in one place. (We set it back to 1000 afterwards.)

Export keeps things private

What happens if the step tries to read the limit directly? We added approvalLimit() to the step's script, without saving:

The plugin step's script with var limit = approvalLimit(); underlined on line 7, and one problem: Function approvalLimit not found. E030

Function approvalLimit not found. It exists in Order rules, but it isn't exported, so to the step it doesn't exist. Export only what other scripts should call, and keep the rest as the script's own business.

Which scripts can import

Script Can import a solution script
Form rule ✔
Command button ✔
Plugin step ✔
Custom API ✔
Scheduled job ✔
Process step not yet

A form rule importing a script runs it in the browser; a plugin step runs it on the server. The same script can be imported by both: it's the same language on each side, and a shared test suite holds the browser and server interpreters to the same answers. Just keep to functions both can call: what a script can see has the lists. The completion article shows a form rule importing one.

Process steps can't import yet. A process script that needs the same rule has to carry its own copy for now.

While writing this we also fixed two screens that said a script can be imported only from "a rule or a command". Both now name plugin steps and Custom APIs too, as the pictures above show.

Try it

Import the sample, try the three orders, then change the limit and try them again. Then add a second exported function to Order rules, say approvalLimitText() returning `Orders over ${approvalLimit()} need a note`, and use it in the step's message.

Next: calling an outside service from a script, with callService.