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
37 lines
1.3 KiB
TypeScript
37 lines
1.3 KiB
TypeScript
"use client";
|
|
|
|
/**
|
|
* PticaBottomGrid — the prototype's `.bottom-grid` row, rendered below the lower
|
|
* grid: Investment Clearance · Buy Signal · Legal Status · Site Verdict. Each
|
|
* card wires to REAL /analyze + §22 data with honest placeholders.
|
|
*/
|
|
|
|
import styles from "@/app/site-finder/analysis/[cad]/ptica/ptica.module.css";
|
|
import type { ParcelAnalysis } from "@/types/site-finder";
|
|
import type { ForecastReport } from "@/types/forecast";
|
|
import type { DrawerKey } from "@/components/site-finder/ptica/drawers/drawer-keys";
|
|
import { InvestmentClearance } from "./InvestmentClearance";
|
|
import { BuySignalCard } from "./BuySignalCard";
|
|
import { LegalStatus } from "./LegalStatus";
|
|
import { SiteVerdictCard } from "./SiteVerdictCard";
|
|
|
|
interface Props {
|
|
analysis: ParcelAnalysis;
|
|
forecastReport?: ForecastReport;
|
|
onOpenDrawer: (key: DrawerKey) => void;
|
|
}
|
|
|
|
export function PticaBottomGrid({
|
|
analysis,
|
|
forecastReport,
|
|
onOpenDrawer,
|
|
}: Props) {
|
|
return (
|
|
<section id="ptica-economy" className={styles.bottomGrid}>
|
|
<InvestmentClearance analysis={analysis} onOpenDrawer={onOpenDrawer} />
|
|
<BuySignalCard forecastReport={forecastReport} />
|
|
<LegalStatus analysis={analysis} onOpenDrawer={onOpenDrawer} />
|
|
<SiteVerdictCard analysis={analysis} forecastReport={forecastReport} />
|
|
</section>
|
|
);
|
|
}
|