mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice 1 of Bill Derivation — the reference-data foundation that later slices price the calculator's per-end-use kWh against: - Fuel enum (canonical billing fuels; the join key between the calculator's SAP-code fuels and the rates snapshot). COAL + HEAT_NETWORK are members with no national rate. - FuelRates value object: unit_rate_p_per_kwh / standing_charge_p_per_day / seg_export_p_per_kwh; raises UnpricedFuel on a fuel it has no rate for rather than billing at a wrong default. - FuelRatesRepository port (ADR-0011 Repo-reads-stored-reference-data) + StaticFileFuelRatesRepository reading a committed JSON snapshot. - Snapshot fuel_rates_2026_q2.json: GB national, Apr-Jun 2026 Ofgem cap (gas/electricity) + DESNZ/NEP May 2026 (off-gas). Carries the full researched data; the value object exposes single-rate fuels this slice. Off-peak (day/night), house coal and heat network raise UnpricedFuel until later slices. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
46 lines
1.4 KiB
Python
46 lines
1.4 KiB
Python
from __future__ import annotations
|
|
|
|
from collections.abc import Mapping
|
|
from dataclasses import dataclass
|
|
|
|
from domain.fuel_rates.fuel import Fuel, UnpricedFuel
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class FuelRate:
|
|
"""One fuel's current tariff: unit price + daily standing charge.
|
|
|
|
Off-gas fuels (oil / LPG / solid / wood) carry a ``0.0`` standing charge —
|
|
they are delivered, not metered, so there is no daily charge.
|
|
"""
|
|
|
|
unit_rate_p_per_kwh: float
|
|
standing_charge_p_per_day: float
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class FuelRates:
|
|
"""A current Fuel Rates snapshot — the rate per billing Fuel plus the SEG
|
|
export credit (ADR-0014). ``period`` records which window it is for, since
|
|
a committed snapshot goes stale on the Ofgem-cap (quarterly) cadence.
|
|
|
|
Pricing a fuel the snapshot does not carry raises ``UnpricedFuel`` rather
|
|
than defaulting — see [[reference-unmapped-sap-code]] for the same strict
|
|
discipline on the calculator side.
|
|
"""
|
|
|
|
period: str
|
|
seg_export_p_per_kwh: float
|
|
rates: Mapping[Fuel, FuelRate]
|
|
|
|
def unit_rate_p_per_kwh(self, fuel: Fuel) -> float:
|
|
return self._rate(fuel).unit_rate_p_per_kwh
|
|
|
|
def standing_charge_p_per_day(self, fuel: Fuel) -> float:
|
|
return self._rate(fuel).standing_charge_p_per_day
|
|
|
|
def _rate(self, fuel: Fuel) -> FuelRate:
|
|
rate = self.rates.get(fuel)
|
|
if rate is None:
|
|
raise UnpricedFuel(fuel)
|
|
return rate
|