Appearance
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_RULEcategory tag matching the operation
18 Loan Operations & Their Rules
| Operation | Rule Code | System Tag | Description |
|---|---|---|---|
| DISBURSE | LOAN.DISBURSE | DISBURSE | New loan disbursement: DR Loan Receivable, CR Cash/Bank |
| REPAY_CASH | LOAN.REPAY.CASH | REPAY_CASH | Cash repayment: DR Till/Cash, CR Loan Receivable |
| REPAY_BANK | LOAN.REPAY.BANK | REPAY_BANK | Bank transfer repayment: DR Bank, CR Loan Receivable |
| REPAY_SPLIT | LOAN.REPAY.SPLIT | REPAY_SPLIT | Multi-component repayment (principal+interest+fees+penalties) |
| REPAY_CASH_REV | LOAN.REPAY.CASH.REV | REPAY_CASH_REV | Reversal of cash repayment |
| REPAY_BANK_REV | LOAN.REPAY.BANK.REV | REPAY_BANK_REV | Reversal of bank repayment |
| REPAY_SPLIT_REV | LOAN.REPAY.SPLIT.REV | REPAY_SPLIT_REV | Reversal of split repayment |
| INT_ACCRUE | LOAN.INT.ACCRUE | INT_ACCRUE | Interest accrual: DR Interest Receivable, CR Interest Income |
| INT_RECV | LOAN.INT.RECV | INT_RECV | Interest collection: DR Cash, CR Interest Receivable |
| INT_CAPITALIZE | LOAN.INT.CAPITALIZE | INT_CAPITALIZE | Capitalize unpaid interest: DR Loan Receivable, CR Interest Receivable |
| INT_SUSPEND | LOAN.INT.SUSPEND | INT_SUSPEND | Suspend interest accrual: DR Interest Income, CR Interest Receivable |
| FEE_CHARGE | LOAN.FEE.CHARGE | FEE_CHARGE | Charge loan fee: DR Fees Receivable, CR Fee Income |
| FEE_RECV | LOAN.FEE.RECV | FEE_RECV | Collect fee: DR Cash, CR Fees Receivable |
| ORIGINATION_FEE | LOAN.ORIGINATION.FEE | LOAN_ORIGINATION_FEE | Origination fee (use LOAN_ prefix to avoid tag conflicts) |
| EARLY_SETTLE | LOAN.EARLY.SETTLE | EARLY_SETTLE | Early settlement: DR Fees Receivable, CR Settlement Income |
| PENALTY | LOAN.PENALTY | LOAN_PENALTY | Late payment penalty (use LOAN_ prefix) |
| PROVISION | LOAN.PROVISION | PROVISION | Create loan loss provision: DR Provision Expense, CR Provision Liability |
| WRITEOFF | LOAN.WRITEOFF | WRITEOFF | Write off loan: DR Provision Liability, CR Loan Receivable |
| RECOVERY | LOAN.RECOVERY | RECOVERY | Recover written-off loan: DR Cash, CR Recovery Income |
| DISBURSE_REV | LOAN.DISBURSE.REV | DISBURSE_REV | Reversal of disbursement |
| WRITEOFF_REV | LOAN.WRITEOFF.REV | WRITEOFF_REV | Reversal of write-off |
| RECOVERY_REV | LOAN.RECOVERY.REV | RECOVERY_REV | Reversal of recovery |
| PROVISION_REV | LOAN.PROVISION.REV | PROVISION_REV | Reversal of provisioning |
Note: Tags with conflicts (PENALTY, ORIGINATION*FEE) use LOAN* prefix. The resolver automatically tries both variants.
2. Creating Rule Headers
Steps:
- Go to Administration → Accounting → GL Posting Rules
- Click Create Rule
- Fill in:
- Rule Code (e.g.,
LOAN.DISBURSE) - Rule Name (e.g., "Loan Disbursement")
- Posting Mode: Select
SYSTEM - Description (optional)
- Rule Code (e.g.,
- 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_TILLtag 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_keyfield references the handler code (e.g.,LOAN_RECEIVABLE_RESOLVE)
Amount Source
| Value | Meaning |
|---|---|
SYSTEM | Amount from domain context (principal, interest, fees, penalties) |
MANUAL | Amount entered by user |
SUM_OF_OTHERS | Auto-calculated as sum of all other lines |
Creating Detail Lines
- Open rule header
- Click Add Detail Line
- 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
- Detail Name (e.g.,
- Click Save
4. Rule Details by Operation
LOAN.DISBURSE
| Detail Name | Line Type | Nature | Tag Key / COA | Amount Source |
|---|---|---|---|---|
| LOAN.DISBURSE.DR.RECV | DEBIT | DOMAIN_RESOLVED | LOAN_RECEIVABLE_RESOLVE | SYSTEM |
| LOAN.DISBURSE.CR.FUND | CREDIT | DOMAIN_RESOLVED | CASH_BANK_RESOLVE | SYSTEM |
LOAN.REPAY.CASH
| Detail Name | Line Type | Nature | Tag Key / COA | Amount Source |
|---|---|---|---|---|
| LOAN.REPAY.CASH.DR.TILL | DEBIT | TAG_RESOLVED | CASH_IN_TILL | SYSTEM |
| LOAN.REPAY.CASH.CR.RECV | CREDIT | DOMAIN_RESOLVED | LOAN_RECEIVABLE_RESOLVE | SYSTEM |
LOAN.REPAY.BANK
| Detail Name | Line Type | Nature | Tag Key / COA | Amount Source |
|---|---|---|---|---|
| LOAN.REPAY.BANK.DR.BANK | DEBIT | DOMAIN_RESOLVED | CASH_BANK_RESOLVE | SYSTEM |
| LOAN.REPAY.BANK.CR.RECV | CREDIT | DOMAIN_RESOLVED | LOAN_RECEIVABLE_RESOLVE | SYSTEM |
LOAN.INT.ACCRUE
| Detail Name | Line Type | Nature | Tag Key / COA | Amount Source |
|---|---|---|---|---|
| LOAN.INT.ACCRUE.DR.RECV | DEBIT | DOMAIN_RESOLVED | LOAN_RECEIVABLE_RESOLVE | SYSTEM |
| LOAN.INT.ACCRUE.CR.INC | CREDIT | STATIC | Interest Income COA | SYSTEM |
LOAN.PENALTY
| Detail Name | Line Type | Nature | Tag Key / COA | Amount Source |
|---|---|---|---|---|
| LOAN.PENALTY.DR.RECV | DEBIT | DOMAIN_RESOLVED | LOAN_RECEIVABLE_RESOLVE | SYSTEM |
| LOAN.PENALTY.CR.INC | CREDIT | STATIC | Penalty Income COA | SYSTEM |
LOAN.PROVISION
| Detail Name | Line Type | Nature | Tag Key / COA | Amount Source |
|---|---|---|---|---|
| LOAN.PROVISION.DR.EXP | DEBIT | STATIC | Provision Expense COA | SYSTEM |
| LOAN.PROVISION.CR.LIA | CREDIT | STATIC | Provision Liability COA | SYSTEM |
LOAN.WRITEOFF
| Detail Name | Line Type | Nature | Tag Key / COA | Amount Source |
|---|---|---|---|---|
| LOAN.WRITEOFF.DR.LIA | DEBIT | STATIC | Provision Liability COA | SYSTEM |
| LOAN.WRITEOFF.CR.RECV | CREDIT | DOMAIN_RESOLVED | LOAN_RECEIVABLE_RESOLVE | SYSTEM |
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:
- For BANK_TRANSFER repayments: Extract
deposit_account_idfrom original transaction - Resolve the deposit account's sub_ledger via
gl_domain_object_registry - Get COA from the sub_ledger
- 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:
- Extract
repayment_methodfrom original transaction (for reversals) - For CASH/TELLER: Use COA 167 (Till Cash Control)
- For BANK_TRANSFER: Use COA 167 (Till Cash Control) as fallback
- 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
- Go to Administration → System Tags
- Click Create Tag
- Fill in:
- Tag Category:
LOAN_GL_RULE - Tag Key: Operation name (e.g.,
DISBURSE,REPAY_CASH) - Description (optional)
- Tag Category:
- Click Save
Binding Tags to Rules
- Go to Administration → Tag Bindings
- Click Create Binding
- 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
- Click Save
7. Product ↔ Rule Binding
Each loan product must have GL rules bound to it.
Binding Rules to Products
- Go to Administration → Loan Products → [Product]
- Click GL Posting Rules tab
- Click Bind Rule
- Select rule header and confirm
- 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 errorValidation
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_RULEcategory 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:
- Go to Loan Products → [Product] → GL Posting Rules
- Verify LOAN.DISBURSE rule is bound
- Go to System Tags and verify DISBURSE tag exists with category
LOAN_GL_RULE - 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:
- Check Fiscal Periods — ensure current period is OPEN
- Check Chart of Accounts — verify all COAs in rule details exist and are APPROVED
- Check Rule Details — verify all DOMAIN_RESOLVED lines have handler bindings
- 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:
- Go to Loan Products → [Product]
- Set Default COA to a valid loan receivable account
- Retry transaction
"Handler produced invalid/multiple coa_id"
Cause: Handler returned NULL or multiple COAs
Fix:
- For BANK_TRANSFER repayments: Verify
deposit_account_idis in transaction payload - Verify deposit account exists and is APPROVED
- Verify deposit account has a sub_ledger registered in
gl_domain_object_registry - Verify sub_ledger has a valid COA assigned
"Some draft rules are incomplete"
Cause: GL draft batch has incomplete lines or tasks
Fix:
- Check GL Posting Draft Batch for the transaction
- Verify all draft lines have
line_status = COMPLETE - Verify all system tasks have
task_status = COMPLETED - Check GL Posting Rule Details — ensure all DOMAIN_RESOLVED lines have handler bindings
"rules not balanced"
Cause: DEBIT ≠ CREDIT totals
Fix:
- Check all detail lines have correct
amount_source(SYSTEM, MANUAL, SUM_OF_OTHERS) - Verify handlers are resolving correct amounts
- Check GL Posting Draft Lines for the transaction
- Verify all amounts are correctly calculated
Best Practices
- GL Rule Setup: Create all 18 loan rules for each product upfront. Don't create rules on-demand.
- System Tags: Use consistent tag naming (DISBURSE, REPAYCASH, etc.). Use LOAN prefix for conflicting tags.
- Handler Bindings: Verify all DOMAIN_RESOLVED lines have handler bindings before posting.
- Deposit Accounts: For BANK_TRANSFER repayments, always include
deposit_account_idin the transaction payload. - Fiscal Periods: Ensure fiscal periods are open before posting. Closed periods reject all GL entries.
- Reversals: Always reverse via the UI. Manual reversals can cause data inconsistencies.
Related Documentation
- GL Posting Rules — General rule creation
- GL Posting Rule Details — Detail line configuration
- Loan Products — Product configuration
- Loan Operations — Transaction management
