mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Define Plan and Scenario domain classes
This commit is contained in:
parent
b3fa7c3051
commit
7c88e22424
4 changed files with 186 additions and 45 deletions
|
|
@ -1,7 +1,17 @@
|
|||
import enum
|
||||
import pytz
|
||||
import datetime
|
||||
from sqlalchemy import Column, Integer, Text, Boolean, Float, DateTime, Enum, ForeignKey, CheckConstraint
|
||||
from sqlalchemy import (
|
||||
Column,
|
||||
Integer,
|
||||
Text,
|
||||
Boolean,
|
||||
Float,
|
||||
DateTime,
|
||||
Enum,
|
||||
ForeignKey,
|
||||
CheckConstraint,
|
||||
)
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from backend.app.db.models.users import UserModel # noqa
|
||||
from backend.app.db.models.materials import MaterialType
|
||||
|
|
@ -31,23 +41,43 @@ class PortfolioGoal(enum.Enum):
|
|||
|
||||
|
||||
class Portfolio(Base):
|
||||
__tablename__ = 'portfolio'
|
||||
__tablename__ = "portfolio"
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
name = Column(Text, nullable=False)
|
||||
budget = Column(Float)
|
||||
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)
|
||||
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
|
||||
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
|
||||
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)
|
||||
labour_days = Column(Float)
|
||||
created_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))
|
||||
updated_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))
|
||||
created_at = Column(
|
||||
DateTime, nullable=False, default=datetime.datetime.now(pytz.utc)
|
||||
)
|
||||
updated_at = Column(
|
||||
DateTime, nullable=False, default=datetime.datetime.now(pytz.utc)
|
||||
)
|
||||
# Aggregations for summary
|
||||
epc_breakdown_pre_retrofit = Column(Text)
|
||||
epc_breakdown_post_retrofit = Column(Text)
|
||||
|
|
@ -71,7 +101,7 @@ class PropertyCreationStatus(enum.Enum):
|
|||
ERROR = "ERROR"
|
||||
|
||||
|
||||
class Epc(enum.Enum):
|
||||
class Epc(enum.Enum): # TODO: Move to domain?
|
||||
A = "A"
|
||||
B = "B"
|
||||
C = "C"
|
||||
|
|
@ -82,20 +112,27 @@ class Epc(enum.Enum):
|
|||
|
||||
|
||||
class PropertyModel(Base):
|
||||
__tablename__ = 'property'
|
||||
__tablename__ = "property"
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
portfolio_id = Column(Integer, ForeignKey('portfolio.id'), nullable=False)
|
||||
portfolio_id = Column(Integer, ForeignKey("portfolio.id"), nullable=False)
|
||||
creation_status = Column(Enum(PropertyCreationStatus), nullable=False)
|
||||
uprn = Column(Integer)
|
||||
landlord_property_id = Column(Text)
|
||||
building_reference_number = Column(Integer)
|
||||
status = Column(Enum(PortfolioStatus, values_callable=lambda x: [e.value for e in x]), nullable=False)
|
||||
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, default=datetime.datetime.now(pytz.utc))
|
||||
updated_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))
|
||||
created_at = Column(
|
||||
DateTime, nullable=False, default=datetime.datetime.now(pytz.utc)
|
||||
)
|
||||
updated_at = Column(
|
||||
DateTime, nullable=False, default=datetime.datetime.now(pytz.utc)
|
||||
)
|
||||
property_type = Column(Text)
|
||||
built_form = Column(Text)
|
||||
local_authority = Column(Text)
|
||||
|
|
@ -127,7 +164,7 @@ rating_lookup = {
|
|||
"Average": FeatureRating.AVERAGE,
|
||||
"Poor": FeatureRating.POOR,
|
||||
"Very Poor": FeatureRating.VERY_POOR,
|
||||
"N/A": FeatureRating.NA
|
||||
"N/A": FeatureRating.NA,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -136,32 +173,45 @@ def get_feature_rating_from_string(rating_str: str):
|
|||
|
||||
|
||||
class PropertyDetailsEpcModel(Base):
|
||||
__tablename__ = 'property_details_epc'
|
||||
__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)
|
||||
property_id = Column(Integer, ForeignKey("property.id"), nullable=False)
|
||||
portfolio_id = Column(Integer, ForeignKey("portfolio.id"), nullable=False)
|
||||
full_address = Column(Text)
|
||||
lodgement_date = Column(DateTime)
|
||||
is_expired = Column(Boolean)
|
||||
total_floor_area = Column(Float)
|
||||
walls = Column(Text)
|
||||
walls_rating = Column(Integer, CheckConstraint('walls_rating>=1 AND walls_rating<=5'))
|
||||
walls_rating = Column(
|
||||
Integer, CheckConstraint("walls_rating>=1 AND walls_rating<=5")
|
||||
)
|
||||
roof = Column(Text)
|
||||
roof_rating = Column(Integer, CheckConstraint('roof_rating>=1 AND roof_rating<=5'))
|
||||
roof_rating = Column(Integer, CheckConstraint("roof_rating>=1 AND roof_rating<=5"))
|
||||
floor = Column(Text)
|
||||
floor_rating = Column(Integer, CheckConstraint('floor_rating>=1 AND floor_rating<=5'))
|
||||
floor_rating = Column(
|
||||
Integer, CheckConstraint("floor_rating>=1 AND floor_rating<=5")
|
||||
)
|
||||
windows = Column(Text)
|
||||
windows_rating = Column(Integer, CheckConstraint('windows_rating>=1 AND windows_rating<=5'))
|
||||
windows_rating = Column(
|
||||
Integer, CheckConstraint("windows_rating>=1 AND windows_rating<=5")
|
||||
)
|
||||
heating = Column(Text)
|
||||
heating_rating = Column(Integer, CheckConstraint('heating_rating>=1 AND heating_rating<=5'))
|
||||
heating_rating = Column(
|
||||
Integer, CheckConstraint("heating_rating>=1 AND heating_rating<=5")
|
||||
)
|
||||
heating_controls = Column(Text)
|
||||
heating_controls_rating = Column(
|
||||
Integer, CheckConstraint('heating_controls_rating>=1 AND heating_controls_rating<=5')
|
||||
Integer,
|
||||
CheckConstraint("heating_controls_rating>=1 AND heating_controls_rating<=5"),
|
||||
)
|
||||
hot_water = Column(Text)
|
||||
hot_water_rating = Column(Integer, CheckConstraint('hot_water_rating>=1 AND hot_water_rating<=5'))
|
||||
hot_water_rating = Column(
|
||||
Integer, CheckConstraint("hot_water_rating>=1 AND hot_water_rating<=5")
|
||||
)
|
||||
lighting = Column(Text)
|
||||
lighting_rating = Column(Integer, CheckConstraint('lighting_rating>=1 AND lighting_rating<=5'))
|
||||
lighting_rating = Column(
|
||||
Integer, CheckConstraint("lighting_rating>=1 AND lighting_rating<=5")
|
||||
)
|
||||
mainfuel = Column(Text)
|
||||
ventilation = Column(Text)
|
||||
solar_pv = Column(Text)
|
||||
|
|
@ -219,7 +269,7 @@ class PropertyDetailsSpatial(Base):
|
|||
|
||||
|
||||
class PropertyDetailsMeter(Base):
|
||||
__tablename__ = 'property_details_meter'
|
||||
__tablename__ = "property_details_meter"
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
uprn = Column(Integer, nullable=False)
|
||||
energy_supplier = Column(Text)
|
||||
|
|
@ -230,11 +280,13 @@ class PropertyDetailsMeter(Base):
|
|||
|
||||
|
||||
class PropertyTargetsModel(Base):
|
||||
__tablename__ = 'property_targets'
|
||||
__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, default=datetime.datetime.now(pytz.utc))
|
||||
property_id = Column(Integer, ForeignKey("property.id"), nullable=False)
|
||||
portfolio_id = Column(Integer, ForeignKey("portfolio.id"), nullable=False)
|
||||
created_at = Column(
|
||||
DateTime, nullable=False, default=datetime.datetime.now(pytz.utc)
|
||||
)
|
||||
epc = Column(Enum(Epc))
|
||||
heat_demand = Column(Text)
|
||||
|
||||
|
|
@ -242,23 +294,36 @@ class PropertyTargetsModel(Base):
|
|||
class PortfolioUsers(Base):
|
||||
__tablename__ = "portfolioUsers"
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
user_id = Column(Integer, ForeignKey('user.id'), nullable=False)
|
||||
portfolioId = Column(Integer, ForeignKey('portfolio.id'), nullable=False)
|
||||
user_id = Column(Integer, ForeignKey("user.id"), nullable=False)
|
||||
portfolioId = Column(Integer, ForeignKey("portfolio.id"), nullable=False)
|
||||
role = Column(Text, nullable=False)
|
||||
created_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))
|
||||
updated_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))
|
||||
created_at = Column(
|
||||
DateTime, nullable=False, default=datetime.datetime.now(pytz.utc)
|
||||
)
|
||||
updated_at = Column(
|
||||
DateTime, nullable=False, default=datetime.datetime.now(pytz.utc)
|
||||
)
|
||||
|
||||
|
||||
class PropertyInstalledMeasures(Base):
|
||||
"""
|
||||
This model keeps a record of the installed measures for each property, at the UPRN level
|
||||
"""
|
||||
__tablename__ = 'property_installed_measures'
|
||||
|
||||
__tablename__ = "property_installed_measures"
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
uprn = Column(Integer, nullable=False)
|
||||
measure_type = Column(
|
||||
Enum(MaterialType, values_callable=lambda x: [e.value for e in x], create_constraint=False),
|
||||
nullable=False
|
||||
Enum(
|
||||
MaterialType,
|
||||
values_callable=lambda x: [e.value for e in x],
|
||||
create_constraint=False,
|
||||
),
|
||||
nullable=False,
|
||||
)
|
||||
created_at = Column(
|
||||
DateTime, nullable=False, default=datetime.datetime.now(pytz.utc)
|
||||
)
|
||||
installed_at = Column(
|
||||
DateTime, nullable=False, default=datetime.datetime.now(pytz.utc)
|
||||
)
|
||||
created_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))
|
||||
installed_at = Column(DateTime, nullable=False, default=datetime.datetime.now(pytz.utc))
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class RecommendationMaterials(Base):
|
|||
estimated_cost = Column(Float, nullable=False)
|
||||
|
||||
|
||||
class PlanTypeEnum(enum.Enum):
|
||||
class PlanTypeEnum(enum.Enum): # TODO: move this to domain?
|
||||
SOLAR_ECO4 = "solar_eco4"
|
||||
SOLAR_HHRSH_ECO4 = "solar_hhrsh_eco4"
|
||||
EMPTY_CAVITY_ECO = "empty_cavity_eco"
|
||||
|
|
@ -93,7 +93,7 @@ class PlanModel(Base):
|
|||
BigInteger, ForeignKey("scenario.id")
|
||||
)
|
||||
|
||||
created_at: Mapped = mapped_column( # type: ignore
|
||||
created_at: Mapped[datetime] = mapped_column( # type: ignore
|
||||
TIMESTAMP, nullable=False, server_default=func.now()
|
||||
)
|
||||
|
||||
|
|
|
|||
30
backend/domain/plan.py
Normal file
30
backend/domain/plan.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from backend.app.db.models.portfolio import Epc
|
||||
from backend.app.db.models.recommendations import PlanTypeEnum
|
||||
from backend.domain.scenario import Scenario
|
||||
|
||||
|
||||
class Plan:
|
||||
property_id: int
|
||||
portfolio_id: int
|
||||
scenario: Scenario
|
||||
created_at: datetime
|
||||
is_default: bool
|
||||
|
||||
valuation_increase_lower_bound: Optional[float] = None
|
||||
valuation_increase_upper_bound: Optional[float] = None
|
||||
valuation_increase_average: Optional[float] = None
|
||||
plan_type: Optional[PlanTypeEnum] = None
|
||||
post_sap_points: Optional[float] = None
|
||||
post_epc_rating: Optional[Epc] = None
|
||||
post_co2_emissions: Optional[float] = None
|
||||
co2_savings: Optional[float] = None
|
||||
post_energy_bill: Optional[float] = None
|
||||
post_energy_consumption: Optional[float] = None
|
||||
energy_consumption_savings: Optional[float] = None
|
||||
valuation_post_retrofit: Optional[float] = None
|
||||
valuation_increase: Optional[float] = None
|
||||
cost_of_works: Optional[float] = None
|
||||
contingency_cost: Optional[float] = None
|
||||
46
backend/domain/scenario.py
Normal file
46
backend/domain/scenario.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class Scenario:
|
||||
name: str
|
||||
created_at: datetime
|
||||
housing_type: str
|
||||
goal: str # TODO: make enum
|
||||
goal_value: str
|
||||
trigger_file_path: str
|
||||
multi_plan: bool
|
||||
is_default: bool # TODO: isn't this Plan-level?
|
||||
|
||||
budget: Optional[float] = None
|
||||
already_installed_file_path: Optional[str] = None
|
||||
patches_file_path: Optional[str] = None
|
||||
non_invasive_recommendations_file_path: Optional[str] = None
|
||||
exclusions: Optional[str] = None
|
||||
|
||||
# Previously portfolio-level fields
|
||||
# TODO: are these needed scenario-level?
|
||||
cost: Optional[float] = None
|
||||
contingency: Optional[float] = None
|
||||
funding: Optional[float] = None
|
||||
total_work_hours: Optional[float] = None
|
||||
energy_savings: Optional[float] = None
|
||||
co2_equivalent_savings: Optional[float] = None
|
||||
energy_cost_savings: Optional[float] = None
|
||||
epc_breakdown_pre_retrofit: Optional[int] = None
|
||||
epc_breakdown_post_retrofit: Optional[int] = None
|
||||
number_of_properties: Optional[int] = None
|
||||
n_units_to_retrofit: Optional[int] = None
|
||||
co2_per_unit_pre_retrofit: Optional[str] = None
|
||||
co2_per_unit_post_retrofit: Optional[str] = None
|
||||
energy_bill_per_unit_pre_retrofit: Optional[str] = None
|
||||
energy_bill_per_unit_post_retrofit: Optional[str] = None
|
||||
energy_consumption_per_unit_pre_retrofit: Optional[str] = None
|
||||
energy_consumption_per_unit_post_retrofit: Optional[str] = None
|
||||
valuation_improvement_per_unit: Optional[str] = None
|
||||
cost_per_unit: Optional[str] = None
|
||||
cost_per_co2_saved: Optional[str] = None
|
||||
cost_per_sap_point: Optional[str] = None
|
||||
valuation_return_on_ivestment: Optional[str] = None
|
||||
property_valuation_increase: Optional[float] = None
|
||||
labour_days: Optional[float] = None
|
||||
Loading…
Add table
Reference in a new issue