Skip to content

Fiscal Years & Periods

Fiscal years define the accounting periods for the company. When a fiscal year is created, 12 monthly periods are automatically generated. Journal entries are scoped to a fiscal year and period, and periods must be closed sequentially before the fiscal year can be closed.

Purpose

  • Define annual accounting periods with start and end dates
  • Auto-generate 12 monthly fiscal periods per year
  • Control which periods accept journal entry postings
  • Enforce sequential period closing
  • Support fiscal year closing (which feeds into year-end closing)

Entity Attributes

Fiscal Year

FieldTypeDescription
idbigintPrimary key
company_idbigintFK to companies
namestringEnglish name (e.g., "FY 2026")
name_arstringArabic name (e.g., "السنة المالية 2026")
start_datedateFirst day of the fiscal year
end_datedateLast day of the fiscal year
statusenumopen or closed
created_attimestampCreation timestamp
updated_attimestampLast update timestamp
deleted_attimestamp?Soft-delete timestamp

Indexes:

  • UNIQUE (company_id, name)

Fiscal Period

FieldTypeDescription
idbigintPrimary key
company_idbigintFK to companies
fiscal_year_idbigintFK to fiscal_years
period_numbertinyintMonth number (1-12)
namestringEnglish name (e.g., "January 2026")
name_arstringArabic name (e.g., "يناير 2026")
start_datedateFirst day of the period
end_datedateLast day of the period
statusenumopen or closed
created_attimestampCreation timestamp
updated_attimestampLast update timestamp
deleted_attimestamp?Soft-delete timestamp

Indexes:

  • UNIQUE (fiscal_year_id, period_number)
  • INDEX (fiscal_year_id)

Relationships

API Endpoints

Fiscal Years

MethodPathDescription
GET/api/accounting/fiscal-yearsList fiscal years
POST/api/accounting/fiscal-yearsCreate a fiscal year (auto-generates 12 periods)
GET/api/accounting/fiscal-years/{id}Get a fiscal year with its periods
DELETE/api/accounting/fiscal-years/{id}Delete a fiscal year
POST/api/accounting/fiscal-years/{id}/closeClose a fiscal year

Fiscal Periods

MethodPathDescription
GET/api/accounting/fiscal-periodsList fiscal periods (filterable by fiscal_year_id)
GET/api/accounting/fiscal-periods/{id}Get a single fiscal period
POST/api/accounting/fiscal-periods/{id}/closeHard-close a fiscal period
POST/api/accounting/fiscal-periods/{id}/soft-closeSoft-close a fiscal period
POST/api/accounting/fiscal-periods/{id}/reopenReopen a soft- or hard-closed period

INFO

Fiscal years do not support an update endpoint. To change a fiscal year, delete it and re-create it (only possible if no journal entries exist).

Period Lifecycle

A fiscal period moves through three states:

StatusOperational entriesAdjustment entries
open✅ accepted✅ accepted
soft_closed❌ rejected✅ accepted
closed❌ rejected❌ rejected

Soft-close is the reversible middle state used at period-end: day-to-day postings stop, but accountants can still book adjustment entries — accruals, FX revaluation (fx-revaluation), and zakat. Hard-close locks the period entirely. Both states can be reopened with the accounting.periods.reopen permission, provided the parent fiscal year is still open.

WARNING

A reversal journal entry cannot be back-dated before the original entry, and only resolves into an open period — it cannot be posted into a soft- or hard-closed period.

Request/Response Examples

Create Fiscal Year

Request POST /api/accounting/fiscal-years

bash
curl -X POST https://moon-erp.test/api/accounting/fiscal-years \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "name": "FY 2026",
    "name_ar": "السنة المالية 2026",
    "start_date": "2026-01-01",
    "end_date": "2026-12-31"
  }'
dart
final response = await http.post(
  Uri.parse('https://moon-erp.test/api/accounting/fiscal-years'),
  headers: {
    'Authorization': 'Bearer $token',
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
  body: jsonEncode({
    'name': 'FY 2026',
    'name_ar': 'السنة المالية 2026',
    'start_date': '2026-01-01',
    'end_date': '2026-12-31',
  }),
);

Response 201 Created

json
{
  "data": {
    "id": 1,
    "company_id": 1,
    "name": "FY 2026",
    "name_en": "FY 2026",
    "name_ar": "السنة المالية 2026",
    "start_date": "2026-01-01",
    "end_date": "2026-12-31",
    "status": "open",
    "status_label": "Open",
    "periods": [
      {
        "id": 1,
        "period_number": 1,
        "name": "January 2026",
        "name_ar": "يناير 2026",
        "start_date": "2026-01-01",
        "end_date": "2026-01-31",
        "status": "open"
      },
      {
        "id": 2,
        "period_number": 2,
        "name": "February 2026",
        "name_ar": "فبراير 2026",
        "start_date": "2026-02-01",
        "end_date": "2026-02-28",
        "status": "open"
      }
    ],
    "created_at": "2026-02-16T12:00:00.000000Z",
    "updated_at": "2026-02-16T12:00:00.000000Z"
  }
}

Close a Fiscal Period

Request POST /api/accounting/fiscal-periods/1/close

Response 200 OK

json
{
  "data": {
    "id": 1,
    "period_number": 1,
    "name": "January 2026",
    "name_ar": "يناير 2026",
    "start_date": "2026-01-01",
    "end_date": "2026-01-31",
    "status": "closed",
    "status_label": "Closed"
  }
}

Business Rules

  1. Auto-generation -- When a fiscal year is created, exactly 12 monthly periods are generated automatically, spanning from start_date to end_date.
  2. Name uniqueness -- Fiscal year names must be unique per company.
  3. Date validation -- end_date must be after start_date. Fiscal years cannot overlap for the same company.
  4. No posting to closed periods -- Journal entries cannot be posted to a closed fiscal period.
  5. Sequential closing -- Fiscal periods must be closed in order (period 1 before period 2, etc.). You cannot close period 3 if period 2 is still open.
  6. Fiscal year close -- A fiscal year can only be closed when all 12 periods are closed.
  7. No deletion with entries -- A fiscal year cannot be deleted if any journal entries exist within it.
  8. Immutability -- Once created, fiscal year dates cannot be changed (no update endpoint).

Workflow / State Diagram

Fiscal Year Lifecycle

Fiscal Period Lifecycle

Period Closing Sequence

Moon ERP API Documentation