Approval Workflow Rules
Approval Workflow Rules
This page allows administrators to create and configure approval workflows and their individual approval levels. A workflow defines who must approve a particular transaction type, in what order, and under what conditions.
Page Layout
The page is divided into two main sections:
- Workflow Management (top) — create, edit, activate, or deactivate workflows.
- Level Management (bottom) — once a workflow is selected, define one or more approval levels within it.
---
Section 1 — Workflow Management
Existing Workflows Table
A table lists all defined workflows with the following columns:
| Column | Description |
| Name | Workflow name (e.g., "Purchase Order Approval") |
| Transaction Type | The type of transaction this workflow handles (e.g., Purchase Order, Journal Entry) |
| Description | Optional description |
| Active | Whether the workflow is currently enabled (Yes/No) |
| Edit | Button to load the workflow into the edit form |
| Delete | Button to remove the workflow (only if no active drafts reference it) |
Workflow Fields (Add/Edit Form)
| Field | Required | Description |
| Transaction Type | Yes | Dropdown of all 23 supported types. Only types that do not already have an active workflow are shown (each type can have at most one active workflow). |
| Name | Yes | A descriptive name for the workflow (max 100 characters). |
| Description | No | Free-text description (max 255 characters). |
| Active | No | Checkbox to enable/disable the workflow. Default: checked. |
| Require Comments on Reject | No | When enabled, approvers must enter comments when rejecting a draft. Default: checked. |
| Require Comments on Approve | No | When enabled, approvers must enter comments when approving. Default: unchecked. |
| Allow Edit on Approve | No | Allows the approver to modify the transaction data before approving. Default: unchecked. |
| Allow Self-Approve | No | Permits the submitter of a draft to also approve it (if they hold the required role). Default: unchecked. By default, the system prevents submitters from approving their own transactions. |
Buttons
- Add Workflow / Update Workflow — save the workflow
- Clear — reset the form
---
Section 2 — Approval Levels
After creating or selecting a workflow, the level-management section becomes visible. Levels define the sequential approval steps within the workflow.
Existing Levels Table
| Column | Description |
| Level | Sequential level number (Level 1, Level 2, etc.) |
| Role | Security role whose members may approve at this level |
| Min Approvers | Minimum number of distinct approvers required at this level before the draft can advance |
| Auto-Approve Threshold | If the draft amount is at or below this value, this level is automatically approved without human action. Dash (—) means no auto-approve. |
| Amount Upper Bound | Optional ceiling amount for this level. Useful for tiered routing (e.g., Level 1 handles up to $1,000, Level 2 handles above $1,000). |
| Escalation Days | Number of days a draft may remain pending at this level before automatic escalation. 0 or blank means escalation is disabled for this level. |
| Escalate To Level | Target level to escalate to. If blank, defaults to next level (current + 1). |
| Location | Location code this level applies to, or All for all locations. |
| Conditions | JSON condition expression for conditional routing, or None. |
| Active | Whether this level is enabled (Yes/No) |
| Edit | Button to load the level into the edit form |
| Delete | Button to remove the level |
Level Fields (Add/Edit Form)
| Field | Required | Description |
| Security Role | Yes | Dropdown of all active security roles defined in Access Setup. Users holding this role can approve at this level. |
| Min Approvers | Yes | Minimum number of unique approvers needed (default: 1). If set to 2, at least two different users with the role must independently approve. |
| Auto-Approve Threshold | No | Amount. Drafts with an amount at or below this value are automatically approved at this level. Leave blank or 0 to always require manual approval. |
| Amount Upper Bound | No | Maximum amount for this level. Drafts above this amount skip this level. |
| Escalation Days | No | Number of days after which a pending draft at this level should be automatically escalated. Set to 0 or leave blank to disable escalation. |
| Escalate To Level | No | Dropdown listing all levels in this workflow. Specifies which level receives the escalated draft. If not set, defaults to the next sequential level. |
| Location | No | Dropdown of system locations, or All Locations. Restricts this level to drafts from a specific location. |
| Conditions (JSON) | No | A JSON expression defining additional conditions that must all be true (AND logic) for this level to apply. See the detailed Conditions (JSON) Reference section below. |
| Active | No | Checkbox. Default: checked. Inactive levels are skipped during approval processing. |
Buttons
- Add Level / Update Level — save the level
- Clear — reset the form
---
Conditions (JSON) Reference
The Conditions (JSON) field on each approval level lets you define rules that control when that level applies to a draft. If a draft does not match the conditions, the level is skipped entirely — it is treated as non-applicable rather than blocking the draft.
JSON Format
You can enter either a single condition object or an array of condition objects:
Single object (auto-wrapped into an array internally):
{"field": "currency", "operator": "==", "value": "USD"}
Array of objects (recommended for multiple conditions):
[
{"field": "amount", "operator": ">", "value": "5000"},
{"field": "currency", "operator": "==", "value": "USD"}
]
Each condition object has three properties:
| Property | Required | Description |
field | Yes | The draft data field to check (see Available Fields below) |
operator | Yes | The comparison operator to use (see Supported Operators below) |
value | Depends | The expected value. Required for most operators; not needed for is_empty and is_not_empty. |
Evaluation Logic
- AND only — all conditions in the array must be true for the level to apply. There is no OR grouping or nesting.
- Empty conditions — if the field is left blank or null, the level always applies (no filtering).
- Non-matching levels are skipped — during auto-approval processing, the system iterates each active level. If a level's conditions do not match the draft, that level is simply skipped (not enforced). This means the draft may advance past a conditional level that does not apply.
Available Fields
The following common fields are suggested in the form, but any key present in the draft data can be used:
| Field Key | Description |
amount | Transaction amount (numeric) |
currency | Currency code (e.g., "USD", "EUR") |
loc_code | Location code |
person_id | Person ID — the customer or supplier ID depending on transaction type |
reference | Transaction reference string |
date_ | Transaction date |
bank_account | Bank account identifier |
pay_type | Payment type |
stock_id | Stock item ID |
location | Warehouse location |
category | Item category |
department | Department |
Advanced: You can also reference nested draft data using dot-notation. For example, header.customer_id accesses the customer_id inside the header object of the stored draft JSON. Similarly, line_items.0.stock_id accesses the first line item's stock ID.
Priority: Context fields (amount, currency, loc_code, person_id, reference) are resolved from the transaction context first. If not found there, the system searches the draft data.
Supported Operators
| Operator | Alias | Description | Example Value |
== | equals | Exact string equality | "USD" |
not_equals | — | String inequality (not equal) | "EUR" |
> | greater_than | Numeric greater than | "5000" |
< | less_than | Numeric less than | "1000" |
>= | greater_or_equal | Numeric greater than or equal | "5000" |
<= | less_or_equal | Numeric less than or equal | "10000" |
contains | — | Field value contains the text | "URGENT" |
not_contains | — | Field value does not contain the text | "TEST" |
starts_with | — | Field value starts with the text | "PO-" |
ends_with | — | Field value ends with the text | "-RUSH" |
in | — | Field value is one of a comma-separated list | "USD,EUR,GBP" |
not_in | — | Field value is not in a comma-separated list | "TEST,DEMO" |
between | — | Numeric value is between two comma-separated bounds (inclusive) | "1000,5000" |
is_empty | — | Field is empty, blank, or null (no value needed) | — |
is_not_empty | — | Field is not empty (no value needed) | — |
Note: For the inequality check, use the word not_equals rather than the symbol !=.
Validation
When saving a level, the system validates the JSON conditions:
- The text must be valid JSON.
- The top level must be an array or an object.
- Each condition must have a non-empty
field. - Each condition must have a valid
operatorfrom the list above. - Invalid JSON or missing required properties will produce an error and prevent saving.
Practical Examples
Example 1 — Level applies only to USD transactions over $10,000:
[
{"field": "amount", "operator": ">", "value": "10000"},
{"field": "currency", "operator": "==", "value": "USD"}
]
Example 2 — Level applies only to a specific warehouse location:
{"field": "loc_code", "operator": "==", "value": "WH-MAIN"}
Example 3 — Level applies to transactions for selected suppliers:
{"field": "person_id", "operator": "in", "value": "5,12,28"}
Example 4 — Level applies to amounts between 5,000 and 50,000:
{"field": "amount", "operator": "between", "value": "5000,50000"}
Example 5 — Level applies only when a bank account is specified:
{"field": "bank_account", "operator": "is_not_empty"}
Example 6 — Using dot-notation to check nested draft data:
{"field": "header.customer_id", "operator": "==", "value": "101"}
---
Auto-Approve Logic
When a draft is submitted, the system iterates through each active level from Level 1 upward:
- Check if the level's JSON Conditions (if any) match the draft data. If conditions are set and do not match, skip this level entirely.
- Check if the draft amount is at or below the level's Auto-Approve Threshold.
- If the threshold check passes, the level is automatically approved (no human approver needed) and the draft advances to the next level.
- If any level is not auto-approved (either the amount exceeds the threshold or there is no threshold), the draft stops there and waits for manual action by an approver with the required role.
This allows common low-value transactions to pass through instantly while high-value ones require human review. Combined with conditions, you can create sophisticated routing where different levels handle different currencies, locations, or departments.
Example Configuration
| Level | Role | Min Approvers | Threshold | Escalation |
| 1 | Department Manager | 1 | $1,000 | 3 days |
| 2 | Finance Director | 1 | $10,000 | 5 days |
| 3 | CFO | 1 | — | 7 days |
In this example:
- Purchase orders up to $1,000 auto-approve at Level 1 and proceed to Level 2.
- Purchase orders up to $10,000 auto-approve at Level 2 (but still require Level 1 manual approval if > $1,000).
- Purchase orders above $10,000 require all three levels of manual approval.
- If Level 1 is not acted on within 3 days, it escalates to Level 2.
Tips
- Each transaction type may have only one active workflow. Deactivate the existing workflow before creating a replacement.
- Use the Amount Upper Bound field to create tiered approval paths where different levels handle different amount ranges.
- Test your workflow configuration with a low-value transaction before going live.
- Remember that inactive levels are skipped — use this to temporarily bypass a level without deleting it.
- The Allow Self-Approve option should generally remain disabled for proper segregation of duties.