Add imap-ingest CLI + ImapProvider: route emails to IE/Schwab parsers
Wires the IE + Schwab email parsers into an actual runnable sync. Walks the IMAP mailbox, routes each message by sender domain: - *@investengine.com → invest_engine.parse_invest_engine_email - *@schwab.com → schwab.parse_schwab_email then pushes the resulting Activities through the shared pipeline. broker-sync imap-ingest — new CLI command taking IMAP_HOST/USER/PASSWORD/ DIRECTORY (mirrors the old wealthfolio-sync image's env shape so the Terraform CronJob's existing env wiring works unchanged). Verified: poetry run pytest -q → 109 passed + 1 skipped; mypy strict clean (37 files); ruff + yapf clean.
This commit is contained in:
parent
f089b8b93a
commit
6efd03570a
6 changed files with 290 additions and 35 deletions
|
|
@ -130,10 +130,7 @@ class WealthfolioSink:
|
|||
"""
|
||||
existing = await self.list_accounts()
|
||||
for a in existing:
|
||||
if (
|
||||
a.get("provider") == account.provider
|
||||
and a.get("providerAccountId") == account.id
|
||||
):
|
||||
if (a.get("provider") == account.provider and a.get("providerAccountId") == account.id):
|
||||
wf_id = a.get("id")
|
||||
assert isinstance(wf_id, str)
|
||||
return wf_id
|
||||
|
|
@ -159,9 +156,7 @@ class WealthfolioSink:
|
|||
created = resp.json()
|
||||
wf_id = created.get("id")
|
||||
if not isinstance(wf_id, str):
|
||||
raise WealthfolioError(
|
||||
f"POST /accounts returned no id: {created}"
|
||||
)
|
||||
raise WealthfolioError(f"POST /accounts returned no id: {created}")
|
||||
return wf_id
|
||||
|
||||
# -- activity import --
|
||||
|
|
@ -213,15 +208,12 @@ class WealthfolioSink:
|
|||
checked = check.json()
|
||||
if not isinstance(checked, list):
|
||||
raise ImportValidationError(
|
||||
f"Wealthfolio /import/check returned non-list: {type(checked).__name__}"
|
||||
)
|
||||
f"Wealthfolio /import/check returned non-list: {type(checked).__name__}")
|
||||
|
||||
invalid = [r for r in checked if isinstance(r, dict) and r.get("errors")]
|
||||
if invalid:
|
||||
raise ImportValidationError(
|
||||
f"Wealthfolio /import/check flagged {len(invalid)} row(s); "
|
||||
f"first: {invalid[0]}"
|
||||
)
|
||||
raise ImportValidationError(f"Wealthfolio /import/check flagged {len(invalid)} row(s); "
|
||||
f"first: {invalid[0]}")
|
||||
# Drop any row the server marked is_valid=false (shouldn't happen
|
||||
# without errors, but defensive).
|
||||
valid_rows = [r for r in checked if isinstance(r, dict) and r.get("isValid")]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue