From a74459bf46b171f37542af3e60ab3498a3822f89 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 22 Nov 2023 11:53:22 +0000 Subject: [PATCH] Creating new cost class to handle new costing data --- backend/app/plan/utils.py | 2 +- recommendations/Costs.py | 139 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 recommendations/Costs.py diff --git a/backend/app/plan/utils.py b/backend/app/plan/utils.py index 36e90d61..e2bf9d86 100644 --- a/backend/app/plan/utils.py +++ b/backend/app/plan/utils.py @@ -173,7 +173,7 @@ def create_recommendation_scoring_data( parts = recommendation["parts"] if len(parts) != 1: raise ValueError("More than one part for roof insulation - investiage me") - + scoring_dict["roof_insulation_thickness_ENDING"] = str(parts[0]["depths"][0]) scoring_dict["ROOF_ENERGY_EFF_ENDING"] = "Very Good" else: diff --git a/recommendations/Costs.py b/recommendations/Costs.py new file mode 100644 index 00000000..efa22fd8 --- /dev/null +++ b/recommendations/Costs.py @@ -0,0 +1,139 @@ +class Costs: + """ + A class to calculate the costs associated with construction works, + specifically focusing on cavity wall insulation. + It includes contingency, preliminaries, profit margin, and VAT calculations. + + As a sense check, there is a useful article from checkatrade on retrofitting walls and expected costs: + https://www.checkatrade.com/blog/cost-guides/retrofit-insulation-cost/ + """ + + # Contingency is a percentage of the total cost of the work and covers unforseen expenses + # We assume a conservative 10% contingency for all works which is a rate defined by SPONs + CONTINGENCY = 0.1 + + # Preliminaries are a percentage of the total cost of the work and covers the cost of site-specific costs + # such as site preparation, safety measures and project management. This rate can vary but we'll assume a 10% + # rate, on the total cost before VAT, as recommended by SPONs + PRELIMINARIES = 0.1 + + VAT_RATE = 0.2 + PROFIT_MARGIN = 0.15 + + def __init__(self, property_instance): + """ + Initializes the Costs class with a property instance. + + :param property_instance: Instance of a Property class containing relevant details like wall area. + """ + if not hasattr(property_instance, 'insulation_wall_area'): + raise ValueError("Property instance must have an 'insulation_wall_area' attribute") + self.property = property_instance + + def cavity_wall_insulation(self, material): + """ + Calculates the total cost for cavity wall insulation based on material and labor costs, + including contingency, preliminaries, profit, and VAT. + + :return: A dictionary containing detailed cost breakdown. + """ + # Cost per m2 + material = { + "description": "Crown Dritherm Cavity Slab 37 (Thermal conductivity 0.037 W/mK) glass fibre batt or other " + "equal; as full or partial cavity fill; including cutting and fitting around wall ties and " + "retaining discs", + "depth": 75, + "thermal_conductivity": 0.037, + "prime_cost": 5.17, + "material_cost": 5.62, + "labour_cost": 2.25, + "labour_hours": 0.13 + } + + material_cost_per_m2 = material["material_cost"] + wall_area = self.property.insulation_wall_area + + # This is the amount of material required in m3, assuming a standard 75mm depth + volume = 0.075 * wall_area + + base_material_cost = material_cost_per_m2 * wall_area + labour_cost = material["labour_cost"] * wall_area + + subtotal_before_profit = base_material_cost + labour_cost + + contingency_cost = subtotal_before_profit * self.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"] * wall_area + + return { + "total": total_cost, + "subtotal": subtotal_before_vat, + "vat": vat_cost, + "contingency": contingency_cost, + "preliminaries": preliminaries_cost, + "material": base_material_cost, + "profit": profit_cost, + "labour_hours": labour_hours + } + + def cavity_wall_insulation(self, material): + """ + Calculates the total cost for cavity wall insulation based on material and labor costs, + including contingency, preliminaries, profit, and VAT. + + :return: A dictionary containing detailed cost breakdown. + """ + # Cost per m2 + material = { + "description": "Crown Dritherm Cavity Slab 37 (Thermal conductivity 0.037 W/mK) glass fibre batt or other " + "equal; as full or partial cavity fill; including cutting and fitting around wall ties and " + "retaining discs", + "depth": 75, + "thermal_conductivity": 0.037, + "prime_cost": 5.17, + "material_cost": 5.62, + "labour_cost": 2.25, + "labour_hours": 0.13 + } + + material_cost_per_m2 = material["material_cost"] + wall_area = self.property.insulation_wall_area + + # This is the amount of material required in m3, assuming a standard 75mm depth + volume = 0.075 * wall_area + + base_material_cost = material_cost_per_m2 * wall_area + labour_cost = material["labour_cost"] * wall_area + + subtotal_before_profit = base_material_cost + labour_cost + + contingency_cost = subtotal_before_profit * self.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"] * wall_area + + return { + "total": total_cost, + "subtotal": subtotal_before_vat, + "vat": vat_cost, + "contingency": contingency_cost, + "preliminaries": preliminaries_cost, + "material": base_material_cost, + "profit": profit_cost, + "labour_hours": labour_hours + }