From bda8a3f276e719a1917758c17e2121e05adbd5fc Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 24 Jun 2026 17:14:51 +0000 Subject: [PATCH] =?UTF-8?q?Expose=20an=20off-peak=20meter's=20standing=20c?= =?UTF-8?q?harge=20and=20full=20day/night=20blend=20range=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- domain/fuel_rates/fuel_rates.py | 4 +++ tests/domain/fuel_rates/test_fuel_rates.py | 34 ++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/domain/fuel_rates/fuel_rates.py b/domain/fuel_rates/fuel_rates.py index 81f78ab0..2266b75a 100644 --- a/domain/fuel_rates/fuel_rates.py +++ b/domain/fuel_rates/fuel_rates.py @@ -69,6 +69,10 @@ class FuelRates: return self._rate(fuel).unit_rate_p_per_kwh def standing_charge_p_per_day(self, fuel: Fuel) -> float: + if fuel is Fuel.ELECTRICITY_OFF_PEAK: + if self.off_peak is None: + raise UnpricedFuel(fuel) + return self.off_peak.standing_charge_p_per_day return self._rate(fuel).standing_charge_p_per_day def _rate(self, fuel: Fuel) -> FuelRate: diff --git a/tests/domain/fuel_rates/test_fuel_rates.py b/tests/domain/fuel_rates/test_fuel_rates.py index 432fcb63..55472aeb 100644 --- a/tests/domain/fuel_rates/test_fuel_rates.py +++ b/tests/domain/fuel_rates/test_fuel_rates.py @@ -36,6 +36,40 @@ def test_off_peak_blended_rate_at_zero_high_fraction_is_the_night_rate() -> None assert blended == 13.89 +def test_off_peak_blended_rate_at_full_high_fraction_is_the_day_rate() -> None: + # Arrange — an all-day load (high-rate fraction 1.0). + rates = _off_peak_rates() + + # Act / Assert — every kWh bills at the dearer day rate. + assert rates.off_peak_blended_p_per_kwh(high_rate_fraction=1.0) == 29.73 + + +def test_off_peak_blended_rate_blends_day_and_night_linearly() -> None: + # Arrange — 25% of the load at the day rate, 75% at night. + rates = _off_peak_rates() + + # Act / Assert — 0.25 * 29.73 + 0.75 * 13.89 = 17.85 + assert rates.off_peak_blended_p_per_kwh(high_rate_fraction=0.25) == pytest.approx(17.85) + + +def test_off_peak_blend_without_a_snapshot_off_peak_entry_raises_unpriced_fuel() -> None: + # Arrange — a snapshot that carries no off-peak entry at all. + rates = _rates() + + # Act / Assert + with pytest.raises(UnpricedFuel) as excinfo: + rates.off_peak_blended_p_per_kwh(high_rate_fraction=0.5) + assert excinfo.value.fuel is Fuel.ELECTRICITY_OFF_PEAK + + +def test_off_peak_meter_standing_charge_reads_back() -> None: + # Arrange — the bill adds the off-peak meter's standing charge once per meter. + rates = _off_peak_rates() + + # Act / Assert + assert rates.standing_charge_p_per_day(Fuel.ELECTRICITY_OFF_PEAK) == 56.99 + + def test_unit_rate_and_standing_charge_read_back_for_a_priced_fuel() -> None: # Arrange rates = _rates()