Opening Balances
Opening balances capture the starting financial position when a company begins using Moon ERP or when a new fiscal year starts. They record the balances of every active GL account, and optionally include outstanding partner invoices (receivables and payables) that carry forward from a previous system or fiscal year.
Purpose
- Enter starting balances for all GL accounts at the beginning of a fiscal year
- Record outstanding customer invoices (accounts receivable) and supplier invoices (accounts payable)
- Enforce that total debits equal total credits before confirmation
- Provide a review report summarizing balances by account classification
- Lock confirmed opening balances to prevent accidental modification
Entity Attributes
Opening Balance
| Field | Type | Description |
|---|---|---|
id | integer | Primary key |
company_id | integer | Owning company |
fiscal_year_id | integer | Fiscal year these balances apply to |
status | enum | draft, confirmed, locked |
total_debit | decimal(12,3) | Sum of all line debits (auto-calculated) |
total_credit | decimal(12,3) | Sum of all line credits (auto-calculated) |
notes | text? | Additional notes |
confirmed_by | integer? | User who confirmed the balance |
confirmed_at | datetime? | When confirmed |
created_at | datetime | Creation timestamp |
updated_at | datetime | Last update timestamp |
Opening Balance Line
| Field | Type | Description |
|---|---|---|
id | integer | Primary key |
company_id | integer | Owning company |
opening_balance_id | integer | Parent opening balance |
account_id | integer | GL account |
debit | decimal(12,3) | Debit amount |
credit | decimal(12,3) | Credit amount |
partner_id | integer? | Business partner (for AR/AP accounts) |
cost_center_id | integer? | Optional cost center |
description | string? | Line description |
Opening Balance Invoice
| Field | Type | Description |
|---|---|---|
id | integer | Primary key |
company_id | integer | Owning company |
opening_balance_id | integer | Parent opening balance |
partner_id | integer | Business partner |
invoice_number | string | Original invoice number |
invoice_date | date? | Original invoice date |
due_date | date | Payment due date |
amount | decimal(12,3) | Invoice amount |
balance_remaining | decimal(12,3) | Unpaid balance |
type | string | receivable or payable |
description | string? | Invoice description |
Relationships
API Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/accounting/opening-balances | List opening balances (paginated, filterable) |
POST | /api/accounting/opening-balances | Create with lines |
GET | /api/accounting/opening-balances/{id} | Get with lines and invoices |
PUT | /api/accounting/opening-balances/{id} | Update a draft balance |
DELETE | /api/accounting/opening-balances/{id} | Soft-delete a draft balance |
POST | /api/accounting/opening-balances/{id}/confirm | Confirm (validates and creates journal entry) |
POST | /api/accounting/opening-balances/{id}/lock | Lock (prevents further changes) |
POST | /api/accounting/opening-balances/{id}/unlock | Unlock (reverts to draft) |
POST | /api/accounting/opening-balances/{id}/invoices | Add a partner invoice |
GET | /api/accounting/opening-balances/{id}/review | Review summary report |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
fiscal_year_id | integer | Filter by fiscal year |
status | string | Filter by status (draft, confirmed, locked) |
State Diagram
Workflow
Request/Response Examples
POST /api/accounting/opening-balances
Create an opening balance with lines.
Request
json
{
"fiscal_year_id": 1,
"notes": "Opening balances migrated from legacy system",
"lines": [
{
"account_id": 1,
"debit": "50000.000",
"credit": "0.000",
"description": "Cash on hand"
},
{
"account_id": 15,
"debit": "120000.000",
"credit": "0.000",
"description": "NBK bank balance"
},
{
"account_id": 30,
"debit": "0.000",
"credit": "100000.000",
"description": "Capital"
},
{
"account_id": 31,
"debit": "0.000",
"credit": "70000.000",
"description": "Retained earnings"
}
]
}Response 201 Created
json
{
"data": {
"id": 1,
"company_id": 1,
"fiscal_year_id": 1,
"status": "draft",
"status_label": "Draft",
"total_debit": "170000.000",
"total_credit": "170000.000",
"notes": "Opening balances migrated from legacy system",
"confirmed_by": null,
"confirmed_at": null,
"lines": [
{
"id": 1,
"account_id": 1,
"debit": "50000.000",
"credit": "0.000",
"description": "Cash on hand"
},
{
"id": 2,
"account_id": 15,
"debit": "120000.000",
"credit": "0.000",
"description": "NBK bank balance"
}
],
"fiscal_year": {
"id": 1,
"name": "2026"
},
"created_at": "2026-02-10T08:00:00.000000Z"
}
}POST /api/accounting/opening-balances/{id}/invoices
Add an outstanding customer invoice.
Request
json
{
"partner_id": 8,
"invoice_number": "INV-2025-0342",
"invoice_date": "2025-11-15",
"due_date": "2026-01-15",
"amount": "3500.000",
"balance_remaining": "3500.000",
"type": "receivable",
"description": "Outstanding balance from 2025"
}Response 201 Created
json
{
"data": {
"id": 5,
"opening_balance_id": 1,
"partner_id": 8,
"invoice_number": "INV-2025-0342",
"invoice_date": "2025-11-15",
"due_date": "2026-01-15",
"amount": "3500.000",
"balance_remaining": "3500.000",
"type": "receivable",
"description": "Outstanding balance from 2025"
}
}GET /api/accounting/opening-balances/{id}/review
Get a validation summary before confirming.
Response 200 OK
json
{
"data": {
"opening_balance_id": 1,
"fiscal_year": "2026",
"status": "draft",
"is_balanced": true,
"total_debit": "170000.000",
"total_credit": "170000.000",
"difference": "0.000",
"by_classification": [
{ "classification": "asset", "debit": "170000.000", "credit": "0.000" },
{ "classification": "equity", "debit": "0.000", "credit": "170000.000" }
],
"line_count": 4,
"invoice_count": 1,
"invoices_by_type": {
"receivable": { "count": 1, "total": "3500.000" },
"payable": { "count": 0, "total": "0.000" }
}
}
}Business Rules
| Rule | Description |
|---|---|
| Balanced required for confirm | Total debits must equal total credits before confirmation |
| Draft only editable | Lines can only be added/modified/deleted while in draft status |
| Confirm creates journal entry | Confirmation generates a journal entry with all opening balance lines |
| Lock prevents changes | Locked opening balances cannot be modified at all |
| Unlock returns to draft | Unlocking moves the balance back to draft for corrections |
| Invoices on draft only | Partner invoices can only be added while the balance is in draft |
| Auto-sum totals | total_debit and total_credit are auto-calculated from lines |
| Invoice types | receivable for customer invoices, payable for supplier invoices |
| Company scoped | All queries filter by the authenticated user's company |