> ## Documentation Index
> Fetch the complete documentation index at: https://docs.alforse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Period close

> Locking and closing a fiscal period: the close checklist, what a locked period stops, and how to reopen.

An accounting period is a calendar month assigned to transactions by posting date. Closing a period prevents further postings and snapshots its balances for reporting. Alforse uses a three-state lifecycle and requires the close checklist to pass before closure.

## The close lifecycle

A period's **close status** (`periodCloseStatus`) advances in one direction unless explicitly reopened. It is independent of the legacy `Active`/`Inactive` flag, which marks the current period for lazy auto-creation.

<details>
  <summary>**Open**</summary>

  Postings land freely. Operational documents (receipts, shipments, invoices, payments) and journals both post by their date.
</details>

<details open>
  <summary>**Locked**</summary>

  Operational postings are refused; accounting adjustments can still be posted. The staging state you review in before finalizing.
</details>

<details>
  <summary>**Closed**</summary>

  The month is final. Nothing enters, leaves, or changes. Balances are snapshotted. Reopen to post again.
</details>

A period must be **Locked before it can be Closed** — closing an Open period is refused with *"Period must be locked before closing."* The transitions live in `accounting.service.ts` (lock, unlock, close and reopen of an accounting period), each rejecting a move from the wrong starting state, and a database trigger (`enforce_financial_period_lifecycle`) enforces the same order underneath.

NOTE

**Locking is stricter than closing for one specific thing**

A **Locked** period still accepts *accounting adjustments* — a manual journal posted with an accounting-adjustment intent goes through. It only blocks *operational* documents. A **Closed** period blocks everything, including reversals into it. Lock when operations are done for the month but the accountants aren't; close when the books are final.

## What a locked or closed period stops

The gate lives in the accounting service's period lookup, which every posting path calls before it writes:

FieldType

<details>
  <summary>**Closed**</summary>

  Any posting is refused with *"Accounting period is closed. Reopen it before posting."* — operational documents and adjustments alike.
</details>

<details>
  <summary>**Locked**</summary>

  Operational documents are refused with *"Accounting period is locked. Post as an accounting adjustment or unlock the period first."* Accounting adjustments pass.
</details>

<details>
  <summary>**Open**</summary>

  Everything posts normally.
</details>

Database triggers are the hard backstop underneath the service check: `protect_closed_period_document_date` rejects dating an unposted invoice or payment into a **Closed** period, `protect_finalized_journal_period` keeps a period's range from changing under posted journals, and the period-control rules refuse to delete or move a journal out of a Closed period (*"Cannot delete journal …: accounting period is closed"*). Locked semantics need actor identity, so they are enforced at the service layer.

## The close checklist

Closing runs through a persisted checklist — a company-level template of task definitions (`periodCloseTaskDefinition`) plus per-period instances (`periodCloseTask`) materialized the first time you open a period's close screen. Nine system tasks seed with every company (they can be deactivated but never deleted). Each task has a **type** (`Auto` or `Action`; custom tasks can also be `Manual`) and Auto tasks carry a **severity**.

FieldType

<details>
  <summary>**Auto**`Task type`</summary>

  A readiness evaluator the system runs live — the task shows Done when the check passes, Open when it fails. You don't tick these; they reflect real state.
</details>

<details>
  <summary>**Action**`Task type`</summary>

  A step you complete yourself. "Lock the period" is an Action task whose button drives the Open→Locked flip, and its Done state is read from the period's close status, not a stored tick. The others ("Review negative on-hand inventory", "Review financial statements") are sign-offs you mark Done.
</details>

<details>
  <summary>**Manual**`Task type`</summary>

  A custom human sign-off you mark Done yourself.
</details>

Auto tasks fail *closed*: an Auto task whose evaluator can't be found is treated as failing, not silently passed, so the close stays gated and the reason stays visible.

### Severities gate differently

An Auto task's **severity** (`periodCloseTaskSeverity`) decides whether a failing check blocks the close or merely warns:

FieldType

<details>
  <summary>**Blocker**</summary>

  A failing Blocker check hard-stops the close. You cannot close the period until it passes (or the task is skipped, which Blockers disallow).
</details>

<details>
  <summary>**Warning**</summary>

  A failing Warning check surfaces the issue but doesn't stop the close. You can proceed, or skip the task with a reason.
</details>

The seeded Auto checks, from `computePeriodReadiness`:

| Check | Severity | Fails when |
| - | - | - |
| Post pending operational documents | Blocker | Un-posted receipts/shipments/invoices dated in this period exist. |
| Post or re-date draft journal entries | Blocker | Draft journal entries are dated in this period. |
| Trial balance in balance for the period | Blocker | Any posted journal has unequal debits and credits. |
| External GL sync complete | Blocker | A journal posted in the period has not been delivered to a connected accounting system. It passes when no accounting integration is active. |
| Post depreciation runs covering the period | Warning | A depreciation run would depreciate for this period, or a draft run ends in it. |
| Match & eliminate intercompany transactions | Warning | Unmatched intercompany transactions involve this company. |

The other three seeded tasks are Actions: **Lock the period**, **Review negative on-hand inventory**, and **Review financial statements**. There is no separate "Close the period" task; closing is the button once the checklist passes.

### Completing and skipping tasks

An `Action`/`Manual` task is marked Done with the `completeTask` intent (optional notes). Any non-Blocker task can be skipped with the `skipTask` intent, which **always requires a non-empty reason** — and the service additionally refuses to skip a **Blocker** task. Auto tasks are never manually completed; their state is derived from the live readiness check every time the checklist loads.

The close itself (`closePeriodWithChecklist`) re-evaluates the whole checklist server-side. It refuses to close unless **every required task resolves to Done or Skipped and no Blocker check is failing**, surfacing the specific blocking task in the error. Never trust a disabled button: the gate is enforced on the server, and the lifecycle trigger is the final backstop.

HEADS UP

**Sequential close and reopen**

Periods close and reopen in order. Closing refuses if any **earlier** period isn't Closed (*"Earlier periods must be closed first"*). Reopening refuses if any **later** period is still Closed (*"Later periods must be reopened first"*) — you reopen from the most recent close backwards.

## Reopening

Reopening flips a **Closed** period back to **Open**, recording a reason with the same command, clears its `closedAt`/`closedBy`, and deletes the balance snapshots the close wrote (its own and any later snapshot that embedded it, since snapshots are cumulative through their period's end date). After reopening, postings into the month resume and the balance reads fall back to a full-history scan until the period is closed again. A period that isn't Closed can't be reopened (*"Period is not closed"*).

Unlocking is the milder inverse: it moves **Locked** back to **Open** so operational documents can post again, clearing `lockedAt`/`lockedBy`. It is refused while the period still has active close evidence. It writes no snapshots and touches no balances.

## Fiscal periods and the calendar

Periods are generated per **fiscal year** — twelve monthly periods from the company's fiscal start month, via `createFiscalYearPeriods` (idempotent; it skips any period number already present). Each period carries a `fiscalYear` and `periodNumber` derived from that start month: a fiscal year is named for the calendar year it *ends* in, so a July-start FY beginning in 2025 is FY2026.

Once the calendar is **committed** — any posting exists, or any period is Locked/Closed — the fiscal start month locks (`getFiscalCalendarCommitted`), because re-labeling already-reported periods would rewrite history. An empty, Open period can still be deleted (`deleteAccountingPeriod`) and regenerated; a period with journals posted to it, or in any non-Open state, cannot.

## Related

**Accounting & the ledger**

Accounts, journals, dimensions, and the postings every flow produces.

[Open](/docs/reference/accounting.md)

**Invoices**

Where sales and purchase invoice postings come from — the operational documents a close gates.

[Open](/docs/reference/invoices.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.