Brokerage data sync (Trading 212, Schwab, Fidelity, IMAP-CSV) → Wealthfolio. Image is published as viktor/wealthfolio-sync per the wealthfolio stack convention.
Find a file
Viktor Barzin ea15b80111 Add InvestEngine email parser — RFC 2822 v1/v2 line format
Context: The old finance/ app had a 324-line IE message parser with four
line-based variants (v1/v2/v3/v4) plus an HTML strategy and a CSV
fallback. Port into broker-sync so we can consume IE trade confirmation
emails as a backup to the live HTTP client (Phase 2b) while IE's public
API remains Bearer-only.

The upstream parser emits storage.model.Position; we emit canonical
Activity with the broker-sync invariants: account_id="invest-engine-primary"
(sink remaps to Wealthfolio UUID), account_type=ISA, currency=GBP, and
external_id="invest-engine:<fingerprint>" where the fingerprint is a
SHA-256 of (date|symbol|quantity|unit_price) — deterministic so repeat
imports of the same email dedup at the sync-record layer.

This change:
- Top-level `parse_invest_engine_email(raw_email: bytes) -> list[Activity]`
  extracts the text/plain body from an RFC 2822 message and dispatches to
  the line-based parser.
- `_parse_rfc2822_lines(body)` tries the v2 layout first (newer IE format
  where `Date: DD Month` is on line 2 and the year on line 3), then the
  v1 layout (where the day alone is on line 2 and `Month YYYY` on line 3).
  v3 and v4 variants are re-added in a follow-up if we find fixtures
  where they matter — initial fixture coverage hits v2.
- Drops the upstream `_ticker_post_processing` VUAG→VUAG.L hack.
  Wealthfolio's /import/check endpoint resolves exchange suffixes; the
  Trading212 provider also emits suffix-free tickers (e.g. `VUAG`), so
  staying consistent avoids double-mapping.
- Notes field records the parse-strategy tag ("rfc2822-v2") plus the
  matched line for debugging.

Test plan:
  poetry run pytest tests/providers/parsers/ -q
  → 3 passed in 0.03s
  poetry run mypy broker_sync/providers/parsers/invest_engine.py tests/providers/parsers/test_invest_engine.py
  → Success: no issues found in 2 source files
  poetry run ruff check broker_sync/providers/parsers/invest_engine.py tests/providers/parsers/test_invest_engine.py
  → All checks passed!
  poetry run yapf --diff broker_sync/providers/parsers/invest_engine.py tests/providers/parsers/test_invest_engine.py
  → clean (no diff)

Manual verification: load the fixture email, call the parser, inspect the
returned Activity has symbol=VUAG, quantity=59.539562, unit_price=60.46,
date=2023-01-17, external_id starts with invest-engine:.
2026-04-17 21:49:52 +00:00
.github/workflows CI: build image from phase-0-scaffold branch too (bootstrap) 2026-04-17 19:51:09 +00:00
.woodpecker Add GHA build + Woodpecker deploy pipelines 2026-04-17 19:32:00 +00:00
broker_sync Add InvestEngine email parser — RFC 2822 v1/v2 line format 2026-04-17 21:49:52 +00:00
tests Add InvestEngine email parser — RFC 2822 v1/v2 line format 2026-04-17 21:49:52 +00:00
.gitignore Initial scaffold + canonical Activity model 2026-04-17 19:16:11 +00:00
Dockerfile Fix live Wealthfolio login + Dockerfile poetry path 2026-04-17 20:17:24 +00:00
poetry.lock Wire T212 pagination, retries, and click<8.2 pin 2026-04-17 19:45:23 +00:00
pyproject.toml Wire T212 pagination, retries, and click<8.2 pin 2026-04-17 19:45:23 +00:00