Added pushing of spatial data to backend

This commit is contained in:
Khalim Conn-Kowlessar 2023-12-01 14:50:46 +00:00
parent 1f53cb3d44
commit 24e22fa56a
4 changed files with 78 additions and 14 deletions

View file

@ -45,7 +45,7 @@ class Property(Definitions):
windows = None windows = None
lighting = None lighting = None
coordinates = None spatial = None
def __init__(self, id, postcode, address1, epc_client=None, data=None): def __init__(self, id, postcode, address1, epc_client=None, data=None):
self.id = id self.id = id
@ -129,13 +129,6 @@ class Property(Definitions):
else: else:
self.uprn = int(self.data["uprn"]) self.uprn = int(self.data["uprn"])
def set_coordinates(self, coordinates):
"""
This method sets the coordinates of the property, given the open uprn data
:param coordinates: dictionary
"""
self.coordinates = {key.lower(): value for key, value in coordinates.items()}
def set_energy(self): def set_energy(self):
""" """
Extracts and formats data about the home's energy and co2 consumption Extracts and formats data about the home's energy and co2 consumption
@ -364,6 +357,9 @@ class Property(Definitions):
def set_spatial(self, spatial: pd.DataFrame): def set_spatial(self, spatial: pd.DataFrame):
""" """
Sets whether the property is in a conservation area given the output of the ConservationAreaClient Sets whether the property is in a conservation area given the output of the ConservationAreaClient
Will store a dictionary, spatial, which is used to populate the property spatial table in the database
:param spatial: Dataframe, containing the spatial data for the property :param spatial: Dataframe, containing the spatial data for the property
""" """
self.in_conservation_area = spatial["conservation_status"].values[0] self.in_conservation_area = spatial["conservation_status"].values[0]
@ -373,6 +369,17 @@ class Property(Definitions):
if self.in_conservation_area is True | self.is_listed is True | self.is_heritage is True: if self.in_conservation_area is True | self.is_listed is True | self.is_heritage is True:
self.restricted_measures = True self.restricted_measures = True
spatial_dict = spatial.to_dict("records")[0]
self.spatial = {
"x_coordinate": spatial_dict["X_COORDINATE"],
"y_coordinate": spatial_dict["Y_COORDINATE"],
"latitude": spatial_dict["LATITUDE"],
"longitude": spatial_dict["LONGITUDE"],
"conservation_status": spatial_dict["conservation_status"],
"is_listed_building": spatial_dict["is_listed_building"],
"is_heritage_building": spatial_dict["is_heritage_building"],
}
def set_year_built(self): def set_year_built(self):
""" """
Estimates when the property was built based on as much available data as possible. Estimates when the property was built based on as much available data as possible.

View file

@ -3,13 +3,15 @@
### ###
import datetime import datetime
import pytz import pytz
from sqlalchemy.orm import Session
from backend.app.db.models.portfolio import ( from backend.app.db.models.portfolio import (
PropertyModel, PropertyCreationStatus, PortfolioStatus, PropertyTargetsModel, PropertyDetailsEpcModel PropertyModel, PropertyCreationStatus, PortfolioStatus, PropertyTargetsModel, PropertyDetailsEpcModel,
PropertyDetailsSpatial
) )
from sqlalchemy.orm.exc import NoResultFound from sqlalchemy.orm.exc import NoResultFound
def create_property(session, portfolio_id: int, address: str, postcode: str) -> (int, bool): def create_property(session: Session, portfolio_id: int, address: str, postcode: str) -> (int, bool):
""" """
This function will create a record for the property in the database if it does not exist. 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. If it does exist, it will just update the updated_at field.
@ -55,7 +57,9 @@ def create_property(session, portfolio_id: int, address: str, postcode: str) ->
return new_property.id, True return new_property.id, True
def create_property_targets(session, property_id: int, portfolio_id: int, epc_target=None, heat_demand_target=None): def create_property_targets(
session: Session, property_id: int, portfolio_id: int, epc_target=None, heat_demand_target=None
):
""" """
This function will create a record for the property targets in the database if it does not exist. This function will create a record for the property targets in the database if it does not exist.
:param session: The database session :param session: The database session
@ -78,7 +82,9 @@ def create_property_targets(session, property_id: int, portfolio_id: int, epc_ta
return True return True
def update_property_data(session, property_id: int, portfolio_id: int, property_data: dict): def update_property_data(
session: Session, property_id: int, portfolio_id: int, property_data: dict
):
now = datetime.datetime.now(pytz.utc) now = datetime.datetime.now(pytz.utc)
try: try:
@ -103,7 +109,9 @@ def update_property_data(session, property_id: int, portfolio_id: int, property_
return True return True
def create_property_details_epc(session, property_details_epc: dict): def create_property_details_epc(
session: Session, property_details_epc: dict
):
""" """
This function will create or update a record for the property details EPC in the database. This function will create or update a record for the property details EPC in the database.
:param session: The database session :param session: The database session
@ -128,3 +136,36 @@ def create_property_details_epc(session, property_details_epc: dict):
session.flush() session.flush()
return True return True
def update_or_create_property_spatial_details(session: Session, uprn: int, property_details_spatial: dict):
"""
Update an existing property details record or create a new one based on the UPRN.
:param session: The SQLAlchemy session for database interaction.
:param uprn: The unique property reference number (UPRN) of the property.
:param property_details_spatial: A dictionary containing the spatial property details to store or update.
:return: True if the operation is successful, otherwise raises an exception.
"""
try:
# Attempt to fetch the existing property details
existing_property_details = session.query(PropertyDetailsSpatial).filter_by(
uprn=uprn
).one()
# Update the fields with the data in property_details
for key, value in property_details_spatial.items():
setattr(existing_property_details, key, value)
# Merge the updated property details back into the session and flush
session.merge(existing_property_details)
session.flush()
except NoResultFound:
# Create a new record if not found
new_property_details = PropertyDetailsSpatial(uprn=uprn, **property_details_spatial)
session.add(new_property_details)
session.flush()
return True

View file

@ -155,6 +155,19 @@ class PropertyDetailsEpcModel(Base):
adjusted_energy_consumption = Column(Float) adjusted_energy_consumption = Column(Float)
class PropertyDetailsSpatial(Base):
__tablename__ = "property_details_spatial"
id = Column(Integer, primary_key=True, autoincrement=True)
uprn = Column(Integer, nullable=False)
x_coordinate = Column(Float)
y_coordinate = Column(Float)
latitude = Column(Float)
longitude = Column(Float)
conservation_status = Column(Boolean)
is_listed_building = Column(Boolean)
is_heritage_building = Column(Boolean)
class PropertyDetailsMeter(Base): class PropertyDetailsMeter(Base):
__tablename__ = 'property_details_meter' __tablename__ = 'property_details_meter'
id = Column(Integer, primary_key=True, autoincrement=True) id = Column(Integer, primary_key=True, autoincrement=True)

View file

@ -13,7 +13,8 @@ from backend.app.db.connection import db_engine
from backend.app.db.functions.materials_functions import get_materials from backend.app.db.functions.materials_functions import get_materials
from backend.app.db.functions.portfolio_functions import aggregate_portfolio_recommendations from backend.app.db.functions.portfolio_functions import aggregate_portfolio_recommendations
from backend.app.db.functions.property_functions import ( from backend.app.db.functions.property_functions import (
create_property, create_property_details_epc, create_property_targets, update_property_data create_property, create_property_details_epc, create_property_targets, update_property_data,
update_or_create_property_spatial_details
) )
from backend.app.db.functions.recommendations_functions import ( from backend.app.db.functions.recommendations_functions import (
create_plan, create_plan_recommendations, upload_recommendations create_plan, create_plan_recommendations, upload_recommendations
@ -507,6 +508,8 @@ async def trigger_plan(body: PlanTriggerRequest):
) )
create_property_details_epc(session, property_details_epc) create_property_details_epc(session, property_details_epc)
update_or_create_property_spatial_details(session, p.uprn, p.spatial)
# TODO: TEMP # TODO: TEMP
if p.data["uprn"] == "": if p.data["uprn"] == "":
print("Get rid of me!") print("Get rid of me!")