"""Product — a catalogue entry a Measure Option installs. Carries the data needed to price an Option: a fully-loaded unit cost and the per-Measure-Type contingency rate carried alongside it (CONTEXT.md). The catalogue is equipment-dominated (heat pumps, glazing, PV) — hence "Product", not "material". Read via a `ProductRepository`. """ from dataclasses import dataclass from typing import Optional @dataclass(frozen=True) class Product: measure_type: str unit_cost_per_m2: float contingency_rate: float # The catalogue row id, threaded onto the persisted Plan Measure as # ``recommendation.material_id`` (the single-material reference that replaces # the retired ``recommendation_materials`` BOM). Optional: the JSON # stopgap catalogue carries no ids. id: Optional[int] = None