In this volume · VOLUME 05
Accounting
Chart of Accounts Journals & Ledger Billing & Invoicing Payments & Receipts Payment Reconciliation Multi-Currency Deferred Revenue Commission Accounting Tax (VAT/GST) Period Close

Chapter 5.1 — Chart of Accounts

chapter: 05-accounting/01-chart-of-accounts
version: 1.0.0
status: stable
last_reviewed: 2026-05-26
owners: [accounting, platform-engineering]

1. Purpose

The Chart of Accounts (CoA) is the vocabulary of the partner's financial statements. Every journal entry, every report, every tax filing references account codes defined here. Getting this right is foundational; getting it wrong is expensive to retrofit.

2. Why this matters in modern travel accounting

Travel businesses have an unusually rich set of account types compared to a generic small business:

  • Multiple receivable streams (B2C, B2B sub-agent, corporate accounts, IATA-net carriers).
  • Multiple payable streams (BSP airlines, non-BSP airlines, hotel suppliers, GDS fees, payment processor fees).
  • Several revenue categories that recognise on different triggers (commission earned at issuance, override commission earned at period close, markup earned at service date, service fees earned at issuance).
  • Pass-through accounts for taxes the agency collects but does not own.
  • Deferred revenue liabilities for tickets issued but not yet flown.

A generic accounting tool's CoA cannot capture this without customisation. travoBooks ships a travel-specific CoA template per country and a guided customiser.

3. Industry relevance

A correctly-structured CoA makes the following tasks trivial; an incorrectly-structured one makes them impossible:

  • Quarterly commission earnings by airline.
  • Net BSP exposure at any moment.
  • Service-date-based revenue (the IFRS 15 requirement).
  • Per-supplier ageing.
  • ADM impact on the P&L.
  • Tax filings broken out by jurisdiction.

4. Compliance considerations

Standard Implication for CoA
IFRS 15 (Revenue from Contracts with Customers) Revenue cannot be recognised at ticket issuance unless control transfers then. CoA must distinguish recognised revenue from deferred.
IFRS 9 (Financial Instruments) Receivables must be measurable for expected credit loss. AR accounts are subdivided by counterparty type.
IAS 21 (Effects of Changes in FX Rates) Realised vs. unrealised FX gains/losses are separate accounts.
IFRS 16 (Leases) If the partner has lease obligations (office, equipment), the CoA includes right-of-use assets and lease liabilities.
US-GAAP ASC 606 Mirrors IFRS 15 for revenue recognition.
IATA BSP A dedicated control account isolates "BSP Cash Payable" — money collected from customers that belongs to airlines via BSP.

5. Business logic

5.1 Structure

The CoA is a hierarchical tree with a fixed top-level structure aligned to the five accounting elements, with travel-specific subtrees beneath.

1xxx  ASSETS
  10xx  Current Assets
    101x  Cash & Equivalents
    102x  Accounts Receivable
    103x  Other Receivables
    105x  Prepayments
    106x  Inventory (vouchers, stock tickets)
  15xx  Non-Current Assets
    151x  Property, Plant & Equipment
    155x  Intangibles
    158x  Right-of-Use Assets (IFRS 16)

2xxx  LIABILITIES
  20xx  Current Liabilities
    201x  Accounts Payable
      2011  BSP Payable (control)
      2012  Non-BSP Airline Payable
      2013  Hotel Suppliers Payable
      2014  GDS / Tech Vendor Payable
    202x  Tax Payable
      2021  VAT/GST Output Payable
      2022  Withholding Tax Payable
    203x  Deferred Revenue (Unearned)
    205x  Customer Advances / Deposits
    206x  Payroll Liabilities
  25xx  Non-Current Liabilities
    251x  Long-Term Loans
    255x  Lease Liabilities (IFRS 16)

3xxx  EQUITY
  301x  Share Capital
  302x  Retained Earnings
  303x  Other Reserves
  309x  Current-Year P&L (system-managed)

4xxx  REVENUE
  401x  Commission Revenue
    4011  Air — Base Commission
    4012  Air — Override Commission
    4013  Hotel Commission
    4014  Non-Air Commission
  402x  Markup Revenue
  403x  Service Fee Revenue
  404x  Cancellation/Change Fee Revenue
  409x  FX Gain — Realised
  4099  FX Gain — Unrealised

5xxx  COST OF SALES
  501x  Air Net Cost
  502x  Hotel Net Cost
  503x  Refund Cost Adjustments
  504x  ADM Net Impact

6xxx  OPERATING EXPENSES
  601x  Salaries & Benefits
  602x  Office Rent (or 158x amortisation if IFRS 16)
  603x  GDS / Tech Subscriptions
  604x  Marketing & Advertising
  605x  Payment Processor Fees
  606x  Depreciation
  609x  FX Loss — Realised
  6099  FX Loss — Unrealised

7xxx  OTHER INCOME
8xxx  OTHER EXPENSES
9xxx  TAX
  901x  Income Tax Expense

5.2 Account anatomy

Each account row has:

Field Purpose
code The numeric or alphanumeric code (e.g. 2011). Unique per partner.
name Human-readable name.
type One of: asset, liability, equity, revenue, expense, contra.
subtype E.g. current_asset, current_liability, cost_of_sales.
normal_balance debit or credit. Validates incoming postings.
is_postable If false, the account is a header/rollup and cannot be posted to directly.
is_control If true, posting is allowed only via auto-generated entries (e.g. AR control).
parent_code The parent in the tree.
currency_mode functional_only | any — whether the account holds only functional currency or accepts foreign-currency postings.
tax_link Optional link to a tax profile (for output VAT/GST accounts).
requires_dimension Required dimensions on a posting (e.g. supplier_id for supplier payable).
is_active Soft disable; cannot delete an account that has ever been posted to.

5.3 Control accounts

Certain accounts (AR, AP, BSP) are control accounts. The balance must equal the sum of the sub-ledger (per-customer, per-supplier). The system enforces this with:

  • Postings to a control account are auto-generated only — never via manual JE.
  • Sub-ledger and control reconcile on a nightly job; mismatch raises an alert.

5.4 Multi-currency accounts

Accounts marked currency_mode = any hold balances in any currency. The ledger row stores transaction_currency, transaction_amount, plus the functional-currency equivalents at posting time. Period-end revaluation produces unrealised FX gain/loss postings to 4099 / 6099. See Multi-Currency.

5.5 Versioning

Account definitions change rarely but they do change. travoBooks versions account metadata: when name changes, the historical name is preserved with effective dates. Reports run "as at" a date use the metadata in effect at that date.

6. Inputs → processing → outputs

6.1 Bootstrapping the CoA (on partner provisioning)

Input: country_code, business_type (B2B / B2C / Mixed), tax_regime (VAT / GST / None).

Processing: render a country-aware template; produce ~150 accounts seeded into chart_of_accounts.

Output: a complete usable CoA, with is_active = true for the common ones and is_active = false for jurisdiction-specific extras.

6.2 Adding / editing an account (input)

account:
  code: "4015"
  name: "Air — Group Booking Commission"
  type: "revenue"
  subtype: "operating_revenue"
  normal_balance: "credit"
  parent_code: "401"
  is_postable: true
  is_control: false
  currency_mode: "any"
  requires_dimension: []

6.3 Outputs

  • New account available immediately.
  • Permission coa.edit.partner required.
  • Audit log entry; emails to subscribed admins.

7. Module dependencies

Reads from Writes to Read by
Country/tax reference chart_of_accounts, chart_of_accounts_history, audit_logs Every accounting module: journals, invoicing, payments, reports

8. Security & permissions

  • coa.read.partner — view CoA.
  • coa.create.partner — add new accounts.
  • coa.edit.partner — edit (name, parent, active flag).
  • coa.deactivate.partner — toggle is_active.
  • 🔒 Account deletion is not exposed. Accounts with any posted ledger row cannot be removed; they are deactivated.
  • 🔒 is_control cannot be flipped on a populated account — would invalidate sub-ledger reconciliation.

Maker–checker: editing an account in active use (>0 ledger rows in current period) requires approver acknowledgement.

9. Validation rules

Rule Error
code unique per partner COA_CODE_DUPLICATE
code matches ^[A-Z0-9-]{2,16}$ COA_CODE_INVALID
parent_code must exist and be is_postable=false COA_PARENT_INVALID
normal_balance must match type (asset/expense = debit; liability/equity/revenue = credit; contra = opposite of its category) COA_NORMAL_BALANCE_MISMATCH
Cannot post to non-postable COA_NOT_POSTABLE
Cannot change type once any ledger row exists COA_TYPE_IMMUTABLE
Control account postings only from system COA_CONTROL_DIRECT_POST
Required dimension missing on posting JE_DIMENSION_REQUIRED

10. Error handling

  • A posting attempt to a deactivated account: 422 with COA_INACTIVE and a hint to use the active equivalent.
  • A posting that violates normal_balance direction is allowed (a contra movement is legitimate) but flagged in the period anomaly report if the net movement contradicts the normal balance.
  • Bulk edits are transactional — if one row fails, none are applied.

11. Real-world example

Scenario. Innovate Travel (partner P-001, functional currency BDT) sells an international ticket on Emirates for a Dhaka–Dubai trip. Sell price BDT 80,000. Net cost BDT 72,000. Base commission BDT 6,000, override BDT 1,200 (estimated, recognised on quarter close). Service fee BDT 800. VAT 15% on service fee = BDT 120 (output tax payable, agency owes).

At issuance, the platform writes a single balanced journal entry that touches the following accounts:

Account Code 🅓 Debit 🅒 Credit
Customer A/R 1021 80,920
BSP Payable 2011 72,000
Air Base Commission Revenue 4011 6,000
Service Fee Revenue 4031 800
VAT Output Payable 2021 120
Deferred Air Revenue 2031 6,000
Air Base Commission Revenue (deferral reversal) 4011 6,000
TOTAL 86,920 86,920

Two things to note from the CoA's role here:

  1. The presence of a dedicated Service Fee Revenue (4031) distinct from Commission Revenue (4011) is what later allows the partner to file VAT correctly — VAT applies to service fees, not to the airline ticket pass-through.
  2. The deferral of the BDT 6,000 commission lives in 2031 (Deferred Air Revenue) because under IFRS 15 the airline's performance obligation (the flight) has not yet been satisfied. At service date, a second journal moves it: 🅓 2031 6,000 / 🅒 4011 6,000.

The override commission (BDT 1,200) is not posted at issuance because it is estimated; it accrues to 4012 Air Override Commission only when the airline confirms the achievement at quarter close.

12. Step-by-step workflow — customising the CoA

flowchart TD A[Open Accounting → Chart of Accounts] --> B{Action} B -->|Add account| C[Pick parent in tree] C --> D[Fill code, name, type, subtype] D --> E[Set normal_balance auto-suggested] E --> F[Optional: tax_link, required dimensions] F --> G[Save → audit log → live] B -->|Edit account| H[Open account] H --> I{Has ledger rows?} I -->|Yes| J[Type and code locked; name/parent editable] I -->|No| K[All fields editable] J --> L[Save → maker-checker if needed] K --> L B -->|Deactivate| M[Confirm modal: no future postings] M --> N[Toggle is_active = false → audit log]

13. Database tables touched

  • chart_of_accounts — current state.
  • chart_of_accounts_history — every edit, with effective dates.
  • account_dimensions — required dimensions per account.
  • tax_profiles — referenced via tax_link.

Full schema in 10-database/03-table-reference.md.

14. Future scalability

Need Approach
Multi-entity consolidation with different CoAs Group-level mapping table maps partner-account → group-account at report time.
IFRS / Local-GAAP dual ledger Each account can carry a local_gaap_code mapping; reports render via the chosen lens.
Industry-segment CoAs (e.g. corporate vs leisure) cost_centre dimension on every posting; CoA stays unified.

15. Common pitfalls

  • ⚠️ Adding a new account in the middle of a fiscal period and posting historical entries to it. Period-comparison reports will spike. Use effective-date metadata or carry on with the existing account and re-categorise next period.
  • ⚠️ Treating BSP Payable like a regular AP. It is a control account with airline-level sub-ledger; never journal it directly.
  • ⚠️ Confusing markup revenue with commission revenue. They have different VAT treatment in most jurisdictions.

Next: 02-journals-and-ledger.md — how journal entries are constructed, validated, and posted to the GL.