implementing database call for funding

This commit is contained in:
Khalim Conn-Kowlessar 2025-08-20 19:26:05 +01:00
parent b715402999
commit 529830ee0f
5 changed files with 121 additions and 34 deletions

View file

@ -218,7 +218,7 @@ class Property:
# self.whlg_eligibility = None # self.whlg_eligibility = None
self.scheme = None self.scheme = None
self.funded_measures = None self.funded_measures = None
self.full_project_funding = None self.project_funding = None
self.total_uplift = None self.total_uplift = None
self.full_project_score = None self.full_project_score = None
self.partial_project_score = None self.partial_project_score = None
@ -1347,7 +1347,7 @@ class Property:
self, self,
scheme, scheme,
funded_measures, funded_measures,
full_project_funding, project_funding,
total_uplift, total_uplift,
full_project_score, full_project_score,
partial_project_score, partial_project_score,
@ -1357,11 +1357,11 @@ class Property:
This method inserts the funding into the property object This method inserts the funding into the property object
""" """
self.scheme = scheme self.scheme = scheme
self.funded_measures = funded_measures, self.funded_measures = funded_measures
self.full_project_funding = full_project_funding, self.project_funding = project_funding
self.total_uplift = total_uplift, self.total_uplift = total_uplift
self.full_project_score = full_project_score, self.full_project_score = full_project_score
self.partial_project_score = partial_project_score, self.partial_project_score = partial_project_score
self.uplift_project_score = uplift_project_score self.uplift_project_score = uplift_project_score
def identify_ventilation(self): def identify_ventilation(self):

View file

@ -0,0 +1,60 @@
from sqlalchemy.orm import Session
from sqlalchemy.exc import SQLAlchemyError
from backend.app.db.models.funding import FundingPackage, FundingPackageMeasures
def upload_funding(session: Session, p, plan_id, property_recommendations):
try:
# Prepare data for bulk insert for Recommendation
funding_package_data = {
"plan_id": plan_id,
"scheme": p.scheme,
"full_project_funding": p.full_project_funding,
"total_uplift": p.total_uplift,
"full_project_score": p.full_project_score,
"partial_project_score": p.partial_project_score,
"uplift_project_score": p.uplift_project_score
}
# upload the funding package data and get back the ID
new_funding_package = FundingPackage(**funding_package_data)
session.add(new_funding_package)
session.flush()
session.commit()
funding_package_id = new_funding_package.id
# We now prepare the list of funding measures to be uploaded
funding_measures_data = []
for part in p.funded_measures:
recommendation_id = part["id"]
recommendation = next(
(x for x in property_recommendations if x["recommendation_id"] == recommendation_id), {}
)
material_id = None
if recommendation["parts"]:
material_id = recommendation["parts"][0]["id"]
funding_measures_data.append({
"funding_package_id": funding_package_id,
"measure": part["type"],
"material_id": material_id,
"innovation_uplift": float(part["innovation_uplift"]),
"partial_project_score": float(part["partial_project_score"]),
"uplift_project_score": float(part["uplift_project_score"])
})
session.bulk_insert_mappings(FundingPackageMeasures, funding_measures_data)
# flush the changes to get the newly created IDs
session.flush()
# Commit the transaction
session.commit()
return True
except SQLAlchemyError as e:
# Rollback the transaction in case of an error
session.rollback()
print(f"An error occurred: {e}")
return False

View file

@ -0,0 +1,45 @@
import enum
from sqlalchemy import Column, Integer, String, Float, Enum, TIMESTAMP, BigInteger, ForeignKey
from sqlalchemy.orm import declarative_base
from sqlalchemy.sql import func
from backend.app.db.models.recommendations import Plan
from backend.app.db.models.materials import MaterialType, Material
Base = declarative_base()
class SchemeEnum(enum.Enum):
eco4 = "eco4"
gbis = "gbis"
whlg = "whlg"
none = "none"
class FundingPackage(Base):
__tablename__ = 'funding_package'
id = Column(Integer, primary_key=True, autoincrement=True)
plan_id = Column(BigInteger, ForeignKey(Plan.id), nullable=False)
scheme = Column(String, nullable=False) # Assuming Scheme is a string representation
created_at = Column(TIMESTAMP, nullable=False, server_default=func.now())
project_funding = Column(Float)
total_uplift = Column(Float)
full_project_score = Column(Float)
partial_project_score = Column(Float)
uplift_project_score = Column(Float)
class FundingPackageMeasures(Base):
__tablename__ = 'funding_package_measures'
id = Column(Integer, primary_key=True, autoincrement=True)
funding_package_id = Column(BigInteger, ForeignKey(FundingPackage.id), nullable=False)
measure = Column(
Enum(MaterialType, values_callable=lambda x: [e.value for e in x], create_constraint=False),
nullable=False
)
material_id = Column(BigInteger, ForeignKey(Material.id), nullable=False) # Assuming material table exists
innovation_uplift = Column(Float)
partial_project_score = Column(Float)
uplift_project_score = Column(Float)

View file

@ -934,8 +934,8 @@ async def model_engine(body: PlanTriggerRequest):
# This is the list of measures that we will recommend # This is the list of measures that we will recommend
funded_measures = optimal_solution["items"] funded_measures = optimal_solution["items"]
solution = funded_measures + optimal_solution["unfunded_items"] solution = funded_measures + optimal_solution["unfunded_items"]
# This is the total amount of funding that the project will product (£) # This is the total amount of funding that the project will produce (including uplifts) (£)
full_project_funding = optimal_solution["full_project_funding"] project_funding = optimal_solution["full_project_funding"]
# This is the total amount of funding associated to the uplift (£) # This is the total amount of funding associated to the uplift (£)
total_uplift = optimal_solution["total_uplift"] total_uplift = optimal_solution["total_uplift"]
# This is the funding scheme selected # This is the funding scheme selected
@ -998,7 +998,7 @@ async def model_engine(body: PlanTriggerRequest):
scheme = "gbis" scheme = "gbis"
funded_measures = solution if scheme in ["gbis", "eco4"] else [] funded_measures = solution if scheme in ["gbis", "eco4"] else []
full_project_funding = 0 if funding.full_project_abs is not None else funding.full_project_abs project_funding = 0 if funding.full_project_abs is not None else funding.full_project_abs
total_uplift = funding.eco4_uplift total_uplift = funding.eco4_uplift
full_project_score = 0 if funding.full_project_abs is not None else funding.full_project_abs full_project_score = 0 if funding.full_project_abs is not None else funding.full_project_abs
partial_project_score = funding.partial_project_abs partial_project_score = funding.partial_project_abs
@ -1022,7 +1022,7 @@ async def model_engine(body: PlanTriggerRequest):
p.insert_funding( p.insert_funding(
scheme=scheme, scheme=scheme,
funded_measures=funded_measures, funded_measures=funded_measures,
full_project_funding=full_project_funding, project_funding=project_funding,
total_uplift=total_uplift, total_uplift=total_uplift,
full_project_score=full_project_score, full_project_score=full_project_score,
partial_project_score=partial_project_score, partial_project_score=partial_project_score,
@ -1055,28 +1055,6 @@ async def model_engine(body: PlanTriggerRequest):
# need to be updated # need to be updated
rec["default"] = True rec["default"] = True
# ~~~~~~~~~~~~~~~~
# Funding
# ~~~~~~~~~~~~~~~~
# for p in input_properties:
# funding_calulator = Funding(
# tenure=body.housing_type,
# starting_epc=p.data["current-energy-rating"],
# starting_sap=int(p.data["current-energy-efficiency"]),
# postcode=p.postcode,
# floor_area=p.floor_area,
# council_tax_band=None, # This is seemingly always None at the moment
# property_recommendations=recommendations[p.id],
# project_scores_matrix=eco_project_scores_matrix,
# whlg_eligible_postcodes=whlg_eligible_postcodes,
# gbis_abs_rate=15,
# eco4_abs_rate=15,
# )
# funding_calulator.check_eligibiltiy()
# # Insert finding
# p.insert_funding(funding_calulator)
logger.info("Uploading recommendations to the database") logger.info("Uploading recommendations to the database")
# If we have any work to do, we create a new scenario # If we have any work to do, we create a new scenario
if body.scenario_id: if body.scenario_id:
@ -1165,6 +1143,10 @@ async def model_engine(body: PlanTriggerRequest):
session, recommendations_to_upload, p.id, new_plan_id session, recommendations_to_upload, p.id, new_plan_id
) )
upload_funding(
session,
)
property_valuation_increases.append( property_valuation_increases.append(
valuations["average_increased_value"] - valuations["current_value"] valuations["average_increased_value"] - valuations["current_value"]
) )

View file

@ -276,7 +276,7 @@ class SolarPvRecommendations:
self.recommendation.append( self.recommendation.append(
{ {
"phase": phase, "phase": phase,
"parts": [], "parts": [solar_pv_product],
"type": "solar_pv", "type": "solar_pv",
"measure_type": "solar_pv", "measure_type": "solar_pv",
"description": description, "description": description,