Originally created by: grynn-in
Fixes [#199] (warehouse side): trial-balance rows are normalised to period movements from each batch's declared amount basis.
Every model downstream reads a trial-balance row as a period movement (gold_balance_sheet running sums, gold_ytd_trial_balance, PRD-22's own header). ERPs export three different things: period movements, year-to-date movements, or period-end balances. Nothing declared which a batch was. On a site that uploaded period-end balances, share capital of one subsidiary showed −10.6M, −21.2M, −30.9M over three year-ends: every balance-sheet figure was the sum of all prior year-ends.
konsol (its PR) puts amount_basis on the claim row of epm_raw.trial_balance_submission_control: Period movement, Year-to-date movement or Period-end balance, never a default. This PR:
amount_basis String DEFAULT '' (byte-equivalent to konsol's _RAW_TABLE_DDL; tests/test_raw_submission_ddl.py pins both, and runs in CI). The CI fixture names its claim columns and declares a basis.assert_tb_submission_has_basis (error) names a claimed batch with an empty or unknown basis instead of guessing.silver_tb_movements (new) normalises every batch once, on a spine of entity periods × entity keys (account, partner): Period movement passes through; Year-to-date differences within the fiscal year; Period-end balance differences against the previous period with data, any year. A key that vanishes produces its closing movement. Two invariant tests: assert_tb_movements_balance (each entity-period nets to zero) and assert_tb_movements_cumulate_to_source (the movements add back to what the batch declared).silver_gl_entries reads the movements instead of bronze; nothing downstream changes.assert_entity_has_one_amount_basis (error): one entity's batches must share one basis.silver_tb_movements in the silver data dictionary, an "Amount Basis" paragraph in the deployment guide, fixture README notes.Test first, all in throwaway zzg_* schemas inside the stack (live tables untouched):
FAILED (failures=2) on main → OK (7991732 → ca8cf32).assert_tb_submission_has_basis: Database Error on main (no column) → PASS with a declared claim; Got 2 results for '' and Balances (0155aeb → 63ca80c).PASS on all three (acc8b32 → 7ac433d). Hand check of the balance case: balances 150/−50/−100 → 170/−30/−140 → 200/–/−200 give movements +20/+20/−40 and +30/+30/−60; each period nets to zero.Period-end balance: +silver_gl_entries builds green (62/62). One parent's share-capital account: declared balances −391.0M (2010), −1,087.3M, −1,215.4M, −1,392.6M; movements −391.0M, −696.3M, −128.1M, −177.2M — the year-over-year change.assert_entity_has_one_amount_basis: Got 1 result on a mixed entity, PASS on a clean one (5701bc3 → 37b5d4a).Merge and fast-forward this after konsol's Set Amount Basis action has declared the existing batches on the stack; until a batch has a basis the build stops at assert_tb_submission_has_basis, by design.
🤖 Generated with Claude Code
Originally posted by: grynn-in
Review round 1: four points.
Period-end balancefiles, P&L accounts reset each fiscal year, so differencing them across the year boundary puts −(prior-year result) into the first period of the new year while every period still nets to zero. Fix in progress on this branch: an explicit year-end close. For each finished year of a balance-basis entity the model synthesises the post-close position in the calendar's Closing period (P&L keys to 0, the result into the chart's declared retained-earnings account), so the close appears as its own movement (posting_layer = 'Year-end close') and the next year starts from zero. The retained-earnings account becomes a declared flag on the group chart (konsol,is_retained_earnings, one per chart); where it or the Closing period is missing,assert_year_end_close_declarednames the entity-year instead of guessing. Two-year fixture with a P&L account, red first.assert_tb_movements_cumulate_to_sourcewill say that the balance test is what catches a missing spine.dbt builddependency.Also noted for the PR body: two source rows for one (account, partner) now collapse to one GL row with an empty description when their descriptions differ.
Originally posted by: grynn-in
Round-1 fixes pushed (D6, D7b, D7):
is_retained_earningsreachessilver_main_accounts(read only when the staging table has the column; DDL pinned to konsol's body).epm_staging.fiscal_periods(the declared fiscal calendar konsol writes) is now a warehouse source: init-db DDL, dbt source, CI seed, DDL test.movement_kind = 'year_end_close',posting_layer = 'Year-end close') and the next year's P&L starts from zero.assert_year_end_close_declared(error) names entity-years that need a close but lack a Closing period or a single retained-earnings account. Fixture: 2025 P12 cash 100 / revenue −100 → 2026 P1 cash 130 / revenue −30 / RE −100 gives P13 revenue +100 / RE −100 and P1 +30 / −30 / 0. On a clone of the stack's data the only failure is that test (577 entity-years: the live chart has no retained-earnings flag yet — konsol's PR adds it; flag account 3100 and it clears).Originally posted by: grynn-in
Re-review round 2: three findings, all accepted, in progress as one row (D8): (1)
assert_year_end_close_declaredonly flags entity-years with a non-zero P&L to close, with a balance-sheet-only must-pass fixture; (2) a warn-levelassert_year_end_close_carriednames a next-year file that omits the flagged retained-earnings account, plus a docs sentence that the flagged account must be the one the ERP's files carry the result in; (3) the Closing period must sort after the year's last claimed period (model and test).Originally posted by: grynn-in
Round-2 fixes pushed (D8, D8b, D8c):
assert_year_end_close_declaredflags only entity-years with a non-zero P&L balance at their last period (bs-only must-pass fixture; a net-zero-result fixture still flagged);assert_year_end_close_carried(warn) names a next-year file that omits the flagged retained-earnings account; the Closing period must sort after the year's last claimed period (model and test); docs reworded.Originally posted by: grynn-in
Round 3: two small points, both fixed in the last commit — the
reasonnow says when a batch was claimed in the Closing period while P&L is still open (fix the file, not the calendar), and the model header says "any non-zero P&L balance". All four fixture gates re-run green.Ticket changed by: grynn-in