FGL Journals and Posting
The general ledger records financial activity through journal entries that are grouped into batches and posted to update stored balances. This page explains the batch/header/line model, the posting process, suspense handling, journal reversal, balance roll-forward, and the reporting views.
Batch / header / line model
Journal entries follow a three-level hierarchy:
Journal Batch
└── Journal Header (one or more per batch)
└── Journal Line (one or more per header)
Batches
A journal batch is the unit of posting. All headers within a batch are posted together when the fgl_post_batch function is called. A batch belongs to a single ledger and carries a status:
| Status | Meaning |
|---|---|
UNPOSTED | Initial state; the batch has not been posted |
POSTED | All headers in the batch posted successfully |
ERROR | One or more headers failed validation during posting |
A batch also records an optional posted_date (set on successful posting) and error_text (set when errors occur).
Headers
A journal header represents a single journal entry. Each header belongs to a batch and records:
| Field | Purpose |
|---|---|
| ledger_id | The ledger this entry belongs to |
| period_id | The accounting period for this entry |
| journal_name | A descriptive name for the entry |
| journal_date | The effective date of the entry |
| source | Where the entry originated: MANUAL, RECEIVABLES, or PAYABLES |
| category | The nature of the entry: ADJUSTMENT, SALES_INVOICES, RECEIPTS, PURCHASE_INVOICES, PAYMENTS, or REVERSAL |
| currency_code | The entry (entered) currency |
| status | UNPOSTED, POSTED, or ERROR |
| reversal_flag | Whether this header is a reversing entry |
| reversed_header_id | For reversals, points to the original header |
| running_total_dr / running_total_cr | Trigger-maintained totals of all line debits and credits |
The running_total_dr and running_total_cr columns are maintained automatically by a database trigger whenever lines are inserted, updated, or deleted. They are never written directly.
Lines
A journal line is a single debit or credit entry on a header. Each line references a code combination (the account being posted to) and records both entered and accounted amounts.
A line is always exactly one of a debit or a credit — the database enforces that exactly one of entered_dr / entered_cr is non-null and greater than zero, and the same rule applies to accounted_dr / accounted_cr.
Entered vs accounted amounts
Each journal line carries two pairs of amount columns:
| Columns | Currency | Purpose |
|---|---|---|
| entered_dr / entered_cr | Entry currency (from the header) | The amount in the currency of the original transaction |
| accounted_dr / accounted_cr | Functional currency (from the ledger) | The amount converted to the ledger's reporting currency |
When the entry currency matches the ledger's functional currency, the entered and accounted amounts are the same and the conversion_rate is 1. When they differ, the conversion_rate on the line records the exchange rate used, and the accounted amounts are the converted values.
The posting process uses accounted amounts for balance checks and balance updates, ensuring that all stored balances are in the ledger's functional currency.
Posting
Posting is performed by the fgl_post_batch function, which processes every UNPOSTED header in a batch. The function runs the following checks and steps for each header:
1. Period check
The GL period status for the header's period must be OPEN. If the period is not open, the header is marked ERROR.
2. Code combination check
Every code combination referenced by the header's lines must be both enabled and allow_posting. If any combination fails this check, the header is marked ERROR.
3. Balance check
The sum of accounted_dr across all lines must equal the sum of accounted_cr. If the header is unbalanced:
- Suspense enabled — if the ledger has
suspense_enabled = TRUEand asuspense_ccidconfigured, the posting function automatically inserts a balancing suspense line using the ledger's suspense code combination. The suspense line records the difference needed to bring the header into balance. - Suspense not enabled — the header is marked
ERRORwith a message indicating the imbalance.
4. Balance upsert
For each line, the function upserts the fgl_balances table:
- If no balance row exists for the combination of ledger, period, code combination, and currency, one is created
- The line's accounted debit or credit is added to
period_net_drorperiod_net_cr - If the entry currency differs from the functional currency, a separate balance row is maintained for the entered currency
5. Roll-forward
After updating the current period's balances, the posting function rolls the closing position (begin balance + period net) into the next period of the same fiscal year as the opening balance. This ensures that the trial balance for any period reflects cumulative activity from the start of the year.
6. Status update
If all checks pass, the header is marked POSTED with the current timestamp as posted_date. After processing all headers, the batch is marked POSTED if every header succeeded, or ERROR if any header failed.
Error statuses
When a header fails posting, its status is set to ERROR and the error_text column records the reason. Common error codes:
| Code | Meaning |
|---|---|
FGL-00100 | Batch is already posted |
FGL-00101 | Batch not found |
FGL-00102 | Period is not open for GL |
FGL-00103 | Code combination is disabled or does not allow posting |
FGL-00104 | Header is unbalanced and suspense is not enabled |
FGL-00105 | Suspense code combination is not configured |
FGL-00106 | Suspense code combination is disabled |
The batch-level error_text aggregates header-level errors.
Suspense
Suspense handling allows unbalanced journals to be posted by automatically inserting a balancing line. This is useful when sub-ledger feeds produce rounding differences or when manual entry errors need to be corrected after the fact.
Suspense is controlled by two ledger-level settings:
suspense_enabled— must beTRUEto activate suspense handlingsuspense_ccid— the code combination that receives the balancing entry
When both are configured and a header's accounted debits do not equal its accounted credits, the posting function inserts a single suspense line that brings the header into balance. The suspense line uses the ledger's functional currency with a conversion rate of 1.
Review suspense entries regularly. A suspense balance that grows over time indicates a systematic data quality issue in journal entry or sub-ledger feeds.
Reversal
The fgl_reverse_header function creates a reversing journal for a previously posted header. Reversal is used to correct errors or to create accrual reversals at the start of a new period.
The function:
- Validates that the source header is
POSTEDand is not itself a reversal - Creates a new batch named
Reversal: {journal_name} - Creates a new header with
reversal_flag = TRUE,reversed_header_idpointing to the original, andcategory = 'REVERSAL' - Copies all lines from the original header with debits and credits swapped
- Posts the new reversal batch by calling
fgl_post_batch - Returns the new header's ID
The target period for the reversal can differ from the original header's period, allowing reversals to be recorded in the current period for entries that were posted in a prior period.
Reversal error codes
| Code | Meaning |
|---|---|
FGL-00110 | Source header not found |
FGL-00111 | Source header is not in POSTED status |
FGL-00112 | Source header is already a reversal |
FGL-00113 | Target period not found |
FGL-00114 | Target period is not open for GL |
Balances and roll-forward
The fgl_balances table stores period-level financial totals for each combination of ledger, period, code combination, and currency. Balance rows are created and updated exclusively by the posting process — they are read-only to application users.
Each balance row contains:
| Column | Purpose |
|---|---|
| begin_balance_dr / begin_balance_cr | Opening position for the period, rolled forward from the prior period's closing position |
| period_net_dr / period_net_cr | Net activity posted during this period |
The closing position for a period is computed as:
end_balance_dr = begin_balance_dr + period_net_dr
end_balance_cr = begin_balance_cr + period_net_cr
When a journal is posted, the posting function updates the current period's period_net columns and then propagates the updated closing position into the next period's begin_balance columns within the same fiscal year. This roll-forward ensures that opening balances are always current without requiring a separate batch process.
Trial balance
The trial balance view (fgl_trial_balance) provides a period-by-period summary of balances across all code combinations. It joins balances with code combinations and periods to present:
- Concatenated segment string and account type
- Period name, year, and number
- Begin balance (DR and CR)
- Period net (DR and CR)
- Computed end balance (DR and CR)
The trial balance is exposed through the General Ledger menu as a read-only entry. It does not support create, edit, or delete actions.
Account activity
The account activity view (fgl_account_activity) provides line-level detail for posted journals. It shows every posted journal line with:
- Code combination and account type
- Period information
- Journal header details (name, date, source, category)
- Line number and description
- Entered amounts (DR and CR) with currency and conversion rate
- Accounted amounts (DR and CR)
This view is useful for drilling into the detail behind a trial balance figure to see which journal entries contributed to a particular account's balance.
General Ledger menu
The General Ledger menu in the application provides access to journals and the trial balance:
| Entry | Schema | Actions |
|---|---|---|
| Journals | ts_fgl_journal_batch | Create, Edit, PostBatch |
| → Headers (child of Journals) | ts_fgl_journal_header | Create, Edit, ReverseHeader |
| → → Lines (child of Headers) | ts_fgl_journal_line | Create, Edit |
| Trial Balance | ts_fgl_trial_balance | Read-only (no create, edit, or delete) |
The PostBatch custom action triggers fgl_post_batch on the selected batch. The ReverseHeader custom action triggers fgl_reverse_header on the selected header.