Adding property table cration to router

This commit is contained in:
Khalim Conn-Kowlessar 2023-07-31 16:26:54 +01:00
parent c71e6fe44f
commit 1ceedc2ebb
5 changed files with 195 additions and 125 deletions

View file

@ -29,7 +29,8 @@ class Property(BaseUtility):
coordinates = None
def __init__(self, postcode, address1, epc_client=None, data=None):
def __init__(self, id, postcode, address1, epc_client=None, data=None):
self.id = id
self.postcode = postcode
self.address1 = address1
self.data = data

View file

@ -0,0 +1,53 @@
###
# This script contains methods for interacting with the property table in the database
###
import datetime
from sqlalchemy.orm import sessionmaker
from backend.app.db.models.portfolio import PropertyModel, PropertyCreationStatus, PortfolioStatus
from backend.app.db.connection import db_engine
from sqlalchemy.orm.exc import NoResultFound
def create_property(portfolio_id: int, address: str, postcode: str):
"""
This function will create a record for the property in the database if it does not exist.
If it does exist, it will just update the updated_at field.
"""
Session = sessionmaker(bind=db_engine)
with Session() as session:
now = datetime.datetime.now()
try:
# Attempt to fetch the existing property
existing_property = session.query(PropertyModel).filter_by(
address=address, postcode=postcode, portfolio_id=portfolio_id
).one()
# Update the 'updated_at' field
existing_property.updated_at = now
# Merge the updated property back into the session
session.merge(existing_property)
session.commit()
return existing_property.id
except NoResultFound:
# Property doesn't exist, create a new one
new_property = PropertyModel(
address=address,
postcode=postcode,
portfolio_id=portfolio_id,
created_at=now,
updated_at=now,
creation_status=PropertyCreationStatus.LOADING,
status=PortfolioStatus.ASSESSMENT.value
)
# Add the new property to the session
session.add(new_property)
session.commit()
return new_property.id

View file

@ -1,10 +1,11 @@
from sqlalchemy import Column, Integer, String, Text, Boolean, Float, DateTime, Enum
import enum
from sqlalchemy import Column, Integer, Text, Boolean, Float, DateTime, Enum, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class PortfolioStatus(Enum):
class PortfolioStatus(enum.Enum):
SCOPING = "scoping"
ASSESSMENT = "assessment"
TENDERING = "tendering"
@ -16,7 +17,7 @@ class PortfolioStatus(Enum):
NEEDS_REVIEW = "needs review"
class PortfolioGoal(Enum):
class PortfolioGoal(enum.Enum):
VALUATION_IMPROVEMENT = "Valuation Improvement"
INCREASING_EPC = "Increasing EPC"
REDUCING_CO2_EMISSIONS = "Reducing CO2 emissions"
@ -24,20 +25,13 @@ class PortfolioGoal(Enum):
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)
status = Column(Enum(PortfolioStatus, values_callable=lambda x: [e.value for e in x]), nullable=False)
goal = Column(Enum(PortfolioGoal, values_callable=lambda x: [e.value for e in x]), 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
@ -48,3 +42,112 @@ class Portfolio(Base):
total_work_hours = Column(Float)
created_at = Column(DateTime, nullable=False)
updated_at = Column(DateTime, nullable=False)
class PropertyCreationStatus(enum.Enum):
LOADING = "LOADING"
READY = "READY"
ERROR = "ERROR"
class Epc(enum.Enum):
A = "A"
B = "B"
C = "C"
D = "D"
E = "E"
F = "F"
G = "G"
class PropertyModel(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, values_callable=lambda x: [e.value for e in x]), nullable=False)
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.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, values_callable=lambda x: [e.value for e in x]))
roof = Column(Text)
roof_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x]))
floor = Column(Text)
floor_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x]))
windows = Column(Text)
windows_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x]))
heating = Column(Text)
heating_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x]))
heating_contols = Column(Text)
heating_contols_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x]))
hot_water = Column(Text)
hot_water_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x]))
lighting = Column(Text)
lighting_rating = Column(Enum(FeatureRating, values_callable=lambda x: [e.value for e in x]))
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)
class PropertyTargets(Base):
__tablename__ = 'property_targets'
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)
created_at = Column(DateTime, nullable=False)
epc = Column(Enum(Epc))
heat_demand = Column(Text)

View file

@ -1,104 +0,0 @@
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)

View file

@ -10,6 +10,9 @@ from recommendations.FloorRecommendations import FloorRecommendations
from recommendations.WallRecommendations import WallRecommendations
from utils.uvalue_estimates import classify_decile_newvalues
# database interaction functions
from backend.app.db.functions.property_functions import create_property
# TODO: This is placeholder until data is stored in DB
from backend.app.plan.temp_cleaned_data import cleaned
from backend.app.plan.uvalue_estimates_walls import uvalue_estimates_walls
@ -72,18 +75,32 @@ async def trigger_plan(body: PlanTriggerRequest):
logger.info("Getting the inputs")
# Read in the trigger file from s3
bucket_name = get_settings().PLAN_TRIGGER_BUCKET
epc_client = EpcClient(auth_token=get_settings().EPC_AUTH_TOKEN)
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
input_properties = []
for config in plan_input:
# We validate each record in the file. If the record is NOT valid, we need to handle this accordingly
# TODO: implment validation
# Create a record in db
property_id = create_property(
portfolio_id=body.portfolio_id, address=config['address'], postcode=config['postcode']
)
return {"message": "success"}
input_properties.append(
Property(
postcode=config['postcode'],
address1=config['address'],
epc_client=epc_client,
id=property_id
)
)
return {"message": "success"}
logger.info("Getting EPC data")
epc_client = EpcClient(auth_token=get_settings().EPC_AUTH_TOKEN)
input_properties = [
Property(postcode=config['postcode'], address1=config['address'], epc_client=epc_client)
for config in plan_input
]
for p in input_properties:
p.search_address_epc()