broker-sync/tests
Viktor Barzin 33810899c9 Add FxCache and convert_to_gbp core
Context
-------
FX for UK users has two lives: live ECB rates for portfolio display
(available same-day), and HMRC monthly/daily rates for CGT basis
(published after month-end). The plan keeps both in one cache table
with an upgradable `source` column, so a later reconciliation job can
replace ECB_LIVE values with HMRC_MONTHLY for the same date without
schema work.

This change
-----------
- FxCache: SQLite table (currency, on_date) -> (rate_gbp, source) with
  ON CONFLICT UPDATE semantics so reconciliation is a single put().
- convert_to_gbp(): GBP short-circuits to identity; any other currency
  must be in the cache (network fetch is the caller's responsibility,
  separately implemented by the ECB and HMRC fetchers).
- Explicit LookupError on cache miss — deliberate, we do NOT want a
  silent fallback that produces wrong cost-basis numbers.

Decisions deferred to later commits:
- Actual ECB daily reference-rate fetcher (eurofxref XML) — lands with
  the Trading212 provider in Phase 1 when non-GBP trades first appear.
- HMRC monthly-rate fetcher + reconciliation CronJob — Phase 1 tail.

Test plan
---------
## Automated
- poetry run pytest tests/test_fx.py -v  →  6 passed
- poetry run mypy broker_sync tests  →  Success: no issues found in 8 source files
- poetry run ruff check .  →  All checks passed!

## Manual Verification
Not applicable — no network yet.
2026-04-17 19:18:41 +00:00
..
__init__.py Initial scaffold + canonical Activity model 2026-04-17 19:16:11 +00:00
test_dedup.py Add SyncRecordStore for authoritative dedup 2026-04-17 19:17:12 +00:00
test_fx.py Add FxCache and convert_to_gbp core 2026-04-17 19:18:41 +00:00
test_models.py Initial scaffold + canonical Activity model 2026-04-17 19:16:11 +00:00