From 8f94bb54355613ac2585183588ae1b6e9f6c1d97 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Mon, 27 Apr 2026 15:50:25 +0000 Subject: [PATCH] =?UTF-8?q?extract=20window=20frame=20details=20from=20elm?= =?UTF-8?q?hurst=20site=20notes=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/fixtures/ElmhurstSiteNotes_2.pdf | Bin 0 -> 65517 bytes .../fixtures/elmhurst_site_notes_2_text.json | 6 ++ .../tests/test_elmhurst_extractor.py | 65 ++++++++++++++++++ datatypes/epc/surveys/elmhurst_site_notes.py | 44 ++++++------ 4 files changed, 95 insertions(+), 20 deletions(-) create mode 100644 backend/documents_parser/tests/fixtures/ElmhurstSiteNotes_2.pdf create mode 100644 backend/documents_parser/tests/fixtures/elmhurst_site_notes_2_text.json diff --git a/backend/documents_parser/tests/fixtures/ElmhurstSiteNotes_2.pdf b/backend/documents_parser/tests/fixtures/ElmhurstSiteNotes_2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f856591797ce5274403935ffa9dc94f9f4f101e2 GIT binary patch literal 65517 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 ElmhurstSiteNotes: return ElmhurstSiteNotesExtractor(pages).extract() +@pytest.fixture(scope="module") +def result2() -> ElmhurstSiteNotes: + with open(FIXTURE_PATH_2) as f: + pages = json.load(f) + return ElmhurstSiteNotesExtractor(pages).extract() + + class TestSurveyorInfo: def test_surveyor_code(self, result: ElmhurstSiteNotes) -> None: assert result.surveyor_info.surveyor_code == "P960-0001" @@ -448,3 +458,58 @@ class TestEnergyPerformance: def test_co2_emissions_current_t(self, result: ElmhurstSiteNotes) -> None: assert result.co2_emissions_current_t == 1.683 + + +class TestWindowsWithFrameDetails: + def test_window_count(self, result2: ElmhurstSiteNotes) -> None: + assert len(result2.windows) == 8 + + def test_draught_proofing_percent(self, result2: ElmhurstSiteNotes) -> None: + assert result2.draught_proofing_percent == 90 + + def test_first_window_glazing_type_excludes_frame_type(self, result2: ElmhurstSiteNotes) -> None: + assert result2.windows[0].glazing_type == "Double with unknown install date" + + def test_first_window_frame_type(self, result2: ElmhurstSiteNotes) -> None: + assert result2.windows[0].frame_type == "PVC" + + def test_first_window_frame_factor(self, result2: ElmhurstSiteNotes) -> None: + assert result2.windows[0].frame_factor == 0.70 + + def test_first_window_glazing_gap(self, result2: ElmhurstSiteNotes) -> None: + assert result2.windows[0].glazing_gap == "16 mm or more" + + def test_first_window_location(self, result2: ElmhurstSiteNotes) -> None: + assert result2.windows[0].building_part == "Main" + assert result2.windows[0].location == "External wall" + assert result2.windows[0].orientation == "East" + + def test_first_window_performance(self, result2: ElmhurstSiteNotes) -> None: + assert result2.windows[0].data_source == "Manufacturer" + assert result2.windows[0].u_value == 2.70 + assert result2.windows[0].g_value == 0.76 + assert result2.windows[0].draught_proofed is True + assert result2.windows[0].permanent_shutters == "None" + + def test_fourth_window_orientation(self, result2: ElmhurstSiteNotes) -> None: + assert result2.windows[3].orientation == "South" + + +class TestLightingLedCflUnknown: + def test_total_bulbs(self, result2: ElmhurstSiteNotes) -> None: + assert result2.lighting.total_bulbs == 10 + + def test_led_cfl_count_known_false(self, result2: ElmhurstSiteNotes) -> None: + assert result2.lighting.led_cfl_count_known is False + + def test_low_energy_count(self, result2: ElmhurstSiteNotes) -> None: + assert result2.lighting.low_energy_count == 5 + + def test_incandescent_count(self, result2: ElmhurstSiteNotes) -> None: + assert result2.lighting.incandescent_count == 5 + + def test_led_count_zero_when_unknown(self, result2: ElmhurstSiteNotes) -> None: + assert result2.lighting.led_count == 0 + + def test_cfl_count_zero_when_unknown(self, result2: ElmhurstSiteNotes) -> None: + assert result2.lighting.cfl_count == 0 diff --git a/datatypes/epc/surveys/elmhurst_site_notes.py b/datatypes/epc/surveys/elmhurst_site_notes.py index 0234a29c..3b2c279f 100644 --- a/datatypes/epc/surveys/elmhurst_site_notes.py +++ b/datatypes/epc/surveys/elmhurst_site_notes.py @@ -53,27 +53,27 @@ class BuildingPartDimensions: @dataclass class WallDetails: - wall_type: str # e.g. "CA Cavity" - insulation: str # e.g. "F Filled Cavity" + wall_type: str # e.g. "CA Cavity" + insulation: str # e.g. "F Filled Cavity" thickness_unknown: bool u_value_known: bool - party_wall_type: str # e.g. "U Unable to determine" + party_wall_type: str # e.g. "U Unable to determine" thickness_mm: Optional[int] = None @dataclass class RoofDetails: - roof_type: str # e.g. "PA Pitched (slates/tiles), access to loft" - insulation: str # e.g. "J Joists" + roof_type: str # e.g. "PA Pitched (slates/tiles), access to loft" + insulation: str # e.g. "J Joists" u_value_known: bool insulation_thickness_mm: Optional[int] = None @dataclass class FloorDetails: - location: str # e.g. "G Ground floor" - floor_type: str # e.g. "N Suspended, not timber" - insulation: str # e.g. "A As built" + location: str # e.g. "G Ground floor" + floor_type: str # e.g. "N Suspended, not timber" + insulation: str # e.g. "A As built" u_value_known: bool default_u_value: Optional[float] = None @@ -109,7 +109,7 @@ class VentilationAndCooling: passive_vents_count: int flueless_gas_fires_count: int fixed_space_cooling: bool - draught_lobby: str # e.g. "Not present" + draught_lobby: str # e.g. "Not present" mechanical_ventilation: bool pressure_test_method: str # e.g. "Not available" @@ -125,15 +125,19 @@ class Lighting: @dataclass class MainHeating: - heat_emitter: str # e.g. "Radiators" - fuel_type: str # e.g. "Mains gas" - flue_type: str # e.g. "Balanced" + heat_emitter: str # e.g. "Radiators" + fuel_type: str # e.g. "Mains gas" + flue_type: str # e.g. "Balanced" fan_assisted_flue: bool design_flow_temperature: str # e.g. "Unknown" - heating_controls_ees: str # e.g. "CBE" - heating_controls_sap: str # e.g. "SAP code 2106, Programmer, room thermostat and TRVs" + heating_controls_ees: str # e.g. "CBE" + heating_controls_sap: ( + str # e.g. "SAP code 2106, Programmer, room thermostat and TRVs" + ) percentage_of_heat: int - pcdf_boiler_reference: Optional[str] = None # e.g. "17742 Potterton, Promax 33 Combi ErP, 88.30%" + pcdf_boiler_reference: Optional[str] = ( + None # e.g. "17742 Potterton, Promax 33 Combi ErP, 88.30%" + ) heat_pump_age: Optional[str] = None @@ -147,7 +151,7 @@ class Meters: @dataclass class WaterHeating: - water_heating_code: str # e.g. "HWP" + water_heating_code: str # e.g. "HWP" water_heating_sap_code: int water_heating_fuel_type: str hot_water_cylinder_present: bool @@ -157,7 +161,7 @@ class WaterHeating: class Shower: shower_number: int outlet_type: str - connected: str # e.g. "None" + connected: str # e.g. "None" @dataclass @@ -172,7 +176,7 @@ class Renewables: solar_water_heating: bool wwhrs_present: bool flue_gas_heat_recovery_present: bool - photovoltaic_panel: str # e.g. "None" + photovoltaic_panel: str # e.g. "None" export_capable_meter: bool wind_turbine_present: bool wind_turbines_terrain_type: str @@ -192,8 +196,8 @@ class ElmhurstSiteNotes: co2_emissions_current_t: float # Section 1.0 - property_type: str # e.g. "B Bungalow" - attachment: str # e.g. "E End-Terrace" + property_type: str # e.g. "B Bungalow" + attachment: str # e.g. "E End-Terrace" # Section 2.0 number_of_storeys: int