gendesign/tradein-mvp/backend/app/services/fns_lookup.py
lekss361 e0bef636e6
All checks were successful
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 4m17s
Deploy Trade-In / build-backend (push) Successful in 1m3s
Deploy Trade-In / deploy (push) Successful in 7m11s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 11s
feat(tradein): bulk-дампы открытых данных ФНС по юрлицам + lookup по ИНН (#3429)
2026-09-08 22:29:10 +00:00

58 lines
2 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""ФНС opendata lookup по ИНН — тонкое чтение `fns_legal_entity_facts`.
CONTEXT: см. `fns_opendata_loader.py`. Этот модуль — единственная точка чтения
загруженных фактов. ПОТРЕБИТЕЛЯ У НЕГО ПОКА НЕТ: ничто в продукте (скоринг
застройщика/УК, estimator и т.п.) сюда не ходит — подключение решается отдельной
задачей вне этого PR.
psycopg v3: SQL через `text(...)` использует `CAST(:x AS type)`, НИКОГДА `:x::type`.
"""
from __future__ import annotations
from collections import defaultdict
from datetime import date
from typing import TypedDict
from sqlalchemy import text
from sqlalchemy.orm import Session
_LOOKUP_SQL = text(
"""
SELECT dataset, series, period, value, org_name
FROM fns_legal_entity_facts
WHERE inn = CAST(:inn AS text)
ORDER BY dataset, series, period
"""
)
class FnsFact(TypedDict):
series: str
period: date
value: float
org_name: str | None
def get_facts_by_inn(db: Session, inn: str) -> dict[str, list[FnsFact]]:
"""Факты по ИНН, сгруппированные по dataset (`revexp`/`sshr2019`/`debtam`/`snr`).
Пустой/пробельный ИНН и отсутствие данных → `{}` (не исключение — вызывающий код
не обязан оборачивать lookup в try/except ради нормального «нет данных»).
"""
normalized = (inn or "").strip()
if not normalized:
return {}
rows = db.execute(_LOOKUP_SQL, {"inn": normalized}).mappings().all()
out: dict[str, list[FnsFact]] = defaultdict(list)
for row in rows:
out[row["dataset"]].append(
{
"series": row["series"],
"period": row["period"],
"value": row["value"],
"org_name": row["org_name"],
}
)
return dict(out)