From 1b82993802b5afac03ac5d7f070bb30956ece40b Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 1 Aug 2023 16:45:45 +0100 Subject: [PATCH] pushing final data to db almost complete --- backend/Property.py | 49 ++++++++++++++++ .../app/db/functions/property_functions.py | 20 ++++++- backend/app/db/models/portfolio.py | 41 +++++++++----- backend/app/plan/router.py | 56 ++----------------- 4 files changed, 100 insertions(+), 66 deletions(-) diff --git a/backend/Property.py b/backend/Property.py index 0dafdd83..3ed42266 100644 --- a/backend/Property.py +++ b/backend/Property.py @@ -315,3 +315,52 @@ class Property(BaseUtility): property_data = self._clean_upload_data(property_data) return property_data + + @classmethod + def _prepare_rating_field(cls, field, rating_lookup): + """ + Utility function for usage in the lambda, for preparing the _rating fields + """ + return rating_lookup[field] if field not in cls.DATA_ANOMALY_MATCHES else None + + def get_property_details_epc(self, portfolio_id: int, rating_lookup): + + property_details_epc = { + "property_id": self.id, + "portfolio_id": portfolio_id, + "full_address": self.data["address"], + "total_floor_area": float(self.data["total-floor-area"]), + "walls": self.walls["clean_description"], + "walls_rating": self._prepare_rating_field(self.data["walls-energy-eff"], rating_lookup), + "roof": self.roof["clean_description"], + "roof_rating": self._prepare_rating_field(self.data["roof-energy-eff"], rating_lookup), + "floor": self.floor["clean_description"], + "floor_rating": self._prepare_rating_field(self.data["floor-energy-eff"], rating_lookup), + "windows": self.windows["clean_description"], + "windows_rating": self._prepare_rating_field(self.data["windows-energy-eff"], rating_lookup), + "heating": self.main_heating["clean_description"], + "heating_rating": self._prepare_rating_field(self.data["mainheat-energy-eff"], rating_lookup), + "heating_controls": self.main_heating_controls["clean_description"], + "heating_controls_rating": self._prepare_rating_field(self.data["mainheatc-energy-eff"], rating_lookup), + "hot_water": self.hotwater["clean_description"], + "hot_water_rating": self._prepare_rating_field(self.data["hot-water-energy-eff"], rating_lookup), + "lighting": self.lighting["clean_description"], + "lighting_rating": self._prepare_rating_field(self.data["lighting-energy-eff"], rating_lookup), + "mainfuel": self.main_fuel["clean_description"], + "ventilation": self.ventilation["ventilation"], + "solar_pv": self.solar_pv["solar_pv"], + "solar_hot_water": self.solar_hot_water["solar_hot_water"], + "wind_turbine": self.wind_turbine["wind_turbine"], + "floor_height": self.data["floor-height"], + "heat_loss_corridor": self.data["heat-loss-corridor"], + "unheated_corridor_length": self.data["unheated-corridor-length"], + "number_of_open_fireplaces": self.number_of_open_fireplaces, + "number_of_extensions": self.number_of_extensions, + "number_of_storeys": self.number_of_storeys, + "mains_gas": self.data["mains-gas-flag"], + "energy_tarrif": self.data["energy-tariff"], + "primary_energy_consumption": self.energy["primary_energy_consumption"], + "co2_emissions": self.energy["co2_emissions"], + } + + return property_details_epc diff --git a/backend/app/db/functions/property_functions.py b/backend/app/db/functions/property_functions.py index 42dd3b0d..63022ace 100644 --- a/backend/app/db/functions/property_functions.py +++ b/backend/app/db/functions/property_functions.py @@ -4,7 +4,9 @@ import datetime import pytz from sqlalchemy.orm import sessionmaker -from backend.app.db.models.portfolio import PropertyModel, PropertyCreationStatus, PortfolioStatus, PropertyTargetsModel +from backend.app.db.models.portfolio import ( + PropertyModel, PropertyCreationStatus, PortfolioStatus, PropertyTargetsModel, PropertyDetailsEpcModel +) from backend.app.db.connection import db_engine from sqlalchemy.orm.exc import NoResultFound @@ -93,7 +95,6 @@ def update_property_data(property_id: int, portfolio_id: int, property_data: dic for key, value in property_data.items(): setattr(existing_property, key, value) - # Optionally, update the 'updated_at' field existing_property.updated_at = now # Merge the updated property back into the session and commit @@ -104,3 +105,18 @@ def update_property_data(property_id: int, portfolio_id: int, property_data: dic raise Exception(f"Property with property_id {property_id} and portfolio_id {portfolio_id} not found") return True + + +def create_property_details_epc(property_details_epc: dict): + """ + This function will create a record for the property details EPC in the database. + :param property_details_epc: A dictionary containing details about the property EPC. + :return: True if successful, False otherwise. + """ + Session = sessionmaker(bind=db_engine) + with Session() as session: + new_property_details_epc = PropertyDetailsEpcModel(**property_details_epc) + session.add(new_property_details_epc) + session.commit() + + return True diff --git a/backend/app/db/models/portfolio.py b/backend/app/db/models/portfolio.py index 7bce3688..f073459c 100644 --- a/backend/app/db/models/portfolio.py +++ b/backend/app/db/models/portfolio.py @@ -88,14 +88,27 @@ class PropertyModel(Base): class FeatureRating(enum.Enum): - VERY_GOOD = "Very good" - GOOD = "Good" - POOR = "Poor" - VERY_POOR = "Very poor" - NA = "N/A" + VERY_GOOD = 5 + GOOD = 4 + POOR = 3 + VERY_POOR = 2 + NA = 1 -class PropertyDetailsEpc(Base): +rating_lookup = { + "Very Good": FeatureRating.VERY_GOOD, + "Good": FeatureRating.GOOD, + "Poor": FeatureRating.POOR, + "Very Poor": FeatureRating.VERY_POOR, + "N/A": FeatureRating.NA +} + + +def get_feature_rating_from_string(rating_str: str): + return rating_lookup.get(rating_str, FeatureRating.NA) + + +class PropertyDetailsEpcModel(Base): __tablename__ = 'property_details_epc' id = Column(Integer, primary_key=True, autoincrement=True) property_id = Column(Integer, ForeignKey('property.id'), nullable=False) @@ -103,21 +116,21 @@ class PropertyDetailsEpc(Base): full_address = Column(Text) total_floor_area = Column(Float) walls = Column(Text) - walls_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x])) + walls_rating = Column(Enum(FeatureRating, )) roof = Column(Text) - roof_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x])) + roof_rating = Column(Enum(FeatureRating, )) floor = Column(Text) - floor_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x])) + floor_rating = Column(Enum(FeatureRating, )) windows = Column(Text) - windows_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x])) + windows_rating = Column(Enum(FeatureRating, )) heating = Column(Text) - heating_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x])) + heating_rating = Column(Enum(FeatureRating, )) heating_contols = Column(Text) - heating_contols_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x])) + heating_contols_rating = Column(Enum(FeatureRating, )) hot_water = Column(Text) - hot_water_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x])) + hot_water_rating = Column(Enum(FeatureRating, )) lighting = Column(Text) - lighting_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x])) + lighting_rating = Column(Enum(FeatureRating)) ventilation = Column(Text) solar_pv = Column(Text) solar_hot_water = Column(Text) diff --git a/backend/app/plan/router.py b/backend/app/plan/router.py index a0b00a38..cb670780 100644 --- a/backend/app/plan/router.py +++ b/backend/app/plan/router.py @@ -1,4 +1,5 @@ from fastapi import APIRouter, Depends +from backend.app.db.models.portfolio import rating_lookup from backend.app.dependencies import validate_token from backend.app.plan.schemas import PlanTriggerRequest from backend.app.utils import read_csv_from_s3 @@ -12,7 +13,9 @@ from utils.uvalue_estimates import classify_decile_newvalues from model_data.EpcClean import EpcClean # database interaction functions -from backend.app.db.functions.property_functions import create_property, create_property_targets, update_property_data +from backend.app.db.functions.property_functions import ( + create_property, create_property_targets, update_property_data, create_property_details_epc +) # TODO: This is placeholder until data is stored in DB from backend.app.plan.uvalue_estimates_walls import uvalue_estimates_walls @@ -212,55 +215,8 @@ async def trigger_plan(body: PlanTriggerRequest): # Upload property data for p in input_properties: - def prepare_rating(field): - rating_lookup = { - "Very Good": 5, - "Good": 4, - "Average": 3, - "Poor": 2, - "Very Poor": 1, - "N/A": None, - } - - return rating_lookup[field] if field not in p.DATA_ANOMALY_MATCHES else None - - property_details_epc = { - "property_id": p.id, - "portfolio_id": body.portfolio_id, - "full_address": p.data["address"], - "total_floor_area": float(p.data["total-floor-area"]), - "walls": p.walls["clean_description"], - "walls_rating": prepare_rating(p.data["walls-energy-eff"]), - "roof": p.roof["clean_description"], - "roof_rating": prepare_rating(p.data["roof-energy-eff"]), - "floor": p.floor["clean_description"], - "floor_rating": prepare_rating(p.data["floor-energy-eff"]), - "windows": p.windows["clean_description"], - "windows_rating": prepare_rating(p.data["windows-energy-eff"]), - "heating": p.main_heating["clean_description"], - "heating_rating": prepare_rating(p.data["mainheat-energy-eff"]), - "heating_controls": p.main_heating_controls["clean_description"], - "heating_controls_rating": prepare_rating(p.data["mainheatc-energy-eff"]), - "hot_water": p.hotwater["clean_description"], - "hot_water_rating": prepare_rating(p.data["hot-water-energy-eff"]), - "lighting": p.lighting["clean_description"], - "lighting_rating": prepare_rating(p.data["lighting-energy-eff"]), - "mainfuel": p.main_fuel["clean_description"], - "ventilation": p.ventilation["ventilation"], - "solar_pv": p.solar_pv["solar_pv"], - "solar_hot_water": p.solar_hot_water["solar_hot_water"], - "wind_turbine": p.wind_turbine["wind_turbine"], - "floor_height": p.data["floor-height"], - "heat_loss_corridor": p.data["heat-loss-corridor"], - "unheated_corridor_length": p.data["unheated-corridor-length"], - "number_of_open_fireplaces": p.number_of_open_fireplaces, - "number_of_extensions": p.number_of_extensions, - "number_of_storeys": p.number_of_storeys, - "mains_gas": p.data["mains-gas-flag"], - "energy_tarrif": p.data["energy-tariff"], - "primary_energy_consumption": p.energy["primary_energy_consumption"], - "co2_emissions": p.energy["co2_emissions"], - } + property_details_epc = p.get_property_details_epc(portfolio_id=body.portfolio_id, rating_lookup=rating_lookup) + create_property_details_epc(property_details_epc) property_data = p.get_full_property_data() update_property_data(property_id=p.id, portfolio_id=body.portfolio_id, property_data=property_data)