# PeriodClose

## Description

PeriodClose is a checklist-driven workflow entity that tracks the process of transitioning an accounting period from open to permanently closed. Each close operation is scoped to a single AccountingPeriod and follows a deterministic sequence of steps: initiation, subledger transfer verification, adjusting entry posting, trial balance verification, preliminary statement generation, review and approval, soft lock, and final permanent close. The entity records the initiating user, completion percentage, and current status. For the final period of a fiscal year, the close process extends to include year-end close steps (closing temporary accounts to retained earnings and generating opening balances for the new fiscal year).

## Domain Model Definitions

### Model type

Stateful

#### State Transitions

```mermaid
stateDiagram-v2
    [*] --> NotStarted: initiatePeriodClose
    NotStarted --> InProgress: beginClose
    InProgress --> SubledgersVerified: verifySubledgerTransfers
    SubledgersVerified --> AdjustmentsPosted: postAdjustingEntries
    AdjustmentsPosted --> TrialBalanceVerified: verifyTrialBalance
    TrialBalanceVerified --> UnderReview: generatePreliminaryStatements
    UnderReview --> SoftLocked: approveAndLockPeriod
    SoftLocked --> InProgress: revertSoftLock
    SoftLocked --> PermanentlyClosed: finalCloseAndLockPeriod
    PermanentlyClosed --> [*]
```

### Command Definitions

- [initiatePeriodClose](../commands/InitiatePeriodClose.md) - Initiate the period close process for an accounting period
- [beginClose](../commands/BeginClose.md) - Begin the close checklist, transitioning from NOT_STARTED to IN_PROGRESS
- [verifySubledgerTransfers](../commands/VerifySubledgerTransfers.md) - Verify all subledger modules have transferred transactions to GL
- [postAdjustingEntries](../commands/PostAdjustingEntries.md) - Confirm adjusting entries (accruals, deferrals, reclassifications) are posted
- [verifyTrialBalance](../commands/VerifyTrialBalance.md) - Verify the period's trial balance is balanced
- [generatePreliminaryStatements](../commands/GeneratePreliminaryStatements.md) - Generate preliminary financial statements for review
- [approveAndLockPeriod](../commands/ApproveAndLockPeriod.md) - Approve and soft-lock the period
- [revertSoftLock](../commands/RevertSoftLock.md) - Revert a soft-locked period back to IN_PROGRESS
- [finalCloseAndLockPeriod](../commands/FinalCloseAndLockPeriod.md) - Permanently close the period (irreversible)
- [executeYearEndClose](../commands/ExecuteYearEndClose.md) - Execute year-end close: close temporary accounts to retained earnings and generate opening balances

### Query Definitions

- [GetPeriodClose](../queries/GetPeriodClose.md) - Retrieve the period close record for an accounting period
- [ListPeriodCloses](../queries/ListPeriodCloses.md) - List period close records for a fiscal year or company with optional status filter
- [GetSubledgerTransferStatus](../queries/GetSubledgerTransferStatus.md) - Retrieve subledger transfer completeness status for an accounting period

### Models

- PeriodClose

### Invariants

- PeriodClose can only be initiated for an AccountingPeriod that is in OPEN status
- PeriodClose cannot be initiated for a period that already has an active close in progress
- PeriodClose lifecycle follows NOT_STARTED → IN_PROGRESS → SUBLEDGERS_VERIFIED → ADJUSTMENTS_POSTED → TRIAL_BALANCE_VERIFIED → UNDER_REVIEW → SOFT_LOCKED → PERMANENTLY_CLOSED
- PeriodClose cannot skip steps; each transition requires the previous step to be completed
- Subledger verification fails if any registered subledger module has pending unposted transactions for the period
- Trial balance verification fails if the period's trial balance has a non-zero difference between total debits and credits
- Approval step requires a user with the appropriate authorization role (controller or finance manager)
- Soft-locking prevents the accounting team from posting new journal entries to the period
- Soft-locked period still allows postings from users with the advisor/auditor role
- Permanently closing a period makes it fully immutable; no further journal entries can be posted regardless of role
- Reverting a soft-locked period to IN_PROGRESS is permitted only before permanent close
- Reverting a permanently closed period is not permitted
- Each period has at most one active PeriodClose record
- Concurrent close attempts for the same period are rejected with a conflict error
- Year-end close can only be initiated for the final period of a fiscal year
- Year-end close requires the standard close checklist to be completed through the soft-lock stage
- Year-end close generates a closing journal entry zeroing temporary accounts to retained earnings
- Year-end close generates opening balance entries for the first period of the new fiscal year
- Year-end close fails if no retained earnings account exists in the active CoA
- Year-end close cannot be run twice for the same fiscal year
- PeriodClose tracks a completionPercentage that increments as each checklist step is completed
- PeriodClose records the userId of the operator who initiated the close and the userId who completed each checklist step
- Each state transition emits an audit event recording the acting user, timestamp, previous status, and new status

### Relationships

- **References AccountingPeriod**: Each PeriodClose is linked to an AccountingPeriod via accountingPeriodId
- **References FiscalYear**: The associated AccountingPeriod's fiscal year determines year-end close eligibility (via AccountingPeriod.fiscalYearId)
- **References User**: Records the initiating user via initiatedByUserId (user-management module)
- **References Account (retained earnings)**: Year-end close references the retained earnings account from the active CoA for closing temporary accounts
