diff --git a/datatypes/epc/domain/epc_property_data.py b/datatypes/epc/domain/epc_property_data.py index d55aa1593..d6e3a70be 100644 --- a/datatypes/epc/domain/epc_property_data.py +++ b/datatypes/epc/domain/epc_property_data.py @@ -306,7 +306,7 @@ class SapConservatory: class SapWindow: frame_material: Optional[str] glazing_gap: Union[int, str] - orientation: Union[int, str] + orientation: Optional[Union[int, str]] # SAP10 octant 1..8; None → no solar gain window_type: Union[int, str] glazing_type: Union[int, str] window_width: float diff --git a/datatypes/epc/domain/mapper.py b/datatypes/epc/domain/mapper.py index 9818c6fa7..d914bec2e 100644 --- a/datatypes/epc/domain/mapper.py +++ b/datatypes/epc/domain/mapper.py @@ -6167,7 +6167,7 @@ def _map_sap_window(window: Window) -> SapWindow: return SapWindow( frame_material=window.frame_type, glazing_gap=window.glazing_gap, - orientation=window.orientation, + orientation=_pashub_orientation_int(window.orientation), window_type=window.window_type, glazing_type=_pashub_glazing_type_int(window.glazing_type), window_width=window.width_m, @@ -7153,6 +7153,23 @@ def _elmhurst_orientation_int(orientation: str) -> int: return _ELMHURST_ORIENTATION_TO_SAP10.get(orientation, 1) +def _pashub_orientation_int(orientation: Optional[str]) -> Optional[int]: + """Map a PasHub window orientation label to the SAP10 octant code (1..8) + at the mapper boundary (ADR-0015). PasHub lodges it space-separated + ("South East") where the shared octant map keys hyphenated, so normalise + before lookup (mirroring `_pashub_pv_arrays`). Blank → None (the solar- + gains cascade skips a window with no orientation). Any uncovered non-empty + label strict-raises (mirroring the other `_pashub_*` coders) — passed + through raw, the string reaches the int-only `_orientation` and silently + zeroes the window's solar-gain contribution.""" + if not orientation: + return None + code = _ELMHURST_ORIENTATION_TO_SAP10.get(orientation.replace(" ", "-")) + if code is None: + raise UnmappedPasHubLabel("window orientation", orientation) + return code + + # RdSAP 10 §3.7.1 (PDF p.21) — the source RdSAP data set classifies # each opening as "Window (vertical)" or "Roof window (inclined)" per # the assessor's discrete lodgement. The Elmhurst Summary PDF §11.0