"""IO contracts for the market indicator endpoints (Issue #99). POST /api/v1/market/ddu-indicator — mirrors the ARN/НСПД request body so the frontend can reuse one UI pattern for primary (наша ДДУ) vs secondary (ARN). Field names are camelCase (ARN-compatible) via validation aliases; snake_case also accepted (populate_by_name). """ from __future__ import annotations from typing import Any from pydantic import BaseModel, ConfigDict, Field class DduIndicatorRequest(BaseModel): """ARN-shaped request body. Unsupported options are reported in `notes` of the response rather than rejected (MVP supports Q / methods 1,2 / subj 66). """ model_config = ConfigDict(populate_by_name=True) # ARN indicator types M/Q/H/Y. MVP supports only 'Q'. indicators: list[str] | None = Field(default=None) # 1 = basis, 2 = previous, (3 = year-ago — unsupported in MVP). calculation_method: int = Field(default=2, ge=1, le=3, alias="calculationMethod") # ARN-style period bounds, e.g. '2025-Q2' .. '2026-Q1'. None = unbounded. period_from: str | None = Field(default=None, alias="periodFrom", max_length=10) period_to: str | None = Field(default=None, alias="periodTo", max_length=10) # ARN federal district ids (e.g. [6] = Уральский). Informational in MVP. federal_district: list[int] | None = Field(default=None, alias="federalDistrict") # ARN subject codes. Only '66' (Свердловская обл.) is backed by data. federal_subject: list[str] | None = Field(default=None, alias="federalSubject") # ARN cadastral quarters. NOT supported (primary-market ДДУ too sparse per # cad_quarter) — accepted for shape-compat, reported as unsupported. cadastral_quarter: list[str] | None = Field(default=None, alias="cadastralQuarter") # ARN area-range ids 1..6 (0 = all-area headline). None → all present. area_ranges: list[int] | None = Field(default=None, alias="areaRanges") class DduIndicatorResponse(BaseModel): """Free-form ARN-mirror response (table + graph + meta + notes).""" meta: dict[str, Any] table: list[dict[str, Any]] graph: list[dict[str, Any]] notes: list[str]