from typing import Any, Dict, Optional, Tuple from datetime import date from backend.condition.domain.aspect_condition import AspectCondition from backend.condition.domain.element import Element from backend.condition.domain.element_type import ElementType 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.domain.property_condition_survey import PropertyConditionSurvey from backend.condition.parsing.records.peabody.peabody_asset_condition import ( PeabodyAssetCondition, ) from backend.condition.parsing.records.peabody.peabody_property import PeabodyProperty from utils.logger import setup_logger logger = setup_logger() class PeabodyMapper(Mapper): def map_asset_conditions_for_property( self, client_property_data: Any, survey_year: Optional[int] = None ) -> PropertyConditionSurvey: assert isinstance( client_property_data, PeabodyProperty ) # TODO: think of a better way to do this elements_by_key: dict[tuple[ElementType, int], Element] = {} for raw_asset in client_property_data.assets: element_mapping = PeabodyMapper._safe_map_element(raw_asset) aspect_condition = PeabodyMapper._build_aspect_condition( raw_asset, element_mapping ) element_key = ( element_mapping.elementType, element_mapping.element_instance or 1, ) PeabodyMapper._attach_aspect_condition_to_element( elements_by_key, element_key, aspect_condition, ) return PropertyConditionSurvey( uprn=client_property_data.uprn, elements=list(elements_by_key.values()), date=date(2000, 1, 1), # Temp - not sure how to get this source="Peabody", # TODO: Make this the system, not the client ) @staticmethod def _safe_map_element(raw_asset: PeabodyAssetCondition) -> Optional[ElementMapping]: try: return PeabodyMapper._map_element( raw_asset.element_code, raw_asset.sub_element_code, ) except KeyError: logger.warning( f"Unrecognised Peabody Asset Element: " f"{raw_asset.element} ({raw_asset.element_code}), " f"Sub-Element: {raw_asset.sub_element} ({raw_asset.sub_element_code}). " "Skipping record" ) return None @staticmethod def _map_element(element_code: int, sub_element_code: int) -> ElementMapping: return PEABODY_ELEMENT_MAP[(element_code, sub_element_code)] @staticmethod def _attach_aspect_condition_to_element( elements_by_key: Dict[Tuple[ElementType, int], Element], element_key: Tuple[ElementType, int], aspect_condition: AspectCondition, ) -> None: element = elements_by_key.get(element_key) if element is None: element = Element( element_type=element_key[0], element_instance=element_key[1], aspect_conditions=[], ) elements_by_key[element_key] = element element.aspect_conditions.append(aspect_condition) @staticmethod def _build_aspect_condition( raw_asset, element_mapping: ElementMapping ) -> AspectCondition: return AspectCondition( aspect_type=element_mapping.aspect_type, aspect_instance=element_mapping.aspect_instance or 1, 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, comments=None, )