diff --git a/backend/condition/domain/aspect_type.py b/backend/condition/domain/aspect_type.py new file mode 100644 index 00000000..45d0f24b --- /dev/null +++ b/backend/condition/domain/aspect_type.py @@ -0,0 +1,20 @@ +from enum import Enum + + +class AspectType(str, Enum): + MATERIAL = "material" + CONDITION = "condition" + TYPE = "type" + CONFIGURATION = "configuration" + PRESENCE = "presence" + RISK = "risk" + SEVERITY = "severity" + LOCATION = "location" + FINISH = "finish" + INSULATION = "insulation" + POINTING = "pointing" + SPALLING = "spalling" + LINTELS = "lintels" + CLADDING = "cladding" + CATEGORY = "category" + QUANTITY = "quantity" diff --git a/backend/condition/domain/asset_condition.py b/backend/condition/domain/asset_condition.py index a489090f..cd57d9ff 100644 --- a/backend/condition/domain/asset_condition.py +++ b/backend/condition/domain/asset_condition.py @@ -1,16 +1,27 @@ from dataclasses import dataclass -from typing import Optional from datetime import date +from typing import Optional +from xml.dom.minidom import Element -from backend.condition.domain.lbwf_element import LbwfElement +from backend.condition.domain.aspect_type import AspectType +from backend.condition.domain.element import Element @dataclass class AssetCondition: uprn: int - element: LbwfElement # TODO: should HHSRS elements be handled differently? - condition_description: str # TODO: this probably needs to be some sort of enum so it's searchable/filterable on the frontend. Could be hard to map from string though - quantity: int - renewal_year: Optional[int] = None - source: Optional[str] = None + + element: Element + aspect_type: AspectType + + value: Optional[str] = None + + quantity: Optional[int] = None install_date: Optional[date] = None + renewal_year: Optional[int] = None + + element_instance: Optional[int] = None + element_location: Optional[str] = None + + source_system: Optional[str] = None + comments: Optional[str] = None diff --git a/backend/condition/domain/element.py b/backend/condition/domain/element.py new file mode 100644 index 00000000..d9698ddf --- /dev/null +++ b/backend/condition/domain/element.py @@ -0,0 +1,152 @@ +from enum import Enum + + +class Element(str, Enum): + + # ====================== + # PROPERTY / GENERAL + # ====================== + PROPERTY_TYPE = "property_type" + PROPERTY_CONSTRUCTION_TYPE = "property_construction_type" + PROPERTY_CLASSIFICATION = "property_classification" + PROPERTY_AGE_BAND = "property_age_band" + STOREY_COUNT = "storey_count" + FLOOR_LEVEL_FRONT_DOOR = "floor_level_front_door" + ACCESSIBLE_HOUSING_REGISTER = "accessible_housing_register" + ASBESTOS = "asbestos" + + # ====================== + # EXTERNAL – ROOF + # ====================== + ROOF_COVERING = "roof_covering" + ROOF_STRUCTURE = "roof_structure" + ROOF_CHIMNEY = "roof_chimney" + ROOF_FASCIA = "roof_fascia" + ROOF_SOFFIT = "roof_soffit" + RAINWATER_GOODS = "rainwater_goods" + ROOF_PORCH_CANOPY = "roof_porch_canopy" + LOFT_INSULATION = "loft_insulation" + + # ====================== + # EXTERNAL – WALLS + # ====================== + EXTERNAL_WALL = "external_wall" + + # ====================== + # EXTERNAL – WINDOWS + # ====================== + WINDOWS = "windows" + COMMUNAL_WINDOWS = "communal_windows" + SECONDARY_GLAZING = "secondary_glazing" + + # ====================== + # EXTERNAL – DOORS + # ====================== + FRONT_DOOR = "front_door" + REAR_DOOR = "rear_door" + STORE_DOOR = "store_door" + GARAGE_DOOR = "garage_door" + COMMUNAL_ENTRANCE_DOOR = "communal_entrance_door" + + # ====================== + # EXTERNAL – AREAS + # ====================== + PATHS_AND_HARDSTANDINGS = "paths_and_hardstandings" + PARKING_AREAS = "parking_areas" + BOUNDARY_WALLS = "boundary_walls" + FENCING = "fencing" + GATES = "gates" + RETAINING_WALLS = "retaining_walls" + PRIVATE_BALCONY = "private_balcony" + BALCONY_BALUSTRADE = "balcony_balustrade" + OUTBUILDINGS = "outbuildings" + GARAGE_STRUCTURE = "garage_structure" + + # ====================== + # INTERNAL – KITCHEN + # ====================== + KITCHEN = "kitchen" + KITCHEN_SPACE_LAYOUT = "kitchen_space_layout" + TENANT_INSTALLED_KITCHEN = "tenant_installed_kitchen" + + # ====================== + # INTERNAL – BATHROOM + # ====================== + BATHROOM = "bathroom" + + # ====================== + # INTERNAL – HEATING / WATER + # ====================== + HEATING_BOILER = "heating_boiler" + HEATING_DISTRIBUTION = "heating_distribution" + HEATING_EXTENT = "heating_extent" + SECONDARY_HEATING = "secondary_heating" + HOT_WATER_SYSTEM = "hot_water_system" + COLD_WATER_STORAGE = "cold_water_storage" + PROGRAMMABLE_HEATING = "programmable_heating" + + # ====================== + # INTERNAL – ELECTRICS / FIRE + # ====================== + ELECTRICAL_WIRING = "electrical_wiring" + CONSUMER_UNIT = "consumer_unit" + SMOKE_DETECTION = "smoke_detection" + HEAT_DETECTION = "heat_detection" + CARBON_MONOXIDE_DETECTION = "carbon_monoxide_detection" + FIRE_DOOR_RATING = "fire_door_rating" + + # ====================== + # COMMUNAL SYSTEMS + # ====================== + COMMUNAL_HEATING = "communal_heating" + COMMUNAL_BOILER = "communal_boiler" + COMMUNAL_ELECTRICS = "communal_electrics" + COMMUNAL_FIRE_ALARM = "communal_fire_alarm" + COMMUNAL_EMERGENCY_LIGHTING = "communal_emergency_lighting" + COMMUNAL_LIFT = "communal_lift" + COMMUNAL_DOOR_ENTRY = "communal_door_entry" + COMMUNAL_CCTV = "communal_cctv" + COMMUNAL_BIN_STORE = "communal_bin_store" + COMMUNAL_REFUSE_CHUTE = "communal_refuse_chute" + + # ========================================================== + # HHSRS – ALL 29 HAZARDS + # ========================================================== + + # --- Physiological requirements (4) + HHSRS_DAMP_AND_MOULD = "hhsrs_damp_and_mould" + HHSRS_EXCESS_COLD = "hhsrs_excess_cold" + HHSRS_EXCESS_HEAT = "hhsrs_excess_heat" + HHSRS_ASBESTOS_AND_MMF = "hhsrs_asbestos_and_mmf" + + # --- Psychological requirements (4) + HHSRS_CROWDING_AND_SPACE = "hhsrs_crowding_and_space" + HHSRS_ENTRY_BY_INTRUDERS = "hhsrs_entry_by_intruders" + HHSRS_LIGHTING = "hhsrs_lighting" + HHSRS_NOISE = "hhsrs_noise" + + # --- Protection against infection (6) + HHSRS_DOMESTIC_HYGIENE_PESTS_REFUSE = "hhsrs_domestic_hygiene_pests_refuse" + HHSRS_FOOD_SAFETY = "hhsrs_food_safety" + HHSRS_PERSONAL_HYGIENE_SANITATION = "hhsrs_personal_hygiene_sanitation" + HHSRS_WATER_SUPPLY = "hhsrs_water_supply" + HHSRS_FALLS_ASSOCIATED_WITH_BATHS = "hhsrs_falls_associated_with_baths" + HHSRS_SURFACES_MOULD = "hhsrs_surfaces_mould" + + # --- Protection against accidents (10) + HHSRS_FALLS_ON_LEVEL_SURFACES = "hhsrs_falls_on_level_surfaces" + HHSRS_FALLS_ON_STAIRS = "hhsrs_falls_on_stairs" + HHSRS_FALLS_BETWEEN_LEVELS = "hhsrs_falls_between_levels" + HHSRS_ELECTRICAL_HAZARDS = "hhsrs_electrical_hazards" + HHSRS_FIRE = "hhsrs_fire" + HHSRS_FLAMES_HOT_SURFACES = "hhsrs_flames_hot_surfaces" + HHSRS_COLLISION_AND_ENTRAPMENT = "hhsrs_collision_and_entrapment" + HHSRS_EXPLOSION = "hhsrs_explosion" + HHSRS_STRUCTURAL_COLLAPSE = "hhsrs_structural_collapse" + HHSRS_UNSAFE_GAS = "hhsrs_unsafe_gas" + + # --- Protection against pollution (4) + HHSRS_CARBON_MONOXIDE = "hhsrs_carbon_monoxide" + HHSRS_LEAD = "hhsrs_lead" + HHSRS_RADIATION = "hhsrs_radiation" + HHSRS_UNCOMBUSTED_FUEL_GAS = "hhsrs_uncombusted_fuel_gas" diff --git a/backend/condition/tests/mapping/test_lbwf_mapper.py b/backend/condition/tests/mapping/test_lbwf_mapper.py index c007b575..f930fdb4 100644 --- a/backend/condition/tests/mapping/test_lbwf_mapper.py +++ b/backend/condition/tests/mapping/test_lbwf_mapper.py @@ -1,7 +1,10 @@ from typing import List +from xml.dom.minidom import Element import pytest from datetime import date +from backend.condition.domain.aspect_type import AspectType +from backend.condition.domain.element import Element from backend.condition.domain.mapping.lbwf_mapper import LbwfMapper from backend.condition.parsing.records.lbwf.lbwf_house import LbwfHouse from backend.condition.parsing.records.lbwf.lbwf_asset_condition import ( @@ -85,6 +88,27 @@ def test_lbwf_mapper_maps_house(): remaining_life=None, element_comments="Source of Data = ACT", ), + LbwfAssetCondition( + prop_ref=100, + domna=100, + address="123 Fake Street, London, A10 1AB", + ownership="LBWF_OWNED", + prop_status="OCCP", + prop_type="HOU", + prop_sub_type="TERRACED", + element_group="ASSETS", + element_code="HHSRSASB", + element_code_description="Asbestos (and MMF)", + attribute_code="TYPRISK", + attribute_code_description="Category 4 - Typical Risk", + element_date_value=None, + element_numerical_value=None, + element_text_value=None, + quantity=None, + install_date=None, + remaining_life=None, + element_comments="Source of Data = ACT", + ), LbwfAssetCondition( prop_ref=100, domna=100, @@ -158,9 +182,9 @@ def test_lbwf_mapper_maps_house(): prop_sub_type="TERRACED", element_group="ASSETS", element_code="EXTWALLFN1", - element_code_description="Wall Finish 1 in External Area", - attribute_code="RENDERPBBL", - attribute_code_description="Render or Pebbledash Wall Finish 1 in External Area", + element_code_description="Wall Finish 2 in External Area", + attribute_code="SMTHRENDER", + attribute_code_description="Smooth Render Wall Finish 1 in External Area", element_date_value=None, element_numerical_value=None, element_text_value=None, @@ -178,66 +202,102 @@ def test_lbwf_mapper_maps_house(): expected_assets: List[AssetCondition] = [ AssetCondition( uprn=1, - element=LbwfElement.AHR_CAT, - condition_description="General Needs", + element=Element.ACCESSIBLE_HOUSING_REGISTER, + aspect_type=AspectType.CATEGORY, + element_instance=None, + value="General Needs", quantity=1, renewal_year=None, - source=None, install_date=None, + comments=None, ), AssetCondition( uprn=1, - element=LbwfElement.FLVL, - condition_description="Ground Floor", + element=Element.FLOOR_LEVEL_FRONT_DOOR, + aspect_type=AspectType.LOCATION, + element_instance=None, + value="Ground Floor", quantity=1, renewal_year=None, - source=None, install_date=None, + comments=None, ), AssetCondition( uprn=1, - element=LbwfElement.ASBESTOS, - condition_description="Yes", + element=Element.ASBESTOS, + aspect_type=AspectType.PRESENCE, + element_instance=None, + value="Yes", quantity=None, renewal_year=None, - source="Source of Data = ACT", install_date=None, + comments="Source of Data = ACT", ), AssetCondition( uprn=1, - element=LbwfElement.INTBTHRLOC, - condition_description="Bathroom on Entrance Level in Property", + element=Element.HHSRS_ASBESTOS_AND_MMF, + aspect_type=AspectType.RISK, + element_instance=None, + value="Category 4 - Typical Risk", + quantity=None, + renewal_year=None, + install_date=None, + comments="Source of Data = ACT", + ), + AssetCondition( + uprn=1, + element=Element.BATHROOM, + aspect_type=AspectType.LOCATION, + element_instance=None, + value="Bathroom on Entrance Level in Property", quantity=1, renewal_year=None, - source="Source of Data = Codeman", install_date=None, + comments="Source of Data = Codeman", ), AssetCondition( uprn=1, - element=LbwfElement.INTCHEXTNT, - condition_description="No Central Heating in Property", + element=Element.HEATING_EXTENT, + aspect_type=AspectType.CONFIGURATION, + element_instance=None, + value="No Central Heating in Property", quantity=1, renewal_year=None, - source="Source of Data = Codeman", install_date=None, + comments="Source of Data = Codeman", ), AssetCondition( uprn=1, - element=LbwfElement.HHSRSFIRE, - condition_description="Category 4 - Typical Risk", + element=Element.HHSRS_FIRE, + aspect_type=AspectType.RISK, + element_instance=None, + value="Category 4 - Typical Risk", quantity=1, renewal_year=None, - source="Source of Data = Morgan Sindall", install_date=None, + comments="Source of Data = Morgan Sindall", ), AssetCondition( uprn=1, - element=LbwfElement.EXTWALLFN1, - condition_description="Render or Pebbledash Wall Finish 1 in External Area", + element=Element.EXTERNAL_WALL, + aspect_type=AspectType.FINISH, + element_instance=1, + value="Render or Pebbledash", quantity=1, renewal_year=2052, - source="Source of Data = Codeman", install_date=date(2009, 4, 1), + comments="Source of Data = Codeman", + ), + AssetCondition( + uprn=1, + element=Element.EXTERNAL_WALL, + aspect_type=AspectType.FINISH, + element_instance=2, + value="Smooth Render Wall Finish 1 in External Area", + quantity=1, + renewal_year=2052, + install_date=date(2009, 4, 1), + comments="Source of Data = Codeman", ), ]