Fiscal Periods & Year-End Closing

v0.1.0

Fiscal calendars, transaction date resolution, soft and hard period locks, nominal account sweeping, and Retained Earnings rollover.

Fiscal Periods & Year-End Closing

Financial reporting requires strict temporal boundaries. Obelawium Accounting provides automated fiscal calendars, multi-stage period locks, and statutory Year-End closing sequences.


1. Fiscal Calendar Hierarchy

The temporal model consists of two tiers:

  • Fiscal Years (FiscalYear): Represents an enterprise financial year (e.g., FY-2026: Jan 1 – Dec 31).
  • Fiscal Periods (FiscalPeriod): Sub-divisions (typically 12 monthly or 4 quarterly periods) with distinct lifecycle lock states.
Fiscal Year: 2026 (Jan 01, 2026 - Dec 31, 2026)
├── Period 01: 2026-01-01 to 2026-01-31 (CLOSED)
├── Period 02: 2026-02-01 to 2026-02-28 (CLOSED)
├── Period 03: 2026-03-01 to 2026-03-31 (OPEN)
└── ...

2. Managing Fiscal Years & Periods

Creating a Fiscal Year and Generating Periods

use Obelaw\Ium\Accounting\Data\CreateFiscalYearDto;

// Create fiscal year with 12 monthly periods generated automatically
$year = ium()->accounting()->fiscalPeriods()->createYear(
    new CreateFiscalYearDto(
        name: 'FY-2026',
        startDate: '2026-01-01',
        endDate: '2026-12-31',
        autoGenerateMonthlyPeriods: true
    )
);

Automatic Date Resolution

When a journal voucher is submitted, the system queries findPeriodForDate() to assign the voucher to the matching period:

$period = ium()->accounting()->fiscalPeriods()->findPeriodForDate('2026-03-15');

if (!$period->status->allowsPosting()) {
    throw new FiscalPeriodClosedException("Period {$period->name} does not permit new postings.");
}

3. Period Lock States

A fiscal period transitions through three governance phases:

Status EnumPosting Allowed?Description
FiscalPeriodStatus::OpenYesNormal daily operations; vouchers can be drafted, approved, and posted.
FiscalPeriodStatus::ClosingReviewRestrictedMonth-end financial close; only users with the accounting.override-review-lock permission may post adjustment entries.
FiscalPeriodStatus::ClosedNoStatutory hard lock; all write attempts throw FiscalPeriodClosedException.

Locking and Closing a Period

// Step 1: Transition into Closing Review (soft lock)
ium()->accounting()->fiscalPeriods()->setReviewStatus($periodId, $actorId);

// Step 2: Finalize hard statutory lock
ium()->accounting()->fiscalPeriods()->closePeriod($periodId, $actorId);

4. Statutory Year-End Closing Workflow

At the end of a fiscal year, nominal (temporary) accounts—Revenues and Expenses—must be zeroed out, and the resulting Net Profit or Loss transferred into the Retained Earnings equity account on the Balance Sheet.

The ium()->accounting()->closing() service automates this sequence:

flowchart LR
    A["Nominal Revenue Accounts<br/>(Credit Balance)"] -->|Debit to Zero| C["Year-End Closing Journal Entry"]
    B["Nominal Expense Accounts<br/>(Debit Balance)"] -->|Credit to Zero| C
    C -->|Net Profit/Loss Rollover| D["Retained Earnings (Equity)<br/>Account 3100"]

Executing the Year-End Close

use Obelaw\Ium\Accounting\Data\FiscalYearCloseDto;

$closeResult = ium()->accounting()->closing()->closeFiscalYear(
    new FiscalYearCloseDto(
        fiscalYearId: $fiscalYearId,
        actorId: $cfoUserId,
        retainedEarningsAccountCode: '3100', // Retained Earnings
        closingDate: '2026-12-31',
        memo: 'FY-2026 Statutory Annual Books Closure'
    )
);

echo "Closed Year: {$closeResult->fiscalYear->name}\n";
echo "Closing Voucher ID: {$closeResult->closingJournalEntry->id}\n";
echo "Net Income Rolled Over: {$closeResult->netIncomeMajor}\n";

Guarantees Enforced During Year-End Closing

  1. Prior Periods Verification: Verifies that all 12 prior monthly periods are already CLOSED.
  2. Atomic Voucher Creation: Generates a zero-sum JournalEntryType::Closing voucher that zeroes every nominal account.
  3. Immutability Seal: Seals the FiscalYear record with is_closed = true.
  4. Append-Only Audit: An immutable audit entry is appended with the calculation breakdown.