From f5e4814bf991dcee6f2d45c6d2bc01fc0e277655 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 14 Jul 2026 23:25:48 +0000 Subject: [PATCH] =?UTF-8?q?Int-code=20the=20surveyed=20cylinder=20insulati?= =?UTF-8?q?on=20label=20for=20the=20storage-loss=20cascade=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- datatypes/epc/domain/mapper.py | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/datatypes/epc/domain/mapper.py b/datatypes/epc/domain/mapper.py index 037bf833a..74d08e4cb 100644 --- a/datatypes/epc/domain/mapper.py +++ b/datatypes/epc/domain/mapper.py @@ -6260,7 +6260,9 @@ def _map_sap_heating( if cylinder_present else None ), - cylinder_insulation_type=heating.water_heating.insulation_type, + cylinder_insulation_type=_pashub_cylinder_insulation_type_code( + heating.water_heating.insulation_type, cylinder_present + ), cylinder_insulation_thickness_mm=heating.water_heating.insulation_thickness_mm, water_heating_code=water_heating_code, water_heating_fuel=water_heating_fuel, @@ -6370,6 +6372,31 @@ def _pashub_cylinder_size_code( return code +# PasHub surveyed §Water-Heating cylinder "Insulation Type:" label → SAP10 +# `cylinder_insulation_type` cascade code (foam=1 / jacket=2, mirroring +# `_ELMHURST_CYLINDER_INSULATION_LABEL_TO_SAP10`). Passed through raw, the +# storage-loss resolver's `_int_or_none` yields None and a real lodged +# cylinder is billed ZERO storage loss. +_PASHUB_CYLINDER_INSULATION_TO_SAP10: Dict[str, int] = { + "Factory fitted": 1, # factory-applied foam +} + + +def _pashub_cylinder_insulation_type_code( + insulation_label: Optional[str], cylinder_present: bool +) -> Optional[int]: + """Resolve a PasHub surveyed cylinder insulation label to the SAP10 code + at the mapper boundary (ADR-0015). Returns None when no cylinder is + present or the label is genuinely absent; any uncovered non-empty label + strict-raises (mirroring `_pashub_cylinder_size_code`).""" + if not cylinder_present or not insulation_label: + return None + code = _PASHUB_CYLINDER_INSULATION_TO_SAP10.get(insulation_label) + if code is None: + raise UnmappedPasHubLabel("cylinder insulation", insulation_label) + return code + + def _map_sap_ventilation(ventilation: Ventilation) -> SapVentilation: return SapVentilation( ventilation_type=ventilation.ventilation_type,