M8-T16: add thermal meter cost APIs

This commit is contained in:
2026-08-23 21:22:06 +02:00
parent 489e5b596a
commit 3eec701448
12 changed files with 1843 additions and 19 deletions
+18
View File
@@ -76,6 +76,24 @@ class PricesResponse(BaseModel):
"Null for tibber contracts and when no active contract exists."
),
)
contract_version_id: int | None = Field(
default=None,
description="Thermal active contract version identifier; omitted for electricity.",
)
effective_from: datetime | None = Field(
default=None,
description="Thermal contract version start; omitted for electricity.",
)
effective_to: datetime | None = Field(
default=None,
description="Thermal contract version end; omitted for electricity.",
)
values: dict[str, dict[str, str]] | None = Field(
default=None,
description="Thermal normalized Decimal-string contract values; omitted for electricity.",
)
model_config = {"ser_json_exclude_none": True}
# ---------------------------------------------------------------------------
+62
View File
@@ -0,0 +1,62 @@
"""Schemas for the commodity-scoped thermal cost ledger."""
from __future__ import annotations
from datetime import datetime
from typing import Literal
from pydantic import BaseModel, Field
class MeterCostPeriodSchema(BaseModel):
"""One auditable thermal ledger row; all Decimal values are JSON strings."""
commodity: Literal["heating", "hot_water"]
period_start: datetime
period_end: datetime
meter_id: int | None
source_binding_id: int | None
contract_version_id: int | None
quantity: str
cost: str
currency: str
cost_breakdown: dict[str, str]
pricing_snapshot: dict[str, dict[str, str]]
quality: str
degraded: bool
degraded_reason: str | None
class MeterCostsResponse(BaseModel):
items: list[MeterCostPeriodSchema]
total: int = Field(description="Total matching rows before pagination.")
class ThermalFixedBreakdown(BaseModel):
"""D11 annual-standing charges accrued per settled local day, as Decimal strings."""
heating_network: str
metering: str
delivery_set: str
hot_water_network: str
other: str
class ThermalCostSummaryResponse(BaseModel):
currency: str
heating: str
hot_water_heating: str
hot_water: str
hot_water_tax: str
variable_subtotal: str
fixed_breakdown: ThermalFixedBreakdown
fixed_subtotal: str
all_in: str
period_count: int
degraded_count: int
class MeterCostRecomputeResponse(BaseModel):
processed: int
normal: int
degraded: int