Skip to content

Loan GL Setup

Complete guide to configuring GL posting rules for all loan operations.

Navigation: Administration → Accounting → GL Posting Rules

Overview

Every loan action (disbursement, repayment, interest accrual, write-off, etc.) triggers automatic GL posting via system tags and dynamic handlers. This guide explains how to set up these rules.


1. Rule Headers & System Tags

All loan GL posting rules must be created with:

  • Posting Mode: SYSTEM (system-initiated, not manual)
  • System Tag: LOAN_GL_RULE category tag matching the operation

18 Loan Operations & Their Rules

OperationRule CodeSystem TagDescription
DISBURSELOAN.DISBURSEDISBURSENew loan disbursement: DR Loan Receivable, CR Cash/Bank
REPAY_CASHLOAN.REPAY.CASHREPAY_CASHCash repayment: DR Till/Cash, CR Loan Receivable
REPAY_BANKLOAN.REPAY.BANKREPAY_BANKBank transfer repayment: DR Bank, CR Loan Receivable
REPAY_SPLITLOAN.REPAY.SPLITREPAY_SPLITMulti-component repayment (principal+interest+fees+penalties)
REPAY_CASH_REVLOAN.REPAY.CASH.REVREPAY_CASH_REVReversal of cash repayment
REPAY_BANK_REVLOAN.REPAY.BANK.REVREPAY_BANK_REVReversal of bank repayment
REPAY_SPLIT_REVLOAN.REPAY.SPLIT.REVREPAY_SPLIT_REVReversal of split repayment
INT_ACCRUELOAN.INT.ACCRUEINT_ACCRUEInterest accrual: DR Interest Receivable, CR Interest Income
INT_RECVLOAN.INT.RECVINT_RECVInterest collection: DR Cash, CR Interest Receivable
INT_CAPITALIZELOAN.INT.CAPITALIZEINT_CAPITALIZECapitalize unpaid interest: DR Loan Receivable, CR Interest Receivable
INT_SUSPENDLOAN.INT.SUSPENDINT_SUSPENDSuspend interest accrual: DR Interest Income, CR Interest Receivable
FEE_CHARGELOAN.FEE.CHARGEFEE_CHARGECharge loan fee: DR Fees Receivable, CR Fee Income
FEE_RECVLOAN.FEE.RECVFEE_RECVCollect fee: DR Cash, CR Fees Receivable
ORIGINATION_FEELOAN.ORIGINATION.FEELOAN_ORIGINATION_FEEOrigination fee (use LOAN_ prefix to avoid tag conflicts)
EARLY_SETTLELOAN.EARLY.SETTLEEARLY_SETTLEEarly settlement: DR Fees Receivable, CR Settlement Income
PENALTYLOAN.PENALTYLOAN_PENALTYLate payment penalty (use LOAN_ prefix)
PROVISIONLOAN.PROVISIONPROVISIONCreate loan loss provision: DR Provision Expense, CR Provision Liability
WRITEOFFLOAN.WRITEOFFWRITEOFFWrite off loan: DR Provision Liability, CR Loan Receivable
RECOVERYLOAN.RECOVERYRECOVERYRecover written-off loan: DR Cash, CR Recovery Income
DISBURSE_REVLOAN.DISBURSE.REVDISBURSE_REVReversal of disbursement
WRITEOFF_REVLOAN.WRITEOFF.REVWRITEOFF_REVReversal of write-off
RECOVERY_REVLOAN.RECOVERY.REVRECOVERY_REVReversal of recovery
PROVISION_REVLOAN.PROVISION.REVPROVISION_REVReversal of provisioning

Note: Tags with conflicts (PENALTY, ORIGINATION*FEE) use LOAN* prefix. The resolver automatically tries both variants.


2. Creating Rule Headers

Steps:

  1. Go to Administration → Accounting → GL Posting Rules
  2. Click Create Rule
  3. Fill in:
    • Rule Code (e.g., LOAN.DISBURSE)
    • Rule Name (e.g., "Loan Disbursement")
    • Posting Mode: Select SYSTEM
    • Description (optional)
  4. Click Save

3. Rule Details (Debit & Credit Lines)

Each rule header requires DEBIT + CREDIT detail lines.

Detail Nature Types

STATIC — COA hardcoded on the detail line

  • Use for: Fixed accounts (provision expense, penalty income, settlement income)
  • No handler needed
  • Example: Penalty Income COA

TAG_RESOLVED — COA resolved via system tag at posting time

  • Use for: Till/vault accounts that vary by business unit
  • Example: CASH_IN_TILL tag resolves to the till account for the current BU

DOMAIN_RESOLVED — COA resolved by a dynamic handler procedure

  • Use for: Loan receivable, cash/bank, interest receivable (varies per product/client)
  • The tag_key field references the handler code (e.g., LOAN_RECEIVABLE_RESOLVE)

Amount Source

ValueMeaning
SYSTEMAmount from domain context (principal, interest, fees, penalties)
MANUALAmount entered by user
SUM_OF_OTHERSAuto-calculated as sum of all other lines

Creating Detail Lines

  1. Open rule header
  2. Click Add Detail Line
  3. Fill in:
    • Detail Name (e.g., LOAN.DISBURSE.DR.RECV)
    • Line Type: DEBIT or CREDIT
    • Detail Nature: STATIC, TAG_RESOLVED, or DOMAIN_RESOLVED
    • Tag Key (if DOMAIN_RESOLVED or TAG_RESOLVED)
    • COA (if STATIC)
    • Amount Source: SYSTEM, MANUAL, or SUM_OF_OTHERS
  4. Click Save

4. Rule Details by Operation

LOAN.DISBURSE

Detail NameLine TypeNatureTag Key / COAAmount Source
LOAN.DISBURSE.DR.RECVDEBITDOMAIN_RESOLVEDLOAN_RECEIVABLE_RESOLVESYSTEM
LOAN.DISBURSE.CR.FUNDCREDITDOMAIN_RESOLVEDCASH_BANK_RESOLVESYSTEM

LOAN.REPAY.CASH

Detail NameLine TypeNatureTag Key / COAAmount Source
LOAN.REPAY.CASH.DR.TILLDEBITTAG_RESOLVEDCASH_IN_TILLSYSTEM
LOAN.REPAY.CASH.CR.RECVCREDITDOMAIN_RESOLVEDLOAN_RECEIVABLE_RESOLVESYSTEM

LOAN.REPAY.BANK

Detail NameLine TypeNatureTag Key / COAAmount Source
LOAN.REPAY.BANK.DR.BANKDEBITDOMAIN_RESOLVEDCASH_BANK_RESOLVESYSTEM
LOAN.REPAY.BANK.CR.RECVCREDITDOMAIN_RESOLVEDLOAN_RECEIVABLE_RESOLVESYSTEM

LOAN.INT.ACCRUE

Detail NameLine TypeNatureTag Key / COAAmount Source
LOAN.INT.ACCRUE.DR.RECVDEBITDOMAIN_RESOLVEDLOAN_RECEIVABLE_RESOLVESYSTEM
LOAN.INT.ACCRUE.CR.INCCREDITSTATICInterest Income COASYSTEM

LOAN.PENALTY

Detail NameLine TypeNatureTag Key / COAAmount Source
LOAN.PENALTY.DR.RECVDEBITDOMAIN_RESOLVEDLOAN_RECEIVABLE_RESOLVESYSTEM
LOAN.PENALTY.CR.INCCREDITSTATICPenalty Income COASYSTEM

LOAN.PROVISION

Detail NameLine TypeNatureTag Key / COAAmount Source
LOAN.PROVISION.DR.EXPDEBITSTATICProvision Expense COASYSTEM
LOAN.PROVISION.CR.LIACREDITSTATICProvision Liability COASYSTEM

LOAN.WRITEOFF

Detail NameLine TypeNatureTag Key / COAAmount Source
LOAN.WRITEOFF.DR.LIADEBITSTATICProvision Liability COASYSTEM
LOAN.WRITEOFF.CR.RECVCREDITDOMAIN_RESOLVEDLOAN_RECEIVABLE_RESOLVESYSTEM

Reversal Rules (REPAY_CASH_REV, REPAY_BANK_REV, etc.)

Reversals use the same detail structure as the original operation, but with reversed amounts:

  • Original DEBIT becomes CREDIT
  • Original CREDIT becomes DEBIT
  • Handlers extract the original transaction's deposit account and payment method

5. Dynamic Handlers

Handlers are registered in gl_dynamic_handler_registry and resolve COAs at posting time.

LOAN_RECEIVABLE_RESOLVE (Handler 47)

Purpose: Resolve loan receivable COA for DEBIT lines

Logic:

  1. For BANK_TRANSFER repayments: Extract deposit_account_id from original transaction
  2. Resolve the deposit account's sub_ledger via gl_domain_object_registry
  3. Get COA from the sub_ledger
  4. Fallback: Use loan_product.coa_id (for CASH payments or when no deposit account)

Used in: DISBURSE (DR), REPAY_CASH (CR), REPAY_BANK (CR), INT_ACCRUE (DR), PENALTY (DR), etc.

CASH_BANK_RESOLVE (Handler 48)

Purpose: Resolve cash/bank COA for CREDIT lines during repayment

Logic:

  1. Extract repayment_method from original transaction (for reversals)
  2. For CASH/TELLER: Use COA 167 (Till Cash Control)
  3. For BANK_TRANSFER: Use COA 167 (Till Cash Control) as fallback
  4. Fallback: Use loan_product.coa_id

Used in: DISBURSE (CR), REPAY_CASH (DR), REPAY_BANK (DR)

Other Handlers

  • LOAN_REPAYMENT_SPLIT — Splits repayment into principal/interest/fees/penalty components
  • LOAN_WRITEOFF_RESOLVE — Resolves write-off COA lines
  • LOAN_RECOVERY_RESOLVE — Resolves recovery COA lines

6. System Tags

Each rule header must be tagged with a LOAN_GL_RULE category system tag.

Creating System Tags

  1. Go to Administration → System Tags
  2. Click Create Tag
  3. Fill in:
    • Tag Category: LOAN_GL_RULE
    • Tag Key: Operation name (e.g., DISBURSE, REPAY_CASH)
    • Description (optional)
  4. Click Save

Binding Tags to Rules

  1. Go to Administration → Tag Bindings
  2. Click Create Binding
  3. Fill in:
    • Tag: Select the LOAN_GL_RULE tag
    • Binding Type: GL_POSTING_RULE_HEADER
    • Scope: Business unit or global
    • Bound Entity: Select the rule header
  4. Click Save

7. Product ↔ Rule Binding

Each loan product must have GL rules bound to it.

Binding Rules to Products

  1. Go to Administration → Loan Products → [Product]
  2. Click GL Posting Rules tab
  3. Click Bind Rule
  4. Select rule header and confirm
  5. Repeat for all 18 loan rules

Resolution Flow

Loan Transaction (e.g., disbursement)

fn_resolve_loan_gl_rule(product_id, 'DISBURSE', business_unit_id, currency_code)

1. Find rules bound to this product (loan_product_gl_posting_rule_binding)
2. Among those, find the one tagged with LOAN_GL_RULE tag matching the operation
3. If not found, fallback to global tag resolution (fn_pick_tag_binding_scope_id)
4. If still not found, transaction FAILS with error

Validation

The system enforces one rule per operation per product. Binding two rules with the same LOAN_GL_RULE tag to the same product is rejected.


8. GL Setup Checklist

For each loan product:

  • [ ] Rule Headers: All 18 rule codes created (LOAN.DISBURSE, LOAN.REPAY.CASH, etc.)
  • [ ] Posting Mode: Each header set to SYSTEM
  • [ ] Detail Lines: Each header has DEBIT + CREDIT lines with correct amounts
  • [ ] Detail Nature: Lines correctly marked as STATIC, TAG_RESOLVED, or DOMAIN_RESOLVED
  • [ ] Handler Bindings: DOMAIN_RESOLVED lines reference correct handler tag_keys
  • [ ] System Tags: Each header tagged with LOAN_GL_RULE category tag
  • [ ] Product Binding: Each header bound to the loan product via GL Posting Rules tab
  • [ ] Static COAs: All STATIC detail lines have valid COA accounts assigned
  • [ ] Tag Bindings: All TAG_RESOLVED lines reference tags with COA bindings in this BU
  • [ ] Reversals: Reversal rules (REPAY_CASH_REV, etc.) created with same detail structure

9. Troubleshooting

"No GL posting rule bound for LOAN DISBURSE"

Cause: Rule not bound to product or system tag missing

Fix:

  1. Go to Loan Products → [Product] → GL Posting Rules
  2. Verify LOAN.DISBURSE rule is bound
  3. Go to System Tags and verify DISBURSE tag exists with category LOAN_GL_RULE
  4. Go to Tag Bindings and verify tag is bound to the rule header

"GL posting failed ... Transaction rolled back"

Cause: GL engine rejected the posting

Fix:

  1. Check Fiscal Periods — ensure current period is OPEN
  2. Check Chart of Accounts — verify all COAs in rule details exist and are APPROVED
  3. Check Rule Details — verify all DOMAIN_RESOLVED lines have handler bindings
  4. Check GL Configuration — verify business unit has proper GL settings

"Cannot resolve coa_id for cash/bank"

Cause: Loan product has no default COA set

Fix:

  1. Go to Loan Products → [Product]
  2. Set Default COA to a valid loan receivable account
  3. Retry transaction

"Handler produced invalid/multiple coa_id"

Cause: Handler returned NULL or multiple COAs

Fix:

  1. For BANK_TRANSFER repayments: Verify deposit_account_id is in transaction payload
  2. Verify deposit account exists and is APPROVED
  3. Verify deposit account has a sub_ledger registered in gl_domain_object_registry
  4. Verify sub_ledger has a valid COA assigned

"Some draft rules are incomplete"

Cause: GL draft batch has incomplete lines or tasks

Fix:

  1. Check GL Posting Draft Batch for the transaction
  2. Verify all draft lines have line_status = COMPLETE
  3. Verify all system tasks have task_status = COMPLETED
  4. Check GL Posting Rule Details — ensure all DOMAIN_RESOLVED lines have handler bindings

"rules not balanced"

Cause: DEBIT ≠ CREDIT totals

Fix:

  1. Check all detail lines have correct amount_source (SYSTEM, MANUAL, SUM_OF_OTHERS)
  2. Verify handlers are resolving correct amounts
  3. Check GL Posting Draft Lines for the transaction
  4. Verify all amounts are correctly calculated

Best Practices

  1. GL Rule Setup: Create all 18 loan rules for each product upfront. Don't create rules on-demand.
  2. System Tags: Use consistent tag naming (DISBURSE, REPAYCASH, etc.). Use LOAN prefix for conflicting tags.
  3. Handler Bindings: Verify all DOMAIN_RESOLVED lines have handler bindings before posting.
  4. Deposit Accounts: For BANK_TRANSFER repayments, always include deposit_account_id in the transaction payload.
  5. Fiscal Periods: Ensure fiscal periods are open before posting. Closed periods reject all GL entries.
  6. Reversals: Always reverse via the UI. Manual reversals can cause data inconsistencies.

PinkApple ERP by Stat Solutions Network