From abec38a3976b8e460b0acc60c9de406c1a917edd Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Fri, 24 Jul 2026 09:18:06 +0000 Subject: [PATCH] =?UTF-8?q?Re-point=20a=20fuel-agnostic=20gas=20boiler=20t?= =?UTF-8?q?o=20oil=20or=20solid=20fuel=20by=20main=5Ffuel=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .../property/landlord_override_overlays.py | 4 ++ .../test_landlord_override_overlays.py | 47 +++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/repositories/property/landlord_override_overlays.py b/repositories/property/landlord_override_overlays.py index 29ebcea00..3d1fcdce5 100644 --- a/repositories/property/landlord_override_overlays.py +++ b/repositories/property/landlord_override_overlays.py @@ -110,6 +110,10 @@ _FUEL_FAMILY: dict[int, str] = { } +def resolve_boiler_archetype(heating_value: str, fuel_value: Optional[str]) -> str: + raise NotImplementedError + + def _override_value(overrides: ResolvedPropertyOverrides, component: str) -> Optional[str]: for row in overrides.rows: if row.override_component == component: diff --git a/tests/repositories/property/test_landlord_override_overlays.py b/tests/repositories/property/test_landlord_override_overlays.py index e35034ebc..c3f30fc3d 100644 --- a/tests/repositories/property/test_landlord_override_overlays.py +++ b/tests/repositories/property/test_landlord_override_overlays.py @@ -15,6 +15,7 @@ from domain.modelling.scoring.overlay_applicator import apply_simulations from repositories.property.landlord_override_overlays import ( flag_fuel_mismatch, overlays_from, + resolve_boiler_archetype, ) from repositories.property.property_overrides_reader import ( ResolvedPropertyOverride, @@ -25,6 +26,52 @@ from tests.domain.sap10_calculator.worksheet._elmhurst_worksheet_000490 import ( ) +@pytest.mark.parametrize( + ("heating_value", "fuel_value", "expected"), + [ + # A fuel-agnostic gas wet boiler re-points by the property's main_fuel + # family (ADR-0067). Oil preserves regular/combi; any solid fuel + # (coal/wood/dual) collapses to the single Solid fuel boiler member. + ("Gas boiler, regular", "oil", "Oil boiler, regular"), + ("Gas boiler, combi", "oil", "Oil boiler, combi"), + ("Gas boiler, regular", "house coal", "Solid fuel boiler"), + ("Gas boiler, regular", "wood logs", "Solid fuel boiler"), + ("Gas boiler, regular", "dual fuel (mineral and wood)", "Solid fuel boiler"), + ("Gas boiler, combi", "house coal", "Solid fuel boiler"), + ], +) +def test_resolve_boiler_archetype_repoints_a_gas_boiler_by_fuel( + heating_value: str, fuel_value: str, expected: str +) -> None: + # Act + resolved = resolve_boiler_archetype(heating_value, fuel_value) + + # Assert + assert resolved == expected + + +@pytest.mark.parametrize( + ("heating_value", "fuel_value"), + [ + # Gas / LPG stay on the gas archetype (RdSAP models LPG on gas), a missing + # fuel can't disambiguate, and a non-boiler archetype is never re-pointed. + ("Gas boiler, regular", "mains gas"), + ("Gas boiler, regular", "LPG (bulk)"), + ("Gas boiler, regular", None), + ("Electric room heaters", "oil"), + ("Solid fuel room heater, closed", "oil"), + ], +) +def test_resolve_boiler_archetype_leaves_other_cases_unchanged( + heating_value: str, fuel_value: str +) -> None: + # Act + resolved = resolve_boiler_archetype(heating_value, fuel_value) + + # Assert + assert resolved == heating_value + + def test_roof_type_row_produces_a_roof_overlay() -> None: # Arrange overrides = ResolvedPropertyOverrides(