Chart of Accounts
The Chart of Accounts (CoA) is the list of GL accounts a company posts to. It is the vocabulary of the financial statements. Every posting in the entire ERP eventually lands on one.
Account types
| Type | Balance sheet or P&L | Normal balance | Resets at year end? |
|---|---|---|---|
| Asset | BS | Debit | No — carries forward |
| Liability | BS | Credit | No |
| Equity | BS | Credit | No |
| Revenue / Income | P&L | Credit | Yes — closed to retained earnings |
| Expense / Cost | P&L | Debit | Yes |
The accounting equation, which the ERP enforces at all times:
Assets = Liabilities + Equity
where Equity includes (Revenue − Expenses)
The numbering convention
Most charts follow a block structure. A very common shape:
1xxxxx Assets
10xxxx Cash and bank
11xxxx Accounts receivable
12xxxx Inventory
13xxxx Prepaid expenses
15xxxx Fixed assets (cost)
16xxxx Accumulated depreciation (contra-asset)
2xxxxx Liabilities
20xxxx Accounts payable
21xxxx Accrued liabilities
22xxxx Tax payable
23xxxx GR/IR clearing
25xxxx Loans
3xxxxx Equity
30xxxx Share capital
32xxxx Retained earnings
33xxxx Current year result
4xxxxx Revenue
40xxxx Product sales
41xxxx Service revenue
45xxxx Sales returns and discounts (contra-revenue)
5xxxxx Cost of goods sold
6xxxxx Operating expenses
7xxxxx Other income/expense
8xxxxx Financial income/expense
9xxxxx Tax and extraordinary
Learn to read an account number at a glance — 4 means revenue, 23 means a clearing account. This is how finance people talk.
Special account categories developers must know
Reconciliation accounts
AR and AP balances are not posted directly. You post to a customer or vendor (a subledger), and the system automatically posts to a reconciliation account in the GL.
Invoice customer ACME for 1,000
Subledger: Customer ACME Dr 1,000
GL: 113000 Trade AR Dr 1,000 ← automatic, from the customer master
400000 Revenue Cr 1,000
You can never post manually to a reconciliation account. The subledger and GL must always agree; manual posting breaks that. This trips up every developer once.
Clearing accounts
Temporary holding accounts that should net to zero over time. The most important:
- GR/IR (Goods Receipt / Invoice Receipt) — sits between receiving goods and receiving the supplier’s invoice. Debited on receipt, credited on invoice. A non-zero aged GR/IR balance means missing invoices or missing receipts, and auditors always look at it.
- Bank clearing — between payment issued and bank statement confirmed
- Payroll clearing — between payroll calculation and payment
- Inter-company clearing — between paired entities
Clearing accounts are managed with open item management: each posting is an open item, cleared when matched against its counterpart.
Contra accounts
Accounts that sit against another and carry the opposite normal balance:
- Accumulated depreciation (contra to fixed assets)
- Allowance for doubtful accounts (contra to AR)
- Sales returns and allowances (contra to revenue)
Statistical / memo accounts
Non-financial quantities used for reporting (headcount, square metres, units produced) so allocations can be driven by them.
Multiple charts of accounts
Large groups run more than one:
| Chart | Purpose |
|---|---|
| Operating / Group chart | The one everybody posts to, used for group consolidated reporting |
| Country / Local chart | Legally mandated local structure (France’s PCG, Bangladesh’s, China’s, Germany’s SKR) |
| Group chart | Mapping target for consolidation |
Postings hit the operating chart; an alternative account number on each account maps to the local chart for statutory reporting. Countries with prescribed charts (France, Belgium, Spain, China, Russia) make this mandatory, not optional.
Account determination — the key developer concept
Business users do not choose GL accounts. The system derives them from configuration. This is called account determination (or posting profiles / posting setup).
Example: goods issue for a sales delivery.
Inputs: Chart of accounts + Valuation area + Valuation class of material
+ Account modifier + Movement type
Output: Debit 500000 COGS, Credit 120000 Inventory
Every ERP has dozens of these determination tables:
| Process | Determination |
|---|---|
| Goods movements | Movement type + valuation class → inventory/expense/COGS accounts |
| Sales billing | Condition type + account key + customer/material account group → revenue, discount, freight accounts |
| Purchasing invoice | Account assignment category → expense/asset/GR-IR accounts |
| Fixed assets | Asset class → APC, accumulated depreciation, depreciation expense |
| Payroll | Wage type → expense and liability accounts |
| Tax | Tax code → input/output tax accounts |
| Bank | House bank + payment method → bank and clearing accounts |
| FX | Valuation method → realised/unrealised gain and loss accounts |
When someone reports “the posting went to the wrong account”, 95% of the time the fix is in an account determination table, not in code. Learn where these tables live in your product; it will make you look like a wizard.
Field status and validation
Each account controls which fields are required, optional, or suppressed on a posting:
- A cost account may require a cost centre
- A bank account may suppress the cost centre
- A revenue account may require a profit centre
This is field status group in SAP, posting profiles/financial dimensions rules elsewhere. It’s the mechanism that stops incomplete postings.
Designing a chart of accounts (if you’re building one)
- Keep it small. 300–800 accounts is healthy for a mid-size company. Charts with 5,000 accounts are almost always misusing accounts as dimensions.
- Do not encode dimensions in the account number.
600100 Salaries – Dhaka – Salesis wrong. Use600100 Salaries+ cost centre + profit centre. Otherwise the chart multiplies with every new location. - One account = one meaning, forever. Never repurpose.
- Leave gaps in numbering for future insertions.
- Mark open-item-managed accounts deliberately — only clearing-style accounts.
- Decide P&L by nature or by function early (nature: “salaries, rent, depreciation”; function: “cost of sales, admin, distribution”). IFRS allows either; the choice reshapes the whole expense block.
Table shape if you’re building it
CREATE TABLE gl_account (
id BIGSERIAL PRIMARY KEY,
chart_id BIGINT NOT NULL REFERENCES chart_of_accounts(id),
account_number VARCHAR(20) NOT NULL,
name VARCHAR(255) NOT NULL,
account_type account_type_enum NOT NULL, -- ASSET|LIABILITY|EQUITY|REVENUE|EXPENSE
is_reconciliation BOOLEAN NOT NULL DEFAULT FALSE,
recon_subledger subledger_enum, -- AR|AP|ASSET when reconciliation
open_item_managed BOOLEAN NOT NULL DEFAULT FALSE,
currency_code CHAR(3), -- NULL = any currency
blocked_for_posting BOOLEAN NOT NULL DEFAULT FALSE,
alternative_account VARCHAR(20), -- local chart mapping
valid_from DATE NOT NULL,
valid_to DATE,
UNIQUE (chart_id, account_number)
);
Note: no balance column. Balances are derived from journal lines. See General Ledger.