StabisoDocs

Accounting and finance

Consolidation

A group of entities reports as one: the parent and its subsidiaries, each in its own currency and books, are translated into the presentation currency, added up, and what they owe and sell each other is eliminated. The design is ADR-0026; the controls are in the control matrix (section "Consolidation", CN1 to CN14).

Slices 1 to 3 of four are built (slice 3 without the opening position of an existing group). What exists:

  • the group structure: groups, member versions, and their approval by a second person;
  • the framework data (ifrs, fer, hgb) with the verification gate: all three run, each rule cited from its standard (Swiss GAAP FER and HGB since 2026-10-12, ADR-0075);
  • rates from data-vNext (the ECB reference rates, and only those);
  • the translation to the reporting currency (IAS 21.39 to 21.41) and the roll-forward of the translation reserve that proves it;
  • aggregation by report line and the group balance sheet and profit and loss;
  • the intragroup eliminations of balances (E1), loans (E2), income and expense (E3) and dividends (E6), read from what the ledgers say about each other through the intercompany view (intercompany), with the exceptions when the two sides do not agree (slice 2, and E2 and E6 with intercompany slice 2);
  • the capital consolidation (slice 3, ADR-0051): the parent's investment against the subsidiary's equity at acquisition with goodwill or a bargain purchase or a negative difference as the framework treats it (E4), the non-controlling interests and their share of what the subsidiary earned since (E5), goodwill amortisation where the framework's policy requires it (E7), each entry with its basis;
  • the group close checklist (slice 2), which can now be ready.

What does not exist yet: the opening position of a member consolidated after its acquisition, purchase price allocation (fair-value adjustments), ownership changes and disposals (each a blocking exception, never a guess); manual adjustments, finalising a run, verify, the reopen guard and the worksheet export (slice 4).

Everything is a REST operation first (/v1, tag "consolidation" in the generated reference); the web UI (Finance, Consolidation) calls the same operations.

The group structure

POST /v1/consolidation-groups creates a group: a parent entity, the reporting currency and the framework. A human does it: the policy action approve_group_structure denies agents (403 policy_denied). The group is written once; a later change of parent, currency or framework is an approved structure change and belongs to a later slice. In this version the reporting currency is the parent's functional currency (the parent is carried over unchanged; translating the parent too needs a starting point it does not have). The group's code may be left out: it is then made from the name (Demo Group is DEMO-GROUP, -2 when taken), as the New group form does while you type; the form's Suggest with AI proposes the framework and the goodwill treatment, and saves nothing.

A subsidiary enters through a member version: POST /v1/consolidation-groups/{group}/members with the ownership share, the control assessment (IFRS 10.5 to 10.7, Art. 963 para. 2 OR: why the parent controls it, mandatory text), when control was acquired and from when the entity is consolidated.

  • By default the request waits for a second person, who sees in the approval's summary the group, its parent, framework and reporting currency, the subsidiary with its name and currency and the version as proposed (including the control assessment) (status: pending_approval, an approval request of the action approve_group_structure); POST /v1/approvals/{approval_id}/approve by a person with the approve scope who is not the requester writes the version. A one-person organization allows approve_group_structure in its approval policy; the version is then in force at once. A key the system issued belongs to no known person: it may request, never approve.
  • Versions are append-only and exist only once approved (group_member); a change is a new version (version 2, effective_from not before the one it replaces). A run takes the version in force at its date and records it.
  • A version can correct the one before it (ADR-0073; corrects_version on the version, shown on the structure screen and in the approval): a version that takes effect on the same date replaces the one before entirely (a share or a date typed wrong), and a version that keeps the share and the acquisition date but states other purchase data (cost, net assets at acquisition, investment account) replaces that data from the acquisition on, whatever date it takes effect from. So a subsidiary first approved without its purchase data is completed by asking for a new version with them. The corrected version stays in the history; a run records which version's purchase data it used (purchase_data_version). No correction once a final run used the version (409 member_version_closed).
  • The subsidiary's functional currency must be one the rate source publishes: otherwise 409 rate_source_missing names the currency, at the request and not at the first run.
  • Only direct subsidiaries of the parent are supported; the parent is not a member.

Frameworks and the verification gate

The framework is a choice of the group and it is data: seed/consolidation_frameworks.yaml holds the group's report-line vocabulary (with the labels of the statements in en, de, fr and it) and, per framework, the switches where frameworks differ (the goodwill policies, the useful life of goodwill, what a negative difference becomes, the presentation of the translation reserve, the statement set), every row with its source. The mechanics are the same for every framework.

A framework runs only when its sources have been read: verified: true needs verified_by, verified_on and sources_read, and no row may still say "to verify". A run under a framework that is not verified is refused (422 framework_unverified, "group statements under ... are not available yet: the rules of the standard have not been checked against its text"), one that is not built too (422 framework_not_implemented); nothing is stored. Today all three run:

ifrs fer (Swiss GAAP FER 30, 2022) hgb (§§ 290 to 315e HGB, DRS 23, DRS 25)
Goodwill policies (goodwill_policy) impairment_only offset_equity (default) or amortise amortise
Useful life (goodwill_years) none 1 to 20 years, 5 when left empty (30/16); also for offset_equity, for the notes 1 to 20 years, 10 when left empty (§ 253 para. 3)
A negative difference a gain (IFRS 3.34) offset against equity, or a liability released over five years (30/17) the "Unterschiedsbetrag aus der Kapitalkonsolidierung" after equity, kept, with a warning (§ 301 para. 3, § 309 para. 2)
Translation reserve other comprehensive income equity (30/24) "Eigenkapitaldifferenz aus Währungsumrechnung" (§ 308a)
Non-controlling interests proportionate share proportionate share (30/10) "Nicht beherrschende Anteile", their share of the equity (§ 307)

The translation is the same under all three (closing rate, historical rate for equity, monthly averages for the profit and loss: IAS 21.39 to 21.41, FER 30/24, § 308a HGB). The resolved switches and their sources, with who verified them, are copied into every run (policy), so a later change of the seed or of the group cannot reinterpret an old snapshot.

How the paragraphs were checked. The ifrs rows rest on the paragraph numbers of the ADR, checked by the project lead from knowledge on 2026-10-03. The fer and hgb rows were checked on 2026-10-12 by an AI assistant against search extracts of Swiss GAAP FER 30 (2022, free on fer.ch) and its summaries by PwC, KPMG and OBT, the statute at gesetze-im-internet.de and DRS 23 and 25; the full pages could not be opened from the build environment. No licensed or full text has been read by a person: the founder reads them before the first final run (backlog B-78).

What a run reads

POST /v1/consolidation-groups/{group}/runs with {"as_of": "2026-09-30"} (a month end, because the rates are calendar months) makes a draft run in one transaction and never edits an earlier one.

The ledger is read without the year-end closing entries (source close; ADR-0023), posted entries only, by entry date, whatever the entity's fiscal calendar. A closing entry would move the year's profit and loss into equity on one date and, translated at that date's rate, replace the monthly average rates of IAS 21.40. Without it the profit and loss accounts hold the cumulative result, which the translation splits by month. The appropriation of the result (source appropriation) is an ordinary equity movement and is read like any other. A ledger with and without the closing entries therefore gives the same inputs digest, statements and reserve (CN5).

The group year is the calendar year of the date: the profit and loss of a run is 1 January to its date, whatever fiscal year an entity keeps.

Rates: the ECB, and only the ECB

Rates are units of the reporting currency per unit of the entity's functional currency, from data-vNext's ECB reference rates: the month's closing rate (last fixing), the month's average (the mean of the fixings) and the ECB rate on a date. A rate data-vNext does not serve (a currency the ECB does not publish, a month with incomplete fixings or one that has not ended yet) is not invented and no manual rate is accepted: it is the blocking exception rate_missing (named by currency and month), the entity is left out of the run and the run says so. Every rate used is stored with its source, its fixing dates and the data-vNext dataset version, so the run can be checked against the same pinned data (GET /v1/consolidation-runs/{id}/rates).

Translation (IAS 21.39 to 21.41)

For a subsidiary with functional currency F, consolidated from the date T0, at the group date T:

Item Rate
Assets and liabilities at T closing rate of the month of T
Income and expenses of the group year each month's movement at that month's average rate, summed (IAS 21.40)
Equity at T0 the ECB rate on T0 (the historical rate)
Equity movements after T0 (a contribution, a dividend, an appropriation) the ECB rate on the entry date
Results of earlier years, and what was earned before T0 one line: the result at T0 at the historical rate and each later month at its average rate
Translation reserve (bs.equity.cta) the balancing amount of the translated trial balance (IAS 21.41)

Every translated amount is rounded half-even to the minor unit of the reporting currency, so the translated trial balance balances exactly. An entity in the reporting currency (the parent, a CHF subsidiary) is carried over unchanged: no rates, no reserve. The reserve starts at zero at T0; an opening position with a carried reserve (an existing group) is a later slice.

The roll-forward proves the reserve

The reserve is not only a plug. For each subsidiary the run also computes

CTA(T) - CTA(T0) = NA(T0) x (R_T - R_T0) + sum over months of P x (R_T - A) + sum over equity movements of D x (R_T - R_k)

(NA net assets in F, P the profit of a month, A the month's average rate, R_T the closing rate, R_k the rate of an equity movement) and compares it with the plug (GET .../cta) exactly, with no tolerance. Each translated amount is rounded to the minor unit; the run keeps the sum of those rounding residuals (rounded less exact, signed like the amount: rounding) and the comparison is

plug - roll-forward (unrounded) - rounding = 0

to the last digit, in a Decimal context wide enough to hold every product (60 digits). A difference of one unit in the last place is not rounding but a defect, and is the blocking exception cta_unreconciled. The roll-forward's own terms are shown rounded for reading, so a displayed sum can differ from the displayed total by a cent; the check is made on the unrounded figures. In the worked example every product is exact, rounding is zero and the difference is zero.

The worked example (the ADR's numbers)

CH01 (CHF) is the parent; DE01 (EUR) holds EUR 1,000,000 of share capital since 1 January 2026 and earns EUR 120,000 over January to September (EUR 20,000 in each of three months, EUR 10,000 in each of six). EUR 1 = CHF 0.9400 on 2 January (T0), the closing rate of September is 0.9350 and every month's average is 0.9380. The parent holds CHF 2,000,000 of capital, CHF 800,000 invested in DE01 and CHF 50,000 of revenue.

DE01 EUR Rate CHF
Cash (asset) 1,120,000 0.9350 closing 1,047,200.00
Share capital (equity) 1,000,000 0.9400 historical 940,000.00
Revenue, year to date 120,000 0.9380 average, month by month 112,560.00
Translation reserve (balancing) -5,360.00
Roll-forward 1,000,000 x (0.9350 - 0.9400) + 120,000 x (0.9350 - 0.9380) -5,000.00 - 360.00 = -5,360.00

Group balance sheet before eliminations: cash 2,297,200.00 (1,250,000 + 1,047,200) and the investment 800,000.00 make assets 3,097,200.00; capital 2,940,000.00, translation reserve -5,360.00 and the result of the year 162,560.00 (112,560 + 50,000) make equity 3,097,200.00. The two entities hold nothing towards each other, so nothing is eliminated. The investment (800,000 in the parent's assets) and DE01's equity are both still in the totals: setting one against the other is the elimination of slice 3. tests/erp/features/consolidation/test_consolidation.py and tests/unit/test_consolidation_* run these numbers.

Aggregation and the statements

Each entity's translated trial balance is added line by line on account.report_line, the vocabulary the charts share (the lines of both chart templates, the generic "other" lines and the lines consolidation adds). The consolidated lines equal the sum of the translated trial balances, so the group trial balance balances. A line outside the vocabulary, or one whose kind (asset, liability, equity, revenue, expense) is not the kind of the account on it, is the blocking exception unmapped_report_line: it is still added, nothing is dropped.

GET .../balance-sheet and GET .../profit-and-loss are built from the stored lines of the run, never from the live ledger: assets, liabilities, equity (capital, retained earnings, the results of earlier years not yet appropriated, the translation reserve, the non-controlling interests) and the result of the year attributable to the owners of the parent; balanced says assets equal liabilities plus equity. The profit and loss's net_income is the group's result before its attribution, split into attributable_to_owners (the balance sheet's result) and attributable_to_nci. The translation reserve is labelled per framework (other comprehensive income under ifrs, equity under fer, "Eigenkapitaldifferenz aus Währungsumrechnung" under hgb). The statement of comprehensive income (.../oci) comes with the non-controlling interests.

Intragroup eliminations (E1, E2, E3, E6)

After the aggregation, a run reverses what the entities of the run hold towards each other (IFRS 10.B86(c); §§ 303 and 305 HGB). The partner is never typed: it is read from the view ic_journal_line, which resolves it from the line's group party (ADR-0025). The ledger is read as for the translation: posted entries by entry date, without the closing entries. A partner that is not in the run (not a member, or consolidated after the date) is external: nothing is eliminated.

Rule What is reversed At What is left over goes to
E1 intragroup balances each entity's balance on its group accounts (ic_ar_control, ic_ap_control, and ic_other_receivable, ic_other_payable: accrued interest and declared dividends) towards each partner the closing rate the entity was translated at sides that agree in the document currency: profit or loss (pl.financial.expense or .income): an exchange difference on an intragroup monetary item stays in consolidated profit or loss (IAS 21.45). It is what an entity that has not revalued its foreign-currency balance has not booked yet
E2 intragroup loans each entity's balance on its loan accounts (ic_loan_receivable, ic_loan_payable) towards each partner the closing rate as E1, profit or loss; for a loan that is part of the net investment (IAS 21.15) the translation reserve, and the exchange differences the entities' revaluations took to profit or loss on it in the group year move there too (IAS 21.32): the fx_unrealized line reversed at its month's average rate
E3 intragroup income and expense each revenue and expense line with a partner (interest included), in the group year and from the date both entities are consolidated (before that the partner was not in the group), month by month; FX results (fx_gain, fx_loss, fx_unrealized) are not intragroup income and stay (IAS 21.45); dividend income is E6 each month's average rate sides that agree in the document currency: the translation reserve (bs.equity.cta): one side translated at an average rate against the other at another rate is a translation difference (IAS 21.41), not profit
E6 intragroup dividends the shareholder's ic_dividend_income from another entity of the run, against the equity the declaring entity's appropriation debited (the movement dividend_declared names the entry), in the group year the income at its month's average rate, the equity at the rate of the resolution date (as the translation took it) sides that agree: the translation reserve (IAS 21.41). A dividend the shareholder has not accepted yet is a difference (ic_difference)

Each line is translated as the translation translates it, so an account that holds one partner only is emptied to the cent: the group receivables and payables lines are zero when both sides are booked.

Two sides that do not agree in the document currency (a mirror not accepted yet, a bill typed by hand for another amount) are still reversed in full. The part the disagreement explains, each currency's difference at the closing rate, goes to a line of its own, bs.assets.current.ic_unreconciled (balances) or pl.ic_unreconciled (income and expense), so nothing is hidden in another line; the rest is treated as for agreed sides. The run carries ic_difference, blocking when that part exceeds the group's ic_tolerance_amount (in the reporting currency, default 1.00), a warning within it. A difference in a currency no entity of the run keeps cannot be converted: all of the residual is then unreconciled. The intercompany reconciliation (GET /v1/ic/reconciliation) names the documents behind it.

A payment in transit (ADR-0073): when one entity has booked the payment of a group invoice and the other has not yet (the reconciliation's timing item payment_in_transit) and those payments are the whole of an E1 pair's disagreement in every document currency, the part goes to cash in transit (bs.assets.current.cash_in_transit, "Cash in transit between group companies"), each currency at its closing rate: Dr cash in transit, Cr the receiver's group receivable. The pair's treatment is cash_in_transit (with in_transit), the run warns (ic_cash_in_transit) and is complete. A disagreement the payments explain only in part stays unreconciled as a whole. Example: DE01 pays the EUR 10,000.00 bill of CH01 on 28 September, CH01 has not booked the receipt on the 30th: E1 reverses CH01's receivable of CHF 9,438.00 and puts EUR 10,000.00 x 0.9438 = CHF 9,438.00 on cash in transit; E3 leaves CHF 5.23 to the translation reserve (9,438.00 of revenue against 10,000.00 x 0.9432772727 = 9,432.77 of expense) (tests/erp/features/consolidation/test_consolidation_cash_in_transit_pure.py, tests/erp/features/consolidation/test_consolidation_cash_in_transit.py).

An intragroup cost capitalised by the buyer (a line with a partner on an asset account that is not a group account or input VAT) would leave the seller's profit in the asset: the blocking exception ic_capitalised, which a manual adjustment resolves (slice 4).

GET /v1/consolidation-runs/{id}/eliminations lists per rule and pair what each side holds in every document currency, whether they agree, every line with its rate and where the residual went; every pair balances. The header of the run keeps the same record (eliminations: the rules applied, the rules pending and the pairs) and eliminations_applied is true. A run made before slice 2 has none.

The ADR's flow (CH01 invoices DE01 CHF 10,000.00; DE01 books EUR 10,638.30 of expense and revalues its payable to EUR 10,695.19; closing 0.9350, September's average 0.9390): E1 reverses CHF 10,000.00 of receivable against 10,695.19 x 0.9350 = 10,000.00 of payable, nothing left; E3 reverses CHF 10,000.00 of revenue against 10,638.30 x 0.9390 = 9,989.36 of expense, and CHF 10.64 goes to the translation reserve (tests/erp/features/consolidation/test_consolidation_eliminate.py). The loans and dividends are worked the same way in tests/erp/features/consolidation/test_consolidation_eliminate_loans.py.

Capital consolidation (E4, E5, E7)

For each subsidiary acquired inside the ledger (consolidated_from = acquired_on), with the consideration (acquisition_cost, in the reporting currency), the parent's investment account and the net assets at acquisition stated on the member version (approved by a second person):

Rule What it does Basis
E4 reverses the subsidiary's whole equity at acquisition at the historical rate (as the translation translated it) against the parent's investment at the consideration; credits the non-controlling interest at its proportionate share of that equity; the difference is goodwill. As an asset (impairment_only, amortise) it is kept in the subsidiary's currency and translated at the closing rate, its translation difference to the owners' reserve (under IFRS not amortised; the run warns that the system does not test it for impairment). Under offset_equity it is debited to retained earnings at its amount at acquisition, and the basis shows the theoretical capitalisation over the group's useful life (the amortisation of the year and the carrying amount the notes show, FER 30/43). A negative difference is, by the framework: a bargain purchase gain on pl.bargain_purchase in the acquisition year (IFRS, with a warning to reassess); credited to retained earnings (FER offset); a liability bs.liabilities.noncurrent.negative_goodwill released straight line over five years to pl.negative_goodwill (FER capitalised); or kept at its amount after equity as the "Unterschiedsbetrag aus der Kapitalkonsolidierung" (bs.after_equity.consolidation_difference, its own section of the balance sheet, neither liabilities nor equity; HGB, the warning negative_goodwill_not_released) IFRS 10.B86(b), 3.18 to 3.36; Swiss GAAP FER 30/10, 30/16 to 30/19, 30/43; §§ 301, 307, 309 HGB, DRS 23.137, 23.139 ff.
E5 gives the non-controlling interests their share of the subsidiary's profit of the year (pl.nci_share, shown as the attribution of the net income, not as an expense), of its translation reserve and of its other equity movements since the acquisition (earlier years' results, capital, dividends), all credited to bs.equity.nci IFRS 10.22, 10.B94; IAS 1.81B
E7 under amortise: straight-line amortisation over goodwill_years from the month of the acquisition, in the subsidiary's currency, each month at its average rate; the accumulated amount off the goodwill at the closing rate, the difference to the reserve Swiss GAAP FER 30/16; § 309 para. 1 with § 253 para. 3 HGB, DRS 23.118, DRS 25.61

The net assets at acquisition are taken at their book value as their fair value: the figure on the member version must equal what the subsidiary's ledger holds at the acquisition date, else the blocking exception fair_value_adjustment_unsupported (no purchase price allocation in this version). A dividend from the subsidiary to the parent is E6; the outside shareholders' part of it leaves their interest through E5.

GET /v1/consolidation-runs/{id}/eliminations returns acquisitions: per subsidiary every figure (consideration, net assets, rates, equity and non-controlling interest at acquisition, goodwill in both currencies and its translation difference, the three parts of E5 and the interest at the date, its exact share and the rounding), the paragraphs each rule follows, and the lines. The worked example of ADR-0026 (80 % of DE01 for CHF 800,000): goodwill CHF 48,000 = EUR 51,063.83, at 0.935 = 47,744.68; NCI 188,000 + 22,512 - 1,072 = 209,440 (tests/erp/features/consolidation/test_consolidation_capital_pure.py, tests/erp/features/consolidation/test_consolidation.py).

The group close checklist

GET /v1/consolidation-groups/{group}/checklist?as_of= (read) has the shape of an entity's close checklist (pass, warn, fail, n/a; ready when nothing fails). Some checks read the books as they are, the others the latest run at the date:

Check Reads Fails or warns when
run the runs fail: no run at the date; warn: an entity's ledger chain moved since the run (make a new one)
periods_closed the books fail: a period of the parent or a member that starts on or before the date is open
ic_reconciled the books the intercompany reconciliation of a relationship between two entities of the group: its own warn (timing items) or fail
rates_available the run fail: rate_missing
report_lines the run fail: unmapped_report_line
ic_eliminated the run fail: ic_difference above the tolerance or ic_capitalised; warn: ic_difference within it, ic_exchange_difference or ic_cash_in_transit, or a run made before the eliminations
cta_reconciled the run fail: a reserve that does not tie to its roll-forward
balanced the run fail: consolidated assets differ from liabilities plus equity
opening_position the members fail: a member consolidated after its acquisition has no opening position
capital_consolidated the run fail: a capital exception (below) or a subsidiary without its capital consolidation; warn: a bargain purchase, goodwill not tested for impairment or an HGB negative difference not released
nci_attributed the run fail: net income is not the owners' plus the non-controlling interests' share
adjustments_approved, final_run_current n/a: later slices

Exceptions

Code Severity Meaning
rate_missing blocking a rate the rate source does not publish; the entity is not in the run
unmapped_report_line blocking an account on a line outside the vocabulary or of another kind
cta_unreconciled blocking the reserve is not exactly its roll-forward plus the rounding of the translated amounts
period_open warning a period of the entity that starts on or before the date is still open (a preview)
member_not_consolidated warning a member starts after the date and is left out
opening_position_missing blocking a member is consolidated from a date after it was acquired: its investment, goodwill, non-controlling interest and reserve at the start cannot be computed from the books (the opening position is a later version)
acquisition_basis_incomplete blocking the member version (or the version that corrects its purchase data) lacks the consideration (in the reporting currency), the investment account or the net assets at acquisition: a new version with the same share and acquisition date completes it
ownership_change_unsupported blocking the versions in force that no later version corrects differ in the share or the acquisition date (a step acquisition or a partial disposal)
investment_differs_from_cost blocking the parent's investment account does not hold the consideration of the members on it
fair_value_adjustment_unsupported blocking the stated net assets at acquisition differ from the subsidiary's books
bargain_purchase warning a gain on a bargain purchase: reassess (IFRS 3.36)
goodwill_impairment_not_tested warning goodwill is carried without amortisation; the system does not test it for impairment
negative_goodwill_not_released warning HGB: a negative difference after equity, which the group releases as its cause allows (§ 309 para. 2 HGB) by a manual adjustment
ic_difference blocking above the tolerance, else warning two entities' intragroup balances, or income and expense, do not agree in the document currency; the part that disagrees is shown apart
ic_capitalised blocking an intragroup cost sits in an asset of the buyer
ic_exchange_difference warning agreed balances differ in the reporting currency by more than the tolerance: a balance was probably not revalued; the difference stays in profit or loss
ic_cash_in_transit warning two entities' group balances disagree only by payments one side booked and the other not yet: shown as cash in transit
eliminations_pending, cta_starts_at_zero only on runs made before the capital consolidation

complete on a run, a statement and the run list means: no blocking exception.

Operations

Operation Scope Does
POST /v1/consolidation-groups draft, human creates a group (Idempotency-Key)
GET /v1/consolidation-groups, GET .../{group} read groups with their latest member versions and pending requests
POST .../{group}/members draft, human requests a member version (second person approves)
GET .../{group}/members read every approved version
POST .../{group}/runs draft makes a draft run (Idempotency-Key)
GET .../{group}/runs read the group's runs
GET /v1/consolidation-runs/{id} read the header: framework and switches, members and versions, digest, chain heads
GET .../{id}/trial-balance?entity= read the entity's translated trial balance with rates
GET .../{id}/balance-sheet, .../profit-and-loss read the group statements, intragroup items eliminated
GET .../{id}/eliminations read the eliminations by rule and pair
GET .../{id}/cta read the translation reserve roll-forward
GET .../{id}/rates, .../exceptions read the rates used, the exceptions
GET /v1/consolidation-groups/{group}/checklist?as_of= read the group close checklist
curl -X POST "$ERP_URL/v1/consolidation-groups/DEMO/members" \
  -H "Authorization: Bearer $ERP_KEY" -H "Idempotency-Key: demo-member-1" \
  -H "Content-Type: application/json" \
  -d '{"entity": "DE01", "ownership_percent": "80", "control_basis": "80 % of the voting rights.",
       "acquired_on": "2026-01-02", "consolidated_from": "2026-01-02",
       "acquisition_cost": "800000", "acquisition_cost_currency": "CHF",
       "investment_account": "1485", "net_assets_at_acquisition": "1000000"}'

curl -X POST "$ERP_URL/v1/consolidation-groups/DEMO/runs" \
  -H "Authorization: Bearer $ERP_KEY" -H "Idempotency-Key: demo-run-1" \
  -H "Content-Type: application/json" -d '{"as_of": "2026-09-30"}'

The snapshot

A run is evidence. consolidation_run keeps everything it was computed from (the members and versions, the framework's switches, every rate, the chain position of each entity's ledger, the digest of the inputs, the reserve roll-forward, the record of the eliminations) and only its state can move (draft to final or superseded, with who and when, by a trigger and a restricted grant); consolidation_line and consolidation_exception are append-only, and only an elimination line names a partner (partner_entity_id, a check); at most one run per group and date can be final. inputs_digest is the SHA-256 of the canonical JSON of the entity balances and monthly movements, what each entity holds towards the others, the member versions, the rates, the policy and the group's tolerance: the same inputs give the same digest. No ledger entry is written by consolidation: there is no second posting path.

Not in this version, and how the design reads

  • Parent in another currency: refused at group creation (the parent would need a starting point).
  • Realised exchange differences on a net-investment loan (a repayment of it) stay in profit or loss; only the revaluation's differences move to the reserve. Reclassifying the reserve on disposal (IAS 21.48) comes with disposals.
  • The reserve's starting point is zero at T0; the opening position with its basis (cta_basis), the acknowledgement of exceptions, adjustments, finalise and supersede, verify, the reopen guard and the worksheet export are later slices of the ADR.
  • Hyperinflation, other rate sources and multi-level groups stay out of scope as in the ADR.
Stabiso, the Enterprise System of Record · generated from the code and its guides · release 20b7dd5b0c4d