diff --git a/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py b/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py index 2e74aa30..ceff10a8 100644 --- a/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py +++ b/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py @@ -286,3 +286,23 @@ def test_summary_001479_main_party_wall_construction_is_cavity_unfilled() -> Non # Assert assert epc.sap_building_parts[0].party_wall_construction == 4 + + +def test_summary_001479_ext2_floor_is_exposed_to_external_air() -> None: + # Arrange — cert 001479 Ext2 §9 lodges "Location: E To external air" + # — a cantilevered exposed timber floor (the upper-storey extension + # over the back garden). The worksheet's §3 row `Exposed floor Ext2 + # … 1.92, 1.20, 1.20` pins this as U=1.20 via Table 20. Pre-slice the + # mapper only routed "U Above unheated space" through `is_exposed_ + # floor=True`; "E To external air" fell through to the BS EN ISO + # 13370 ground-floor cascade, dropping the lodged exposure entirely. + pages = _summary_pdf_to_textract_style_pages(_SUMMARY_001479_PDF) + site_notes = ElmhurstSiteNotesExtractor(pages).extract() + + # Act + epc = EpcPropertyDataMapper.from_elmhurst_site_notes(site_notes) + + # Assert + ext2 = epc.sap_building_parts[2] + assert ext2.floor_type == "To external air" + assert ext2.sap_floor_dimensions[0].is_exposed_floor is True diff --git a/datatypes/epc/domain/mapper.py b/datatypes/epc/domain/mapper.py index 07a461e7..a9c7f94f 100644 --- a/datatypes/epc/domain/mapper.py +++ b/datatypes/epc/domain/mapper.py @@ -1880,11 +1880,17 @@ _UPPER_FLOOR_HEIGHT_ADD_M: float = 0.25 def _is_floor_exposed_to_unheated_space(location: Optional[str]) -> bool: - """True when the floor sits above an unheated space (lodged by the - Elmhurst surveyor as 'U Above unheated space'). The cascade routes - these through `u_exposed_floor` rather than the BS EN ISO 13370 - ground-floor formula.""" - return location is not None and "above unheated" in location.lower() + """True when the floor sits above an unheated space OR is exposed + directly to external air. Both lodgements route through + `u_exposed_floor` (Table 20) rather than the BS EN ISO 13370 ground- + floor formula. Elmhurst lodges either 'U Above unheated space' + (extension over a porch / car-park) or 'E To external air' (cantile- + vered floor of an upper-storey extension, first seen on cert 001479 + Ext2 — a 1.92 m² exposed timber floor at U=1.20).""" + if location is None: + return False + lower = location.lower() + return "above unheated" in lower or "external air" in lower def _extract_age_band(age_range: str) -> str: