Skip to content

Multi-currency: corrections, data export, and pro-rata capture - #57

Open
ItsThompson wants to merge 7 commits into
mc/04-fx-conversion-legacy-reportingfrom
mc/05-corrections-export-prorata-capture
Open

Multi-currency: corrections, data export, and pro-rata capture#57
ItsThompson wants to merge 7 commits into
mc/04-fx-conversion-legacy-reportingfrom
mc/05-corrections-export-prorata-capture

Conversation

@ItsThompson

@ItsThompson ItsThompson commented Aug 15, 2026

Copy link
Copy Markdown
Owner

Summary

Implements three multi-currency epic tickets: currency-aware corrections with expense detail, enriched Datarights CSV export with currency snapshots, and pro-rata schedule capture with trusted period context.

What changed

Backend: Expense service

  • CorrectExpenseRequest accepts transactionCurrency over REST and gRPC.
  • Corrections resolve FX snapshot before any ledger mutation. FX failure leaves the original expense active with no correction row appended.
  • Same-currency corrections write an identity snapshot; foreign-currency corrections write a provider snapshot.
  • CreateProRataInstallment internal RPC accepts TrustedPeriodContext and CapturedRateSnapshot. Expense validates context consistency, currency catalog membership, and snapshot coverage without calling Finance back.
  • fx_client.go adds ConvertWithSnapshot for snapshot-based conversion.
  • Proto additions: CorrectExpenseRequest currency fields, CreateProRataInstallment RPC, TrustedPeriodContext, CapturedRateSnapshot.

Backend: Finance service

  • CreateProRataExpense requires explicit periodYear and periodMonth. Service clock no longer selects the creation period.
  • Validated creation period exists before FX capture or any ledger write.
  • FX CaptureRateSnapshot runs before first installment and future schedule inserts. Capture failure returns CONVERSION_UNAVAILABLE with no writes.
  • pro_rata_schedules migration adds transaction amount/currency, creation reporting currency, captured snapshot payload, and failure reason fields.
  • New FxClient interface and GRPCFxClient for rate capture.

Backend: Datarights service

  • expenses.csv gains seven new columns: transaction_amount, transaction_currency, reporting_amount, reporting_currency, exchange_rate, exchange_rate_source, exchange_rate_timestamp.
  • budget_periods.csv gains reporting_currency as the fifth column.
  • formatMinorUnits formats amounts using each currency minor-unit digits. JPY rows render as plain integers.
  • Rows missing required snapshot fields fail the export job.
  • export_currency_formatting_fallback_total counter tracks default-settings fallback renders.

Frontend

  • Correction form initializes from active expense transaction amount and currency. Submits transactionCurrency.
  • Expense detail shows "Period Amount" for same-currency rows, and transaction amount / budget impact / exchange rate / timestamp for foreign-currency rows.
  • Correction history renders each row with its own transaction/reporting snapshot and status.
  • moneyFacts.ts provides pure helpers for snapshot resolution.

Tests

  • services/expense: go build ./... and go test ./... pass. Coverage includes same-currency correction, foreign-currency correction, FX-failure no-write, trusted-context validation, and shared snapshot persistence.
  • services/finance: go build ./... and go test ./... pass. Coverage includes missing period fields, FX capture failure, and gRPC handler error mapping.
  • services/fx: go build ./... and go test ./... pass.
  • services/datarights: go build ./..., go test ./..., and go vet ./... pass. Coverage includes same-currency, foreign-currency, JPY, budget period reporting currency, pro-rata metadata rows, and fallback counter.
  • frontend: vitest run passes 54 files, 504 tests. eslint clean. Pro-rata frontend tests pass (10 tests).

Notes

  • docker-compose.yml: FX_SERVICE_ADDR=fx-service:9085 added to finance-service for pro-rata capture.
  • services/finance/go.mod: added fx module dependency and replace directive.

References

  • Ticket 8: Currency-aware corrections and expense detail
  • Ticket 12: Enriched data export with currency snapshots
  • Ticket 13: Pro-rata schedule capture with trusted period context

@ItsThompson ItsThompson changed the title mc/05 corrections export prorata capture Multi-currency: corrections, data export, and pro-rata capture Aug 15, 2026
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from 1a01787 to fe30b55 Compare August 15, 2026 22:49
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from fe30b55 to 4353a82 Compare August 15, 2026 22:55
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch 3 times, most recently from 3cc4c53 to 8e3c365 Compare August 15, 2026 23:28
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from 8e3c365 to 1bd065e Compare August 15, 2026 23:53
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from 1bd065e to 70cd707 Compare August 16, 2026 14:52
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch 2 times, most recently from adf2d4c to 961d935 Compare August 16, 2026 15:45
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from 961d935 to 51754ec Compare August 16, 2026 18:45
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from 51754ec to af59ff5 Compare August 18, 2026 23:36
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from af59ff5 to 4243590 Compare August 18, 2026 23:45
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch 2 times, most recently from 77caf01 to 5a71a68 Compare August 19, 2026 06:30
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from 5a71a68 to 3d60268 Compare August 19, 2026 19:05
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from 3d60268 to 1c0409a Compare August 20, 2026 13:48
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from 1c0409a to e011c98 Compare August 20, 2026 14:58
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from e011c98 to a69e9f2 Compare August 20, 2026 15:10
Format budget-period, default-settings, and expense export amounts using
each currency's minor-unit digits, add reporting_currency to budget periods,
and add transaction/reporting/FX columns to expenses. Legacy migration rows
normalize to period reporting currency; incomplete version-1 snapshots fail
the export safely.
Correction forms initialize from the active expense transaction amount and
currency and submit the canonical transactionCurrency field instead of the
deprecated currency alias.
Expense detail shows the period amount for same-currency rows and separates
transaction amount, budget impact, exchange rate, and rate timestamp for
foreign-currency rows. Correction history renders each row's own snapshot.
Increment a Prometheus counter when default settings use the two-decimal
fallback for an unsupported stored currency, so the fallback is observable
instead of silently discarding the formatting error.
…context

Finance now creates pro-rata schedules against an explicit, validated creation
period instead of the service clock. It captures one full USD-based provider
snapshot before any write, writes the first installment through a new internal
Expense contract carrying trusted period context and the captured snapshot,
and stores future rows with the same snapshot plus the fields future application
needs.

- CreateProRataRequest requires periodYear/periodMonth (REST + gRPC proto).
- CreateProRataExpense validates the creation period, resolves the currency
  alias (same rules as standard expense create, defaults to period currency),
  captures an FX snapshot, and writes no rows on capture failure.
- Migration 000007 adds transaction_amount, transaction_currency,
  creation_reporting_currency, captured_rate_snapshot (JSONB), failure_reason,
  and a failed status to finance.pro_rata_schedules.
- New Expense CreateProRataInstallment RPC/service method validates trusted
  context consistency, currency catalog membership, and snapshot coverage, then
  converts via FX ConvertWithSnapshot without calling Finance back.
- Wires FX_SERVICE_ADDR into the finance service config/main/docker-compose.
…ias compatibility

CorrectExpenseRequest accepts transactionCurrency and deprecated currency
over REST and gRPC. Corrections resolve the currency alias (defaulting to the
active expense transaction currency), convert against the original period
reporting currency, write identity/provider snapshots, and call FX before any
ledger mutation so a conversion outage leaves the original active.

Review should-fix items addressed:
- Parameterize the default-branch telemetry field name so the create flow
  keeps reporting_currency and the correction flow uses transaction_currency.
- Add a gRPC handler test that sends differing transaction_currency/currency
  and asserts CURRENCY_FIELD_CONFLICT, locking in both field mappings.
@ItsThompson
ItsThompson force-pushed the mc/05-corrections-export-prorata-capture branch from a69e9f2 to 3bbcd78 Compare August 20, 2026 16:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant