diff --git a/backend/Property.py b/backend/Property.py index 1094e7b2..2359ea6a 100644 --- a/backend/Property.py +++ b/backend/Property.py @@ -288,10 +288,16 @@ class Property(Definitions): for description, attribute in cleaned.items(): if self.data[description] in self.DATA_ANOMALY_MATCHES: + template = cleaned[description][0] + fill_dict = dict(zip(template.keys(), [None] * len(template))) + fill_dict.update({ + "original_description": self.data[description], + "clean_description": self.data[description], + }) setattr( self, self.ATTRIBUTE_MAP[description], - {"original_description": self.data[description], "clean_description": self.data[description]} + fill_dict, ) continue diff --git a/backend/app/plan/router.py b/backend/app/plan/router.py index 23ad4262..e531896e 100644 --- a/backend/app/plan/router.py +++ b/backend/app/plan/router.py @@ -39,7 +39,6 @@ from recommendations.optimiser.optimiser_functions import prepare_input_measures from recommendations.WallRecommendations import WallRecommendations from utils.logger import setup_logger from utils.s3 import read_dataframe_from_s3_parquet -from tqdm import tqdm logger = setup_logger() @@ -122,35 +121,6 @@ async def trigger_plan(body: PlanTriggerRequest): # TODO: Move this to a class. We probably want a Recommender class which takes the injects the optimisers # in as a dependency and then the optimisers can take the input measures in as part of the setup() method - # import pickle - # with open("input_properties.pickle", "rb") as f: - # input_properties = pickle.load(f) - # - # import pickle - # with open("new_sap_dataset.pickle", "rb") as f: - # new_sap_dataset = pickle.load(f) - - # import pickle - # with open("cleaned.pickle", "rb") as f: - # cleaned = pickle.load(f) - - # with open("sap_dataset.pickle", "rb") as f: - # sap_dataset = pickle.load(f) - - # with open("materials_by_type", "rb") as f: - # materials_by_type = pickle.load(f) - - # materials_by_type["floor"].append( - # {'id': 18, 'type': 'exposed_floor_insulation', 'description': 'Rockwool Stone Wool insulation', - # 'depths': [50, 100, 140], 'depth_unit': 'mm', 'cost': [8, 11, 15], - # 'cost_unit': 'gbp_sq_meter', 'r_value_per_mm': 0.026315789473684213, - # 'r_value_unit': 'square_meter_kelvin_per_watt', - # 'thermal_conductivity': 0.038, 'thermal_conductivity_unit': 'watt_per_meter_kelvin', - # 'link': 'https://insulation4less.co.uk/products/rockwool-flexi-slab-all-sizes?variant=33409590853685', - # 'created_at': datetime(2023, 8, 10, 16, 59, 10, 815531), 'is_active': True} - # - # ) - recommendations = {} recommendations_scoring_data = [] diff --git a/backend/app/plan/utils.py b/backend/app/plan/utils.py index 71a61be1..36e90d61 100644 --- a/backend/app/plan/utils.py +++ b/backend/app/plan/utils.py @@ -17,7 +17,7 @@ def filter_materials(materials): "walls": ["internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation"], "floor": ["suspended_floor_insulation", "solid_floor_insulation", "exposed_floor_insulation"], "ventilation": ["mechanical_ventilation"], - "roof": ["loft_insulation"] + "roof": ["loft_insulation", "flat_roof_insulation", "room_roof_insulation"] } materials = [row2dict(material) for material in materials] diff --git a/recommendations/RoofRecommendations.py b/recommendations/RoofRecommendations.py index e5200904..bfa63908 100644 --- a/recommendations/RoofRecommendations.py +++ b/recommendations/RoofRecommendations.py @@ -36,6 +36,10 @@ class RoofRecommendations: self.materials = materials def recommend(self): + + if self.property.roof["has_dwelling_above"]: + return + u_value = self.property.roof["thermal_transmittance"] insulation_thickness = convert_thickness_to_numeric( @@ -53,6 +57,12 @@ class RoofRecommendations: # If we have a u-value already, need to implement this if u_value: + if u_value <= self.BUILDING_REGULATIONS_PART_L_MAX_U_VALUE: + # The floor is already compliant + return + + if self.property.data["transaction-type"] == "new dwelling": + return raise NotImplementedError("Implement me") u_value = get_roof_u_value(**{**self.property.roof, "age_band": self.property.age_band}) diff --git a/recommendations/recommendation_utils.py b/recommendations/recommendation_utils.py index 13f58fd9..063a274c 100644 --- a/recommendations/recommendation_utils.py +++ b/recommendations/recommendation_utils.py @@ -585,6 +585,9 @@ def convert_thickness_to_numeric(string_thickness, is_pitched): :return: integer measure of insulation thickness """ + if string_thickness is None: + return 0 + if is_pitched: lookup = { "none": 0, diff --git a/recommendations/tests/test_roof_recommendations.py b/recommendations/tests/test_roof_recommendations.py index 37cc2daf..551407da 100644 --- a/recommendations/tests/test_roof_recommendations.py +++ b/recommendations/tests/test_roof_recommendations.py @@ -427,3 +427,26 @@ class TestRoofRecommendations: assert roof_recommender13.recommendations[0]["description"] == \ "Insulate the home's flat roof with 220mm of Example flat roof insulation" + + def test_property_above(self): + property_instance14 = Property(id=0, address1="fake", postcode="fake", epc_client=Mock()) + property_instance14.age_band = "F" + property_instance14.floor_area = 100 + property_instance14.roof = { + 'original_description': '(other premises above)', + 'clean_description': '(other premises above)', 'thermal_transmittance': 0, + 'thermal_transmittance_unit': 'w/m-¦k', 'is_pitched': False, 'is_roof_room': False, + 'is_loft': False, 'is_flat': False, 'is_thatched': False, 'is_at_rafters': False, + 'is_assumed': False, 'has_dwelling_above': True, 'is_valid': True, + 'insulation_thickness': None + } + + roof_recommender14 = RoofRecommendations( + property_instance=property_instance14, materials=loft_insulation_materials + ) + + assert not roof_recommender14.recommendations + + roof_recommender14.recommend() + + assert not roof_recommender14.recommendations