413 Ledger & statements
Today: 9 Nov 2026

JV-2026-0349

Payment PAY-2026-0049 for BILL-2026-0049

#AccountCost centerMemoDebitCredit
1 2000 Accounts payable CloudStack Inc. 39,953.77
2 1010 Bank - KBank current account Bank transfer 39,793.36
3 4850 Foreign exchange gain Rate 33.574600 -> 33.439800 160.41
Total39,953.7739,953.77

Entry details

Date16 Oct 2026 Created byBill payment DocumentPAY-2026-0049 CurrencyUSD Exchange rate33.4398
Debits = credits. The entry balances.

Lines are always in THB. Debit lines are written first, credit lines indented - the way accountants write a journal.

How this works - feature 413 Chart of accounts, trial balance, journals and account ledgers.

Concepts

  • Double entry: every entry has debits = credits; JournalService.post refuses anything else.
  • CHECK constraint: a line is either a debit or a credit, never negative.
  • Trial balance: if total debits = total credits the books are in balance.
  • Ledger running balance: SUM(...) OVER (ORDER BY ... ROWS UNBOUNDED PRECEDING).
  • Document numbers come from one MERGE ... OUTPUT statement (NumberingService).

Read the code

  • service/JournalService
  • service/JournalDraft
  • service/ReportService#trialBalance
  • service/NumberingService

SQL behind this page

SELECT a.id, a.code, a.name, a.type,
       COALESCE(SUM(l.debit), 0)  AS debit,
       COALESCE(SUM(l.credit), 0) AS credit
FROM account a
LEFT JOIN v_ledger l ON l.account_id = a.id AND l.entry_date <= :asOf
GROUP BY a.id, a.code, a.name, a.type
ORDER BY a.code

-- account ledger
SELECT entry_id, entry_no, entry_date, entry_description, source_type, source_ref, memo, debit, credit,
       SUM(natural_amount) OVER (ORDER BY entry_date, entry_id, line_id
                                 ROWS UNBOUNDED PRECEDING) AS running
FROM v_ledger
WHERE account_id = :accountId AND entry_date BETWEEN :from AND :to
ORDER BY entry_date, entry_id, line_id