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.lbwf.lbwf_element_map import LBWF_ELEMENT_MAP from backend.condition.domain.mapping.mapper import Mapper from backend.condition.domain.property_condition_survey import PropertyConditionSurvey from backend.condition.parsing.records.lbwf.lbwf_asset_condition import ( LbwfAssetCondition, ) from backend.condition.parsing.records.lbwf.lbwf_house import LbwfHouse from utils.logger import setup_logger logger = setup_logger() class LbwfMapper(Mapper): def map_asset_conditions_for_property( self, client_property_data: Any, survey_year: Optional[int] = None ) -> PropertyConditionSurvey: assert isinstance( client_property_data, LbwfHouse ) # 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: if raw_asset.element_code in ["DECNTHMINC", "EICINSFREQ"]: # skip metadata rows continue element_mapping = LbwfMapper._safe_map_element(raw_asset) if not element_mapping: continue aspect_condition = LbwfMapper._build_aspect_condition( raw_asset, element_mapping, survey_year ) element_key = ( element_mapping.elementType, element_mapping.element_instance or 1, ) LbwfMapper._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="LBWF", # TODO: Make this the system, not the client ) @staticmethod def _safe_map_element(raw_asset: LbwfAssetCondition) -> Optional[ElementMapping]: try: return LbwfMapper._map_element(raw_asset.element_code) except KeyError: logger.warning( logger.warning( f"Unrecognised LBWF Asset Element: " f"{raw_asset.element_code} ({raw_asset.element_code_description})). " "Skipping record" ) ) return None @staticmethod def _map_element(lbwf_element_code: str) -> ElementMapping: return LBWF_ELEMENT_MAP[lbwf_element_code] @staticmethod def _build_aspect_condition( raw_asset, element_mapping: ElementMapping, survey_year: int ) -> AspectCondition: return AspectCondition( aspect_type=element_mapping.aspect_type, aspect_instance=element_mapping.aspect_instance or 1, value=raw_asset.attribute_code_description, quantity=raw_asset.quantity, install_date=raw_asset.install_date, renewal_year=LbwfMapper._calculate_renewal_year(raw_asset, survey_year), comments=raw_asset.element_comments, ) @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 _calculate_renewal_year( lbwf_asset: LbwfAssetCondition, survey_year: Optional[int] ) -> Optional[int]: remaining_life_years: Optional[int] = lbwf_asset.remaining_life if not remaining_life_years: return None if not survey_year: return None try: return survey_year + remaining_life_years except: logger.debug( f"Unable to map LBWF Asset remaining life {remaining_life_years} to renewal year, returning None" ) return None