From c71e6fe44f21e69bd37d7c83f35c5d69069b9fe9 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 31 Jul 2023 15:02:12 +0100 Subject: [PATCH] added property and portfolio models' --- backend/app/db/models/portfolio.py | 50 ++++++++++++++ backend/app/db/models/property.py | 104 +++++++++++++++++++++++++++++ backend/app/plan/router.py | 2 + 3 files changed, 156 insertions(+) create mode 100644 backend/app/db/models/portfolio.py create mode 100644 backend/app/db/models/property.py diff --git a/backend/app/db/models/portfolio.py b/backend/app/db/models/portfolio.py new file mode 100644 index 00000000..be67a7aa --- /dev/null +++ b/backend/app/db/models/portfolio.py @@ -0,0 +1,50 @@ +from sqlalchemy import Column, Integer, String, Text, Boolean, Float, DateTime, Enum +from sqlalchemy.ext.declarative import declarative_base + +Base = declarative_base() + + +class PortfolioStatus(Enum): + SCOPING = "scoping" + ASSESSMENT = "assessment" + TENDERING = "tendering" + PROJECT_UNDERWAY = "project underway" + COMPLETION_ON_TRACK = "completion; status: on track" + COMPLETION_DELAYED = "completion; status: delayed" + COMPLETION_AT_RISK = "completion; status: at risk" + COMPLETED = "completion; status: completed" + NEEDS_REVIEW = "needs review" + + +class PortfolioGoal(Enum): + VALUATION_IMPROVEMENT = "Valuation Improvement" + INCREASING_EPC = "Increasing EPC" + REDUCING_CO2_EMISSIONS = "Reducing CO2 emissions" + ENERGY_SAVINGS = "Energy Savings" + NONE = "None" + + +class PortfolioRole(Enum): + CREATOR = "creator" + ADMIN = "admin" + READ = "read" + WRITE = "write" + + +class Portfolio(Base): + __tablename__ = 'portfolio' + id = Column(Integer, primary_key=True, autoincrement=True) + name = Column(Text, nullable=False) + budget = Column(Float) + status = Column(Enum(PortfolioStatus), nullable=False) + goal = Column(Enum(PortfolioGoal), nullable=False) + cost = Column(Float) + number_of_properties = Column(Integer) + co2_equivalent_savings = Column(Float) # Unit is always tonnes so we don't need to store the unit + energy_savings = Column(Float) # Unit is always kWh so we don't need to store the unit + energy_cost_savings = Column(Float) # Unit is always £ so we don't need to store the unit for the moment + property_valuation_increase = Column(Float) # Unit is always £ so we don't need to store the unit for the moment + rental_yield_increase = Column(Float) # Unit is always £ so we don't need to store the unit for the moment + total_work_hours = Column(Float) + created_at = Column(DateTime, nullable=False) + updated_at = Column(DateTime, nullable=False) diff --git a/backend/app/db/models/property.py b/backend/app/db/models/property.py new file mode 100644 index 00000000..243967f7 --- /dev/null +++ b/backend/app/db/models/property.py @@ -0,0 +1,104 @@ +from sqlalchemy import Column, Integer, Text, Boolean, Float, DateTime, Enum, ForeignKey +from sqlalchemy.ext.declarative import declarative_base +from backend.app.db.models.portfolio import PortfolioStatus + +Base = declarative_base() + + +class PropertyCreationStatus(Enum): + LOADING = "LOADING" + READY = "READY" + ERROR = "ERROR" + + +class Epc(Enum): + A = "A" + B = "B" + C = "C" + D = "D" + E = "E" + F = "F" + G = "G" + + +class Property(Base): + __tablename__ = 'property' + id = Column(Integer, primary_key=True, autoincrement=True) + portfolio_id = Column(Integer, ForeignKey('portfolio.id'), nullable=False) + creation_status = Column(Enum(PropertyCreationStatus), nullable=False) + uprn = Column(Integer) + status = Column(Enum(PortfolioStatus)) + address = Column(Text) + postcode = Column(Text) + has_pre_condition_report = Column(Boolean) + has_recommendations = Column(Boolean) + created_at = Column(DateTime, nullable=False) + updated_at = Column(DateTime, nullable=False) + property_type = Column(Text) + built_form = Column(Text) + local_authority = Column(Text) + constituency = Column(Text) + number_of_rooms = Column(Integer) + year_built = Column(Text) + tenure = Column(Text) + current_epc_rating = Column(Enum(Epc)) + current_sap_points = Column(Float) + + +class FeatureRating(Enum): + VERY_GOOD = "Very good" + GOOD = "Good" + POOR = "Poor" + VERY_POOR = "Very poor" + NA = "N/A" + + +class PropertyDetailsEpc(Base): + __tablename__ = 'property_details_epc' + id = Column(Integer, primary_key=True, autoincrement=True) + property_id = Column(Integer, ForeignKey('property.id'), nullable=False) + portfolio_id = Column(Integer, ForeignKey('portfolio.id'), nullable=False) + full_address = Column(Text) + total_floor_area = Column(Float) + walls = Column(Text) + walls_rating = Column(Enum(FeatureRating)) + roof = Column(Text) + roof_rating = Column(Enum(FeatureRating)) + floor = Column(Text) + floor_rating = Column(Enum(FeatureRating)) + windows = Column(Text) + windows_rating = Column(Enum(FeatureRating)) + heating = Column(Text) + heating_rating = Column(Enum(FeatureRating)) + heating_contols = Column(Text) + heating_contols_rating = Column(Enum(FeatureRating)) + hot_water = Column(Text) + hot_water_rating = Column(Enum(FeatureRating)) + lighting = Column(Text) + lighting_rating = Column(Enum(FeatureRating)) + ventilation = Column(Text) + solar_pv = Column(Text) + solar_hot_water = Column(Text) + wind_turbine = Column(Text) + floor_height = Column(Float) + number_heated_rooms = Column(Integer) + heat_loss_corridor = Column(Boolean) + unheated_corridor_length = Column(Float) + number_of_open_fireplaces = Column(Integer) + number_of_extensions = Column(Integer) + number_of_storeys = Column(Integer) + mains_gas = Column(Boolean) + energy_tariff = Column(Text) + primary_energy_consumption = Column(Float) + co2_emissions = Column(Float) + + +class PropertyDetailsMeter(Base): + __tablename__ = 'property_details_meter' + id = Column(Integer, primary_key=True, autoincrement=True) + uprn = Column(Integer, nullable=False) + energy_supplier = Column(Text) + gas_supplier = Column(Text) + meter_reading_total = Column(Float) + meter_reading_electricity = Column(Float) + meter_reading_gas = Column(Float) diff --git a/backend/app/plan/router.py b/backend/app/plan/router.py index 4934042e..4729b081 100644 --- a/backend/app/plan/router.py +++ b/backend/app/plan/router.py @@ -75,6 +75,8 @@ async def trigger_plan(body: PlanTriggerRequest): plan_input = read_csv_from_s3(bucket_name=bucket_name, filepath=body.trigger_file_path) # TODO: Add validation to the file + # for config in plan_input: + # # We validate each record in the file. If the record is NOT valid, we need to handle this accordingly logger.info("Getting EPC data") epc_client = EpcClient(auth_token=get_settings().EPC_AUTH_TOKEN)