Model/backend/app/db/functions/property_functions.py
2024-01-02 15:45:42 +00:00

172 lines
5.9 KiB
Python

###
# This script contains methods for interacting with the property table in the database
###
import datetime
import pytz
from sqlalchemy.orm import Session
from backend.app.db.models.portfolio import (
PropertyModel, PropertyCreationStatus, PortfolioStatus, PropertyTargetsModel, PropertyDetailsEpcModel,
PropertyDetailsSpatial
)
from sqlalchemy.orm.exc import NoResultFound
def create_property(session: Session, portfolio_id: int, address: str, postcode: str, uprn: str) -> (int, bool):
"""
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.
:param session: The database session
:param portfolio_id: The ID of the portfolio the property belongs to
:param address: The address of the property
:param postcode: The postcode of the property
:return: The ID of the property and a boolean indicating whether it was created or not
"""
try:
# Attempt to fetch the existing property
existing_property = session.query(PropertyModel).filter_by(
uprn=uprn, portfolio_id=portfolio_id
).one()
# Update the 'updated_at' field
existing_property.updated_at = datetime.datetime.now(pytz.utc)
# Merge the updated property back into the session
session.merge(existing_property)
session.flush()
return existing_property.id, False
except NoResultFound:
# Property doesn't exist, create a new one
new_property = PropertyModel(
address=address,
postcode=postcode,
portfolio_id=portfolio_id,
uprn=uprn,
creation_status=PropertyCreationStatus.LOADING,
status=PortfolioStatus.ASSESSMENT.value,
has_pre_condition_report=False,
has_recommendations=False
)
# Add the new property to the session
session.add(new_property)
session.flush()
return new_property.id, True
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.
:param session: The database session
:param property_id: The ID of the property the targets belong to
:param portfolio_id: The ID of the portfolio the property belongs to
:param epc_target: Goal EPC value for the property
:param heat_demand_target: Heat demand target for the property in kwh/m^2/year
:return:
"""
new_target = PropertyTargetsModel(
property_id=property_id,
portfolio_id=portfolio_id,
epc=epc_target,
heat_demand=heat_demand_target
)
session.add(new_target)
session.flush()
return True
def update_property_data(
session: Session, property_id: int, portfolio_id: int, property_data: dict
):
now = datetime.datetime.now(pytz.utc)
try:
# Attempt to fetch the existing property
existing_property = session.query(PropertyModel).filter_by(
id=property_id, portfolio_id=portfolio_id
).one()
# Update the fields with the data in property_data
for key, value in property_data.items():
setattr(existing_property, key, value)
existing_property.updated_at = now
# Merge the updated property back into the session and flush
session.merge(existing_property)
session.flush()
except NoResultFound:
raise Exception(f"Property with property_id {property_id} and portfolio_id {portfolio_id} not found")
return True
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.
:param session: The database session
:param property_details_epc: A dictionary containing details about the property EPC.
:return: True if successful, False otherwise.
"""
existing_record = session.query(PropertyDetailsEpcModel).filter_by(
portfolio_id=property_details_epc["portfolio_id"],
property_id=property_details_epc["property_id"]
).first()
if existing_record:
# If the record exists, update its fields
for key, value in property_details_epc.items():
setattr(existing_record, key, value)
else:
# If the record doesn't exist, create a new one
new_property_details_epc = PropertyDetailsEpcModel(**property_details_epc)
session.add(new_property_details_epc)
session.flush()
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