From 0135f0f27b33a1d0f9e871d5c6fa4c36a27155df Mon Sep 17 00:00:00 2001 From: Jun-te Kim Date: Fri, 19 Jun 2026 13:41:20 +0000 Subject: [PATCH] =?UTF-8?q?Resolve=20a=20landlord=20age-band=20override=20?= =?UTF-8?q?onto=20the=20main=20building=20part=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) --- .../construction_age_band_overlay.py | 22 ++++++++++++++++++ domain/modelling/simulation.py | 6 +++++ .../epc/test_construction_age_band_overlay.py | 23 +++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 domain/epc/property_overlays/construction_age_band_overlay.py create mode 100644 tests/domain/epc/test_construction_age_band_overlay.py diff --git a/domain/epc/property_overlays/construction_age_band_overlay.py b/domain/epc/property_overlays/construction_age_band_overlay.py new file mode 100644 index 00000000..d4cc6eae --- /dev/null +++ b/domain/epc/property_overlays/construction_age_band_overlay.py @@ -0,0 +1,22 @@ +"""Map a Landlord-Override construction-age-band value to a fabric Simulation +Overlay. + +A construction-age-band value is the RdSAP England-&-Wales letter code (A..M) +the calculator's U-value cascades key on (`SapBuildingPart.construction_age_band`, +read via `.strip().upper()` against the letter-code bands). The overlay targets +the override's building part and sets the band; an unrecognised code produces no +overlay. Re-dating a part re-derives its construction-default U-values, so this +is the highest-leverage fabric override. +""" + +from __future__ import annotations + +from typing import Optional + +from domain.modelling.simulation import EpcSimulation + + +def age_band_overlay_for( + age_band_value: str, building_part: int +) -> Optional[EpcSimulation]: + raise NotImplementedError diff --git a/domain/modelling/simulation.py b/domain/modelling/simulation.py index 217d446b..caee5fb5 100644 --- a/domain/modelling/simulation.py +++ b/domain/modelling/simulation.py @@ -28,6 +28,12 @@ class BuildingPartOverlay: # The wall material (RdSAP `wall_construction` code). Left `None` by Measures # — insulating a wall doesn't change its material — but set by a Landlord # Override that corrects the construction itself (ADR-0032). + # RdSAP England-&-Wales construction age band — the letter code A..M the + # calculator's U-value cascades key on (`SapBuildingPart.construction_age_band`). + # Left `None` by Measures (retrofits don't change build era); set by a Landlord + # Override that corrects the lodged age band, which re-derives this part's + # fabric U-value defaults. Folds onto the part via the generic field loop. + construction_age_band: Optional[str] = None wall_construction: Optional[int] = None wall_insulation_type: Optional[int] = None # Added solid-wall insulation depth (mm) — drives the calculator's Table 6 diff --git a/tests/domain/epc/test_construction_age_band_overlay.py b/tests/domain/epc/test_construction_age_band_overlay.py new file mode 100644 index 00000000..066244a6 --- /dev/null +++ b/tests/domain/epc/test_construction_age_band_overlay.py @@ -0,0 +1,23 @@ +"""The Landlord-Override construction-age-band → fabric Simulation Overlay. + +An age-band value resolves to the RdSAP letter code the calculator's U-value +cascades read from `SapBuildingPart.construction_age_band`; the overlay targets +the override's building part. +""" + +from __future__ import annotations + +from datatypes.epc.domain.epc_property_data import BuildingPartIdentifier +from domain.epc.property_overlays.construction_age_band_overlay import ( + age_band_overlay_for, +) + + +def test_age_band_overlays_the_main_building_part() -> None: + # Act — band B (1900-1929) on the main building part. + simulation = age_band_overlay_for("B", 0) + + # Assert + assert simulation is not None + overlay = simulation.building_parts[BuildingPartIdentifier.MAIN] + assert overlay.construction_age_band == "B"