gendesign/backend/tests/services/site_finder
Light1YT 67b65c8d8a
All checks were successful
CI / frontend-tests (pull_request) Successful in 57s
CI / openapi-codegen-check (pull_request) Successful in 1m49s
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Successful in 9m54s
feat(site-finder): bridge финмодели (DCF) в кокпит Investment Clearance (epic #1881 PR-4)
Investment Clearance в site-finder кокпите больше не «—»: синтезируем лёгкий
ТЭП из buildability участка (площадь + предельные параметры зоны НСПД/ПЗЗ —
КСИТ/%застройки/этажность) → прогоняем через полноценную финмодель (каскад
затрат PR-1 + калибр.цена PR-2 + помесячный DCF PR-3) → GDV/Cost/Profit/ROI/
IRR/NPV/PBP в кокпите.

Backend:
- new app/services/site_finder/parcel_financial.py (ЧИСТЫЕ функции, без БД):
  synthesize_teap_from_buildability (GFA=area×max_far, degradation pct+floors;
  residential=GFA×eff; apartments/parking — нормативы teap.py, не дублируются)
  + synthesize_parcel_financial (housing_class из цены, development_type из
  этажей, land_cost=кадастровая). None когда нельзя строить МКД / нет зонинга /
  нет площади.
- parcels.py: 1 вызов в try/except (hot-path-safe → None при сбое) + ключ
  financial_estimate в /analyze. Схема не тронута (AnalyzeResponse extra=allow,
  codegen не нужен). +18 тестов.

Frontend:
- ParcelFinancialEstimate тип (site-finder.ts, hand-typed).
- adaptInvestmentClearance(financial)/adaptFinanceDrawer(financial): реальные
  числа (GDV/Cost/Profit/ROI/IRR + NPV + срок окуп.) или честный placeholder
  когда null. Локализация класса/типа (high_rise→высотная). Прокинут analysis
  через PticaBottomGrid/drawer-registry. +6 тестов, 144 passed.

HEAVY caveat везде: ОРИЕНТИРОВОЧНАЯ модель по МАКС.застройке НСПД, НЕ реальная
концепция; land=кадастровая (не рыночная); график — типовой; IRR proxy-флаг.
mypy strict clean (generative.*), ruff/tsc/lint clean.

Закрывает эпик #1881 (финмодель = полноценная DCF, видна в кокпите).
Follow-up: финансирование (кредит/займы), §22 sales-pace, гео-радиус калибровки.

Refs #1881
2026-06-23 22:44:04 +05:00
..
test_best_layouts.py fix(site-finder): normalize supply room_bucket vocabulary to velocity side (#1229) 2026-06-13 15:02:50 +05:00
test_competitor_relevance.py feat(site-finder): per-competitor relevance_weight (#949 PR B) (#1000) 2026-06-02 19:45:38 +00:00
test_competitors_parking.py feat(site-finder): domrf→cad geom-match + parking_ratio конкурентов (#96) (#1327) 2026-06-14 14:49:28 +00:00
test_developer_attribution.py feat(site-finder): детерминированная атрибуция застройщика в analyze (#1088) 2026-06-13 16:13:45 +05:00
test_district_resolver.py feat(forecast): resolve admin district -> micro set in §9.x market/supply/sales filters 2026-06-05 07:03:37 +05:00
test_future_supply.py feat(forecasting): §9.x→§22 orchestrator + fix supply-side district resolution (3a) 2026-06-05 08:21:04 +05:00
test_locations.py fix(site_finder): make Location demand_index city-relative (#948) 2026-06-08 13:58:12 +05:00
test_macro.py fix(#945): indicator-aware default region in macro reader + document debt data-quality 2026-06-04 11:49:41 +05:00
test_market_metrics.py fix(forecasting): thread room_bucket into base_pace/compute_market_metrics for real format ranking (#1593) 2026-06-17 20:55:34 +03:00
test_own_portfolio.py feat(site-finder): own-portfolio data source for §25.3 cannibalization (#1169 PR1) 2026-06-08 16:21:53 +05:00
test_parcel_financial.py feat(site-finder): bridge финмодели (DCF) в кокпит Investment Clearance (epic #1881 PR-4) 2026-06-23 22:44:04 +05:00
test_pat_subzones.py fix(sf): робастный путь к koltsovo JSON в pat-loader (#1155) 2026-06-07 15:34:10 +00:00
test_premises_lookup.py feat(site-finder): per-building помещения/машино-места + parking_ratio (on-demand MVP, #96) 2026-06-14 18:48:16 +05:00
test_riasurt_lookup.py feat(site-finder): РИАСУРТ Свердл 14-layer harvest client+schema+task for ЕКБ agglomeration (#108) 2026-06-17 21:49:04 +03:00
test_supply_layers.py feat(forecast): resolve admin district -> micro set in §9.x market/supply/sales filters 2026-06-05 07:03:37 +05:00