From 42f9821f1b4a9f279e716cd9ed2725754d161b41 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Fri, 23 Jan 2026 12:50:48 +0000 Subject: [PATCH] =?UTF-8?q?Map=20to=20dataclasses=20from=20Peabody=20objec?= =?UTF-8?q?ts=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mapping/peabody/peabody_element_map.py | 70 +++++++++++-------- .../domain/mapping/peabody/peabody_mapper.py | 44 +++++++++++- 2 files changed, 85 insertions(+), 29 deletions(-) diff --git a/backend/condition/domain/mapping/peabody/peabody_element_map.py b/backend/condition/domain/mapping/peabody/peabody_element_map.py index 2a1203c0..5b89c578 100644 --- a/backend/condition/domain/mapping/peabody/peabody_element_map.py +++ b/backend/condition/domain/mapping/peabody/peabody_element_map.py @@ -1,40 +1,54 @@ +from backend.condition.domain.aspect_type import AspectType +from backend.condition.domain.element import Element from backend.condition.domain.mapping.element_mapping import ElementMapping PEABODY_ELEMENT_MAP = { - # -------------------- - # GENERAL - # -------------------- - ("100", "1"): ElementMapping(element="property", aspect="type"), - ("100", "3"): ElementMapping(element="property", aspect="age_band"), - ("100", "14"): ElementMapping(element="property", aspect="construction_type"), - # -------------------- - # EXTERNALS - # -------------------- - ("120", "1"): ElementMapping(element="external_wall", aspect="structure"), - ("120", "2"): ElementMapping(element="external_wall", aspect="finish"), - ("110", "1"): ElementMapping(element="roof", aspect="covering"), - # -------------------- - # INTERNALS - # -------------------- - ("160", "1"): ElementMapping(element="kitchen", aspect="condition"), - ("190", "1"): ElementMapping(element="bathroom", aspect="condition"), + # ========================================================== + # PROPERTY / GENERAL + # ========================================================== + (100, 1): ElementMapping(element=Element.PROPERTY, aspect_type=AspectType.TYPE), + # (100, 3): ElementMapping(element=Element.PROPERTY, aspect_type=AspectType.AGE), + # (100, 14): ElementMapping(element="property", aspect_type="construction_type"), + # ========================================================== + # EXTERNAL – WALLS + # ========================================================== + (120, 1): ElementMapping( + element=Element.EXTERNAL_WALL, aspect_type=AspectType.STRUCTURE + ), + (120, 2): ElementMapping( + element=Element.EXTERNAL_WALL, aspect_type=AspectType.FINISH + ), + # ========================================================== + # EXTERNAL – ROOFS + # ========================================================== + (110, 1): ElementMapping(element=Element.ROOF, aspect_type=AspectType.COVERING), + # ========================================================== + # EXTERNAL – DOORS & WINDOWS + # ========================================================== + (130, 1): ElementMapping( + element=Element.EXTERNAL_WINDOWS, aspect_type=AspectType.MATERIAL + ), + # ========================================================== + # INTERNAL – BATHROOMS & KITCHENS + # ========================================================== + (160, 1): ElementMapping(element=Element.KITCHEN, aspect_type=AspectType.CONDITION), + (190, 1): ElementMapping( + element=Element.BATHROOM, aspect_type=AspectType.CONDITION + ), # -------------------- # HHSRS (PEABODY) # -------------------- - ("54", "1"): ElementMapping( - element="hhsrs", aspect="risk", is_hhsrs=True, hhsrs_hazard_id=1 + (54, 1): ElementMapping( + element=Element.HHSRS_DAMP_AND_MOULD, aspect_type=AspectType.RISK ), - ("54", "2"): ElementMapping( - element="hhsrs", aspect="risk", is_hhsrs=True, hhsrs_hazard_id=2 + (54, 4): ElementMapping( + element=Element.HHSRS_ASBESTOS_AND_MMF, aspect_type=AspectType.RISK ), - ("54", "4"): ElementMapping( - element="hhsrs", aspect="risk", is_hhsrs=True, hhsrs_hazard_id=4 + (54, 15): ElementMapping( + element=Element.HHSRS_DOMESTIC_HYGIENE_PESTS_REFUSE, aspect_type=AspectType.RISK ), - ("54", "24"): ElementMapping( - element="hhsrs", aspect="risk", is_hhsrs=True, hhsrs_hazard_id=24 - ), - ("54", "29"): ElementMapping( - element="hhsrs", aspect="risk", is_hhsrs=True, hhsrs_hazard_id=29 + (54, 29): ElementMapping( + element=Element.HHSRS_STRUCTURAL_COLLAPSE, aspect_type=AspectType.RISK ), } diff --git a/backend/condition/domain/mapping/peabody/peabody_mapper.py b/backend/condition/domain/mapping/peabody/peabody_mapper.py index 3f0ee931..44dbd56e 100644 --- a/backend/condition/domain/mapping/peabody/peabody_mapper.py +++ b/backend/condition/domain/mapping/peabody/peabody_mapper.py @@ -1,6 +1,10 @@ from typing import Any, List, Optional from backend.condition.domain.asset_condition import AssetCondition +from backend.condition.domain.mapping.element_mapping import ElementMapping +from backend.condition.domain.mapping.peabody.peabody_element_map import ( + PEABODY_ELEMENT_MAP, +) from backend.condition.domain.mapping.mapper import Mapper from backend.condition.parsing.records.peabody.peabody_asset_condition import ( PeabodyAssetCondition, @@ -15,4 +19,42 @@ class PeabodyMapper(Mapper): def map_asset_conditions_for_property( self, client_data: Any, survey_year: Optional[int] = None ) -> List[AssetCondition]: - raise NotImplementedError + assert isinstance( + client_data, PeabodyProperty + ) # TODO: think of a better way to do this + + mapped_assets: List[AssetCondition] = [] + + uprn: int = client_data.uprn + for raw_asset in client_data.assets: + try: + element_mapping: ElementMapping = PeabodyMapper._map_element( + raw_asset.element_code, raw_asset.sub_element_code + ) + except: + logger.warning( + f"""Unrecognised Peabody Asset Element: {raw_asset.element} ({raw_asset.element_code}), + Sub-Element: {raw_asset.sub_element} ({raw_asset.sub_element_code}). Skipping record""" + ) + continue + + mapped_assets.append( + AssetCondition( + uprn=uprn, + element=element_mapping.element, + aspect_type=element_mapping.aspect_type, + value=raw_asset.material_or_answer, + quantity=raw_asset.renewal_quantity, + install_date=None, # Not available in peabody data + renewal_year=raw_asset.renewal_year, + element_instance=element_mapping.element_instance, + source_system=None, # Once we know the system name we'll set it here + comments=None, # Not available in peabody data + ) + ) + + return mapped_assets + + @staticmethod + def _map_element(element_code: int, sub_element_code: int) -> ElementMapping: + return PEABODY_ELEMENT_MAP[(element_code, sub_element_code)]