# Periods & the close

> The month-end close in accounting software: fiscal calendars, period states, cutoff, reconciliation vs tie-out, adjusting entries and restatement.

Source: https://lopifi.com/docs/domain/02-periods-and-close
Part of: Lopifi — US GAAP books on autopilot, reviewed by a CPA (https://lopifi.com)

---

# Periods & the close

<!-- description: The month-end close in accounting software: fiscal calendars, period states, cutoff, reconciliation vs tie-out, adjusting entries and restatement. -->

The month-end close is the central workflow of accounting software. It is also the workflow that generic dashboard components cannot express at all, because it depends on a concept they don't have: **a period has a state, and that state governs what the UI may offer.**

---

## 1. Fiscal calendars

```ts
type FiscalCalendar = {
  /** 1–12. A June year-end means fiscalYearStartMonth = 7. */
  fiscalYearStartMonth: number;
  /** How periods are cut. */
  type: "calendar" | "4-4-5" | "4-5-4" | "5-4-4" | "13-period";
  /** Which calendar year labels the FY. A FY starting Jul 2026 may be "FY26" or "FY27". */
  yearLabelConvention: "start" | "end";
  /** Some entities run a 53-week year periodically. */
  weekAlignedYearEnd?: boolean;
};
```

**Never assume January.** This is the most common fiscal bug in finance UI, and it is silent — a Q1 label that means Jan–Mar for an entity whose Q1 is Jul–Sep produces confident, wrong analysis.

**Retail calendars (4-4-5 and friends) are not exotic.** They make every "month" a whole number of weeks so week-over-week comparison works. Consequences:
- A "month" is 28 or 35 days, not a calendar month.
- Period boundaries fall mid-calendar-month.
- Every 5–6 years there is a 53rd week, and the extra week distorts every year-over-year comparison in that year. **Flag it** — a component that shows `+8.4% YoY` in a 53-week year without a note is misleading.

**UI rules:**
- `PeriodPicker` renders the fiscal label **and** the resolved dates, always: `FY26 Q1 (1 Jul – 30 Sep 2026)`.
- Never render a bare `Q1`, `Sep`, or `Last quarter`.
- Comparative columns state their own resolved period; the header never says "Prior".

---

## 2. Period states

A period is not just a date range. It is a state machine, and the state determines the available actions.

```
┌──────────┐   ┌─────────────┐   ┌────────────┐   ┌────────┐   ┌───────┐
│  future  │ → │    open     │ → │ soft close │ → │ closed │ → │ filed │
└──────────┘   └─────────────┘   └────────────┘   └────────┘   └───────┘
                      ↑                                │
                      └────── reopen (approval) ───────┘
```

| State | Posting | Who can post | UI treatment |
|---|---|---|---|
| **future** | Blocked | — | Greyed in every picker; selecting it explains why |
| **open** | Free | Anyone with the role | Normal |
| **soft close** | Adjusting entries only | Controller and above | Amber banner; the entry form defaults to `adjusting` |
| **closed** | **Blocked** | Nobody without a reopen | Lock glyph; statements marked final |
| **filed** | **Blocked** | Nobody. Never reopened; corrections go through restatement, revision or a current-period adjustment. | Lock + "Filed" badge; restatement workflow only |

### The `PeriodStatus` banner
Every surface scoped to a period displays its state. This is not decoration — it is the answer to "why can't I post this?", asked before the user has to ask.

```
🔒  September 2026 · Closed 4 Oct 2026 by A. Rivera
    Entries dated in this period must be posted to October and will
    be flagged for cutoff review.                        [Request reopen]
```

Three things in that banner: the state, the provenance (who and when), and **the next action**. A lock icon alone is a dead end.

### Reopening
- Requires an approval from a role that did not request it.
- Writes to the audit trail with a mandatory reason.
- **Invalidates every statement generated from that period.** Any export or saved report carrying that period is marked stale, because a PDF someone emailed to a lender is now wrong.
- The UI states the blast radius before confirming: "Reopening September will mark 4 published statements as superseded."

---

## 3. Cutoff

Cutoff is the boundary problem: a transaction dated in one period, entered in another. Getting cutoff wrong shifts revenue or expense between periods, which is the most common form of unintentional misstatement.

**The `CutoffWarning` component fires when:**
- An entry's transaction date falls in a closed or soft-closed period.
- An entry's date is within N days of a period boundary (configurable, default 5) and the period is in close.
- A bank transaction settles in one period but was initiated in another.
- An invoice dated in the prior period arrives after close.

The warning is **inline at the date field**, not a toast, and it states the consequence:

> This is dated 29 Sep, which is in a closed period. It will post to October. If it belongs in September, request a reopen, or record it in October as an out-of-period adjustment.

That last clause is the useful part: it names the two legitimate remedies rather than just blocking.

---

## 4. The close pipeline

Lopifi models the close as a sequence of gated sections. This structure comes from how closes are actually run, and it drives `CloseChecklist`, `CloseStatus`, and the dashboard.

| # | Section | Gate — what "done" means |
|---|---|---|
| 1 | **Cutoff & capture** | All source documents in; AP and AR cutoff tested |
| 2 | **Cash** | Every bank and card account reconciled; exceptions explained |
| 3 | **Subledgers** | AR and AP agree to the GL control accounts |
| 4 | **Schedules** | Prepaids, accruals, deferred revenue, fixed assets rolled forward and tied |
| 5 | **Adjusting entries** | Accruals, depreciation, amortization, provisions, reclasses posted |
| 6 | **Balance sheet tie-out** | Every BS account supported by a schedule or reconciliation |
| 7 | **Review & flux** | Material variances explained; statements reviewed and signed off |

**Rules:**
- **Sections gate in order.** You cannot tie out the balance sheet before the schedules are rolled. The UI shows downstream sections as blocked, with the blocker named.
- **Every check has an owner, a due date, and a state**: `not started` → `in progress` → `blocked` → `done` → `reviewed`.
- **A blocked item names its blocker and who owns it.** "Blocked: waiting on Sep bank statement — Treasury."
- **Sign-off is irreversible and audited.** It uses `HoldToConfirm` and writes who, when, and on what version of the numbers.
- **The close percentage is by weighted check, not by count.** Ten trivial checks and one bank rec is not 91% done.

---

## 5. Reconciliation vs tie-out

Two different controls, constantly conflated, and each has its own component.

| | **Bank reconciliation** | **Balance sheet tie-out** |
|---|---|---|
| Question | Does our cash record match the bank's? | Is this balance supported by evidence? |
| Compares | Book cash vs. bank statement | GL balance vs. a supporting schedule |
| Output | Reconciling items (timing differences) | A walk-down with a difference of zero or an explanation |
| Component | `ReconciliationView` | `AccountTieOut` |
| Applies to | Cash and card accounts | **Every balance sheet account** |

### The bank reconciliation summary
The standard form, and the component renders exactly this:

```
  Bank statement balance                    412,880.14
  Add: deposits in transit                    8,420.00
  Less: outstanding checks                  (22,140.55)
  Add/less: other reconciling items               0.00
                                           ────────────
  Adjusted bank balance                     399,159.59
  Book (GL) balance                         399,159.59
                                           ════════════
  Difference                                      0.00   ✓
```

**The difference line is the whole component.** It is always visible, never scrolls away, and it is the number the user is working to zero. When it is non-zero, that is the primary state of the screen.

### The tie-out walk-down
```
  1310 · Prepaid expenses
  GL balance at 30 Sep 2026                  84,220.00
  Supporting schedule closing balance         84,220.00
                                           ────────────
  Difference                                       0.00   ✓  Tied
  Supported by: Prepaid schedule (14 items) · reviewed A. Rivera 3 Oct
```

Every balance sheet account gets one. An account with no supporting evidence is itself a finding — `AccountTieOut` renders an explicit "Unsupported" state rather than showing nothing.

---

## 6. Reconciling items and exceptions

A reconciling item is a legitimate timing difference. An exception is a break that needs work. The UI must not conflate them.

| Kind | Meaning | Aging behavior |
|---|---|---|
| **Deposit in transit** | Booked, not yet on the bank statement | Should clear next period; flag if > 5 days |
| **Outstanding check** | Issued, not yet cashed | Flag if > 90 days; stale-dated after six months (a bank may refuse it, UCC §4-404). Still a liability — void and reissue, or escheat under state unclaimed-property law after the dormancy period. Never write it back to income |
| **Bank-only item** | Fee, interest, NSF the bank booked and we didn't | **Requires a journal entry.** Should never age. |
| **Book-only item** | We booked something the bank has no record of | Investigate immediately |
| **Unmatched** | No counterpart found | The actual exception |

**Aging is the priority signal.** A 3-day-old outstanding check is normal; a 200-day-old one is a control finding. `ReconciliationView` sorts exceptions by age descending by default, not by amount — old breaks are what auditors find.

---

## 7. Adjusting entries

The entries that make accrual accounting work. Each has a distinct shape, and `AdjustingEntryForm` offers them as templates rather than a blank journal entry.

| Type | Pattern | Auto-reverses? |
|---|---|---|
| **Accrual** | Dr Expense / Cr Accrued liability | **Yes** — day 1 of next period |
| **Deferral** | Dr Prepaid asset / Cr Expense | No — released by schedule |
| **Depreciation** | Dr Depreciation expense / Cr Accumulated depreciation | No |
| **Amortization** | Dr Amortization expense / Cr Accumulated amortization | No |
| **Revenue recognition** | Dr Deferred revenue / Cr Revenue | No — released by schedule |
| **Provision / allowance** | Dr Bad debt expense / Cr Allowance | No — trued up each period |
| **Reclassification** | Dr Account A / Cr Account B | Sometimes |
| **True-up** | Adjusts an estimate to actual | No |

**The auto-reversal rule is critical.** An accrual that doesn't reverse double-counts the expense when the actual invoice arrives and is coded to expense. `AdjustingEntryForm` **defaults `autoReverse` to true for accruals** and shows the reversal date inline: "Reverses 1 Oct 2026". Making the user remember this is how expenses get double-counted.

The reversal is created at posting time as a scheduled entry, visible in the next period before it posts — so a reviewer can see it coming.

---

## 8. Subsequent events

Events after the period end but before the statements are issued (or available to be issued, for an entity that is not an SEC filer). Two types, and the distinction has real consequences. ASC 855 calls them **recognized** and **nonrecognized** subsequent events; IAS 10 calls them **adjusting** and **non-adjusting**.

| | Type 1 — Adjusting | Type 2 — Non-adjusting |
|---|---|---|
| Condition | Existed at the balance sheet date | Arose after |
| Example | A customer whose finances were already deteriorating at 30 Sep files for bankruptcy in October; a lawsuit about a September incident settles | A fire destroys a warehouse in October; the company issues debt or equity, or acquires a business |
| Treatment | **Adjust the statements** (ASC 855-10-25-1) | **Disclose** the nature and an estimate of the effect, if material (ASC 855-10-25-3, -50-2) |

`SubsequentEventLog` captures these during the review window with the type, the date discovered, and the treatment decision. It matters because the same event handled the wrong way is a misstatement in one direction or an omitted disclosure in the other.

---

## 9. Restatement

When a closed and filed period is found to be materially wrong.

- A **restatement** ("Big R", ASC 250-10-45-23) is required when the error is material to the previously issued statements: they are reissued, the cumulative effect lands in opening retained earnings of the earliest period presented, and the error is disclosed.
- The prior period is **not silently edited**. A restatement entry is posted, and the comparative column is labeled **"Restated"** everywhere it appears.
- The UI never shows a restated comparative without the label. A prior-year column that quietly changed between two reports destroys trust faster than the original error.
- `StatementTable` supports a `restated` flag per period column, rendering the label in the header and a footnote naming the reason.
- Errors immaterial to the prior period but material if corrected now revise the comparatives, labeled **"As revised"**. Errors immaterial either way are corrected in the current period as an out-of-period adjustment. Materiality is assessed under both the rollover and iron-curtain approaches (SEC SAB No. 108), quantitatively and qualitatively (SAB No. 99). The materiality policy decides which, and the decision is recorded.

---

## 10. Period-scoped UI rules

Applying across every component:

1. **Every figure declares its period.** No exceptions.
2. **Every period label shows resolved dates.**
3. **Every period-scoped surface shows the period's state.**
4. **A closed period's numbers cannot change**, so any UI affordance implying they can is removed, not disabled.
5. **Comparatives are on the same basis, same framework, same entity set, and same currency.** Mixing is blocked at the type level, not warned about at render time.
6. **A statement generated from a period that later reopens is marked superseded**, wherever it was saved or exported.
