diff --git a/recommendations/Costs.py b/recommendations/Costs.py index 69ff6073..08b05a8a 100644 --- a/recommendations/Costs.py +++ b/recommendations/Costs.py @@ -290,9 +290,9 @@ class Costs: "labour_days": labour_days } - def loft_insulation(self, floor_area, material): + def loft_and_flat_insulation(self, floor_area, material): """ - Calculates the total cost for cavity wall insulation based on material and labor costs, + Calculates the total cost for loft/flat roof insulation based on material and labor costs, including contingency, preliminaries, profit, and VAT. :return: A dictionary containing detailed cost breakdown. @@ -624,92 +624,6 @@ class Costs: "labour_cost": labour_cost } - def flat_roof_insulation(self, floor_area, material, non_insulation_materials): - """ - A model of a warm, flat roof construction can be seen in this video: - https://www.youtube.com/watch?v=WZ6Ng6YI9OA - Warm, flat roof insulation will normally be 100-125mm in depth - - We break this measure down into the following jobs to be done - 1) Preparation of the room. This involves cleaning the existing roof surface, removing any debris and repairing - any damage. Additionally, an edge barrier will likely need to be installed, to protect the sides of the - roof from water ingress. - 2) Primer Application. A layer of primer is applied to the clean roof surface to enhance the adhestia of - subsequent layers, and seal the existing roof surface. - 3) Vapour Proof Layer Installation. Lay a vapour control layer to prevent moisture ingress from inside the - building, which is essential in warm roof construction. - 4) Insulation Layer Application. Place and securely fix insulation boards over the roof. These could be rigid - boards like PIR (Polyisocyanurate). - 5) Waterproofing Membrane Installation: Cover the insulation (and timber layer, if used) with a - waterproofing membrane, like EPDM, PVC, or bituminous felt. Carefully seal all joints, edges, and around any - roof penetrations to ensure water tightness - - :param floor_area: Area of the flat roof to be insulated, based on the area of the floor - :param material: Selected insulation material - :param non_insulation_materials: Non-insulation materials required for the job - :return: - """ - - preparation_data_m2 = [ - x for x in non_insulation_materials if - (x["type"] == "flat_roof_preparation") and (x["cost_unit"] == "gbp_per_m2") - ] - vapour_barrier_data = [x for x in non_insulation_materials if x["type"] == "flat_roof_vapour_barrier"] - waterproofing_data = [x for x in non_insulation_materials if x["type"] == "flat_roof_waterproofing"] - - if (len(preparation_data_m2) != 2) or (len(vapour_barrier_data) != 1) or ( - len(waterproofing_data) != 1): - raise ValueError("Incorrect number of data entries for non-insulation materials") - - # Break out the individual material costs - preparation_m2_material_costs = sum([x["material_cost"] * floor_area for x in preparation_data_m2]) - vapour_barrier_material_costs = vapour_barrier_data[0]["material_cost"] * floor_area - insulation_material_costs = material["material_cost"] * floor_area - - preparation_m2_labour_costs = sum([x["labour_cost"] * floor_area for x in preparation_data_m2]) - vapour_barrier_labour_costs = vapour_barrier_data[0]["labour_cost"] * floor_area - - # For waterproofing and upstand, we only have a total cost - waterproofing_total_costs = waterproofing_data[0]["total_cost"] * floor_area - - labour_costs = preparation_m2_labour_costs + vapour_barrier_labour_costs - labour_costs = labour_costs * self.labour_adjustment_factor - - materials_costs = preparation_m2_material_costs + vapour_barrier_material_costs + insulation_material_costs - - subtotal_before_profit = labour_costs + materials_costs + waterproofing_total_costs - - contingency_cost = subtotal_before_profit * self.FLAT_ROOF_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 - - preparation_m2_labour_hours = sum([x["labour_hours_per_unit"] * floor_area for x in preparation_data_m2]) - vapour_barrier_labour_hours = vapour_barrier_data[0]["labour_hours_per_unit"] * floor_area - waterproofing_labour_hours = waterproofing_data[0]["labour_hours_per_unit"] * floor_area - - labour_hours = preparation_m2_labour_hours + vapour_barrier_labour_hours + waterproofing_labour_hours - - # To install flat roof insulation, assume a small/medium project might be conducted by a team of 2-4. - # We'll assume a team of 2 since a lot of the roofs will be on the smaller side and will review this later - labour_days = (labour_hours / 8) / 2 - - return { - "total": total_cost, - "subtotal": subtotal_before_vat, - "vat": vat_cost, - "contingency": contingency_cost, - "preliminaries": preliminaries_cost, - "material": materials_costs, - "profit": profit_cost, - "labour_hours": labour_hours, - "labour_days": labour_days, - "labour_cost": labour_costs - } - def window_glazing(self, number_of_windows, material, is_secondary_glazing=False): """ We characterise the jobs to be done for window glazing as the following: diff --git a/recommendations/FireplaceRecommendations.py b/recommendations/FireplaceRecommendations.py index 9a9d7f76..163728dd 100644 --- a/recommendations/FireplaceRecommendations.py +++ b/recommendations/FireplaceRecommendations.py @@ -9,7 +9,7 @@ class FireplaceRecommendations(Definitions): """ # This is our base assumption for the cost of the work - COST_OF_WORK = 300 + COST_OF_WORK = 235 def __init__( self, diff --git a/recommendations/RoofRecommendations.py b/recommendations/RoofRecommendations.py index 8c7e2291..89b8205f 100644 --- a/recommendations/RoofRecommendations.py +++ b/recommendations/RoofRecommendations.py @@ -46,19 +46,12 @@ class RoofRecommendations: self.loft_insulation_materials = [ part for part in materials if (part["type"] == "loft_insulation") and (part["is_installer_quote"]) ] - self.loft_non_insulation_materials = [] # We don't have proper installer quotes for flat roof insulation self.flat_roof_insulation_materials = [ part for part in materials if part["type"] == "flat_roof_insulation" ] - self.flat_roof_non_insulation_materials = [ - part for part in materials if part["type"] in [ - "flat_roof_preparation", "flat_roof_vapour_barrier", "flat_roof_waterproofing" - ] - ] - # Extract the insulation thickness from the roof, which is used throughout this method self.insulation_thickness = convert_thickness_to_numeric( self.property.roof["insulation_thickness"], @@ -252,10 +245,8 @@ class RoofRecommendations: if is_pitched: insulation_materials = self.loft_insulation_materials - non_insulation_materials = self.loft_non_insulation_materials elif is_flat: insulation_materials = self.flat_roof_insulation_materials - non_insulation_materials = self.flat_roof_non_insulation_materials else: raise ValueError("Roof is not pitched or flat") @@ -297,14 +288,16 @@ class RoofRecommendations: if new_u_value <= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE: lowest_selected_u_value = update_lowest_selected_u_value(lowest_selected_u_value, new_u_value) + cost_result = self.costs.loft_and_flat_insulation( + floor_area=self.property.insulation_floor_area, + material=material + ) + + already_installed = material["type"] in self.property.already_installed + if already_installed: + cost_result = override_costs(cost_result) + if material["type"] == "loft_insulation": - cost_result = self.costs.loft_insulation( - floor_area=self.property.insulation_floor_area, - material=material - ) - already_installed = "loft_insulation" in self.property.already_installed - if already_installed: - cost_result = override_costs(cost_result) new_thickness = insulation_thickness + material["depth"] # This is based on the values we have in the training data @@ -341,14 +334,6 @@ class RoofRecommendations: new_description = f"Pitched, {int(proposed_depth)}mm loft insulation" elif material["type"] == "flat_roof_insulation": - cost_result = self.costs.flat_roof_insulation( - floor_area=self.property.insulation_floor_area, - material=material, - non_insulation_materials=non_insulation_materials - ) - already_installed = "flat_roof_insulation" in self.property.already_installed - if already_installed: - cost_result = override_costs(cost_result) new_description = "Flat, insulated" new_efficiency = "Good" else: