diff --git a/domain/sap10_calculator/rdsap/cert_to_inputs.py b/domain/sap10_calculator/rdsap/cert_to_inputs.py index 952b0a77..caff68c0 100644 --- a/domain/sap10_calculator/rdsap/cert_to_inputs.py +++ b/domain/sap10_calculator/rdsap/cert_to_inputs.py @@ -8154,6 +8154,17 @@ def cert_to_inputs( eff, ) + # ADR-0014 Bill Derivation — Off-Peak Meter day/night billing metadata. + # The off-peak `_fuel_cost` path returns the zero `FuelCostResult` (deferring + # to the legacy scalar rates), so the bill's per-end-use High-Rate Fractions + # are sourced here from the SAME Table 12a helpers the scalar cost path uses, + # keeping the bill's day/night split identical to the rating's. + _billing_tariff = _rdsap_tariff(epc) + _is_off_peak_meter = _billing_tariff is not Tariff.STANDARD + _main_high_rate_fraction = _main_space_heating_high_rate_fraction( + main, _billing_tariff + ) + return CalculatorInputs( dimensions=dim, heat_transmission=ht, @@ -8218,6 +8229,8 @@ def cert_to_inputs( ), secondary_heating_fuel_code=_secondary_fuel_code(epc), hot_water_fuel_code=_water_heating_fuel_code(epc), + is_off_peak_meter=_is_off_peak_meter, + main_heating_high_rate_fraction=_main_high_rate_fraction, space_heating_fuel_cost_gbp_per_kwh=_space_heating_fuel_cost_gbp_per_kwh( main, _rdsap_tariff(epc), prices ), diff --git a/tests/domain/sap10_calculator/rdsap/test_cert_to_inputs.py b/tests/domain/sap10_calculator/rdsap/test_cert_to_inputs.py index b269c448..1a0cb680 100644 --- a/tests/domain/sap10_calculator/rdsap/test_cert_to_inputs.py +++ b/tests/domain/sap10_calculator/rdsap/test_cert_to_inputs.py @@ -836,6 +836,42 @@ def test_integrated_storage_heater_408_bills_table_12a_grid1_high_rate_fraction( assert abs(inputs.space_heating_fuel_cost_gbp_per_kwh - 0.07458) <= 1e-9 +def test_off_peak_storage_cert_surfaces_billing_meter_flag_and_main_fraction() -> None: + # Arrange — the same integrated-storage (code 408) Economy-7 cert. For + # ADR-0014 Bill Derivation, cert_to_inputs surfaces the Off-Peak Meter flag + # and the main-heating High-Rate Fraction — the SAME Table 12a Grid 1 value + # (0.20) the SAP cost path blends above, so the bill never re-derives it. + from dataclasses import replace + + main = MainHeatingDetail( + has_fghrs=False, + main_fuel_type=29, # electricity + heat_emitter_type=1, + emitter_temperature=1, + main_heating_control=2401, + main_heating_category=7, # electric storage heaters + sap_main_heating_code=408, + ) + base = make_minimal_sap10_epc( + total_floor_area_m2=_TYPICAL_TFA_M2, + habitable_rooms_count=4, + country_code="ENG", + sap_building_parts=[make_building_part(construction_age_band="E")], + sap_heating=make_sap_heating(main_heating_details=[main]), + ) + epc = replace( + base, + sap_energy_source=replace(base.sap_energy_source, meter_type="1"), # Dual + ) + + # Act + inputs = cert_to_inputs(epc) + + # Assert — whole-meter off-peak, main heating high-rate fraction 0.20. + assert inputs.is_off_peak_meter is True + assert inputs.main_heating_high_rate_fraction == 0.20 + + def test_off_peak_immersion_unlodged_type_defaults_to_dual_table13_blend() -> None: # Arrange — electric immersion DHW (WHC 903) on a Dual / Economy-7 (7-hour) # meter with a cylinder present (Normal / 110 L), but the cert does NOT lodge