mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
Load the off-peak day/night rate from the committed snapshot 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bda8a3f276
commit
1acfc08fce
2 changed files with 32 additions and 8 deletions
|
|
@ -5,7 +5,7 @@ from pathlib import Path
|
|||
from typing import Any, Optional
|
||||
|
||||
from domain.fuel_rates.fuel import Fuel
|
||||
from domain.fuel_rates.fuel_rates import FuelRate, FuelRates
|
||||
from domain.fuel_rates.fuel_rates import FuelRate, FuelRates, OffPeakRate
|
||||
from repositories.fuel_rates.fuel_rates_repository import FuelRatesRepository
|
||||
|
||||
_DEFAULT_SNAPSHOT = Path(__file__).parent / "data" / "fuel_rates_2026_q2.json"
|
||||
|
|
@ -14,10 +14,12 @@ _DEFAULT_SNAPSHOT = Path(__file__).parent / "data" / "fuel_rates_2026_q2.json"
|
|||
class FuelRatesStaticFileRepository(FuelRatesRepository):
|
||||
"""Reads Fuel Rates from a committed JSON snapshot (ADR-0014).
|
||||
|
||||
Only **single-rate** fuels (those lodging a ``unit_rate_p_per_kwh``) are
|
||||
exposed. Off-peak (day/night) and the unpriced gaps (null entries — house
|
||||
coal, heat network) are skipped, so pricing them raises ``UnpricedFuel``.
|
||||
The day/night accessor for off-peak lands in a later slice.
|
||||
**Single-rate** fuels (those lodging a ``unit_rate_p_per_kwh``) populate the
|
||||
``rates`` map. The **off-peak** entry — a dual-rate meter lodging
|
||||
``day_p_per_kwh`` / ``night_p_per_kwh`` — loads as an ``OffPeakRate`` (each
|
||||
end use blends day/night by its own High-Rate Fraction). The unpriced gaps
|
||||
(null entries — house coal, heat network) are skipped, so pricing them
|
||||
raises ``UnpricedFuel``.
|
||||
"""
|
||||
|
||||
def __init__(self, snapshot_path: Optional[Path] = None) -> None:
|
||||
|
|
@ -27,11 +29,19 @@ class FuelRatesStaticFileRepository(FuelRatesRepository):
|
|||
payload: dict[str, Any] = json.loads(self._snapshot_path.read_text())
|
||||
fuels: dict[str, Any] = payload["fuels"]
|
||||
rates: dict[Fuel, FuelRate] = {}
|
||||
off_peak: Optional[OffPeakRate] = None
|
||||
for name, entry in fuels.items():
|
||||
if entry is None:
|
||||
continue # an unpriced gap (house coal / heat network)
|
||||
if name == Fuel.ELECTRICITY_OFF_PEAK.name:
|
||||
off_peak = OffPeakRate(
|
||||
day_p_per_kwh=float(entry["day_p_per_kwh"]),
|
||||
night_p_per_kwh=float(entry["night_p_per_kwh"]),
|
||||
standing_charge_p_per_day=float(entry["standing_charge_p_per_day"]),
|
||||
)
|
||||
continue
|
||||
if "unit_rate_p_per_kwh" not in entry:
|
||||
continue # off-peak day/night — priced in a later slice
|
||||
continue # an unpriced gap with no single rate
|
||||
rates[Fuel[name]] = FuelRate(
|
||||
unit_rate_p_per_kwh=float(entry["unit_rate_p_per_kwh"]),
|
||||
standing_charge_p_per_day=float(entry["standing_charge_p_per_day"]),
|
||||
|
|
@ -40,4 +50,5 @@ class FuelRatesStaticFileRepository(FuelRatesRepository):
|
|||
period=str(payload["period"]),
|
||||
seg_export_p_per_kwh=float(payload["seg_export_p_per_kwh"]),
|
||||
rates=rates,
|
||||
off_peak=off_peak,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -55,8 +55,21 @@ def test_dual_fuel_carries_a_derived_midpoint_rate() -> None:
|
|||
assert rates.standing_charge_p_per_day(Fuel.DUAL_FUEL_MINERAL_AND_WOOD) == 0.0
|
||||
|
||||
|
||||
def test_off_peak_remains_unpriced_pending_the_day_night_accessor() -> None:
|
||||
# Arrange — off-peak still needs the day/night split a later slice adds (ADR-0014).
|
||||
def test_off_peak_meter_prices_day_night_from_the_snapshot() -> None:
|
||||
# Arrange — the committed snapshot's off-peak entry carries a day/night
|
||||
# split (ADR-0014 2026-06-24 amendment); the repo loads it as an OffPeakRate.
|
||||
rates = FuelRatesStaticFileRepository().get_current()
|
||||
|
||||
# Act / Assert — an all-night load bills at the night rate, an all-day load
|
||||
# at the day rate, and the off-peak meter carries its own standing charge.
|
||||
assert rates.off_peak_blended_p_per_kwh(high_rate_fraction=0.0) == 13.89
|
||||
assert rates.off_peak_blended_p_per_kwh(high_rate_fraction=1.0) == 29.73
|
||||
assert rates.standing_charge_p_per_day(Fuel.ELECTRICITY_OFF_PEAK) == 56.99
|
||||
|
||||
|
||||
def test_off_peak_has_no_single_unit_rate() -> None:
|
||||
# Arrange — off-peak has no single blended unit rate; callers must price it
|
||||
# day/night via a High-Rate Fraction, so unit_rate_p_per_kwh still raises.
|
||||
rates = FuelRatesStaticFileRepository().get_current()
|
||||
|
||||
# Act / Assert
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue