From be1e10e3373a9595e3d2bcb5d7840bdfe6426b5c Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 15 Jul 2026 00:26:51 +0000 Subject: [PATCH] =?UTF-8?q?Int-code=20the=20surveyed=20secondary-heating?= =?UTF-8?q?=20label=20to=20its=20Table=204a=20room-heater=20code=20?= =?UTF-8?q?=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 | 35 +++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/datatypes/epc/domain/mapper.py b/datatypes/epc/domain/mapper.py index 74d08e4cb..c12f87d4e 100644 --- a/datatypes/epc/domain/mapper.py +++ b/datatypes/epc/domain/mapper.py @@ -6250,7 +6250,9 @@ def _map_sap_heating( ], has_fixed_air_conditioning=ventilation.has_fixed_air_conditioning, secondary_fuel_type=secondary_fuel_type, - secondary_heating_type=heating.secondary_heating.secondary_system, + secondary_heating_type=_pashub_secondary_heating_type_code( + heating.secondary_heating.secondary_system + ), shower_outlets=shower_outlets, cylinder_size=( _pashub_cylinder_size_code( @@ -6372,6 +6374,37 @@ def _pashub_cylinder_size_code( return code +# PasHub surveyed "Secondary System:" label → SAP 10.2 Table 4a room-heater +# code (PCDB `room_heaters` descriptions). Passed through raw, the string +# hits `_secondary_efficiency`'s `_int_or_none` and silently defaults to +# code 693 (portable electric heater, eff 1.00) — over-crediting a gas/solid +# open fire that should bill at 40-63% / 32%. +_PASHUB_SECONDARY_HEATING_TYPE_TO_SAP10: Dict[str, int] = { + # Electric direct-acting (eff 1.00) — modal cohort heater. + "Panel, convector or radiant heaters": 691, + # Gas room heaters (Table 4a column A). + "Flush fitting live fuel effect open front fire, sealed to fireplace": 605, + "1980 or later - Open front fire with open flue, sealed to fireplace": 603, + # Solid fuel (eff 0.32 column B). + "Open fire in grate": 631, +} + + +def _pashub_secondary_heating_type_code( + system_label: Optional[str], +) -> Optional[int]: + """Resolve a PasHub surveyed secondary-heating system label to its SAP + 10.2 Table 4a code at the mapper boundary (ADR-0015). Blank/"No + Secondary Heating" → None; any uncovered non-empty label strict-raises + (mirroring `_pashub_secondary_fuel_code`).""" + if not system_label or system_label == "No Secondary Heating": + return None + code = _PASHUB_SECONDARY_HEATING_TYPE_TO_SAP10.get(system_label) + if code is None: + raise UnmappedPasHubLabel("secondary heating type", system_label) + 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