working on costing for led installation

This commit is contained in:
Khalim Conn-Kowlessar 2023-11-28 16:54:14 +00:00
parent e441e5f018
commit 96b49aa680
6 changed files with 92 additions and 2 deletions

View file

@ -83,6 +83,7 @@ class Property(Definitions):
self.floor_area = None self.floor_area = None
self.pitched_roof_area = None self.pitched_roof_area = None
self.insulation_floor_area = None self.insulation_floor_area = None
self.number_lighting_outlets = None
if epc_client: if epc_client:
self.epc_client = epc_client self.epc_client = epc_client
@ -703,7 +704,6 @@ class Property(Definitions):
'PROPERTY_TYPE', 'PROPERTY_TYPE',
'UPRN', 'UPRN',
'NUMBER_OPEN_FIREPLACES', 'NUMBER_OPEN_FIREPLACES',
'FIXED_LIGHTING_OUTLETS_COUNT',
'MULTI_GLAZE_PROPORTION', 'MULTI_GLAZE_PROPORTION',
'MECHANICAL_VENTILATION', 'MECHANICAL_VENTILATION',
'PHOTO_SUPPLY', 'PHOTO_SUPPLY',
@ -752,9 +752,21 @@ class Property(Definitions):
"FLOOR_HEIGHT": self.floor_height, "FLOOR_HEIGHT": self.floor_height,
"NUMBER_HABITABLE_ROOMS": self.number_of_rooms, "NUMBER_HABITABLE_ROOMS": self.number_of_rooms,
"TOTAL_FLOOR_AREA": self.floor_area, "TOTAL_FLOOR_AREA": self.floor_area,
"FIXED_LIGHTING_OUTLETS_COUNT": self.number_lighting_outlets,
**epc_raw_data, **epc_raw_data,
"BUILT_FORM": built_form, "BUILT_FORM": built_form,
"POSTCODE": self.data["postcode"], "POSTCODE": self.data["postcode"],
} }
return property_data return property_data
def set_number_lighting_outlets(self, cleaned_property_data):
"""
Extracts and cleans the estimated number of lighting outlets
:return:
"""
if self.data["fixed-lighting-outlets-count"] == "":
self.number_lighting_outlets = round(cleaned_property_data["FIXED_LIGHTING_OUTLETS_COUNT"].values[0])
else:
self.number_lighting_outlets = float(self.data["fixed-lighting-outlets-count"])

View file

@ -32,6 +32,7 @@ class MaterialType(enum.Enum):
ewi_wall_demolition = "ewi_wall_demolition" ewi_wall_demolition = "ewi_wall_demolition"
ewi_wall_preparation = "ewi_wall_preparation" ewi_wall_preparation = "ewi_wall_preparation"
ewi_wall_redecoration = "ewi_wall_redecoration" ewi_wall_redecoration = "ewi_wall_redecoration"
low_energy_lighting_installation = "low_energy_lighting_installation"
class DepthUnit(enum.Enum): class DepthUnit(enum.Enum):

View file

@ -124,6 +124,14 @@ async def trigger_plan(body: PlanTriggerRequest):
# Property recommendations # Property recommendations
p.get_components(cleaned) p.get_components(cleaned)
# This is temp - this should happen after scoring
cleaned_property_data = DataProcessor.apply_averages_cleaning(
data_to_clean=pd.DataFrame([dict(**p.get_model_data(), LOCAL_AUTHORITY=p.data["local-authority"])]),
cleaning_data=cleaning_data,
cols_to_merge_on=['PROPERTY_TYPE', 'BUILT_FORM', 'CONSTRUCTION_AGE_BAND', 'LOCAL_AUTHORITY'],
)
p.set_number_lighting_outlets(cleaned_property_data)
recommender = Recommendations(property_instance=p, materials=materials) recommender = Recommendations(property_instance=p, materials=materials)
property_recommendations = recommender.recommend() property_recommendations = recommender.recommend()

View file

@ -595,3 +595,33 @@ class Costs:
contingency = self.HIGH_RISK_CONTINGENCY contingency = self.HIGH_RISK_CONTINGENCY
else: else:
contingency = self.CONTINGENCY contingency = self.CONTINGENCY
material_cost = material["material_cost"] * number_of_lights
labour_cost = material["labour_cost"] * number_of_lights * self.labour_adjustment_factor
subtotal_before_profit = material_cost + labour_cost
contingency_cost = subtotal_before_profit * contingency
preliminaries_cost = subtotal_before_profit * self.PRELIMINARIES
profit_cost = subtotal_before_profit * self.PROFIT_MARGIN
subtotal_before_vat = subtotal_before_profit + contingency_cost + preliminaries_cost + profit_cost
vat_cost = subtotal_before_vat * self.VAT_RATE
total_cost = subtotal_before_vat + vat_cost
labour_hours = material["labour_hours_per_unit"] * number_of_lights
# Assume a single electrician installing
labour_days = (labour_hours / 8)
return {
"total": total_cost,
"subtotal": subtotal_before_vat,
"vat": vat_cost,
"contingency": contingency_cost,
"preliminaries": preliminaries_cost,
"material": material_cost,
"profit": profit_cost,
"labour_hours": labour_hours,
"labour_days": labour_days,
"labour_cost": labour_cost
}

View file

@ -1,5 +1,6 @@
from backend.Property import Property from backend.Property import Property
from typing import List from typing import List
from recommendations.Costs import Costs
class LightingRecommendations: class LightingRecommendations:
@ -11,7 +12,16 @@ class LightingRecommendations:
""" """
self.property = property_instance self.property = property_instance
self.materials = materials self.costs = Costs(self.property)
material = [
material for material in materials if material["type"] == "low_energy_lighting_installation"
]
if len(material) != 1:
raise ValueError("Incorrect number of low energy lighting materials specified")
self.material = material[0]
self.recommendation = []
def recommend(self): def recommend(self):
""" """
@ -32,3 +42,25 @@ class LightingRecommendations:
) )
number_non_lel_outlets = round(number_non_lel_outlets) number_non_lel_outlets = round(number_non_lel_outlets)
if number_non_lel_outlets == 0:
return
# Get the cost of the fittings
cost_result = self.costs.low_energy_lighting(
number_of_lights=number_non_lel_outlets,
number_current_lel_lights=number_lighting_outlets - number_non_lel_outlets,
material=self.material
)
self.recommendation = [
{
"parts": [],
"type": "sealing_open_fireplace",
"description": "Install low energy lighting in %s outlets" % str(number_non_lel_outlets),
"starting_u_value": None,
"new_u_value": None,
"sap_points": None,
**cost_result
}
]

View file

@ -5,6 +5,7 @@ from recommendations.WallRecommendations import WallRecommendations
from recommendations.RoofRecommendations import RoofRecommendations from recommendations.RoofRecommendations import RoofRecommendations
from recommendations.VentilationRecommendations import VentilationRecommendations from recommendations.VentilationRecommendations import VentilationRecommendations
from recommendations.FireplaceRecommendations import FireplaceRecommendations from recommendations.FireplaceRecommendations import FireplaceRecommendations
from recommendations.LightingRecommendations import LightingRecommendations
from backend.ml_models.AnnualBillSavings import AnnualBillSavings from backend.ml_models.AnnualBillSavings import AnnualBillSavings
@ -34,6 +35,7 @@ class Recommendations:
materials=[part for part in materials if part["type"] == "mechanical_ventilation"] materials=[part for part in materials if part["type"] == "mechanical_ventilation"]
) )
self.fireplace_recommender = FireplaceRecommendations(property_instance=property_instance) self.fireplace_recommender = FireplaceRecommendations(property_instance=property_instance)
self.lighting_recommender = LightingRecommendations(property_instance=property_instance, materials=materials)
def recommend(self): def recommend(self):
@ -69,6 +71,11 @@ class Recommendations:
if self.fireplace_recommender.recommendation: if self.fireplace_recommender.recommendation:
property_recommendations.append(self.fireplace_recommender.recommendation) property_recommendations.append(self.fireplace_recommender.recommendation)
# Lighting recommendations
self.lighting_recommender.recommend()
if self.lighting_recommender.recommendation:
property_recommendations.append(self.lighting_recommender.recommendation)
# We insert temporary ids into the recommendations which is important for the optimiser later # We insert temporary ids into the recommendations which is important for the optimiser later
property_recommendations = self.insert_temp_recommendation_id(property_recommendations) property_recommendations = self.insert_temp_recommendation_id(property_recommendations)