Originally created by: grynn-in
Adds IAS 21 acquisition-date FX translation for equity to the Contoso demo, on top of [#103].
epm_raw.exchange_rates for EUR/GBP/JPY/USD→USD (2020 levels). Equity is translated at the rate on the date the subsidiary was acquired (group inception, matching the ownership_periods effective_date), not the period/closing rate.epm_staging.historical_equity_rates emission — equity accounts 3010/3100 × 4 entities @ 2020-01-01 (8 rows): USMF→USD 1.0, DEMF→EUR 1.1213, GBMF→GBP 1.3257, JPMF→JPY 0.009201.Exercises the historical-equity-rate path documented in [#102] and consumed by gold_consolidated_trial_balance (PRD-10).
demo-data.sql is regenerated from generate_demo_data.py; the large line count is sequential recid (uid) reflow from inserting rows mid-stream — not a data rewrite. Regeneration is deterministic.d365_raw table names from [#103] are preserved (0 PascalCase refs); historical_equity_rates is epm_staging (unaffected by the d365 rename).🤖 Generated with Claude Code
Tickets: #102
Tickets: #103
Tickets: #120
Tickets: #121
Tickets: #123
Tickets: #130
Originally posted by: grynn-in
Review — feat(demo-data): IAS 21 acquisition-date FX + historical equity rates for Contoso
Adversarial review (correctness/data-integrity + nits). Traced the new seed data through
gold_consolidated_trial_balance.sql,stg_d365_fo__exchange_rates.sql,silver_exchange_rates.sql,consolidation_groups.csvandinit-db.sql. dbt parse run; norun/build/seed(prod-mutating).Blocking issues
1. Historical equity rates for DEMF/GBMF use
GROUP_EMEA, which never joins → IAS 21 translation silently does NOT apply to the two foreign EMEA subs (the PR's whole purpose).scripts/generate_demo_data.py:1456-1457(CX_HER) and generatedclickhouse/demo-data.sql:4381-4384emit equity rates keyed toconsolidation_group = 'GROUP_EMEA'for DEMF and GBMF.gold_consolidated_trial_balance.sql:256joins the historical-rate CTE oneo.consolidation_group = hr.consolidation_group, andeo.consolidation_groupis sourced from theconsolidation_groupsseed (gold_consolidated_trial_balance.sql:71), which flat-maps all Contoso entities toGROUP_CORP(dbt_project/seeds/consolidation_groups.csv:2-5).GROUP_EMEAnever appears in that seed, so the consolidated TB never emits aGROUP_EMEArow.historical_equity_rateis NULL → thecaseatgold_consolidated_trial_balance.sql:214-220falls back toclosing_rate. So the acquisition-date equity translation works only for USMF (USD, rate 1.0, a no-op) and JPMF (GROUP_CORP, matches). The two foreign EMEA subs that actually need IAS 21 get the closing rate.assert_equity_historical_rate_is_asof.sql:22filters tohistorical_equity_rate is not null, so the join-miss rows are excluded and the test is vacuously green.consolidation_group = 'GROUP_CORP'for the DEMF/GBMF rows inCX_HER(match theconsolidation_groupsseed), then regeneratedemo-data.sql.CX_OWNERSHIP(generate_demo_data.py:1435-1439, pre-existing) uses the sameGROUP_EMEAconvention, but there it's masked because ownership has a seed/hierarchy fallback (gold_consolidated_trial_balance.sql:208). The historical-rate path has no fallback to the right group, so the same convention is a real regression here.2. JPY acquisition-date
exchange_ratesrows skip the ×100 store-scale → 100× too small after the silver round-trip.scripts/generate_demo_data.py:1123-1130/demo-data.sql:2316-2318store JPY at raw0.009201withConversionFactor='Hundred'. The monthly loop 10 lines above (generate_demo_data.py:1106-1112) appliesstore_scale=100for JPY (stored value0.678, seedemo-data.sql:2172); the acq loop does not.stg_d365_fo__exchange_rates.sql:14-16passes'Hundred'rows through unscaled andsilver_exchange_rates.sql:14divides everything by 100, so this acq row round-trips to0.00009201— 100× too small.rate_lookupmatchesperiod_dateexactly, sogold_consolidated_trial_balancenever reads them. But it is inconsistent with the convention 10 lines above and would be 100× wrong if anything ever looks up FX as-of acquisition. Fix: either store JPY as0.9201(0.009201 × 100), or drop theseexchange_ratesacq rows entirely (see nit below).Non-blocking nits
exchange_ratesrows (demo-data.sql:2307-2318) appear to have no consumer: equity translation readshistorical_equity_rates, notexchange_rates, andrate_lookuponly matches 2024 periods. Consider dropping them or documenting their intended use. (This is also what makes finding [#2] currently inert.)gold_consolidated_trial_balance.sql:215. Harmless.Verification
dbt parse --no-partial-parse --profiles-dir .indbt_project/: PASS (only pre-existingMissingArgumentsPropertyInGenericTestDeprecationwarnings; no errors).rate_date2020-01-01 aligns withownership_periodseffective_date;Decimal(18,6)DDL (init-db.sql:58) holds all values.dbt run/build/seed(mutates live prod).MERGE RECOMMENDATION: BLOCKING — finding [#1] defeats the PR's stated purpose for DEMF/GBMF and is silent in CI.
Related
Tickets:
#1Tickets:
#2Ticket changed by: grynn-in