from typing import Any, Literal from pydantic import BaseModel, Field class ConceptInput(BaseModel): """Stage 1a — input contract. Frozen interface for frontend codegen.""" parcel_geojson: dict[str, Any] = Field( ..., description="GeoJSON Polygon of the parcel (WGS84 / EPSG:4326)" ) housing_class: Literal["econom", "comfort", "business"] = "comfort" target_floors: int = Field(9, ge=1, le=30) development_type: Literal["spot", "mid_rise", "high_rise"] = "mid_rise" land_cost_rub: float | None = Field( None, ge=0, description="Optional land cost for financial model" ) class TEAP(BaseModel): """Технико-экономические показатели.""" built_area_sqm: float total_floor_area_sqm: float residential_area_sqm: float apartments_count: int density: float parking_spaces: int class FinancialModel(BaseModel): """Static developer P&L for a concept variant (PR-1, эпик #1881). Full static cost cascade + VAT + profit tax → net profit + ROI. NOT a DCF — timing/discounting lands in PR-3. VAT is a documented simplification (see ``compute_financial`` docstring), not exact НК РФ mechanics. The legacy summary fields (``revenue_rub`` / ``cost_rub`` / ``gross_margin_rub`` / ``irr``) are kept for backward-compat; the new fields expose the full cascade and the net P&L. """ # ── Legacy summary (backward-compat) ─────────────────────────────────────── revenue_rub: float cost_rub: float gross_margin_rub: float irr: float # ── Revenue breakdown ────────────────────────────────────────────────────── revenue_residential_rub: float revenue_parking_rub: float # ── Cost cascade ─────────────────────────────────────────────────────────── construction_rub: float pir_rub: float networks_rub: float developer_services_rub: float contingency_rub: float marketing_rub: float land_rub: float # ── БДР / taxes → net profit ─────────────────────────────────────────────── vat_rub: float profit_before_tax_rub: float profit_tax_rub: float net_profit_rub: float # ── Metrics ──────────────────────────────────────────────────────────────── roi: float # net profit / total cost margin_pct: float # net profit / revenue irr_is_proxy: bool = True # frontend caveat: not a real DCF IRR (см. PR-3) class ConceptVariant(BaseModel): strategy: Literal["max_area", "max_insolation", "balanced"] buildings_geojson: dict[str, Any] teap: TEAP financial: FinancialModel class ConceptOutput(BaseModel): variants: list[ConceptVariant]