feat(ledger): импорт отчётов в леджер — приём, дедупликация, pending_instrument
Поток: upload -> raw_report_file (sha256 UNIQUE) -> parse -> raw_report_line,
событий в леджере ещё нет -> preview -> POST /imports/{id}/commit ->
ledger/ingest.py резолвит инструмент, считает dedupe_key, пишет event
confirmed | shadow (plan §1.6 B) — сравнивая account.primary_event_source
с источником отчёта, а не гадая. Нерезолвленный инструмент ждёт в
pending_instrument, никогда не угадывается; POST /instruments/pending/{id}/resolve
привязывает и пересобирает лоты.
ledger/dedupe.py — shadow-матчинг случая B двумя проходами (точная дата, затем
±1 рабочий день, жадно 1:1, |price| ±0,5 %). Шаги shadow_dedupe и
report_reconcile зарегистрированы перед quality: оба говорят через FINDINGS.
/instruments/pending регистрируется в app.py ДО routers/instruments.py:
FastAPI сопоставляет маршруты по порядку, и /instruments/{id} с типом int
отвечает 422 на нечисловой сегмент, а не проваливается дальше.
Контракт — docs/ai/import-contract.md, общий для бэкенда и Flutter.
This commit is contained in:
@@ -114,8 +114,10 @@ def register_steps() -> None:
|
||||
valuation,
|
||||
)
|
||||
from fintracker.ledger.corporate_actions import rebuild_corporate_actions
|
||||
from fintracker.ledger.dedupe import rebuild_shadow_matches
|
||||
from fintracker.ledger.matching import rebuild_flow_links
|
||||
from fintracker.ledger.rebuild import rebuild_lots
|
||||
from fintracker.ledger.report_import import reconcile_reports
|
||||
from fintracker.metrics.refresh import register_step
|
||||
|
||||
register_step("fx", _step_fx)
|
||||
@@ -136,6 +138,12 @@ def register_steps() -> None:
|
||||
register_step("cashflow", cashflow.rebuild_cash_flow_monthly)
|
||||
register_step("spending", spending.rebuild_spending_by_category)
|
||||
register_step("runway", runway.rebuild_runway)
|
||||
# Both report steps speak through FINDINGS, which `quality` drains — so they have to run
|
||||
# before it, and inside a refresh at all. `shadow_dedupe` pairs a report's events with
|
||||
# the API's before `report_reconcile` compares the closing balances, or every shadowed
|
||||
# position would read as a discrepancy.
|
||||
register_step("shadow_dedupe", rebuild_shadow_matches)
|
||||
register_step("report_reconcile", reconcile_reports)
|
||||
register_step("quality", quality.rebuild_data_quality)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user