Skip to content

GL Posting Approval

GL Posting Approval controls when a GL draft batch can post immediately and when it must stop for approval first.

Navigation: Administration -> Accounting -> GL Posting Approval

This page has four working areas:

  • Approval Chains
  • Approval Policies
  • Authority Limits
  • Pending Approvals

What The Engine Does

Approval is evaluated at the draft-batch level, not line by line.

The runtime checks GL posting in this order:

  1. Posting date, fiscal period, and posting-rule validation must pass.
  2. Pre-post handler work such as VALIDATE, RESOLVE, and PREVIEW must pass.
  3. Override rules are evaluated.
  4. Approval policies are evaluated by priority.
  5. If a policy matches, the batch is routed to the linked chain.
  6. If no policy matched, authority limits for the preparer role are evaluated.
  7. If no policy matched and the authority limit is exceeded, submit fails with an authority-limit error.
  8. If no policy matched and no authority-limit block applies, entity-level fallback approval is checked.
  9. After final approval, deferred posting work runs and the journals are posted.

This means approval does not replace posting validation. Approval sits on top of posting eligibility.

Screen Layout

Approval Chains

Use this tab to define who approves and in what order.

Approval Policies

Use this tab to define when a chain should apply.

Authority Limits

Use this tab to define what a preparer role may post directly before approval is required.

Pending Approvals

Use this tab to review, approve, reject, or return submitted GL posting batches.

Approval Chains

An approval chain defines the approver path.

Examples:

  • branch accountant then branch manager
  • finance reviewer and controller in parallel
  • any one senior approver

Chain Header Fields

FieldWhat it meansRuntime implication
Chain NameBusiness-facing name of the chain.Shown in admin lists, approval routing traces, and matched-policy references.
Chain CodeBackend-generated identifier.Used as a stable system reference. Users do not type it.
Chain TypeSEQUENTIAL, PARALLEL, or ANY_ONE.Controls whether steps run one after another, all together, or stop after the first approval.
SLA HoursOptional default turnaround target for the chain.Used as the default SLA when a step does not carry its own SLA.
DescriptionPlain-language purpose of the chain.Does not change routing logic, but improves support and audit readability.
ActiveWhether the chain is available for policy routing.Inactive chains should not be used by effective approval policies.

Chain Step Fields

FieldWhat it meansRuntime implication
Step OrderSequence number of the step.Determines progression order in sequential chains.
RoleApprover role for the step.Users mapped to this role become eligible approvers for the step.
Specific UserOptional named approver.Narrows the step to one user where supported by the chain design.
Business Unit ScopeSAME, ANY, or SPECIFIC.Controls whether approvers must belong to the batch BU, any BU, or one chosen BU.
Specific Business UnitRequired when scope is SPECIFIC.Restricts the step to approvers assigned in that BU only.
SLA HoursStep-specific turnaround target.Overrides the chain SLA for this step.
Can DelegateWhether the approver may delegate.Allows delegation flows where the engine supports them.
Is MandatoryWhether the step must be completed.In parallel chains, a non-mandatory step may not block completion.

Approval Policies

An approval policy decides when a draft batch should be routed into a chain.

Examples:

  • high-value manual journal
  • reversal batch
  • backdated posting
  • projected abnormal balance batch

Policy Header Fields

FieldWhat it meansRuntime implication
Policy NameBusiness-facing name of the policy.Shown in admin lists and matched-policy diagnostics.
Policy CodeBackend-generated identifier.Used as the stable system reference. Users do not type it.
PriorityEvaluation rank, where lower values are checked first.The first matching active policy normally wins, so priority directly affects routing.
Approval ChainThe chain to use when the policy matches.Links policy evaluation to a concrete approval path.
Business Unit ScopeOptional BU filter for the policy itself.Blank means the policy can match globally; populated means it only applies in that BU.
DescriptionPlain-language purpose of the policy.Helps support, audit, and policy maintenance.
ActiveWhether the policy is enabled.Inactive policies remain in history but should not match live batches.

Condition Tree Model

Each policy contains one or more conditions.

Conditions can be either:

  • a leaf condition: compares one posting attribute to one operand
  • a group node: combines child conditions with AND or OR

Important UI behavior:

  • Condition # is the form-local reference number
  • Parent Group / Condition uses that form-local number, not the database condition_id
  • if Group Operator is filled with AND or OR, that row acts as a grouping node and its attribute and comparison fields are usually left empty
  • the condition catalog is backend-owned; the form loads attributes, operators, and code-backed value options from the API before the drawer opens

Condition Fields

FieldWhat it meansRuntime implication
Condition #Visual reference number inside the form.Used by the UI to let other rows point to this row as a parent.
AttributeThe posting attribute to inspect, such as total_amount, source_type, or currency_code.Comes from the backend condition-metadata catalog and tells the evaluator what value to read from the draft-batch context.
Comparison OperatorOperator such as eq, gt, between, in, or intersects.Comes from the backend condition-metadata catalog and determines which operand field is meaningful and how evaluation is performed.
Group OperatorAND or OR for group nodes.Makes the row a grouping node that combines child rows instead of evaluating a direct comparison itself.
Parent Group / ConditionOptional parent row reference.Builds the condition tree instead of leaving the row as a root condition.
Value (text / code)String-style operand.The UI is backend-driven. Where the backend exposes a finite code set, the field behaves like a guided select/combobox; where the backend marks the attribute as open-ended, typed code entry is still allowed.
Value (JSON / list)JSON array or object operand.Used for list-style or array-style operators such as in, not_in, or intersects.
Value (numeric)Numeric operand or lower bound.Used for numeric operators such as gt, gte, lt, lte, and between.
Value High (numeric)Upper bound for range comparisons.Used only for between.
Sort OrderExplicit ordering value.Keeps condition rendering and evaluation order stable when multiple sibling rows exist.

How To Use The Value Fields

OperatorMain value fieldTypical usage
eq, neqValue (text / code) or Value (numeric)Use numeric for amounts/counts and text/code for string-style fields.
gt, gte, lt, lteValue (numeric)Use for thresholds such as amount or count.
betweenValue (numeric) and Value High (numeric)Use for numeric ranges.
in, not_inValue (JSON / list)Use JSON arrays or comma-separated lists.
containsValue (text / code)Use for substring checks.
is_null, is_not_nullnoneNo operand is required.
intersectsValue (JSON / list)Use for array overlap such as COA IDs or foundation types.

value_text Clarification

The backend stores value_text as VARCHAR(500), but operationally it is often a system code field rather than free prose.

The important rule now is this:

  • the backend is the source of truth for which attributes exist
  • the backend is the source of truth for which operators each attribute allows
  • the backend is the source of truth for any finite code list shown in the UI
  • the frontend should not invent its own condition catalog

Examples where value_text should normally be a controlled code:

  • source_type
  • rule_header_code
  • currency_code
  • journal_entry_type
  • preparer_role_type
  • fiscal_period_status

Examples:

  • source_type = MANUAL
  • journal_entry_type = REGULAR
  • currency_code = UGX
  • preparer_role_type = TELLER

So the safe rule is:

  • if the attribute is code-like, enter the system code, not a descriptive sentence
  • if the operator is contains, use real text only when the underlying attribute itself is truly textual

The current UI reflects this by calling the backend metadata endpoint before opening the policy form. The backend now tells the UI whether an operand should be authored through:

  • a backend-controlled single select
  • a backend-controlled multi-select
  • a tenant lookup field
  • a tenant multi-lookup field
  • numeric entry
  • open text/code entry

Practical examples:

  • currency_code, rule_header_code: tenant lookup, single select behavior
  • business_unit_id: tenant lookup that stores the numeric BU ID
  • coa_ids, projected_abnormal_coa_ids: tenant multi-lookup
  • journal_entry_type, preparer_role_type, foundation_types: backend-controlled select or multi-select
  • source_type: backend-controlled single select, currently expected as MANUAL or SYSTEM
  • contains: only makes sense for genuinely textual attributes; code-backed attributes should usually use exact match operators

Important distinction:

  • preparer_role_type is a system role-type code such as TELLER or ADMINISTRATOR, not a lookup to individual roles
  • has_subledger is a Yes/No system code, not a subledger picker
  • business_unit_id uses a tenant lookup but stores a numeric ID
  • rule_header_code and currency_code use tenant lookups but store code values
  • foundation_types and projected_abnormal_foundation_types use backend-controlled multi-select values, not free JSON typing in the normal case

Operand Control Mapping

The policy form should not make every operand look like generic text. It should choose the control from the backend-owned attribute semantics.

Attribute styleUI controlExamplesStored value
Tenant single lookup, text/codeLookup pickercurrency_code, rule_header_codeCode/text value
Tenant single lookup, numericLookup pickerbusiness_unit_idNumeric ID
Tenant multi-lookupMulti lookup pickercoa_ids, projected_abnormal_coa_idsJSON array of IDs
Backend-controlled single selectSelect / comboboxjournal_entry_type, preparer_role_type, boolean-like flagsSystem code
Backend-controlled multi-selectMulti-selectfoundation_types, projected_abnormal_foundation_typesJSON array of system codes
Open text/code entryText inputtruly free-text attributes onlyRaw text/code
Numeric entryNumber fieldtotal_amount, entry_count, numeric rangesNumeric value

Common Condition Attributes

These are the main policy attributes exposed in the current UI:

AttributeMeaningUsually compare with
total_amountTotal batch amount.Numeric threshold.
max_single_entry_amountLargest single journal entry amount in the batch.Numeric threshold.
entry_countNumber of journal entries in the batch.Numeric threshold.
line_countNumber of journal lines in the batch.Numeric threshold.
source_typeOrigin of the posting.Backend-controlled single select using system source codes.
rule_header_codeGL posting rule code.Tenant lookup storing the rule code.
currency_codeBatch currency.Tenant currency lookup storing the currency code.
journal_entry_typePosting classification.Backend-controlled single select.
has_till_sessionWhether the batch is tied to a till session.Boolean-like comparison, usually 1 or 0.
is_cross_buWhether multiple BUs are involved.Boolean-like comparison, usually 1 or 0.
is_backdatedWhether journal date is earlier than today.Boolean-like comparison, usually 1 or 0.
is_future_datedWhether journal date is later than today.Boolean-like comparison, usually 1 or 0.
has_subledgerWhether any line uses a subledger.Boolean-like comparison, usually 1 or 0.
preparer_role_typeRole type of the submitting user.Backend-controlled single select.
business_unit_idSubmitting BU.Tenant business-unit lookup storing the numeric BU ID.
coa_idsImpacted chart-of-account IDs.Multi-lookup with in, not_in, or intersects.
foundation_typesImpacted foundation account categories.Backend-controlled multi-select.
projected_abnormal_balance_countNumber of accounts projected abnormal.Numeric threshold.
has_projected_abnormal_balanceWhether any abnormal-balance risk exists.Boolean-like comparison, usually 1 or 0.
projected_negative_debit_nature_countCount of debit-nature accounts projected negative.Numeric threshold.
projected_negative_credit_nature_countCount of credit-nature accounts projected negative.Numeric threshold.
projected_abnormal_coa_idsCOA IDs projected abnormal.Multi-lookup with in, not_in, or intersects.
projected_abnormal_foundation_typesFoundation types projected abnormal.Backend-controlled multi-select.

Authority Limits

Authority limits control what a preparer role may post directly before approval is required.

Use authority limits for ceilings. Use approval policies for routing logic.

Authority Limit Fields

FieldWhat it meansRuntime implication
Business UnitOptional BU scope.Blank means the limit applies across BUs; populated means it only applies in that BU.
RolePreparer role the limit applies to.The draft submitter is checked against this role before direct posting is allowed.
CurrencyCurrency in which the thresholds are interpreted.Threshold evaluation uses this currency context.
Max Single Entry AmountCeiling for one journal entry.Exceeding it means the user cannot post directly under this limit.
Max Daily TotalCeiling for what that role can submit in a day.Exceeding it means approval is required.
Max Batch TotalCeiling for the total batch amount.Exceeding it means approval is required.
Allowed Source TypesOptional source filter list.Limit applies only to those posting source codes; blank means all sources.
Allowed GL Posting RulesOptional rule filter list.Limit applies only to the selected GL posting rules; blank means all rules.
ActiveWhether the limit is enabled.Inactive limits remain in history but do not affect live posting decisions.

Important:

  • authority limits are not linked to approval chains
  • if a policy already matched, the batch routes by policy before authority limits are considered
  • if no policy matched and a matching authority limit is exceeded, submit fails with an authority-limit error
  • authority limits do not choose approvers; policies and chains do

Pending Approvals

This tab is where approvers work on submitted GL draft batches.

Common actions:

  • Approve
  • Reject
  • Return
  • View History

What Each Action Means

ActionMeaningRuntime implication
ApproveAccept the batch at the current step.Moves the batch to the next approval step or final posting if this was the last required approval.
RejectStop the batch completely.The batch does not post and remains rejected until a new business action is taken.
ReturnSend the batch back for correction.The submitter can reopen, edit, and resubmit the draft.
View HistoryInspect the approval timeline.Does not change state; used for audit and support.

Visibility Rules

  • approvers are resolved from the current chain step
  • business-unit scope on the step is enforced
  • the submitter cannot approve their own batch

If a batch is not showing for an approver, check:

  • the current chain step role
  • the user’s role assignment
  • the step BU scope
  • whether the draft is already moved to another step or final state

Posting Status Flow

Typical states are:

  1. DRAFT
  2. SUBMITTED
  3. PENDING_APPROVAL
  4. APPROVED
  5. POSTING
  6. POSTED

Failure/return states include:

  • RETURNED
  • REJECTED
  • FAILED
  • OVERRIDE_REQUIRED where override rules are in use

Practical Configuration Patterns

High-Value Manual Journals

  • authority limit blocks direct posting above the ceiling
  • policy checks source_type = MANUAL
  • policy checks total_amount > threshold
  • matched chain routes to finance approvers

Teller Over Threshold To Manager Chain

  • create the teller authority limit to define what may post directly
  • create an approval policy that checks fields such as preparer_role_type = TELLER, total_amount, source_type, and rule_header_code
  • link that policy to the manager chain
  • do not expect the authority limit itself to choose the manager chain

Backdated Posting Control

  • policy checks is_backdated = 1
  • optionally add business_unit_id or source_type
  • route to a stricter chain than ordinary postings

Reversal Control

  • policy checks journal_entry_type = REVERSAL
  • optionally add amount thresholds or rule-code filters
  • route to senior review

Troubleshooting

Batch Posted Directly But Should Have Gone For Approval

Check:

  • whether a higher-priority policy should have matched first
  • whether an authority limit allowed it after no policy matched
  • whether the intended policy was active
  • whether the policy priority was too low
  • whether the condition values used the correct system codes

Policy Did Not Match

Check:

  • attribute
  • operator
  • whether you used value_text, value_numeric, or value_json correctly
  • whether the operand should be a code instead of plain text
  • whether the current UI/backend contract expects rule_header_code instead of legacy rule_header_id
  • whether the policy BU scope excluded the batch

Submit Failed On Authority Limit

Current runtime behavior:

  • this happens only when no approval policy matched the batch
  • the submit call fails with an authority-limit error instead of auto-picking a chain
  • if the business wants approval routing on that scenario, configure a matching approval policy and attach the intended chain

Approver Cannot See The Batch

Check:

  • the current chain step role
  • the user’s business-unit role assignment
  • step BU scope
  • whether the submitter is trying to approve their own batch

PinkApple ERP by Stat Solutions Network