Skip to content

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

FieldTypeDescription
idbigintPrimary key
company_idbigintFK to companies
codestring(50)Unique account code (e.g., 1101)
namestringEnglish name
name_arstringArabic name
parent_idbigint?FK to accounts (self-referencing, null for root)
classificationenumassets, liabilities, equity, revenue, expenses
natureenumdebit or credit
account_typeenumheader (group) or detail (postable)
leveltinyintDepth in the tree (1 = root)
statusenumactive, inactive, frozen
is_systembooleanSystem-created account (cannot be deleted)
has_childrenbooleanWhether the account has child accounts
descriptiontext?English description
description_artext?Arabic description
created_attimestampCreation timestamp
updated_attimestampLast update timestamp
deleted_attimestamp?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:

CodeEnglish NameArabic NameClassificationNature
1Assetsالأصولassetsdebit
11Current Assetsالأصول المتداولةassetsdebit
1101Cash on Handالنقدية بالصندوقassetsdebit
1102Cash at Bankالنقدية بالبنكassetsdebit
1103Accounts Receivableالمدينونassetsdebit
2Liabilitiesالالتزاماتliabilitiescredit
21Current Liabilitiesالالتزامات المتداولةliabilitiescredit
2101Accounts Payableالدائنونliabilitiescredit
3Equityحقوق الملكيةequitycredit
3101Capitalرأس المالequitycredit
4Revenueالإيراداتrevenuecredit
4101Sales Revenueإيرادات المبيعاتrevenuecredit
5Expensesالمصروفاتexpensesdebit
5201Salaries & Wagesالرواتب والأجورexpensesdebit

API Endpoints

MethodPathDescription
GET/api/accounting/accountsList accounts (paginated, filterable)
GET/api/accounting/accounts/treeGet full tree structure
POST/api/accounting/accountsCreate 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}/balanceGet account balance

Query Parameters (List)

ParameterTypeDescription
pageintegerPage number (default: 1)
classificationstringFilter by classification
account_typestringFilter by header or detail
statusstringFilter by status
searchstringSearch by code, name, or name_ar

Query Parameters (Balance)

ParameterTypeDescription
as_of_datestringDate 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

  1. Code uniqueness -- Account codes must be unique within a company (company_id + code).
  2. Parent classification -- A child account must share the same classification as its parent.
  3. Header vs. detail -- Only detail accounts can be posted to in journal entries. Header accounts are for grouping only.
  4. Auto-promotion -- When a child account is added to a detail account, the parent is automatically promoted to header type.
  5. Level auto-calculation -- The level is automatically set to parent.level + 1 when a parent is specified.
  6. Cannot delete system accounts -- Accounts where is_system = true cannot be deleted.
  7. Cannot delete accounts with entries -- Accounts that have journal entry lines cannot be deleted.
  8. Cannot delete accounts with children -- Deleting a parent account requires all children to be removed first.
  9. Nature consistency -- The account nature is determined by its classification (assets/expenses = debit, liabilities/equity/revenue = credit), though contra accounts may differ.
  10. Status restrictions -- Frozen or inactive accounts cannot be used in new journal entries.

Moon ERP API Documentation