From c0801b9e072e216e37043bf1d9a9bd4c96bf048f Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 16 Apr 2026 14:12:58 +0000 Subject: [PATCH] =?UTF-8?q?Load=20RoofSpace=20from=20SiteNotes=20JSON=20?= =?UTF-8?q?=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/documents_parser/extractor.py | 77 ++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/backend/documents_parser/extractor.py b/backend/documents_parser/extractor.py index 376aa0da..59a84686 100644 --- a/backend/documents_parser/extractor.py +++ b/backend/documents_parser/extractor.py @@ -228,7 +228,82 @@ class PasHubRdSapSiteNotesExtractor: ) def extract_roof_space(self) -> RoofSpace: - raise NotImplementedError + rs_section = self._section("Roof Space", "Windows") + + extension_markers = [] + i = 1 + while f"Extension {i}" in rs_section: + extension_markers.append(f"Extension {i}") + i += 1 + + main_start = rs_section.index("Main Building") + main_end = ( + rs_section.index(extension_markers[0]) + if extension_markers + else len(rs_section) + ) + main_data = rs_section[main_start:main_end] + + extensions = [] + for n, marker in enumerate(extension_markers): + ext_start = rs_section.index(marker) + ext_end = ( + rs_section.index(extension_markers[n + 1]) + if n + 1 < len(extension_markers) + else len(rs_section) + ) + ext_data = rs_section[ext_start:ext_end] + extensions.append(self._parse_extension_roof_space(n + 1, ext_data)) + + return RoofSpace( + main_building=self._parse_roof_space_detail(main_data), + extensions=extensions if extensions else None, + ) + + def _parse_insulation_thickness( + self, val: Optional[str] + ) -> tuple[Optional[int], Optional[str]]: + if val is None: + return None, None + try: + return int(val.split()[0]), None + except (ValueError, IndexError): + return None, val + + def _parse_roof_space_detail(self, data: List[str]) -> RoofSpaceDetail: + thickness_mm, thickness_str = self._parse_insulation_thickness( + self._get_in(data, "Roofs - Insulation Thickness:") + ) + return RoofSpaceDetail( + construction_type=self._get_in(data, "Roofs - Construction Type:") or "", + insulation_at=self._get_in(data, "Roofs - Insulation At:") or "", + roof_u_value_known=self._is_known_in(data, "Roof U-Value:"), + cavity_wall_construction_indicators=self._get_in( + data, "Record indicators of Cavity Wall Construction in roof", offset=2 + ) or "", + rooms_in_roof=self._bool_in(data, "Are there rooms in the roof?"), + insulation_thickness_mm=thickness_mm, + insulation_thickness=thickness_str, + ) + + def _parse_extension_roof_space( + self, ext_id: int, data: List[str] + ) -> ExtensionRoofSpace: + thickness_mm, thickness_str = self._parse_insulation_thickness( + self._get_in(data, "Roofs - Insulation Thickness:") + ) + return ExtensionRoofSpace( + id=ext_id, + construction_type=self._get_in(data, "Roofs - Construction Type:") or "", + insulation_at=self._get_in(data, "Roofs - Insulation At:") or "", + roof_u_value_known=self._is_known_in(data, "Roof U-Value:"), + cavity_wall_construction_indicators=self._get_in( + data, "Record indicators of Cavity Wall Construction in roof", offset=2 + ) or "", + rooms_in_roof=self._bool_in(data, "Are there rooms in the roof?"), + insulation_thickness_mm=thickness_mm, + insulation_thickness=thickness_str, + ) def _parse_floor_measurements(self, data: List[str]) -> List[FloorMeasurement]: floors = []