Chart of Accounts
The Chart of Accounts (COA) is the foundation of the accounting system. It organizes all financial accounts into a hierarchical tree structure using parent-child relationships. Each account belongs to one of five classifications and is either a header (grouping) or detail (postable) account.
Purpose
- Define the complete list of financial accounts for the company
- Organize accounts in a multi-level tree via
parent_id - Enforce classification consistency (assets, liabilities, equity, revenue, expenses)
- Support bilingual names (English and Arabic)
- Auto-generate account codes based on parent hierarchy
- Provide tree and flat views, plus per-account balance queries
Entity Attributes
Account
| Field | Type | Description |
|---|---|---|
id | bigint | Primary key |
company_id | bigint | FK to companies |
code | string(50) | Unique account code (e.g., 1101) |
name | string | English name |
name_ar | string | Arabic name |
parent_id | bigint? | FK to accounts (self-referencing, null for root) |
classification | enum | assets, liabilities, equity, revenue, expenses |
nature | enum | debit or credit |
account_type | enum | header (group) or detail (postable) |
level | tinyint | Depth in the tree (1 = root) |
status | enum | active, inactive, frozen |
is_system | boolean | System-created account (cannot be deleted) |
has_children | boolean | Whether the account has child accounts |
description | text? | English description |
description_ar | text? | Arabic description |
created_at | timestamp | Creation timestamp |
updated_at | timestamp | Last update timestamp |
deleted_at | timestamp? | Soft-delete timestamp |
Indexes:
UNIQUE (company_id, code)INDEX (parent_id)INDEX (classification)
Relationships
Default Chart of Accounts
The system seeds a default COA with the following top-level structure:
| Code | English Name | Arabic Name | Classification | Nature |
|---|---|---|---|---|
1 | Assets | الأصول | assets | debit |
11 | Current Assets | الأصول المتداولة | assets | debit |
1101 | Cash on Hand | النقدية بالصندوق | assets | debit |
1102 | Cash at Bank | النقدية بالبنك | assets | debit |
1103 | Accounts Receivable | المدينون | assets | debit |
2 | Liabilities | الالتزامات | liabilities | credit |
21 | Current Liabilities | الالتزامات المتداولة | liabilities | credit |
2101 | Accounts Payable | الدائنون | liabilities | credit |
3 | Equity | حقوق الملكية | equity | credit |
3101 | Capital | رأس المال | equity | credit |
4 | Revenue | الإيرادات | revenue | credit |
4101 | Sales Revenue | إيرادات المبيعات | revenue | credit |
5 | Expenses | المصروفات | expenses | debit |
5201 | Salaries & Wages | الرواتب والأجور | expenses | debit |
API Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/accounting/accounts | List accounts (paginated, filterable) |
GET | /api/accounting/accounts/tree | Get full tree structure |
POST | /api/accounting/accounts | Create a new account |
GET | /api/accounting/accounts/{id} | Get a single account |
PUT | /api/accounting/accounts/{id} | Update an account |
DELETE | /api/accounting/accounts/{id} | Soft-delete an account |
GET | /api/accounting/accounts/{id}/balance | Get account balance |
Query Parameters (List)
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number (default: 1) |
classification | string | Filter by classification |
account_type | string | Filter by header or detail |
status | string | Filter by status |
search | string | Search by code, name, or name_ar |
Query Parameters (Balance)
| Parameter | Type | Description |
|---|---|---|
as_of_date | string | Date to calculate balance up to (YYYY-MM-DD) |
Request/Response Examples
Create Account
Request POST /api/accounting/accounts
bash
curl -X POST https://moon-erp.test/api/accounting/accounts \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"code": "1107",
"name": "Checks Under Collection",
"name_ar": "شيكات تحت التحصيل",
"parent_id": 2,
"classification": "assets",
"nature": "debit",
"account_type": "detail"
}'dart
final response = await http.post(
Uri.parse('https://moon-erp.test/api/accounting/accounts'),
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: jsonEncode({
'code': '1107',
'name': 'Checks Under Collection',
'name_ar': 'شيكات تحت التحصيل',
'parent_id': 2,
'classification': 'assets',
'nature': 'debit',
'account_type': 'detail',
}),
);Response 201 Created
json
{
"data": {
"id": 50,
"company_id": 1,
"code": "1107",
"name": "Checks Under Collection",
"name_en": "Checks Under Collection",
"name_ar": "شيكات تحت التحصيل",
"parent_id": 2,
"classification": "assets",
"classification_label": "Assets",
"nature": "debit",
"account_type": "detail",
"level": 3,
"status": "active",
"is_system": false,
"has_children": false,
"description": null,
"created_at": "2026-02-16T12:00:00.000000Z",
"updated_at": "2026-02-16T12:00:00.000000Z"
}
}Get Account Tree
Request GET /api/accounting/accounts/tree
Response 200 OK
json
{
"data": [
{
"id": 1,
"code": "1",
"name": "الأصول",
"name_en": "Assets",
"name_ar": "الأصول",
"classification": "assets",
"nature": "debit",
"account_type": "header",
"level": 1,
"children": [
{
"id": 2,
"code": "11",
"name": "الأصول المتداولة",
"classification": "assets",
"account_type": "header",
"level": 2,
"children": [
{
"id": 3,
"code": "1101",
"name": "النقدية بالصندوق",
"classification": "assets",
"account_type": "detail",
"level": 3,
"children": []
}
]
}
]
}
]
}Get Account Balance
Request GET /api/accounting/accounts/3/balance?as_of_date=2026-12-31
Response 200 OK
json
{
"data": {
"account_id": 3,
"total_debit": "15000.000",
"total_credit": "5000.000",
"balance": "10000.000"
}
}Business Rules
- Code uniqueness -- Account codes must be unique within a company (
company_id+code). - Parent classification -- A child account must share the same
classificationas its parent. - Header vs. detail -- Only
detailaccounts can be posted to in journal entries.Headeraccounts are for grouping only. - Auto-promotion -- When a child account is added to a
detailaccount, the parent is automatically promoted toheadertype. - Level auto-calculation -- The
levelis automatically set toparent.level + 1when a parent is specified. - Cannot delete system accounts -- Accounts where
is_system = truecannot be deleted. - Cannot delete accounts with entries -- Accounts that have journal entry lines cannot be deleted.
- Cannot delete accounts with children -- Deleting a parent account requires all children to be removed first.
- Nature consistency -- The account
natureis determined by itsclassification(assets/expenses = debit, liabilities/equity/revenue = credit), though contra accounts may differ. - Status restrictions -- Frozen or inactive accounts cannot be used in new journal entries.