mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
additional fields mapped from pdf 4 🟥
This commit is contained in:
parent
e406b11be8
commit
c5c3f3fc83
5 changed files with 578 additions and 4 deletions
BIN
backend/documents_parser/tests/fixtures/ExampleSiteNotes_4.pdf
vendored
Normal file
BIN
backend/documents_parser/tests/fixtures/ExampleSiteNotes_4.pdf
vendored
Normal file
Binary file not shown.
480
backend/documents_parser/tests/fixtures/site_notes_example_4_text.json
vendored
Normal file
480
backend/documents_parser/tests/fixtures/site_notes_example_4_text.json
vendored
Normal file
|
|
@ -0,0 +1,480 @@
|
|||
[
|
||||
"SMART EPC: Record of",
|
||||
"Inspection & Site Notes",
|
||||
"Inspection Surveyor:",
|
||||
"Rebecca Mcwilliam",
|
||||
"E-Mail Address:",
|
||||
"rebeccamcdea@gmail.com",
|
||||
"Report Reference:",
|
||||
"DA1A93D9-354C-4B4B-A299-3A681231D4B5",
|
||||
"Created On:",
|
||||
"15 October 2025",
|
||||
"Date of Inspection:",
|
||||
"13 October 2025",
|
||||
"Property Address:",
|
||||
"18,",
|
||||
"Oakfield Close,",
|
||||
"Wrenbury,",
|
||||
"CW5 8ET",
|
||||
"Property Photo",
|
||||
"Page 1",
|
||||
"",
|
||||
"Photo of electricity meter:",
|
||||
"Photo of electricity meter:",
|
||||
"RdSAP Assessment",
|
||||
"General",
|
||||
"Confirm you have checked for the existence of an",
|
||||
"EPC before carrying out another energy assessment.",
|
||||
"Yes",
|
||||
"Does an EPC exist at the point of carrying out this",
|
||||
"energy assessment?",
|
||||
"Yes",
|
||||
"Please select why another energy assessment needs",
|
||||
"to be undertaken:",
|
||||
"Assessor instructed to produce a new EPC upon request from building",
|
||||
"owner/tenant/landlord after confirming to the requestor that a valid EPC",
|
||||
"already exists",
|
||||
"Inspection Date:",
|
||||
"13/10/2025",
|
||||
"Transaction Type:",
|
||||
"None of the Above",
|
||||
"Tenure:",
|
||||
"Rented Social",
|
||||
"Type of Property:",
|
||||
"Bungalow",
|
||||
"Detachment Type:",
|
||||
"End-terrace",
|
||||
"Number of storeys:",
|
||||
"1 Storey",
|
||||
"Terrain Type:",
|
||||
"Suburban",
|
||||
"Number of Extensions:",
|
||||
"No Extensions",
|
||||
"Is an electricity smart meter present?",
|
||||
"Yes",
|
||||
"Electric meter type:",
|
||||
"Single",
|
||||
"Page 2",
|
||||
"",
|
||||
"Photo of electricity meter:",
|
||||
"Photo of electricity meter:",
|
||||
"External indicators of Cavity Wall Construction:",
|
||||
"External indicators of Cavity Wall Construction:",
|
||||
"Is the dwelling export-capable?",
|
||||
"Yes",
|
||||
"Is mains gas available?",
|
||||
"No",
|
||||
"Select Measurements Location:",
|
||||
"Internal",
|
||||
"Building Construction",
|
||||
"Main Building",
|
||||
"Age Range:",
|
||||
"1950-1966",
|
||||
"Record indicators of property age:",
|
||||
"local knowledge, enquiries of owner, period building features",
|
||||
"Walls - Construction Type:",
|
||||
"Cavity",
|
||||
"Record external indicators of Cavity Construction:",
|
||||
"stretcher bond, wall thickness over 270 mm",
|
||||
"Walls - Insulation Type:",
|
||||
"Filled Cavity",
|
||||
"Record indicators of filled cavity:",
|
||||
"evidence of cavity fill drill holes, Boroscope",
|
||||
"Page 3",
|
||||
"",
|
||||
"Photo indicators of filled cavity insulation:",
|
||||
"Photo indicators of filled cavity insulation:",
|
||||
"Photo indicators of filled cavity insulation:",
|
||||
"Photo indicators of filled cavity insulation:",
|
||||
"Photo indicators of filled cavity insulation:",
|
||||
"Photo indicators of filled cavity insulation:",
|
||||
"Page 4",
|
||||
"",
|
||||
"Photo indicators of filled cavity insulation:",
|
||||
"Photo indicators of filled cavity insulation:",
|
||||
"Photo indicators of filled cavity insulation:",
|
||||
"Photo wall thickness:",
|
||||
"Thermal conductivity of wall insulation:",
|
||||
"Unknown",
|
||||
"Wall U-Value known?",
|
||||
"Not Known",
|
||||
"Wall thickness:",
|
||||
"300 mm",
|
||||
"Party wall construction type:",
|
||||
"Unable to determine",
|
||||
"Floor type:",
|
||||
"Ground Floor",
|
||||
"Floor Construction:",
|
||||
"Solid",
|
||||
"Floor Insulation Type:",
|
||||
"As Built",
|
||||
"Floor U-Value known?",
|
||||
"Not Known",
|
||||
"Page 5",
|
||||
"",
|
||||
"Loft insulation:",
|
||||
"Loft insulation:",
|
||||
"Building Measurements",
|
||||
"Area (m2)",
|
||||
"Height (m)",
|
||||
"Heat Loss Perimeter (m)",
|
||||
"PWL (m)",
|
||||
"Main Building",
|
||||
"Floor 0",
|
||||
"46.08",
|
||||
"2.44",
|
||||
"20.49",
|
||||
"6.67",
|
||||
"Roof Space",
|
||||
"Main Building",
|
||||
"Roofs - Construction Type:",
|
||||
"Pitched roof (Slates or tiles), No access",
|
||||
"Identify the reason for restricted access:",
|
||||
"access hatch blocked",
|
||||
"Roofs - Insulation At:",
|
||||
"Unknown",
|
||||
"Page 6",
|
||||
"",
|
||||
"Loft insulation:",
|
||||
"Record indicators of Cavity Wall Construction in roof",
|
||||
"space:",
|
||||
"No indicator of construction visible",
|
||||
"Are there rooms in the roof?",
|
||||
"No",
|
||||
"Windows",
|
||||
"Window 1",
|
||||
"Window location:",
|
||||
"Main Building",
|
||||
"Window wall type:",
|
||||
"External wall",
|
||||
"Glazing Type:",
|
||||
"Double glazing, Unknown install date",
|
||||
"Window type:",
|
||||
"Window",
|
||||
"Window frame type:",
|
||||
"Wooden or PVC",
|
||||
"What size is the glazing gap?",
|
||||
"12 mm",
|
||||
"Is the window draught proofed?",
|
||||
"Yes",
|
||||
"Are there permanent shutters present?",
|
||||
"No",
|
||||
"Window height:",
|
||||
"0.97 m",
|
||||
"Window width:",
|
||||
"1.54 m",
|
||||
"Orientation:",
|
||||
"North East",
|
||||
"Page 7",
|
||||
"",
|
||||
"Photo of glazing type:",
|
||||
"Photo of glazing type:",
|
||||
"Photo of glazing type:",
|
||||
"Photo of glazing type:",
|
||||
"Window 2",
|
||||
"Window location:",
|
||||
"Main Building",
|
||||
"Window wall type:",
|
||||
"External wall",
|
||||
"Glazing Type:",
|
||||
"Double glazing, Unknown install date",
|
||||
"Window type:",
|
||||
"Window",
|
||||
"Window frame type:",
|
||||
"Wooden or PVC",
|
||||
"What size is the glazing gap?",
|
||||
"12 mm",
|
||||
"Is the window draught proofed?",
|
||||
"Yes",
|
||||
"Are there permanent shutters present?",
|
||||
"No",
|
||||
"Window height:",
|
||||
"1.01 m",
|
||||
"Window width:",
|
||||
"1.04 m",
|
||||
"Orientation:",
|
||||
"North East",
|
||||
"Window 3",
|
||||
"Window location:",
|
||||
"Main Building",
|
||||
"Window wall type:",
|
||||
"External wall",
|
||||
"Glazing Type:",
|
||||
"Double glazing, Unknown install date",
|
||||
"Window type:",
|
||||
"Window",
|
||||
"Window frame type:",
|
||||
"Wooden or PVC",
|
||||
"Page 8",
|
||||
"",
|
||||
"Photo of glazing type:",
|
||||
"Photo of glazing type:",
|
||||
"Photo of glazing type:",
|
||||
"Photo of glazing type:",
|
||||
"What size is the glazing gap?",
|
||||
"12 mm",
|
||||
"Is the window draught proofed?",
|
||||
"Yes",
|
||||
"Are there permanent shutters present?",
|
||||
"No",
|
||||
"Window height:",
|
||||
"0.99 m",
|
||||
"Window width:",
|
||||
"1.07 m",
|
||||
"Orientation:",
|
||||
"South West",
|
||||
"Window 4",
|
||||
"Window location:",
|
||||
"Main Building",
|
||||
"Window wall type:",
|
||||
"External wall",
|
||||
"Glazing Type:",
|
||||
"Double glazing, Unknown install date",
|
||||
"Window type:",
|
||||
"Window",
|
||||
"Window frame type:",
|
||||
"Wooden or PVC",
|
||||
"What size is the glazing gap?",
|
||||
"12 mm",
|
||||
"Is the window draught proofed?",
|
||||
"Yes",
|
||||
"Are there permanent shutters present?",
|
||||
"No",
|
||||
"Window height:",
|
||||
"1.28 m",
|
||||
"Window width:",
|
||||
"2.07 m",
|
||||
"Orientation:",
|
||||
"South",
|
||||
"Page 9",
|
||||
"",
|
||||
"Photo of heating system:",
|
||||
"Photo of heating system:",
|
||||
"Photo of heating system:",
|
||||
"Photo of heating system:",
|
||||
"Heating & Hot Water",
|
||||
"Main Heating Systems",
|
||||
"Main Heating 1",
|
||||
"How would you like to select the Heating System?",
|
||||
"PCDF Search",
|
||||
"System type:",
|
||||
"Heat pump with radiators or underfloor heating",
|
||||
"Product Id",
|
||||
"102421",
|
||||
"Manufacturer",
|
||||
"Daikin Altherma",
|
||||
"Model",
|
||||
"EDLQ05CAV3",
|
||||
"Year",
|
||||
"2014 - current",
|
||||
"Fuel",
|
||||
"Electricity, any tariff",
|
||||
"Status",
|
||||
"Normal status for an actual product",
|
||||
"Central heating pump age:",
|
||||
"Unknown",
|
||||
"MCS installed heat pump:",
|
||||
"Yes",
|
||||
"Controls:",
|
||||
"Programmer, room thermostat and TRVs",
|
||||
"Emitter:",
|
||||
"Radiators",
|
||||
"Emitter Temperature:",
|
||||
"Unknown",
|
||||
"Page 10",
|
||||
"",
|
||||
"Photo of heating controls:",
|
||||
"Photo of heating controls:",
|
||||
"Photo of heating controls:",
|
||||
"Photo of heating controls:",
|
||||
"Photo of heating controls:",
|
||||
"Photo of heating controls:",
|
||||
"Page 11",
|
||||
"",
|
||||
"Photo of heating controls:",
|
||||
"Photo of secondary heating system",
|
||||
"Secondary Heating System",
|
||||
"Secondary Fuel",
|
||||
"Electricity",
|
||||
"Secondary System:",
|
||||
"Panel, convector or radiant heaters",
|
||||
"Water Heating & Cylinder",
|
||||
"Water Heating Type:",
|
||||
"Regular",
|
||||
"Water Heating System:",
|
||||
"From main heating 1",
|
||||
"Page 12",
|
||||
"",
|
||||
"Photo of water heating system:",
|
||||
"Photo of water heating system:",
|
||||
"Photo of water heating system:",
|
||||
"Cylinder Size:",
|
||||
"Medium (131-170 litres)",
|
||||
"What is the cylinder measured heat loss:",
|
||||
"Not known",
|
||||
"Insulation Type:",
|
||||
"Factory fitted",
|
||||
"Thickness:",
|
||||
"50 mm",
|
||||
"Page 13",
|
||||
"",
|
||||
"Photo of cylinder and thermostat if present:",
|
||||
"Photo of cylinder and thermostat if present:",
|
||||
"Photo of ventilation type:",
|
||||
"Photo of ventilation type:",
|
||||
"Has thermostat?",
|
||||
"Yes",
|
||||
"Ventilation",
|
||||
"Ventilation type:",
|
||||
"Mechanical Extract - Decentralised",
|
||||
"Has fixed air conditioning?",
|
||||
"No",
|
||||
"Is the ventilation in the PCDF database?",
|
||||
"No",
|
||||
"Number of open flues:",
|
||||
"0",
|
||||
"Number of closed flues:",
|
||||
"0",
|
||||
"Number of boiler flues:",
|
||||
"0",
|
||||
"Page 14",
|
||||
"",
|
||||
"Photo of extract fans:",
|
||||
"Number of other flues:",
|
||||
"0",
|
||||
"Number of extract fans:",
|
||||
"1",
|
||||
"Number of passive vents:",
|
||||
"0",
|
||||
"Number of flueless gas fires:",
|
||||
"0",
|
||||
"Pressure test:",
|
||||
"No test",
|
||||
"Is there a draught lobby?",
|
||||
"No",
|
||||
"Conservatories",
|
||||
"Is there conservatory?",
|
||||
"No conservatory",
|
||||
"Renewables",
|
||||
"Wind Turbines",
|
||||
"Has wind turbines?",
|
||||
"No",
|
||||
"Solar hot water",
|
||||
"Has solar hot water?",
|
||||
"No",
|
||||
"Photovoltaics",
|
||||
"Has photovoltaic array?",
|
||||
"No",
|
||||
"Number of PV batteries:",
|
||||
"None",
|
||||
"Hydro",
|
||||
"Is the dwelling connected to Hydro?",
|
||||
"No",
|
||||
"Room Count Elements",
|
||||
"Number of habitable rooms?",
|
||||
"2",
|
||||
"Are any of these rooms unheated?",
|
||||
"No",
|
||||
"Page 15",
|
||||
"",
|
||||
"Photo of LED bulbs:",
|
||||
"Photo of LED bulbs:",
|
||||
"Photo of LED bulbs:",
|
||||
"Photo of LED bulbs:",
|
||||
"Photo of LED bulbs:",
|
||||
"Photo of LED bulbs:",
|
||||
"Number of external doors?",
|
||||
"2",
|
||||
"Number of insulated external doors?",
|
||||
"0",
|
||||
"Number of draughtproofed external doors?",
|
||||
"2",
|
||||
"Number of open chimneys?",
|
||||
"0",
|
||||
"Number of blocked chimneys?",
|
||||
"0",
|
||||
"Number of fixed incandescent bulbs:",
|
||||
"0",
|
||||
"Is the exact number of LED and CFL bulbs known?",
|
||||
"Yes",
|
||||
"Number of fixed LED bulbs:",
|
||||
"7",
|
||||
"Page 16",
|
||||
"",
|
||||
"Photo of LED bulbs:",
|
||||
"Photo of shower:",
|
||||
"Photo of shower:",
|
||||
"Number of fixed CFL bulbs:",
|
||||
"0",
|
||||
"Are there any waste water heat recovery systems?",
|
||||
"None",
|
||||
"Number of baths:",
|
||||
"1",
|
||||
"How many special features are there at the",
|
||||
"property?",
|
||||
"0",
|
||||
"Showers",
|
||||
"Shower 1",
|
||||
"Shower outlet type:",
|
||||
"Electric Shower",
|
||||
"Customer Response",
|
||||
"Customer present?",
|
||||
"Yes",
|
||||
"Customer willing to answer satisfaction survey?",
|
||||
"No",
|
||||
"Addendum + Related Party Disclosure",
|
||||
"Addendum",
|
||||
"None",
|
||||
"Page 17",
|
||||
"",
|
||||
"General Photos:",
|
||||
"General Photos:",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"Related party disclosure",
|
||||
"No related party",
|
||||
"Hard to treat cavity walls: Property has access",
|
||||
"issues?",
|
||||
"No",
|
||||
"Hard to treat cavity walls: Property has high",
|
||||
"exposure?",
|
||||
"No",
|
||||
"Hard to treat cavity walls: Property has narrow",
|
||||
"cavities?",
|
||||
"No",
|
||||
"Photographs Required",
|
||||
"Page 18",
|
||||
"",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"Page 19",
|
||||
"",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"Page 20",
|
||||
"",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"Page 21",
|
||||
"",
|
||||
"External Elevations:",
|
||||
"External Elevations:",
|
||||
"Page 22",
|
||||
"",
|
||||
"Additional Notes",
|
||||
"Additional Notes",
|
||||
"The loft hatch is a drop-down hatch with a ladder above. The hatch is broken",
|
||||
"and it could not be opened. She is about to have a new door made so loft will",
|
||||
"be able to be accessed at some point soon but on the day I could not.",
|
||||
"Page 23",
|
||||
""
|
||||
]
|
||||
|
|
@ -294,11 +294,49 @@ class TestPdfToEpcPropertyDataFixture3:
|
|||
assert result.sap_heating.immersion_heating_type == "Dual"
|
||||
|
||||
def test_pv_connection(self, result: EpcPropertyData) -> None:
|
||||
assert result.sap_energy_source.pv_connection == "Connected to dwellings electricity meter"
|
||||
assert (
|
||||
result.sap_energy_source.pv_connection
|
||||
== "Connected to dwellings electricity meter"
|
||||
)
|
||||
|
||||
def test_photovoltaic_supply_percent_roof(self, result: EpcPropertyData) -> None:
|
||||
assert result.sap_energy_source.photovoltaic_supply is not None
|
||||
assert result.sap_energy_source.photovoltaic_supply.none_or_no_details.percent_roof_area == 45
|
||||
assert (
|
||||
result.sap_energy_source.photovoltaic_supply.none_or_no_details.percent_roof_area
|
||||
== 45
|
||||
)
|
||||
|
||||
def test_electric_storage_heater_fuel_type(self, result: EpcPropertyData) -> None:
|
||||
assert result.sap_heating.main_heating_details[0].main_fuel_type == "Electricity"
|
||||
assert (
|
||||
result.sap_heating.main_heating_details[0].main_fuel_type == "Electricity"
|
||||
)
|
||||
|
||||
|
||||
PDF_PATH_4 = os.path.join(
|
||||
os.path.dirname(__file__), "fixtures", "ExampleSiteNotes_4.pdf"
|
||||
)
|
||||
|
||||
|
||||
class TestPdfToEpcPropertyDataFixture4:
|
||||
@pytest.fixture
|
||||
def result(self) -> EpcPropertyData:
|
||||
with open(PDF_PATH_4, "rb") as f:
|
||||
pdf_bytes = f.read()
|
||||
site_notes = PasHubRdSapSiteNotesExtractor(
|
||||
pdf_to_text_list(pdf_bytes)
|
||||
).extract()
|
||||
return EpcPropertyDataMapper.from_site_notes(site_notes)
|
||||
|
||||
def test_cylinder_insulation_type(self, result: EpcPropertyData) -> None:
|
||||
assert result.sap_heating.cylinder_insulation_type == "Factory fitted"
|
||||
|
||||
def test_heat_pump_fuel_type(self, result: EpcPropertyData) -> None:
|
||||
assert (
|
||||
result.sap_heating.main_heating_details[0].main_fuel_type == "Electricity"
|
||||
)
|
||||
|
||||
def test_roof_insulation_location_unknown(self, result: EpcPropertyData) -> None:
|
||||
assert result.sap_building_parts[0].roof_insulation_location == "Unknown"
|
||||
|
||||
def test_roof_insulation_thickness_none(self, result: EpcPropertyData) -> None:
|
||||
assert result.sap_building_parts[0].roof_insulation_thickness is None
|
||||
|
|
|
|||
|
|
@ -51,6 +51,11 @@ def load_text_fixture_3() -> list[str]:
|
|||
return json.load(f)
|
||||
|
||||
|
||||
def load_text_fixture_4() -> list[str]:
|
||||
with open(os.path.join(FIXTURES, "site_notes_example_4_text.json")) as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
class TestInspectionMetadata:
|
||||
def test_full_inspection_metadata(self) -> None:
|
||||
result = PasHubRdSapSiteNotesExtractor(load_text_fixture()).extract_inspection_metadata()
|
||||
|
|
@ -675,3 +680,54 @@ class TestSurveyAddendum:
|
|||
hard_to_treat_cavity_high_exposure=False,
|
||||
hard_to_treat_cavity_narrow_cavities=False,
|
||||
)
|
||||
|
||||
|
||||
# --- fixture 4: heat pump, factory-fitted cylinder, blocked loft ---
|
||||
|
||||
|
||||
class TestCylinderInsulationType:
|
||||
@pytest.fixture
|
||||
def hhw(self) -> HeatingAndHotWater:
|
||||
return PasHubRdSapSiteNotesExtractor(
|
||||
load_text_fixture_4()
|
||||
).extract_heating_and_hot_water()
|
||||
|
||||
def test_insulation_type_extracted(self, hhw: HeatingAndHotWater) -> None:
|
||||
assert hhw.water_heating.insulation_type == "Factory fitted"
|
||||
|
||||
def test_insulation_thickness_mm(self, hhw: HeatingAndHotWater) -> None:
|
||||
assert hhw.water_heating.insulation_thickness_mm == 50
|
||||
|
||||
def test_cylinder_size(self, hhw: HeatingAndHotWater) -> None:
|
||||
assert hhw.water_heating.cylinder_size == "Medium (131-170 litres)"
|
||||
|
||||
|
||||
class TestHeatPumpFuelExtraction:
|
||||
@pytest.fixture
|
||||
def hhw(self) -> HeatingAndHotWater:
|
||||
return PasHubRdSapSiteNotesExtractor(
|
||||
load_text_fixture_4()
|
||||
).extract_heating_and_hot_water()
|
||||
|
||||
def test_fuel_raw_value(self, hhw: HeatingAndHotWater) -> None:
|
||||
assert hhw.main_heating.fuel == "Electricity, any tariff"
|
||||
|
||||
def test_system_type(self, hhw: HeatingAndHotWater) -> None:
|
||||
assert hhw.main_heating.system_type == "Heat pump with radiators or underfloor heating"
|
||||
|
||||
|
||||
class TestRoofSpaceUnknownInsulation:
|
||||
@pytest.fixture
|
||||
def roof_space(self) -> RoofSpace:
|
||||
return PasHubRdSapSiteNotesExtractor(
|
||||
load_text_fixture_4()
|
||||
).extract_roof_space()
|
||||
|
||||
def test_insulation_at_unknown(self, roof_space: RoofSpace) -> None:
|
||||
assert roof_space.main_building.insulation_at == "Unknown"
|
||||
|
||||
def test_insulation_thickness_mm_none(self, roof_space: RoofSpace) -> None:
|
||||
assert roof_space.main_building.insulation_thickness_mm is None
|
||||
|
||||
def test_insulation_thickness_str_none(self, roof_space: RoofSpace) -> None:
|
||||
assert roof_space.main_building.insulation_thickness is None
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ class SapHeating:
|
|||
water_heating_fuel: Optional[int] = None # TODO: make enum?
|
||||
immersion_heating_type: Optional[Union[int, str]] = None # TODO: make enum?
|
||||
shower_outlets: Optional[ShowerOutlets] = None
|
||||
cylinder_insulation_type: Optional[int] = None
|
||||
cylinder_insulation_type: Optional[Union[int, str]] = None
|
||||
cylinder_thermostat: Optional[str] = None
|
||||
secondary_fuel_type: Optional[int] = None
|
||||
secondary_heating_type: Optional[Union[int, str]] = None # int from API; str from site notes
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue