From 5220b51961c53d95e39846f327561cf3cc64e24d Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 14 Jul 2026 21:43:00 +0000 Subject: [PATCH] =?UTF-8?q?Dispatch=20PasHub=20mechanical=20ventilation=20?= =?UTF-8?q?into=20the=20=C2=A72=20ACH=20cascade=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) --- .../epc/domain/tests/test_from_site_notes.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/datatypes/epc/domain/tests/test_from_site_notes.py b/datatypes/epc/domain/tests/test_from_site_notes.py index 48094d833..0fbab02fa 100644 --- a/datatypes/epc/domain/tests/test_from_site_notes.py +++ b/datatypes/epc/domain/tests/test_from_site_notes.py @@ -122,6 +122,52 @@ class TestPhotovoltaicArrayMapping: assert result.sap_energy_source.photovoltaic_arrays is None +class TestMechanicalVentilationKindCoding: + """The surveyed "Ventilation type" label must resolve to the + `MechanicalVentilationKind` enum name the ยง2 cascade dispatches on โ€” + left None, `ventilation_from_cert` silently defaults every mechanical + system to NATURAL (24d), dropping its ACH heat loss (issue #1590 bug 4; + 76/205 cohort fixtures lodge a mechanical system). Targets mirror the + gov-API table `_API_MECHANICAL_VENTILATION_TO_KIND` (dMEV/MEV/PIV-outside + โ†’ EXTRACT_OR_PIV_OUTSIDE; PIV-from-loft is "as natural" โ†’ None). + """ + + @pytest.mark.parametrize( + "label, expected_kind", + [ + ("Natural", None), + ("Mechanical Extract - Decentralised", "EXTRACT_OR_PIV_OUTSIDE"), + ("Mechanical Extract - Centralised", "EXTRACT_OR_PIV_OUTSIDE"), + ("Positive Input - From Outside", "EXTRACT_OR_PIV_OUTSIDE"), + ("Positive Input - From Loft (As Natural)", None), + ], + ) + def test_label_maps_to_mechanical_kind( + self, label: str, expected_kind: Optional[str] + ) -> None: + # Arrange + data = load("pashub_rdsap_site_notes_example1.json") + data["ventilation"]["ventilation_type"] = label + survey = from_dict(PasHubRdSapSiteNotes, data) + + # Act + result = EpcPropertyDataMapper.from_site_notes(survey) + + # Assert + assert result.sap_ventilation is not None + assert result.sap_ventilation.mechanical_ventilation_kind == expected_kind + + def test_unknown_label_strict_raises(self) -> None: + # Arrange + data = load("pashub_rdsap_site_notes_example1.json") + data["ventilation"]["ventilation_type"] = "Some novel system" + survey = from_dict(PasHubRdSapSiteNotes, data) + + # Act / Assert + with pytest.raises(UnmappedPasHubLabel, match="ventilation type"): + EpcPropertyDataMapper.from_site_notes(survey) + + class TestPvConnectionCoding: """The surveyed "PV Connection" label must resolve to the gov-API int enum the calculator's credit gate keys off (`_pv_connected_to_dwelling_meter`: