Year-end close
A fiscal year is closed by one entry of source close per entity and year: every profit and loss
account with a balance is brought to zero against the account with the role annual_result (2979
Jahresgewinn oder Jahresverlust in the Swiss template, 3199 in the generic one). The books then continue
into the next year with the balance sheet as it was. What the general meeting decides about the result
is a second, later entry (source appropriation). The design is
ADR-0023; the controls are in the
control matrix (section "Year-end close", YC1 to YC9).
Everything below is a REST operation first (/v1, tag "year-end close" in the
generated reference); the web UI (Finance → Period close → Year-end) and
the MCP read tools call the same operations. The screen reads the year close
(GET .../fiscal-years/{year}/close) only for a year whose fiscal year lists a close: a year never
proposed is an empty state, not a 404 on every load.
What closing does
| Before | After | |
|---|---|---|
| Profit and loss accounts (3xxx to 8xxx) | the year's flows | zero |
annual_result (2979) |
nothing | the result of the year (credit for a profit, debit for a loss) |
| Balance sheet totals | assets = liabilities + equity + unclosed earnings | the same totals; the unclosed earnings are now in 2979 |
| Reports | profit and loss, period profit and loss and the analytics leave out source close, so the year's income statement is what it was before the close; the trial balance and the general ledger show the closing lines (closing: true on a ledger line), and closing=exclude / include_close=false give the pre-closing view |
Nothing is posted at the start of the new year. The opening balances of a year are the closing
balance sheet of the year before, account by account
(GET /v1/entities/{entity}/fiscal-years/{year}/opening-balances).
The entry is dated the last day of the year and posted in the year's last adjustment period when it has
any, else in its last regular period; that period must be open. An entity needs an account with the role
annual_result (both chart templates have one; otherwise 409 role_missing says how: creating the account with the role,
POST /v1/entities/{entity}/accounts, takes one person; giving the role to an existing account, PATCH,
is a change of a required role and needs a second person. The preview shows the chart template's code in
result_account_suggestion: 2979 or 3199).
The proposal, the lock and the approval
GET .../fiscal-years/{year}/close-previewshows what would be posted and what stands in the way (blockers): a draft journal entry, an entry or a document waiting for approval dated in the year, a last period that is not open, a missing annual-result account, a year that is already held, and a period-end run of the year's last regular period that is due and not done (depreciation, FX revaluation, deferred tax: the message names the run and its operation; the closing entry locks the year, so a run left for later could only be done after a reopening). It stores nothing, so an agent may call it.POST .../fiscal-years/{year}/close(a person; the policy actionclose_fiscal_yeardenies agents) refuses with409 year_close_blockedwhile anything stands in the way and otherwise writes the entry and afiscal_year_closerowpending. From that moment the year is locked: no other entry is posted into the fiscal year, whatever its source, until the close is approved, cancelled or reopened. The application says why (409, "fiscal year 2026 of CH01 is being closed"); a database trigger refuses it even if the application is bypassed.- By default a second person approves the entry
(
POST /v1/approvals/{approval_id}/approve; ruleclose_entries_need_a_second_person, which a one-person organization turns intoallowfor the sourcescloseandappropriationin its approval policy). At approval the account totals are computed again and compared with a digest kept at the proposal: a difference is409 year_changedand nothing changes, so a closing entry never posts over figures it was not made from. Proposals are serialised on the entity: a second one, simultaneous or later, gets409 year_close_blocked("already has a year close"), never a database error. A proposal locks the entity's chain sequence as every posting does, so a posting in flight finishes first and the totals read next include it, and it reads the totals once: the closing lines and the digest come from the same read. While a proposal waits for approval the close checklist fails the checkyear_closeon the period the entry is posted in, so that period is not closed under it. POST .../close/cancel(a person, with a reason) withdraws a pending proposal: its approval and its entry are rejected and the lock is lifted. A rejected approval does the same. A closed year is not cancelled but reopened.
Reopening
POST .../fiscal-years/{year}/reopen-close (a person with the approve scope, a reason) is the
decision to reopen. It reopens the period that holds the closing entry, reverses the closing entry
itself (same date and period), and sets the close reopened. The reversal needs no second
approval: the decision covers it, like the decision on an accrual covers its automatic reversal.
Afterwards periods reopen as usual and the year can be closed again (a new close; both are kept).
- A period of a closed year is reopened only this way (
POST /v1/periods/{id}/reopenanswers409while the close stands). - A year whose result is appropriated, or has an appropriation waiting for approval, is reopened after the appropriations are reversed.
- The closing entry is reversed by this operation and by no other: the generic reversal of a journal
entry does not accept a closing or appropriation entry (
tests/architecturepins who may call the reversal engine).
Appropriating the result
POST /v1/entities/{entity}/appropriations books the shareholders' resolution as one entry dated the
day of the resolution (a dividend is a liability only from then, IAS 10.12-13): for a profit
Dr annual_result / Cr the destinations, for a loss the mirror image. Destinations:
retained_earnings (the account defaults to the one with that role), legal_profit_reserve,
voluntary_reserve (equity accounts you name), dividend_payable (a liability account you name,
for a profit only; a loss is carried forward or covered from reserves) and group_dividend (a dividend
to a shareholder that is another entity of the organization: the line goes to ic_other_payable, and
the posting drafts the shareholder's entry, intercompany; such an
appropriation is not reversed). The year must be closed. A
second person approves it by default. The resolution date must fall in a fiscal year that no close
holds: a date in a year that is closed or being closed (the next year may already be closed), or before a
catch-up that stands, is refused at the request by name, so nobody is asked to approve what the lock would
refuse; reopen that year first or date the resolution in an open one.
- The remainder is tracked.
fiscal_year_close.appropriatedis kept by a database trigger on the append-onlyappropriationtable, which also refuses an appropriation beyond what is left; a partial resolution leaves the rest visible (remainder). The application refuses it first, by name (409 appropriation_exceeds_remainder, counting resolutions that wait for approval). For a loss theremainderis negative (what is left to cover), and the destinations' amounts are positive: the amounts that cover it. The screen says so: "Loss still to cover: -2,000.00 CHF", and "Covered" for the total typed, where a profit has its "remainder". - A resolution is withdrawn by a reversal of its own
(
POST .../appropriations/{id}/reverse): the opposite entry through the same approval, a row with the opposite sign. - Swiss entities get
warningsandwithholding_tax: 5 % of the annual profit, after a loss carried forward (a debit balance of retained earnings) is eliminated, must go to the legal profit reserve (Art. 672 para. 1 OR; the system does not know the share capital, so it only warns), and a dividend bears 35 % withholding tax (Verrechnungssteuer, below). No other jurisdiction has a rule until one is cited.
Withholding tax on a Swiss dividend
A Swiss company deducts 35 % from the dividend it pays (Art. 4 para. 1 lit. b, Art. 13 para. 1 lit. a,
Art. 14 para. 1 VStG) and pays it to the Federal Tax Administration within 30 days of the claim arising,
which is when the dividend falls due (Art. 12 para. 1, Art. 16 para. 1 lit. c VStG). A destination of kind
dividend_payable or group_dividend says how with withholding_tax:
withholding_tax |
Entry at the resolution date | When |
|---|---|---|
deduct |
Dr annual result (gross) / Cr the destination (65 %) / Cr withholding_tax_payable (35 %) |
the normal case |
notification |
Dr annual result / Cr the destination (gross), nothing withheld | a group dividend to a Swiss shareholder that may report instead of paying (Art. 26a VStV); refused otherwise |
| not set | as before: the gross dividend, and a warning that names the 35 % and the 30 days | to book the tax by hand |
The answer carries withholding_tax (the amount) and withholding_tax_due (the resolution date plus 30
days; the system assumes the dividend falls due on the day of the resolution, and a later due date in the
resolution moves the deadline with it). The tax is paid like any other liability: the bank line of the
payment is posted to the account with the role withholding_tax_payable (POST /v1/bank-lines/{id}/post).
The close check withholding_tax_due (order 180, a warning) names the amount still owed past its due
date at the period's end. The notification procedure needs a participation of at least 10 % and the
notification form; the system does not know the participation, so it states the condition
in a warning and does not check it. A group shareholder's side holds the net dividend as a receivable and
the 35 % as a claim on the tax administration (withholding_tax_receivable, recovered by the shareholder's
refund application, Art. 29 VStG); see intercompany. The
roles are optional: ch_kmu 2206 and 1176 Verrechnungssteuer, the generic chart 2230 and 1410
(409 role_missing names them for an existing entity). Foreign recipients and treaty refunds are not
built.
- The general meeting is due six months after the year end (Art. 699 para. 2 OR). A Swiss entity's
closed year with a remainder after that day is
appropriation_overdue; the close checklist warns in every later period (appropriation_pending),GET .../fiscal-years?unappropriated=truelists the years, and the Role Center shows the count as a cue that opens Period close.
Catching up
An entity that has been posting for years has profit and loss accounts that accumulate over all of
them. POST /v1/entities/{entity}/year-close/catch-up with first_clean_year posts one entry
(source close) dated the first day of that year, in its first period (which must be open:
409 catch_up_period_not_open names it): the balance of every profit and loss account of everything
before that date is brought to zero against retained_earnings, the earlier results being treated as
carried forward (the system does not know the resolutions of those years). The most recent year
before may still be waiting for its general meeting: leave_latest_year_unappropriated (default: true when
that year ended less than six months before) puts its result on annual_result instead, with a
catch_up close of its own, so appropriation tracking and the six-month warning apply to it. The
same lock, digest, approval and cancellation apply, and it is refused (409 year_close_blocked) while any
earlier period is open. While it stands, waiting or posted, no entry is dated before its date and no
period ending before it is reopened. The years carried forward share one close,
filed under the latest of them; their periods are normally closed already, and the lock holds that year.
Permissions
| Operation | Needs | Policy action |
|---|---|---|
| preview, get, opening balances, list | read |
none |
| propose, cancel, catch-up, appropriate, reverse an appropriation | draft (a person) |
close_fiscal_year, denied to agents |
| approve the entry | approve, another person than the proposer |
approve |
| reopen | approve (a person) |
reopen_period, denied to agents |
MCP tools (read only): year_close_preview, year_close_status, opening_balances,
list_appropriations, unappropriated_years.
Not built (yet)
- A dividend to a group shareholder (an intercompany receivable) waits for intercompany (ADR-0025).
- The withholding tax of a foreign shareholder (a treaty rate, a refund) and the notification procedure's Form 106 itself.
- Interim dividends and the Bilanzgewinn presentation of § 268 HGB.