mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
pashub rdsap sitenotes pdf output to dataclasses
This commit is contained in:
parent
6f8a304568
commit
a7d460a2d4
8 changed files with 1221 additions and 3 deletions
|
|
@ -42,8 +42,8 @@ logger = setup_logger()
|
||||||
|
|
||||||
def run_job() -> None:
|
def run_job() -> None:
|
||||||
|
|
||||||
username: str = "" # TODO: get from github secrets
|
username: str = "joseph.westwood@domna.homes" # TODO: get from github secrets
|
||||||
password: str = ""
|
password: str = "DomnaTest123!"
|
||||||
|
|
||||||
property_list_file: str = (
|
property_list_file: str = (
|
||||||
"hubspot-crm-exports-southern-ra-lite-programme-3103-2026-03-31-2.xlsx"
|
"hubspot-crm-exports-southern-ra-lite-programme-3103-2026-03-31-2.xlsx"
|
||||||
|
|
|
||||||
3
datatypes/epc/surveys/__init__.py
Normal file
3
datatypes/epc/surveys/__init__.py
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
from .pashub_rdsap_site_notes import PasHubRdSapSiteNotes
|
||||||
|
|
||||||
|
__all__ = ["PasHubRdSapSiteNotes"]
|
||||||
291
datatypes/epc/surveys/pashub_rdsap_site_notes.py
Normal file
291
datatypes/epc/surveys/pashub_rdsap_site_notes.py
Normal file
|
|
@ -0,0 +1,291 @@
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import List, Optional
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class InspectionMetadata:
|
||||||
|
inspection_surveyor: str
|
||||||
|
email_address: str
|
||||||
|
report_reference: str
|
||||||
|
created_on: str
|
||||||
|
date_of_inspection: str
|
||||||
|
property_address: str
|
||||||
|
property_photo: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class General:
|
||||||
|
epc_checked_before_assessment: bool
|
||||||
|
epc_exists_at_point_of_assessment: bool
|
||||||
|
inspection_date: str
|
||||||
|
transaction_type: str
|
||||||
|
tenure: str
|
||||||
|
property_type: str
|
||||||
|
detachment_type: str
|
||||||
|
number_of_storeys: int
|
||||||
|
terrain_type: str
|
||||||
|
number_of_extensions: int
|
||||||
|
electricity_smart_meter: bool
|
||||||
|
electric_meter_type: str
|
||||||
|
dwelling_export_capable: bool
|
||||||
|
mains_gas_available: bool
|
||||||
|
gas_smart_meter: bool
|
||||||
|
gas_meter_accessible: bool
|
||||||
|
measurements_location: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MainBuildingConstruction:
|
||||||
|
age_range: str
|
||||||
|
age_indicators: str
|
||||||
|
walls_construction_type: str
|
||||||
|
cavity_construction_indicators: str
|
||||||
|
walls_insulation_type: str
|
||||||
|
thermal_conductivity_of_wall_insulation: str
|
||||||
|
wall_u_value_known: bool
|
||||||
|
wall_thickness_mm: int
|
||||||
|
party_wall_construction_type: str
|
||||||
|
filled_cavity_indicators: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ExtensionConstruction:
|
||||||
|
id: int
|
||||||
|
age_range: str
|
||||||
|
age_indicators: str
|
||||||
|
walls_construction_type: str
|
||||||
|
cavity_construction_indicators: str
|
||||||
|
walls_insulation_type: str
|
||||||
|
thermal_conductivity_of_wall_insulation: str
|
||||||
|
wall_u_value_known: bool
|
||||||
|
wall_thickness_mm: int
|
||||||
|
party_wall_construction_type: str
|
||||||
|
filled_cavity_indicators: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FloorConstruction:
|
||||||
|
floor_type: str
|
||||||
|
floor_construction: str
|
||||||
|
floor_insulation_type: str
|
||||||
|
floor_u_value_known: bool
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BuildingConstruction:
|
||||||
|
main_building: MainBuildingConstruction
|
||||||
|
floor: FloorConstruction
|
||||||
|
extensions: Optional[List[ExtensionConstruction]] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FloorMeasurement:
|
||||||
|
name: str
|
||||||
|
area_m2: float
|
||||||
|
height_m: float
|
||||||
|
heat_loss_perimeter_m: float
|
||||||
|
pwl_m: float
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MainBuildingMeasurements:
|
||||||
|
floors: List[FloorMeasurement]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ExtensionMeasurements:
|
||||||
|
id: int
|
||||||
|
floors: List[FloorMeasurement]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BuildingMeasurements:
|
||||||
|
main_building: MainBuildingMeasurements
|
||||||
|
extensions: Optional[List[ExtensionMeasurements]] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RoofSpaceDetail:
|
||||||
|
construction_type: str
|
||||||
|
insulation_at: str
|
||||||
|
roof_u_value_known: bool
|
||||||
|
cavity_wall_construction_indicators: str
|
||||||
|
rooms_in_roof: bool
|
||||||
|
# Numeric thickness (mm) when known; string (e.g. "As built") when not measured
|
||||||
|
insulation_thickness_mm: Optional[int] = None
|
||||||
|
insulation_thickness: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ExtensionRoofSpace:
|
||||||
|
id: int
|
||||||
|
construction_type: str
|
||||||
|
insulation_at: str
|
||||||
|
roof_u_value_known: bool
|
||||||
|
cavity_wall_construction_indicators: str
|
||||||
|
rooms_in_roof: bool
|
||||||
|
insulation_thickness_mm: Optional[int] = None
|
||||||
|
insulation_thickness: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RoofSpace:
|
||||||
|
main_building: RoofSpaceDetail
|
||||||
|
extensions: Optional[List[ExtensionRoofSpace]] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Window:
|
||||||
|
id: int
|
||||||
|
location: str
|
||||||
|
wall_type: str
|
||||||
|
glazing_type: str
|
||||||
|
window_type: str
|
||||||
|
frame_type: str
|
||||||
|
glazing_gap: str
|
||||||
|
draught_proofed: bool
|
||||||
|
permanent_shutters: bool
|
||||||
|
height_m: float
|
||||||
|
width_m: float
|
||||||
|
orientation: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class MainHeating:
|
||||||
|
selection_method: str
|
||||||
|
system_type: str
|
||||||
|
product_id: int
|
||||||
|
manufacturer: str
|
||||||
|
model: str
|
||||||
|
orig_manufacturer: str
|
||||||
|
fuel: str
|
||||||
|
summer_efficiency: float
|
||||||
|
type: str
|
||||||
|
condensing: bool
|
||||||
|
year: str
|
||||||
|
mount: str
|
||||||
|
open_flue: str
|
||||||
|
fan_assist: bool
|
||||||
|
status: str
|
||||||
|
central_heating_pump_age: str
|
||||||
|
controls: str
|
||||||
|
flue_gas_heat_recovery_system: bool
|
||||||
|
weather_compensator: bool
|
||||||
|
emitter: str
|
||||||
|
emitter_temperature: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SecondaryHeating:
|
||||||
|
secondary_fuel: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class WaterHeating:
|
||||||
|
type: str
|
||||||
|
system: str
|
||||||
|
cylinder_size: str
|
||||||
|
cylinder_measured_heat_loss: Optional[str] = None
|
||||||
|
insulation_type: Optional[str] = None
|
||||||
|
insulation_thickness_mm: Optional[int] = None
|
||||||
|
has_thermostat: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class HeatingAndHotWater:
|
||||||
|
main_heating: MainHeating
|
||||||
|
secondary_heating: SecondaryHeating
|
||||||
|
water_heating: WaterHeating
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Ventilation:
|
||||||
|
ventilation_type: str
|
||||||
|
has_fixed_air_conditioning: bool
|
||||||
|
number_of_open_flues: int
|
||||||
|
number_of_closed_flues: int
|
||||||
|
number_of_boiler_flues: int
|
||||||
|
number_of_other_flues: int
|
||||||
|
number_of_extract_fans: int
|
||||||
|
number_of_passive_vents: int
|
||||||
|
number_of_flueless_gas_fires: int
|
||||||
|
pressure_test: str
|
||||||
|
draught_lobby: bool
|
||||||
|
ventilation_in_pcdf_database: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Conservatories:
|
||||||
|
has_conservatory: bool
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Renewables:
|
||||||
|
wind_turbines: bool
|
||||||
|
solar_hot_water: bool
|
||||||
|
photovoltaic_array: bool
|
||||||
|
number_of_pv_batteries: int
|
||||||
|
hydro: bool
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class RoomCountElements:
|
||||||
|
number_of_habitable_rooms: int
|
||||||
|
any_unheated_rooms: bool
|
||||||
|
number_of_external_doors: int
|
||||||
|
number_of_insulated_external_doors: int
|
||||||
|
number_of_draughtproofed_external_doors: int
|
||||||
|
number_of_open_chimneys: int
|
||||||
|
number_of_blocked_chimneys: int
|
||||||
|
number_of_fixed_incandescent_bulbs: int
|
||||||
|
exact_led_cfl_count_known: bool
|
||||||
|
number_of_fixed_led_bulbs: int
|
||||||
|
number_of_fixed_cfl_bulbs: int
|
||||||
|
waste_water_heat_recovery: str
|
||||||
|
number_of_heated_rooms: Optional[int] = None
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Shower:
|
||||||
|
id: int
|
||||||
|
outlet_type: str
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class WaterUse:
|
||||||
|
number_of_baths: int
|
||||||
|
number_of_special_features: int
|
||||||
|
showers: List[Shower]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CustomerResponse:
|
||||||
|
customer_present: bool
|
||||||
|
willing_to_answer_satisfaction_survey: bool
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SurveyAddendum:
|
||||||
|
addendum: str
|
||||||
|
related_party_disclosure: str
|
||||||
|
hard_to_treat_cavity_access_issues: bool
|
||||||
|
hard_to_treat_cavity_high_exposure: bool
|
||||||
|
hard_to_treat_cavity_narrow_cavities: bool
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PasHubRdSapSiteNotes:
|
||||||
|
inspection_metadata: InspectionMetadata
|
||||||
|
general: General
|
||||||
|
building_construction: BuildingConstruction
|
||||||
|
building_measurements: BuildingMeasurements
|
||||||
|
roof_space: RoofSpace
|
||||||
|
windows: List[Window]
|
||||||
|
heating_and_hot_water: HeatingAndHotWater
|
||||||
|
ventilation: Ventilation
|
||||||
|
conservatories: Conservatories
|
||||||
|
renewables: Renewables
|
||||||
|
room_count_elements: RoomCountElements
|
||||||
|
water_use: WaterUse
|
||||||
|
customer_response: CustomerResponse
|
||||||
|
addendum: SurveyAddendum
|
||||||
0
datatypes/epc/surveys/tests/__init__.py
Normal file
0
datatypes/epc/surveys/tests/__init__.py
Normal file
232
datatypes/epc/surveys/tests/fixtures/pashub_rdsap_site_notes_example1.json
vendored
Normal file
232
datatypes/epc/surveys/tests/fixtures/pashub_rdsap_site_notes_example1.json
vendored
Normal file
|
|
@ -0,0 +1,232 @@
|
||||||
|
{
|
||||||
|
"inspection_metadata": {
|
||||||
|
"inspection_surveyor": "test",
|
||||||
|
"email_address": "test@test.com",
|
||||||
|
"report_reference": "49D422A9-0779-44DD-9665-464D35DFF1A8",
|
||||||
|
"created_on": "2026-03-31",
|
||||||
|
"date_of_inspection": "2026-03-31",
|
||||||
|
"property_address": "test"
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"epc_checked_before_assessment": true,
|
||||||
|
"epc_exists_at_point_of_assessment": false,
|
||||||
|
"inspection_date": "2026-03-31",
|
||||||
|
"transaction_type": "None of the Above",
|
||||||
|
"tenure": "Rented Social",
|
||||||
|
"property_type": "House",
|
||||||
|
"detachment_type": "Mid-terrace",
|
||||||
|
"number_of_storeys": 2,
|
||||||
|
"terrain_type": "Suburban",
|
||||||
|
"number_of_extensions": 0,
|
||||||
|
"electricity_smart_meter": true,
|
||||||
|
"electric_meter_type": "Single",
|
||||||
|
"dwelling_export_capable": true,
|
||||||
|
"mains_gas_available": true,
|
||||||
|
"gas_smart_meter": true,
|
||||||
|
"gas_meter_accessible": true,
|
||||||
|
"measurements_location": "Internal"
|
||||||
|
},
|
||||||
|
"building_construction": {
|
||||||
|
"main_building": {
|
||||||
|
"age_range": "I: 1996 - 2002",
|
||||||
|
"age_indicators": "local knowledge",
|
||||||
|
"walls_construction_type": "Cavity",
|
||||||
|
"cavity_construction_indicators": "stretcher bond",
|
||||||
|
"walls_insulation_type": "As built",
|
||||||
|
"thermal_conductivity_of_wall_insulation": "Unknown",
|
||||||
|
"wall_u_value_known": false,
|
||||||
|
"wall_thickness_mm": 280,
|
||||||
|
"party_wall_construction_type": "Cavity Masonry, Unfilled"
|
||||||
|
},
|
||||||
|
"floor": {
|
||||||
|
"floor_type": "Ground Floor",
|
||||||
|
"floor_construction": "Suspended, not timber",
|
||||||
|
"floor_insulation_type": "As Built",
|
||||||
|
"floor_u_value_known": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"building_measurements": {
|
||||||
|
"main_building": {
|
||||||
|
"floors": [
|
||||||
|
{
|
||||||
|
"name": "Floor 1",
|
||||||
|
"area_m2": 24.78,
|
||||||
|
"height_m": 2.37,
|
||||||
|
"heat_loss_perimeter_m": 14.21,
|
||||||
|
"pwl_m": 6.15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Floor 0",
|
||||||
|
"area_m2": 24.78,
|
||||||
|
"height_m": 2.35,
|
||||||
|
"heat_loss_perimeter_m": 14.21,
|
||||||
|
"pwl_m": 6.15
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roof_space": {
|
||||||
|
"main_building": {
|
||||||
|
"construction_type": "Pitched roof (Slates or tiles), Access to loft",
|
||||||
|
"insulation_at": "Joists",
|
||||||
|
"roof_u_value_known": false,
|
||||||
|
"insulation_thickness_mm": 100,
|
||||||
|
"cavity_wall_construction_indicators": "No indicator of construction visible",
|
||||||
|
"rooms_in_roof": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"windows": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"location": "Main Building",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 1.36,
|
||||||
|
"width_m": 1.0,
|
||||||
|
"orientation": "South East"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"location": "Main Building",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 1.33,
|
||||||
|
"width_m": 0.96,
|
||||||
|
"orientation": "South East"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"location": "Main Building",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 1.04,
|
||||||
|
"width_m": 0.96,
|
||||||
|
"orientation": "North West"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"location": "Main Building",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 1.02,
|
||||||
|
"width_m": 0.97,
|
||||||
|
"orientation": "North West"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"heating_and_hot_water": {
|
||||||
|
"main_heating": {
|
||||||
|
"selection_method": "PCDF Search",
|
||||||
|
"system_type": "Boiler with radiators or underfloor heating",
|
||||||
|
"product_id": 18400,
|
||||||
|
"manufacturer": "Vaillant",
|
||||||
|
"model": "ecoFIT sustain 415",
|
||||||
|
"orig_manufacturer": "Vaillant",
|
||||||
|
"fuel": "Mains gas",
|
||||||
|
"summer_efficiency": 0,
|
||||||
|
"type": "Regular",
|
||||||
|
"condensing": true,
|
||||||
|
"year": "2018 - current",
|
||||||
|
"mount": "Wall",
|
||||||
|
"open_flue": "Room-sealed",
|
||||||
|
"fan_assist": true,
|
||||||
|
"status": "Normal status for an actual product",
|
||||||
|
"central_heating_pump_age": "Unknown",
|
||||||
|
"controls": "Programmer, room thermostat and TRVs",
|
||||||
|
"flue_gas_heat_recovery_system": false,
|
||||||
|
"weather_compensator": false,
|
||||||
|
"emitter": "Radiators",
|
||||||
|
"emitter_temperature": "Unknown"
|
||||||
|
},
|
||||||
|
"secondary_heating": {
|
||||||
|
"secondary_fuel": "No Secondary Heating"
|
||||||
|
},
|
||||||
|
"water_heating": {
|
||||||
|
"type": "Regular",
|
||||||
|
"system": "From main heating 1",
|
||||||
|
"cylinder_size": "Normal (90-130 litres)",
|
||||||
|
"cylinder_measured_heat_loss": "Not known",
|
||||||
|
"insulation_type": "Factory fitted",
|
||||||
|
"insulation_thickness_mm": 12,
|
||||||
|
"has_thermostat": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ventilation": {
|
||||||
|
"ventilation_type": "Natural",
|
||||||
|
"has_fixed_air_conditioning": false,
|
||||||
|
"number_of_open_flues": 0,
|
||||||
|
"number_of_closed_flues": 0,
|
||||||
|
"number_of_boiler_flues": 0,
|
||||||
|
"number_of_other_flues": 0,
|
||||||
|
"number_of_extract_fans": 2,
|
||||||
|
"number_of_passive_vents": 0,
|
||||||
|
"number_of_flueless_gas_fires": 0,
|
||||||
|
"pressure_test": "No test",
|
||||||
|
"draught_lobby": false
|
||||||
|
},
|
||||||
|
"conservatories": {
|
||||||
|
"has_conservatory": false
|
||||||
|
},
|
||||||
|
"renewables": {
|
||||||
|
"wind_turbines": false,
|
||||||
|
"solar_hot_water": false,
|
||||||
|
"photovoltaic_array": false,
|
||||||
|
"number_of_pv_batteries": 0,
|
||||||
|
"hydro": false
|
||||||
|
},
|
||||||
|
"room_count_elements": {
|
||||||
|
"number_of_habitable_rooms": 2,
|
||||||
|
"any_unheated_rooms": true,
|
||||||
|
"number_of_heated_rooms": 0,
|
||||||
|
"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,
|
||||||
|
"exact_led_cfl_count_known": true,
|
||||||
|
"number_of_fixed_led_bulbs": 5,
|
||||||
|
"number_of_fixed_cfl_bulbs": 4,
|
||||||
|
"waste_water_heat_recovery": "None"
|
||||||
|
},
|
||||||
|
"water_use": {
|
||||||
|
"number_of_baths": 1,
|
||||||
|
"number_of_special_features": 0,
|
||||||
|
"showers": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"outlet_type": "Non-Electric Shower"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"customer_response": {
|
||||||
|
"customer_present": true,
|
||||||
|
"willing_to_answer_satisfaction_survey": false
|
||||||
|
},
|
||||||
|
"addendum": {
|
||||||
|
"addendum": "PV Recommended",
|
||||||
|
"related_party_disclosure": "No related party",
|
||||||
|
"hard_to_treat_cavity_access_issues": false,
|
||||||
|
"hard_to_treat_cavity_high_exposure": false,
|
||||||
|
"hard_to_treat_cavity_narrow_cavities": false
|
||||||
|
}
|
||||||
|
}
|
||||||
330
datatypes/epc/surveys/tests/fixtures/pashub_rdsap_site_notes_example2.json
vendored
Normal file
330
datatypes/epc/surveys/tests/fixtures/pashub_rdsap_site_notes_example2.json
vendored
Normal file
|
|
@ -0,0 +1,330 @@
|
||||||
|
{
|
||||||
|
"inspection_metadata": {
|
||||||
|
"inspection_surveyor": "test",
|
||||||
|
"email_address": "test@test.com",
|
||||||
|
"report_reference": "6EA2A86D-94CE-4792-8D49-AB495C744EDD",
|
||||||
|
"created_on": "2025-11-10",
|
||||||
|
"date_of_inspection": "2025-09-25",
|
||||||
|
"property_address": "test",
|
||||||
|
"property_photo": true
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"epc_checked_before_assessment": true,
|
||||||
|
"epc_exists_at_point_of_assessment": false,
|
||||||
|
"inspection_date": "2025-09-25",
|
||||||
|
"transaction_type": "Grant-Scheme (ECO, RHI, etc.)",
|
||||||
|
"tenure": "Rented Social",
|
||||||
|
"property_type": "House",
|
||||||
|
"detachment_type": "Mid-terrace",
|
||||||
|
"number_of_storeys": 2,
|
||||||
|
"terrain_type": "Suburban",
|
||||||
|
"number_of_extensions": 1,
|
||||||
|
"electricity_smart_meter": true,
|
||||||
|
"electric_meter_type": "Single",
|
||||||
|
"dwelling_export_capable": true,
|
||||||
|
"mains_gas_available": true,
|
||||||
|
"gas_smart_meter": true,
|
||||||
|
"gas_meter_accessible": true,
|
||||||
|
"measurements_location": "Internal"
|
||||||
|
},
|
||||||
|
"building_construction": {
|
||||||
|
"main_building": {
|
||||||
|
"age_range": "1950-1966",
|
||||||
|
"age_indicators": "local knowledge, enquiries of owner",
|
||||||
|
"walls_construction_type": "Cavity",
|
||||||
|
"cavity_construction_indicators": "wall thickness over 270 mm",
|
||||||
|
"walls_insulation_type": "Filled Cavity",
|
||||||
|
"filled_cavity_indicators": "evidence of cavity fill drill holes",
|
||||||
|
"thermal_conductivity_of_wall_insulation": "Unknown",
|
||||||
|
"wall_u_value_known": false,
|
||||||
|
"wall_thickness_mm": 310,
|
||||||
|
"party_wall_construction_type": "Cavity Masonry, Filled"
|
||||||
|
},
|
||||||
|
"extensions": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"age_range": "2003-2006",
|
||||||
|
"age_indicators": "local knowledge, enquiries of owner",
|
||||||
|
"walls_construction_type": "Cavity",
|
||||||
|
"cavity_construction_indicators": "wall thickness over 270 mm",
|
||||||
|
"walls_insulation_type": "As built",
|
||||||
|
"thermal_conductivity_of_wall_insulation": "Unknown",
|
||||||
|
"wall_u_value_known": false,
|
||||||
|
"wall_thickness_mm": 310,
|
||||||
|
"party_wall_construction_type": "Cavity Masonry, Filled"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"floor": {
|
||||||
|
"floor_type": "Ground Floor",
|
||||||
|
"floor_construction": "Solid",
|
||||||
|
"floor_insulation_type": "As Built",
|
||||||
|
"floor_u_value_known": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"building_measurements": {
|
||||||
|
"main_building": {
|
||||||
|
"floors": [
|
||||||
|
{
|
||||||
|
"name": "Floor 1",
|
||||||
|
"area_m2": 35.68,
|
||||||
|
"height_m": 2.19,
|
||||||
|
"heat_loss_perimeter_m": 13.44,
|
||||||
|
"pwl_m": 10.62
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Floor 0",
|
||||||
|
"area_m2": 35.68,
|
||||||
|
"height_m": 2.17,
|
||||||
|
"heat_loss_perimeter_m": 11.0,
|
||||||
|
"pwl_m": 10.62
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"extensions": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"floors": [
|
||||||
|
{
|
||||||
|
"name": "Floor 0",
|
||||||
|
"area_m2": 3.8,
|
||||||
|
"height_m": 2.0,
|
||||||
|
"heat_loss_perimeter_m": 5.7,
|
||||||
|
"pwl_m": 0.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"roof_space": {
|
||||||
|
"main_building": {
|
||||||
|
"construction_type": "Pitched roof (Slates or tiles), Access to loft",
|
||||||
|
"insulation_at": "Joists",
|
||||||
|
"roof_u_value_known": false,
|
||||||
|
"insulation_thickness_mm": 100,
|
||||||
|
"cavity_wall_construction_indicators": "cavity visible in roof space",
|
||||||
|
"rooms_in_roof": false
|
||||||
|
},
|
||||||
|
"extensions": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"construction_type": "Pitched roof, Sloping ceiling",
|
||||||
|
"insulation_at": "Sloping ceiling insulation",
|
||||||
|
"roof_u_value_known": false,
|
||||||
|
"insulation_thickness": "As built",
|
||||||
|
"cavity_wall_construction_indicators": "No indicator of construction visible",
|
||||||
|
"rooms_in_roof": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"windows": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"location": "Main Building",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 1.2,
|
||||||
|
"width_m": 2.3,
|
||||||
|
"orientation": "North West"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 2,
|
||||||
|
"location": "Main Building",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 1.2,
|
||||||
|
"width_m": 1.0,
|
||||||
|
"orientation": "North West"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 3,
|
||||||
|
"location": "Main Building",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 0.9,
|
||||||
|
"width_m": 1.0,
|
||||||
|
"orientation": "North East"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"location": "Extension 1",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 0.9,
|
||||||
|
"width_m": 1.0,
|
||||||
|
"orientation": "North"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"location": "Extension 1",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 0.9,
|
||||||
|
"width_m": 1.7,
|
||||||
|
"orientation": "North East"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"location": "Extension 1",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 0.9,
|
||||||
|
"width_m": 2.3,
|
||||||
|
"orientation": "North West"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"location": "Extension 1",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 1.0,
|
||||||
|
"width_m": 1.2,
|
||||||
|
"orientation": "North West"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 8,
|
||||||
|
"location": "Extension 1",
|
||||||
|
"wall_type": "External wall",
|
||||||
|
"glazing_type": "Double glazing, Unknown install date",
|
||||||
|
"window_type": "Window",
|
||||||
|
"frame_type": "Wooden or PVC",
|
||||||
|
"glazing_gap": "16 mm or more",
|
||||||
|
"draught_proofed": true,
|
||||||
|
"permanent_shutters": false,
|
||||||
|
"height_m": 0.9,
|
||||||
|
"width_m": 1.0,
|
||||||
|
"orientation": "North East"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"heating_and_hot_water": {
|
||||||
|
"main_heating": {
|
||||||
|
"selection_method": "PCDF Search",
|
||||||
|
"system_type": "Boiler with radiators or underfloor heating",
|
||||||
|
"product_id": 16839,
|
||||||
|
"manufacturer": "Vaillant",
|
||||||
|
"model": "ecoTEC pro 28",
|
||||||
|
"orig_manufacturer": "Vaillant",
|
||||||
|
"fuel": "Mains gas",
|
||||||
|
"summer_efficiency": 0,
|
||||||
|
"type": "Combi",
|
||||||
|
"condensing": true,
|
||||||
|
"year": "2005 - 2015",
|
||||||
|
"mount": "Wall",
|
||||||
|
"open_flue": "Room-sealed",
|
||||||
|
"fan_assist": true,
|
||||||
|
"status": "Normal status for an actual product",
|
||||||
|
"central_heating_pump_age": "Unknown",
|
||||||
|
"controls": "Programmer, room thermostat and TRVs",
|
||||||
|
"flue_gas_heat_recovery_system": false,
|
||||||
|
"weather_compensator": false,
|
||||||
|
"emitter": "Radiators",
|
||||||
|
"emitter_temperature": "Unknown"
|
||||||
|
},
|
||||||
|
"secondary_heating": {
|
||||||
|
"secondary_fuel": "No Secondary Heating"
|
||||||
|
},
|
||||||
|
"water_heating": {
|
||||||
|
"type": "Regular",
|
||||||
|
"system": "From main heating 1",
|
||||||
|
"cylinder_size": "No Cylinder",
|
||||||
|
"cylinder_measured_heat_loss": null,
|
||||||
|
"insulation_type": null,
|
||||||
|
"insulation_thickness_mm": null,
|
||||||
|
"has_thermostat": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ventilation": {
|
||||||
|
"ventilation_type": "Mechanical Extract - Decentralised",
|
||||||
|
"ventilation_in_pcdf_database": false,
|
||||||
|
"has_fixed_air_conditioning": false,
|
||||||
|
"number_of_open_flues": 0,
|
||||||
|
"number_of_closed_flues": 0,
|
||||||
|
"number_of_boiler_flues": 0,
|
||||||
|
"number_of_other_flues": 0,
|
||||||
|
"number_of_extract_fans": 0,
|
||||||
|
"number_of_passive_vents": 0,
|
||||||
|
"number_of_flueless_gas_fires": 0,
|
||||||
|
"pressure_test": "No test",
|
||||||
|
"draught_lobby": false
|
||||||
|
},
|
||||||
|
"conservatories": {
|
||||||
|
"has_conservatory": false
|
||||||
|
},
|
||||||
|
"renewables": {
|
||||||
|
"wind_turbines": false,
|
||||||
|
"solar_hot_water": false,
|
||||||
|
"photovoltaic_array": false,
|
||||||
|
"number_of_pv_batteries": 0,
|
||||||
|
"hydro": false
|
||||||
|
},
|
||||||
|
"room_count_elements": {
|
||||||
|
"number_of_habitable_rooms": 3,
|
||||||
|
"any_unheated_rooms": false,
|
||||||
|
"number_of_heated_rooms": null,
|
||||||
|
"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": 4,
|
||||||
|
"exact_led_cfl_count_known": true,
|
||||||
|
"number_of_fixed_led_bulbs": 0,
|
||||||
|
"number_of_fixed_cfl_bulbs": 1,
|
||||||
|
"waste_water_heat_recovery": "None"
|
||||||
|
},
|
||||||
|
"water_use": {
|
||||||
|
"number_of_baths": 1,
|
||||||
|
"number_of_special_features": 0,
|
||||||
|
"showers": [
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"outlet_type": "Non-Electric Shower"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"customer_response": {
|
||||||
|
"customer_present": true,
|
||||||
|
"willing_to_answer_satisfaction_survey": false
|
||||||
|
},
|
||||||
|
"addendum": {
|
||||||
|
"addendum": "None",
|
||||||
|
"related_party_disclosure": "No related party",
|
||||||
|
"hard_to_treat_cavity_access_issues": false,
|
||||||
|
"hard_to_treat_cavity_high_exposure": false,
|
||||||
|
"hard_to_treat_cavity_narrow_cavities": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,362 @@
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from typing import Any, Dict
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from datatypes.epc.schema.tests.helpers import from_dict
|
||||||
|
from datatypes.epc.surveys.pashub_rdsap_site_notes import (
|
||||||
|
ExtensionConstruction,
|
||||||
|
ExtensionMeasurements,
|
||||||
|
ExtensionRoofSpace,
|
||||||
|
PasHubRdSapSiteNotes,
|
||||||
|
)
|
||||||
|
|
||||||
|
FIXTURES = os.path.join(os.path.dirname(__file__), "fixtures")
|
||||||
|
|
||||||
|
|
||||||
|
def load(filename: str) -> Dict[str, Any]:
|
||||||
|
with open(os.path.join(FIXTURES, filename)) as f:
|
||||||
|
return json.load(f) # type: ignore[no-any-return]
|
||||||
|
|
||||||
|
|
||||||
|
class TestExample1:
|
||||||
|
"""No extensions; regular boiler with hot water cylinder; natural ventilation."""
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def survey(self) -> PasHubRdSapSiteNotes:
|
||||||
|
return from_dict(PasHubRdSapSiteNotes, load("example1.json"))
|
||||||
|
|
||||||
|
# --- inspection_metadata ---
|
||||||
|
|
||||||
|
def test_report_reference(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert (
|
||||||
|
survey.inspection_metadata.report_reference
|
||||||
|
== "49D422A9-0779-44DD-9665-464D35DFF1A8"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_created_on(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.inspection_metadata.created_on == "2026-03-31"
|
||||||
|
|
||||||
|
def test_property_photo_absent(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.inspection_metadata.property_photo is None
|
||||||
|
|
||||||
|
# --- general ---
|
||||||
|
|
||||||
|
def test_transaction_type(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.general.transaction_type == "None of the Above"
|
||||||
|
|
||||||
|
def test_number_of_extensions(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.general.number_of_extensions == 0
|
||||||
|
|
||||||
|
def test_smart_meters(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.general.electricity_smart_meter is True
|
||||||
|
assert survey.general.gas_smart_meter is True
|
||||||
|
|
||||||
|
# --- building_construction ---
|
||||||
|
|
||||||
|
def test_main_building_wall_thickness(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.building_construction.main_building.wall_thickness_mm == 280
|
||||||
|
|
||||||
|
def test_main_building_walls_insulation_type(
|
||||||
|
self, survey: PasHubRdSapSiteNotes
|
||||||
|
) -> None:
|
||||||
|
assert (
|
||||||
|
survey.building_construction.main_building.walls_insulation_type
|
||||||
|
== "As built"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_filled_cavity_indicators_absent(
|
||||||
|
self, survey: PasHubRdSapSiteNotes
|
||||||
|
) -> None:
|
||||||
|
assert (
|
||||||
|
survey.building_construction.main_building.filled_cavity_indicators is None
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_no_extensions_in_construction(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.building_construction.extensions is None
|
||||||
|
|
||||||
|
def test_floor_construction(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert (
|
||||||
|
survey.building_construction.floor.floor_construction
|
||||||
|
== "Suspended, not timber"
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- building_measurements ---
|
||||||
|
|
||||||
|
def test_main_building_floor_count(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert len(survey.building_measurements.main_building.floors) == 2
|
||||||
|
|
||||||
|
def test_floor_area(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.building_measurements.main_building.floors[0].area_m2 == 24.78
|
||||||
|
|
||||||
|
def test_no_extension_measurements(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.building_measurements.extensions is None
|
||||||
|
|
||||||
|
# --- roof_space ---
|
||||||
|
|
||||||
|
def test_roof_insulation_thickness_mm(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.roof_space.main_building.insulation_thickness_mm == 100
|
||||||
|
|
||||||
|
def test_roof_insulation_thickness_string_absent(
|
||||||
|
self, survey: PasHubRdSapSiteNotes
|
||||||
|
) -> None:
|
||||||
|
assert survey.roof_space.main_building.insulation_thickness is None
|
||||||
|
|
||||||
|
def test_no_extension_roof_spaces(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.roof_space.extensions is None
|
||||||
|
|
||||||
|
def test_rooms_in_roof_false(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.roof_space.main_building.rooms_in_roof is False
|
||||||
|
|
||||||
|
# --- windows ---
|
||||||
|
|
||||||
|
def test_window_count(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert len(survey.windows) == 4
|
||||||
|
|
||||||
|
def test_window_dimensions(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
w = survey.windows[0]
|
||||||
|
assert w.height_m == 1.36
|
||||||
|
assert w.width_m == 1.0
|
||||||
|
|
||||||
|
def test_window_orientation(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.windows[0].orientation == "South East"
|
||||||
|
assert survey.windows[2].orientation == "North West"
|
||||||
|
|
||||||
|
def test_window_glazing_gap(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.windows[0].glazing_gap == "16 mm or more"
|
||||||
|
|
||||||
|
# --- heating_and_hot_water ---
|
||||||
|
|
||||||
|
def test_main_heating_manufacturer(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.heating_and_hot_water.main_heating.manufacturer == "Vaillant"
|
||||||
|
|
||||||
|
def test_main_heating_model(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.heating_and_hot_water.main_heating.model == "ecoFIT sustain 415"
|
||||||
|
|
||||||
|
def test_main_heating_product_id(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.heating_and_hot_water.main_heating.product_id == 18400
|
||||||
|
|
||||||
|
def test_main_heating_type_regular(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.heating_and_hot_water.main_heating.type == "Regular"
|
||||||
|
|
||||||
|
def test_water_heating_cylinder_present(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
wh = survey.heating_and_hot_water.water_heating
|
||||||
|
assert wh.cylinder_size == "Normal (90-130 litres)"
|
||||||
|
assert wh.insulation_type == "Factory fitted"
|
||||||
|
assert wh.insulation_thickness_mm == 12
|
||||||
|
assert wh.has_thermostat is True
|
||||||
|
|
||||||
|
def test_secondary_heating_none(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert (
|
||||||
|
survey.heating_and_hot_water.secondary_heating.secondary_fuel
|
||||||
|
== "No Secondary Heating"
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- ventilation ---
|
||||||
|
|
||||||
|
def test_ventilation_type(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.ventilation.ventilation_type == "Natural"
|
||||||
|
|
||||||
|
def test_ventilation_pcdf_absent(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.ventilation.ventilation_in_pcdf_database is None
|
||||||
|
|
||||||
|
def test_extract_fans(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.ventilation.number_of_extract_fans == 2
|
||||||
|
|
||||||
|
# --- room_count_elements ---
|
||||||
|
|
||||||
|
def test_habitable_rooms(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.room_count_elements.number_of_habitable_rooms == 2
|
||||||
|
|
||||||
|
def test_heated_rooms_zero(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.room_count_elements.number_of_heated_rooms == 0
|
||||||
|
|
||||||
|
def test_led_bulbs(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.room_count_elements.number_of_fixed_led_bulbs == 5
|
||||||
|
|
||||||
|
def test_cfl_bulbs(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.room_count_elements.number_of_fixed_cfl_bulbs == 4
|
||||||
|
|
||||||
|
# --- water_use ---
|
||||||
|
|
||||||
|
def test_shower_outlet_type(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert len(survey.water_use.showers) == 1
|
||||||
|
assert survey.water_use.showers[0].outlet_type == "Non-Electric Shower"
|
||||||
|
|
||||||
|
# --- addendum ---
|
||||||
|
|
||||||
|
def test_addendum_value(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.addendum.addendum == "PV Recommended"
|
||||||
|
|
||||||
|
def test_related_party_disclosure(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.addendum.related_party_disclosure == "No related party"
|
||||||
|
|
||||||
|
def test_hard_to_treat_flags_false(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.addendum.hard_to_treat_cavity_access_issues is False
|
||||||
|
assert survey.addendum.hard_to_treat_cavity_high_exposure is False
|
||||||
|
assert survey.addendum.hard_to_treat_cavity_narrow_cavities is False
|
||||||
|
|
||||||
|
|
||||||
|
class TestExample2:
|
||||||
|
"""With extensions; combi boiler (no cylinder); mechanical extract ventilation."""
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def survey(self) -> PasHubRdSapSiteNotes:
|
||||||
|
return from_dict(PasHubRdSapSiteNotes, load("example2.json"))
|
||||||
|
|
||||||
|
# --- inspection_metadata ---
|
||||||
|
|
||||||
|
def test_report_reference(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert (
|
||||||
|
survey.inspection_metadata.report_reference
|
||||||
|
== "6EA2A86D-94CE-4792-8D49-AB495C744EDD"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_property_photo_present(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.inspection_metadata.property_photo is True
|
||||||
|
|
||||||
|
def test_created_on_differs_from_inspection_date(
|
||||||
|
self, survey: PasHubRdSapSiteNotes
|
||||||
|
) -> None:
|
||||||
|
assert survey.inspection_metadata.created_on == "2025-11-10"
|
||||||
|
assert survey.inspection_metadata.date_of_inspection == "2025-09-25"
|
||||||
|
|
||||||
|
# --- general ---
|
||||||
|
|
||||||
|
def test_number_of_extensions(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.general.number_of_extensions == 1
|
||||||
|
|
||||||
|
def test_transaction_type(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.general.transaction_type == "Grant-Scheme (ECO, RHI, etc.)"
|
||||||
|
|
||||||
|
# --- building_construction ---
|
||||||
|
|
||||||
|
def test_main_building_filled_cavity_indicators(
|
||||||
|
self, survey: PasHubRdSapSiteNotes
|
||||||
|
) -> None:
|
||||||
|
assert (
|
||||||
|
survey.building_construction.main_building.filled_cavity_indicators
|
||||||
|
== "evidence of cavity fill drill holes"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_extension_construction_present(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.building_construction.extensions is not None
|
||||||
|
assert len(survey.building_construction.extensions) == 1
|
||||||
|
|
||||||
|
def test_extension_construction_type(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.building_construction.extensions is not None
|
||||||
|
ext: ExtensionConstruction = survey.building_construction.extensions[0]
|
||||||
|
assert ext.id == 1
|
||||||
|
assert ext.walls_insulation_type == "As built"
|
||||||
|
assert ext.wall_thickness_mm == 310
|
||||||
|
|
||||||
|
def test_extension_no_filled_cavity_indicators(
|
||||||
|
self, survey: PasHubRdSapSiteNotes
|
||||||
|
) -> None:
|
||||||
|
assert survey.building_construction.extensions is not None
|
||||||
|
assert (
|
||||||
|
survey.building_construction.extensions[0].filled_cavity_indicators is None
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- building_measurements ---
|
||||||
|
|
||||||
|
def test_main_building_floor_count(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert len(survey.building_measurements.main_building.floors) == 2
|
||||||
|
|
||||||
|
def test_extension_measurements_present(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.building_measurements.extensions is not None
|
||||||
|
assert len(survey.building_measurements.extensions) == 1
|
||||||
|
|
||||||
|
def test_extension_floor_area(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.building_measurements.extensions is not None
|
||||||
|
ext: ExtensionMeasurements = survey.building_measurements.extensions[0]
|
||||||
|
assert ext.id == 1
|
||||||
|
assert len(ext.floors) == 1
|
||||||
|
assert ext.floors[0].area_m2 == 3.8
|
||||||
|
|
||||||
|
# --- roof_space ---
|
||||||
|
|
||||||
|
def test_main_roof_insulation_thickness_mm(
|
||||||
|
self, survey: PasHubRdSapSiteNotes
|
||||||
|
) -> None:
|
||||||
|
assert survey.roof_space.main_building.insulation_thickness_mm == 100
|
||||||
|
|
||||||
|
def test_extension_roof_spaces_present(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.roof_space.extensions is not None
|
||||||
|
assert len(survey.roof_space.extensions) == 1
|
||||||
|
|
||||||
|
def test_extension_roof_uses_string_thickness(
|
||||||
|
self, survey: PasHubRdSapSiteNotes
|
||||||
|
) -> None:
|
||||||
|
assert survey.roof_space.extensions is not None
|
||||||
|
ext: ExtensionRoofSpace = survey.roof_space.extensions[0]
|
||||||
|
assert ext.insulation_thickness == "As built"
|
||||||
|
assert ext.insulation_thickness_mm is None
|
||||||
|
|
||||||
|
def test_extension_roof_construction_type(
|
||||||
|
self, survey: PasHubRdSapSiteNotes
|
||||||
|
) -> None:
|
||||||
|
assert survey.roof_space.extensions is not None
|
||||||
|
assert (
|
||||||
|
survey.roof_space.extensions[0].construction_type
|
||||||
|
== "Pitched roof, Sloping ceiling"
|
||||||
|
)
|
||||||
|
|
||||||
|
# --- windows ---
|
||||||
|
|
||||||
|
def test_window_count(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert len(survey.windows) == 8
|
||||||
|
|
||||||
|
def test_extension_windows(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
extension_windows = [w for w in survey.windows if w.location == "Extension 1"]
|
||||||
|
assert len(extension_windows) == 5
|
||||||
|
|
||||||
|
def test_window_ids_sequential(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
ids = [w.id for w in survey.windows]
|
||||||
|
assert ids == list(range(1, 9))
|
||||||
|
|
||||||
|
# --- heating_and_hot_water ---
|
||||||
|
|
||||||
|
def test_main_heating_type_combi(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.heating_and_hot_water.main_heating.type == "Combi"
|
||||||
|
|
||||||
|
def test_main_heating_model(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.heating_and_hot_water.main_heating.model == "ecoTEC pro 28"
|
||||||
|
|
||||||
|
def test_water_heating_no_cylinder(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
wh = survey.heating_and_hot_water.water_heating
|
||||||
|
assert wh.cylinder_size == "No Cylinder"
|
||||||
|
assert wh.cylinder_measured_heat_loss is None
|
||||||
|
assert wh.insulation_type is None
|
||||||
|
assert wh.insulation_thickness_mm is None
|
||||||
|
assert wh.has_thermostat is None
|
||||||
|
|
||||||
|
# --- ventilation ---
|
||||||
|
|
||||||
|
def test_ventilation_type(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert (
|
||||||
|
survey.ventilation.ventilation_type == "Mechanical Extract - Decentralised"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_ventilation_in_pcdf_database(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.ventilation.ventilation_in_pcdf_database is False
|
||||||
|
|
||||||
|
def test_no_extract_fans_for_mev(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.ventilation.number_of_extract_fans == 0
|
||||||
|
|
||||||
|
# --- room_count_elements ---
|
||||||
|
|
||||||
|
def test_habitable_rooms(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.room_count_elements.number_of_habitable_rooms == 3
|
||||||
|
|
||||||
|
def test_heated_rooms_null(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.room_count_elements.number_of_heated_rooms is None
|
||||||
|
|
||||||
|
def test_incandescent_bulbs(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.room_count_elements.number_of_fixed_incandescent_bulbs == 4
|
||||||
|
|
||||||
|
# --- addendum ---
|
||||||
|
|
||||||
|
def test_addendum_none(self, survey: PasHubRdSapSiteNotes) -> None:
|
||||||
|
assert survey.addendum.addendum == "None"
|
||||||
|
|
@ -3,6 +3,6 @@ pythonpath = .
|
||||||
log_cli = true
|
log_cli = true
|
||||||
log_cli_level = INFO
|
log_cli_level = INFO
|
||||||
addopts = --cov-report term-missing --cov=etl/epc --cov=recommendations --cov=backend --cov=etl/epc_clean --cov=etl/spatial
|
addopts = --cov-report term-missing --cov=etl/epc --cov=recommendations --cov=backend --cov=etl/epc_clean --cov=etl/spatial
|
||||||
testpaths = recommendations/tests backend/tests etl/epc/tests etl/epc_clean/tests etl/spatial/tests backend/condition/tests backend/address2UPRN/tests backend/onboarders/tests backend/categorisation/tests backend/export/tests etl/hubspot/tests backend/hubspot_trigger_orchestrator/tests datatypes/epc/schema/tests
|
testpaths = recommendations/tests backend/tests etl/epc/tests etl/epc_clean/tests etl/spatial/tests backend/condition/tests backend/address2UPRN/tests backend/onboarders/tests backend/categorisation/tests backend/export/tests etl/hubspot/tests backend/hubspot_trigger_orchestrator/tests datatypes/epc/schema/tests datatypes/epc/surveys/tests
|
||||||
markers =
|
markers =
|
||||||
integration: mark a test as an integration test
|
integration: mark a test as an integration test
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue