gendesign/tradein-mvp/backend/app/tasks/zhkh_flats_load.py
bot-backend 77c01b6d3b
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
feat(tradein/zhkh): ЖКХ-приоритет знаменателя «квартир в доме» + loader
ГАР дико недосчитывает квартиры в МКД (прод-замер: Крауля 89А ГАР=11 vs
ЖКХ=429; 27 из 347 домов ГАР ≥2× недосчёт). ГИС ЖКХ точнее — резолвит ~90%
вторички с gar_house_guid.

- мигр.149: COALESCE знаменателя → ЖКХ ПЕРВЫЙ
  (zhkh_flat_count, gar_flat_count, total_units, flat_count) во всех 7 местах
  view v_building_sale_share; +houses.zhkh_year/zhkh_floors_raw; +transparency-
  колонки zhkh_flat_count/flat_count_source.
- app/services/zhkh_flats_loader.py + app/tasks/zhkh_flats_load.py: фетч ГИС ЖКХ
  searchByAddress (батч ≤100 по gar_house_guid == ЖКХ houseGuid, pageIndex=1,
  cookieless), идемпотентный UPDATE houses.zhkh_* (CAST(:x AS type) +
  IS DISTINCT FROM gate, SAVEPOINT-чанки, dry-run).

Безопасно к мержу: до ручного прогона loader'а zhkh_flat_count=NULL → COALESCE
падает на ГАР → поведение идентично до-149. ruff clean, pytest 8 green.
2026-06-28 21:55:05 +03:00

83 lines
3.1 KiB
Python
Raw 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.

"""CLI: загрузка ЖКХ-знаменателя «квартир на дом» → houses.zhkh_* (мигр. 146/149).
Тянет точный счёт квартир из публичного API ГИС ЖКХ (dom.gosuslugi.ru) и проставляет
`houses.zhkh_flat_count` / `zhkh_house_guid` / `zhkh_matched_at` / `zhkh_year` /
`zhkh_floors_raw`. Матч ТРИВИАЛЬНЫЙ: `houses.gar_house_guid` — это И ЕСТЬ ЖКХ `houseGuid`
(проверено), поэтому ищем дом по нему, без нормализации/канона адреса.
Запуск из контейнера tradein-backend (у прода есть интернет к dom.gosuslugi.ru):
python -m app.tasks.zhkh_flats_load # полный прогон
python -m app.tasks.zhkh_flats_load --limit 300 --dry-run # сэмпл, без записи
В режиме --dry-run выборка/фетч происходят, но НИ ОДНОЙ записи в БД не делается.
"""
from __future__ import annotations
import argparse
import logging
from app.core.db import SessionLocal
from app.services.zhkh_flats_loader import match_houses_to_zhkh
logger = logging.getLogger(__name__)
def build_parser() -> argparse.ArgumentParser:
"""Парсер CLI (вынесен для тестируемости флагов без запуска main)."""
parser = argparse.ArgumentParser(
description="ГИС ЖКХ loader: квартир на дом → houses.zhkh_* по gar_house_guid"
)
parser.add_argument(
"--region", default="66", help="код региона (информационно, по умолчанию 66)"
)
parser.add_argument(
"--limit", type=int, default=None, help="ограничить число домов (сэмпл); по умолчанию все"
)
parser.add_argument(
"--dry-run", action="store_true", help="без записи в БД — только фетч и подсчёт"
)
parser.add_argument(
"--sleep", type=float, default=0.4, help="пауза между батчами, сек (по умолчанию 0.4)"
)
return parser
def main() -> None:
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)
parser = build_parser()
args = parser.parse_args()
db = SessionLocal()
try:
counts = match_houses_to_zhkh(
db,
region_code=args.region,
limit=args.limit,
dry_run=args.dry_run,
sleep_sec=args.sleep,
)
if not args.dry_run:
db.commit()
finally:
db.close()
logger.info(
"zhkh_flats_load DONE: region=%s limit=%s dry_run=%s seen=%d resolved=%d "
"with_flatcount=%d updated=%d",
args.region,
args.limit,
args.dry_run,
counts["houses_seen"],
counts["zhkh_resolved"],
counts["zhkh_with_flatcount"],
counts["houses_updated"],
)
if __name__ == "__main__":
main()