diff --git a/.idea/Model.iml b/.idea/Model.iml index b0f9c00d..4413bb06 100644 --- a/.idea/Model.iml +++ b/.idea/Model.iml @@ -7,7 +7,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index 1122b380..6f308057 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,7 +3,7 @@ - + diff --git a/backend/Property.py b/backend/Property.py index 79bd1659..4c8bd5bc 100644 --- a/backend/Property.py +++ b/backend/Property.py @@ -10,7 +10,7 @@ from utils.logger import setup_logger from utils.s3 import read_dataframe_from_s3_parquet from epc_api.client import EpcClient from BaseUtility import Definitions -from recommendations.rdsap_tables import england_wales_age_band_lookup +from recommendations.rdsap_tables import england_wales_age_band_lookup, FLOOR_LEVEL_MAP from recommendations.recommendation_utils import ( estimate_perimeter, get_wall_type, estimate_external_wall_area, esimtate_pitched_roof_area ) @@ -84,6 +84,7 @@ class Property(Definitions): self.pitched_roof_area = None self.insulation_floor_area = None self.number_lighting_outlets = None + self.floor_level = None self.current_adjusted_energy = None self.expected_adjusted_energy = None @@ -324,6 +325,7 @@ class Property(Definitions): self.set_wall_type() self.set_floor_type() + self.set_floor_level() def set_age_band(self): """ @@ -642,6 +644,27 @@ class Property(Definitions): floor_area=self.insulation_floor_area, floor_height=self.floor_height ) + def set_floor_level(self): + self.floor_level = ( + FLOOR_LEVEL_MAP[self.data["floor-level"]] if + self.data["floor-level"] not in self.DATA_ANOMALY_MATCHES else None + ) + + # We perform some extra checks, if the property is not on the ground floor, as we have found cases + # where a property is marked as being on the first floor + if self.floor_level > 0: + + # We check if there is another property below + if not self.floor["another_property_below"]: + self.floor_level = 0 + return + + if self.floor_level == 0: + # Check if another property below + if self.floor["another_property_below"]: + self.floor_level = 1 + return + def set_wall_type(self): """ This method sets the wall type of the property, using a simple approach based on the wall description diff --git a/backend/tests/test_property.py b/backend/tests/test_property.py index 39a7e86e..9188f545 100644 --- a/backend/tests/test_property.py +++ b/backend/tests/test_property.py @@ -375,3 +375,51 @@ class TestProperty: assert not prop2.is_listed assert not prop2.is_heritage assert not prop2.restricted_measures + + def test_set_floor_level(self, mock_epc_client): + # In this case, we have a flat which looks looks it's on the first floor, but it's actually on the ground + # floor, so we should set floor_level to 0 + prop = Property(1, "AB12CD", "Test Address", mock_epc_client) + prop.data = {'floor-level': '01', 'property-type': 'Flat'} + prop.floor = { + 'original_description': 'Solid, no insulation (assumed)', 'clean_description': 'Solid, no insulation', + 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_assumed': True, + 'is_to_unheated_space': False, 'is_to_external_air': False, 'is_suspended': False, 'is_solid': True, + 'another_property_below': False, 'insulation_thickness': 'none', 'floor_thermal_transmittance': None, + 'floor_insulation_thickness': 'none' + } + + prop.set_floor_level() + + assert prop.floor_level == 0 + + # This property is labelled as being on the ground floor but actually has another property below + # so we set floor level to 1 + prop2 = Property(1, "AB12CD", "Test Address", mock_epc_client) + prop2.data = {'floor-level': 'Ground', 'property-type': 'Flat'} + prop2.floor = { + 'original_description': '(Another dwelling below)', 'clean_description': 'Solid, no insulation', + 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_assumed': False, + 'is_to_unheated_space': False, 'is_to_external_air': False, 'is_suspended': False, 'is_solid': False, + 'another_property_below': True, 'insulation_thickness': 'none', 'floor_thermal_transmittance': None, + 'floor_insulation_thickness': 'none' + } + + prop2.set_floor_level() + + assert prop2.floor_level == 1 + + # this property is correctly labelled as being on the 2nd floor + prop3 = Property(1, "AB12CD", "Test Address", mock_epc_client) + prop3.data = {'floor-level': '02', 'property-type': 'Flat'} + prop3.floor = { + 'original_description': '(Another dwelling below)', 'clean_description': 'Solid, no insulation', + 'thermal_transmittance': None, 'thermal_transmittance_unit': None, 'is_assumed': False, + 'is_to_unheated_space': False, 'is_to_external_air': False, 'is_suspended': False, 'is_solid': False, + 'another_property_below': True, 'insulation_thickness': 'none', 'floor_thermal_transmittance': None, + 'floor_insulation_thickness': 'none' + } + + prop3.set_floor_level() + + assert prop3.floor_level == 2 diff --git a/recommendations/FloorRecommendations.py b/recommendations/FloorRecommendations.py index 48245554..a246c8cb 100644 --- a/recommendations/FloorRecommendations.py +++ b/recommendations/FloorRecommendations.py @@ -10,7 +10,6 @@ from recommendations.recommendation_utils import ( r_value_per_mm_to_u_value, calculate_u_value_uplift, is_diminishing_returns, update_lowest_selected_u_value, get_recommended_part, get_floor_u_value ) -from recommendations.rdsap_tables import FLOOR_LEVEL_MAP from recommendations.Costs import Costs @@ -73,10 +72,6 @@ class FloorRecommendations(Definitions): def recommend(self): u_value = self.property.floor["thermal_transmittance"] - floor_level = ( - FLOOR_LEVEL_MAP[self.property.data["floor-level"]] if - self.property.data["floor-level"] not in self.DATA_ANOMALY_MATCHES else None - ) property_type = self.property.data["property-type"] floor_area = self.property.insulation_floor_area @@ -90,7 +85,9 @@ class FloorRecommendations(Definitions): return # If the property is a flat that isn't at ground level, it's likely impractical to recommend a floor upgrade - if (floor_level != 0) and (property_type == "Flat"): + if (self.property.floor_level != 0) and (property_type == "Flat") and ( + self.property.floor["another_property_below"] + ): return if u_value: