Int-code the surveyed cylinder insulation label for the storage-loss cascade 🟩

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-07-14 23:25:48 +00:00
parent 87922b622a
commit f5e4814bf9

View file

@ -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,