diff --git a/recommendations/WindowsRecommendations.py b/recommendations/WindowsRecommendations.py index 235d9ee2..a8fd2a87 100644 --- a/recommendations/WindowsRecommendations.py +++ b/recommendations/WindowsRecommendations.py @@ -48,6 +48,15 @@ class WindowsRecommendations: if not any(x in measures for x in MEASURE_MAP["windows"]): return + if self.property.windows["glazing_type"] in ["triple", "high performance"]: + # We don't make any recommendations in this case. The property already has outstanding glazing + return + + if self.property.windows["has_glazing"] & ( + self.property.windows["glazing_coverage"] == "full" + ): + return + # If the property is in a conservation area or is a listed building, it becomes more difficult to install # double glazing. Therefore, we don't recommend it. It is still possible but is not practical as it # requires planning permission and might require a more expensive window type, such as timber. @@ -67,11 +76,6 @@ class WindowsRecommendations: if not number_of_windows: raise ValueError("Number of windows not specified") - if self.property.windows["has_glazing"] & ( - self.property.windows["glazing_coverage"] == "full" - ): - return - if windows_area is not None: # TODO - we don't have a price for this so we can't recommend it print("We have windows area, we should use this data for our recommendations!!!") @@ -122,6 +126,95 @@ class WindowsRecommendations: ". Secondary glazing recommended due to conservation area status" ) + # Set up the simulation config + if self.property.windows["glazing_type"] == "multiple": + glazing_type_ending = "multiple" + glazed_type_ending = ( + "secondary glazing" if is_secondary_glazing else "double glazing installed during or after 2002" + ) + windows_energy_eff = "Good" + new_windows_description = "Multiple glazing throughout" + + elif self.property.windows["glazing_type"] == "single": + # We will only recommend either secondary or double glazing + glazing_type_ending = ( + "secondary" if is_secondary_glazing else "double" + ) + glazed_type_ending = ( + "secondary glazing" if is_secondary_glazing else "double glazing installed during or after 2002" + ) + + if is_secondary_glazing: + windows_energy_eff = "Good" + new_windows_description = "Full secondary glazing" + else: + windows_energy_eff = "Average" + new_windows_description = "Fully double glazed" + + elif self.property.windows["glazing_type"] == "double": + glazing_type_ending = ( + "multiple" if is_secondary_glazing else "double" + ) + + # We set glazed type depending on which window type is more prevalent. Since there is already double + # glazing in place, if we're recommending more double glazing, we set the glazed type to double glazing + # otherwise, if we're recommending secondary glazing and the proportion of glazing in place already that + # is double is less than 50% we set the glazed type to secondary glazing + + if not is_secondary_glazing: + glazed_type_ending = "double glazing installed during or after 2002" + new_windows_description = "Fully double glazed" + windows_energy_eff = "Average" + else: + if self.property.data["multi-glaze-proportion"] < 50: + glazed_type_ending = "secondary glazing" + else: + glazed_type_ending = "double glazing installed during or after 2002" + + new_windows_description = "Multiple glazing throughout" + windows_energy_eff = "Good" + + elif self.property.windows["glazing_type"] == "secondary": + glazing_type_ending = ( + "secondary" if is_secondary_glazing else "multiple" + ) + windows_energy_eff = "Good" + # This is the opposite. If there is secondary glazing in place, and we're recommending double + # we set glazed_type_ending, depending on the proportion of glazing in place + if is_secondary_glazing: + glazed_type_ending = "secondary glazing" + new_windows_description = "Full secondary glazing" + else: + if self.property.data["multi-glaze-proportion"] < 50: + glazed_type_ending = "double glazing installed during or after 2002" + else: + glazed_type_ending = "secondary glazing" + new_windows_description = "Multiple glazing throughout" + + else: + raise ValueError("Invalid glazing type - implement me") + + windows_ending_config = WindowAttributes(new_windows_description).process() + + windows_simulation_config = check_simulation_difference( + new_config=windows_ending_config, old_config=self.property.windows, prefix="windows_" + ) + + simulation_config = { + **windows_simulation_config, + "multi_glaze_proportion_ending": 100, + "windows_energy_eff_ending": windows_energy_eff, + "glazing_type_ending": glazing_type_ending, + "glazed_type_ending": glazed_type_ending, + } + + description_simulation = { + "multi-glaze-proportion": 100, + "windows-energy-eff": windows_energy_eff, + "windows-description": new_windows_description, + "glazed-type": glazed_type_ending, + } + self.recommendation = [ { "phase": phase, @@ -134,13 +227,8 @@ class WindowsRecommendations: "already_installed": already_installed, **cost_result, "is_secondary_glazing": is_secondary_glazing, - # TODO: Make this condition on is_secondary_glazing - "description_simulation": { - "multi-glaze-proportion": 100, - "windows-energy-eff": "Average", - "windows-description": "Fully double glazed", - "glazed-type": "double glazing installed during or after 2002", - } + "description_simulation": description_simulation, + "simulation_config": simulation_config, } ] diff --git a/recommendations/tests/test_window_recommendations.py b/recommendations/tests/test_window_recommendations.py index 36e70834..02978051 100644 --- a/recommendations/tests/test_window_recommendations.py +++ b/recommendations/tests/test_window_recommendations.py @@ -37,11 +37,13 @@ class TestWindowRecommendations: recommender.recommend() assert recommender.recommendation == [ - {'parts': [], 'type': 'windows_glazing', 'description': 'Install double glazing to all windows', - 'starting_u_value': None, 'new_u_value': None, 'sap_points': None, 'total': 5721.943248, - 'subtotal': 4768.28604, 'vat': 953.6572080000001, 'contingency': 340.59186, 'preliminaries': 340.59186, - 'material': 1275.75, 'profit': 681.18372, 'labour_hours': 45.5, 'labour_cost': 994.8624, - 'labour_days': 2.84375, 'is_secondary_glazing': False}] + {'phase': 0, 'parts': [], 'type': 'windows_glazing', 'description': 'Install double glazing to all windows', + 'starting_u_value': None, 'new_u_value': None, 'sap_points': None, 'already_installed': False, + 'total': 7980.0, 'labour_hours': 0.0, 'labour_days': 0.0, 'is_secondary_glazing': False, + 'description_simulation': {'multi-glaze-proportion': 100, 'windows-energy-eff': 'Average', + 'windows-description': 'Fully double glazed', + 'glazed-type': 'double glazing installed during or after 2002'}} + ] def test_partial_double_glazed(self): """ @@ -73,11 +75,14 @@ class TestWindowRecommendations: recommender2.recommend() assert recommender2.recommendation == [ - {'parts': [], 'type': 'windows_glazing', 'description': 'Install double glazing to the remaining windows', - 'starting_u_value': None, 'new_u_value': None, 'sap_points': None, 'total': 4087.10232, - 'subtotal': 3405.9186, 'vat': 681.18372, 'contingency': 243.2799, 'preliminaries': 243.2799, - 'material': 911.25, 'profit': 486.5598, 'labour_hours': 32.5, 'labour_cost': 710.6160000000001, - 'labour_days': 2.03125, 'is_secondary_glazing': False}] + {'phase': 0, 'parts': [], 'type': 'windows_glazing', + 'description': 'Install double glazing to the remaining windows', 'starting_u_value': None, + 'new_u_value': None, 'sap_points': None, 'already_installed': False, 'total': 5700.0, 'labour_hours': 0.0, + 'labour_days': 0.0, 'is_secondary_glazing': False, + 'description_simulation': {'multi-glaze-proportion': 100, 'windows-energy-eff': 'Average', + 'windows-description': 'Fully double glazed', + 'glazed-type': 'double glazing installed during or after 2002'}} + ] def test_fully_double_glazed(self): """ @@ -160,12 +165,14 @@ class TestWindowRecommendations: recommender5.recommend() assert recommender5.recommendation == [ - {'parts': [], 'type': 'windows_glazing', - 'description': 'Install secondary glazing to the remaining windows', - 'starting_u_value': None, 'new_u_value': None, 'sap_points': None, 'total': 1089.893952, - 'subtotal': 908.24496, 'vat': 181.64899200000002, 'contingency': 64.87464, 'preliminaries': 64.87464, - 'material': 729.0, 'profit': 129.74928, 'labour_hours': 13.0, 'labour_cost': 568.4928, - 'labour_days': 0.8125, 'is_secondary_glazing': True}] + {'phase': 0, 'parts': [], 'type': 'windows_glazing', + 'description': 'Install secondary glazing to the remaining windows', 'starting_u_value': None, + 'new_u_value': None, 'sap_points': None, 'already_installed': False, 'total': 4560.0, 'labour_hours': 0.0, + 'labour_days': 0.0, 'is_secondary_glazing': True, + 'description_simulation': {'multi-glaze-proportion': 100, 'windows-energy-eff': 'Good', + 'windows-description': 'Full secondary glazing', + 'glazed-type': 'secondary glazing'}} + ] def test_single_glazed_restricted_measures(self): epc_record = EPCRecord() @@ -195,14 +202,14 @@ class TestWindowRecommendations: recommender6.recommend() assert recommender6.recommendation == [ - {'parts': [], 'type': 'windows_glazing', - 'description': 'Install secondary glazing to all windows. Secondary ' - 'glazing recommended due to herigate building status', - 'starting_u_value': None, 'new_u_value': None, 'sap_points': None, - 'total': 1907.314416, 'subtotal': 1589.42868, 'vat': 317.885736, - 'contingency': 113.53062, 'preliminaries': 113.53062, - 'material': 1275.75, 'profit': 227.06124, 'labour_hours': 22.75, - 'labour_cost': 994.8624, 'labour_days': 1.421875, 'is_secondary_glazing': True} + {'phase': 0, 'parts': [], 'type': 'windows_glazing', + 'description': 'Install secondary glazing to all windows. Secondary glazing recommended due to herigate ' + 'building status', + 'starting_u_value': None, 'new_u_value': None, 'sap_points': None, 'already_installed': False, + 'total': 7980.0, 'labour_hours': 0.0, 'labour_days': 0.0, 'is_secondary_glazing': True, + 'description_simulation': {'multi-glaze-proportion': 100, 'windows-energy-eff': 'Good', + 'windows-description': 'Full secondary glazing', + 'glazed-type': 'secondary glazing'}} ] def test_full_triple_glazed(self): @@ -233,7 +240,7 @@ class TestWindowRecommendations: def test_partial_triple_glazed(self): """ - We should just recommend double glazing to the remaining windows, since it's a cheaper option + We don't recommend anything here """ epc_record = EPCRecord() epc_record.prepared_epc = { @@ -258,9 +265,4 @@ class TestWindowRecommendations: recommender8.recommend() - assert recommender8.recommendation == [ - {'parts': [], 'type': 'windows_glazing', 'description': 'Install double glazing to the remaining windows', - 'starting_u_value': None, 'new_u_value': None, 'sap_points': None, 'total': 1634.840928, - 'subtotal': 1362.36744, 'vat': 272.47348800000003, 'contingency': 97.31196, 'preliminaries': 97.31196, - 'material': 364.5, 'profit': 194.62392, 'labour_hours': 13.0, 'labour_cost': 284.2464, - 'labour_days': 0.8125, 'is_secondary_glazing': False}] + assert not recommender8.recommendation