mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Merge branch 'main' into feature/automate-categorisation-of-works
This commit is contained in:
commit
e0857ab7a2
10 changed files with 76 additions and 29 deletions
1
.idea/inspectionProfiles/profiles_settings.xml
generated
1
.idea/inspectionProfiles/profiles_settings.xml
generated
|
|
@ -1,5 +1,6 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="PROJECT_PROFILE" value="Default" />
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
|
|
|
|||
|
|
@ -69,24 +69,24 @@ def app():
|
|||
Property UPRN
|
||||
"""
|
||||
|
||||
data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Aspire"
|
||||
data_filename = "ASPIRE ASSET LIST.xlsx"
|
||||
sheet_name = "Asset List"
|
||||
postcode_column = "Postcode"
|
||||
data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/West Kent"
|
||||
data_filename = "West Kent Asset List.xlsx"
|
||||
sheet_name = "Sheet1"
|
||||
postcode_column = "POSTCODE"
|
||||
address1_column = None
|
||||
address1_method = "house_number_extraction"
|
||||
fulladdress_column = "Address"
|
||||
fulladdress_column = "ADDRESS"
|
||||
address_cols_to_concat = []
|
||||
missing_postcodes_method = None
|
||||
landlord_year_built = None
|
||||
landlord_os_uprn = None
|
||||
landlord_property_type = "Property Type"
|
||||
landlord_property_type = "PROPERTY TYPE"
|
||||
landlord_built_form = None
|
||||
landlord_wall_construction = None
|
||||
landlord_roof_construction = None
|
||||
landlord_wall_construction = "wall combined"
|
||||
landlord_roof_construction = "HEATING SYSTEM"
|
||||
landlord_heating_system = None
|
||||
landlord_existing_pv = None
|
||||
landlord_property_id = "LLUPRN"
|
||||
landlord_property_id = "UPRN"
|
||||
landlord_sap = None
|
||||
outcomes_filename = None
|
||||
outcomes_sheetname = None
|
||||
|
|
|
|||
|
|
@ -308,6 +308,18 @@ ROOF_CONSTRUCTION_MAPPINGS = {
|
|||
'Flat: No Insulation': 'flat uninsulated',
|
||||
'AnotherDwellingAbove: Unknown, PitchedNormalLoftAccess: 250mm': 'another dwelling above',
|
||||
'PitchedNormalLoftAccess: 175mm': 'pitched insulated',
|
||||
'AnotherDwellingAbove: 300mm': 'another dwelling above'
|
||||
'AnotherDwellingAbove: 300mm': 'another dwelling above',
|
||||
|
||||
'Another dwelling above, As built': 'another dwelling above',
|
||||
'Pitched (slates or tiles) no loft access, 400mm+': 'pitched insulated',
|
||||
'Pitched (slates or tiles) access to loft, 400mm+': 'pitched insulated',
|
||||
'Pitched (slates or tiles) access to loft, 300mm': 'pitched insulated',
|
||||
'Pitched (slates or tiles) access to loft, 75mm': 'pitched less than 100mm insulation',
|
||||
'Pitched (slates or tiles) no loft access, 300mm': 'pitched insulated',
|
||||
'Pitched (slates or tiles) access to loft, 270mm': 'pitched insulated',
|
||||
'Pitched (slates or tiles) access to loft, 100mm': 'pitched insulated',
|
||||
'Pitched (slates or tiles) no loft access, 200mm': 'pitched insulated',
|
||||
'Pitched (slates or tiles) access to loft, 200mm': 'pitched insulated',
|
||||
'Pitched (slates or tiles) access to loft, 50mm': 'pitched less than 100mm insulation'
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -363,6 +363,12 @@ WALL_CONSTRUCTION_MAPPINGS = {
|
|||
'Timber Frame, As Built': 'timber frame unknown insulation',
|
||||
'Solid Brick, Internal Insulation': 'insulated solid brick',
|
||||
'Granite or Whinstone, As Built': 'granite or whinstone unknown insulation',
|
||||
'Solid Brick, External': 'insulated solid brick'
|
||||
'Solid Brick, External': 'insulated solid brick',
|
||||
|
||||
'Cavity, Filled cavity': 'filled cavity',
|
||||
'Solid Brick, As built': 'solid brick unknown insulation',
|
||||
'System built, As built': 'system built unknown insulation',
|
||||
'Timber frame, As built': 'timber frame unknown insulation',
|
||||
'Cavity, As built': 'cavity unknown insulation'
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ def get_data(
|
|||
searcher.find_property(skip_os=True)
|
||||
|
||||
# Check if we have a flat or appartment
|
||||
if searcher.newest_epc is None and uprn is None:
|
||||
if not searcher.newest_epc and uprn is None:
|
||||
# Try again:
|
||||
if SearchEpc.get_house_number(address=str(house_number), postcode=postcode) is None:
|
||||
# Backup
|
||||
|
|
@ -252,12 +252,12 @@ def get_data(
|
|||
searcher.find_property(skip_os=True)
|
||||
|
||||
# As a final resort, we estimate the EPC
|
||||
if property_type is not None and searcher.newest_epc is None:
|
||||
if property_type is not None and not searcher.newest_epc:
|
||||
searcher.ordnance_survey_client.property_type = property_type
|
||||
searcher.ordnance_survey_client.built_form = built_form
|
||||
searcher.find_property(skip_os=True)
|
||||
|
||||
if searcher.newest_epc is None:
|
||||
if not searcher.newest_epc:
|
||||
no_epc.append(home[row_id_name])
|
||||
continue
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from typing import Iterator
|
||||
from backend.addresses.Address import Address
|
||||
|
||||
|
||||
|
|
@ -12,6 +13,9 @@ class Addresses:
|
|||
def __len__(self) -> int:
|
||||
return len(self._addresses)
|
||||
|
||||
def __iter__(self) -> Iterator[Address]:
|
||||
return iter(self._addresses)
|
||||
|
||||
@classmethod
|
||||
def from_plan_input(cls, plan_input: list[dict], body) -> "Addresses":
|
||||
addresses = []
|
||||
|
|
|
|||
|
|
@ -74,6 +74,8 @@ class RoofAttributes(Definitions):
|
|||
"insulation_thickness",
|
||||
]
|
||||
|
||||
NODATA_NULLS = ["insulation_thickness", "thermal_transmittance", "thermal_transmittance_unit"]
|
||||
|
||||
def __init__(self, description: str):
|
||||
"""
|
||||
:param description: Description of the roof.
|
||||
|
|
@ -153,6 +155,10 @@ class RoofAttributes(Definitions):
|
|||
if self.nodata:
|
||||
for key in self.DEFAULT_KEYS:
|
||||
result[key] = False
|
||||
# Insulation thickness, thermal transmittance and thermal transmittance unit are set to None for nodata
|
||||
# cases
|
||||
for k in self.NODATA_NULLS:
|
||||
result[k] = None
|
||||
return result
|
||||
|
||||
description = self.description
|
||||
|
|
|
|||
|
|
@ -26,11 +26,10 @@ class TestRoofAttributes:
|
|||
def test_empty_str(self):
|
||||
# Test initialization with an empty description
|
||||
assert RoofAttributes('').process() == {
|
||||
'thermal_transmittance': False, 'thermal_transmittance_unit': False, 'is_pitched': False,
|
||||
'thermal_transmittance': None, 'thermal_transmittance_unit': None, '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': False, 'is_valid': False, 'insulation_thickness': False
|
||||
'is_assumed': False, 'has_dwelling_above': False, 'is_valid': False, 'insulation_thickness': None
|
||||
}
|
||||
assert set(list(RoofAttributes('').process().values())) == {False}
|
||||
|
||||
def test_clean_roof(self):
|
||||
result = RoofAttributes('Pitched, 270 mm loft insulation').process()
|
||||
|
|
@ -92,15 +91,6 @@ class TestRoofAttributes:
|
|||
with pytest.raises(ValueError):
|
||||
RoofAttributes('nonsense string').process()
|
||||
|
||||
def test_clean_roof_no_description(self):
|
||||
roof = RoofAttributes('').process()
|
||||
assert roof == {
|
||||
'thermal_transmittance': False, 'thermal_transmittance_unit': False, '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': False, 'is_valid': False,
|
||||
'insulation_thickness': False
|
||||
}
|
||||
|
||||
def test_clean_roof_edge_cases(self):
|
||||
# Insulation thickness edge case
|
||||
assert RoofAttributes('Pitched, 99999 mm loft insulation').process()['insulation_thickness'] == "99999"
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@ class RoofRecommendations:
|
|||
|
||||
# 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"],
|
||||
self.property.roof["is_pitched"],
|
||||
self.property.roof["is_flat"]
|
||||
string_thickness=self.property.roof["insulation_thickness"],
|
||||
is_pitched=self.property.roof["is_pitched"],
|
||||
is_flat=self.property.roof["is_flat"]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
@ -300,6 +300,10 @@ class RoofRecommendations:
|
|||
):
|
||||
return False
|
||||
|
||||
if self.property.roof["original_description"] is None:
|
||||
# There is no description so we cannot make an assessment
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
|
|
|
|||
|
|
@ -8,6 +8,30 @@ from recommendations.tests.test_data.materials import materials
|
|||
|
||||
class TestRoofRecommendations:
|
||||
|
||||
def test_null_roof_description(self):
|
||||
epc_record = EPCRecord()
|
||||
epc_record.prepared_epc = {
|
||||
"county": "Cambridgeshire",
|
||||
}
|
||||
property_instance = Property(id=0, address="fake", postcode="fake", epc_record=epc_record)
|
||||
property_instance.age_band = "F"
|
||||
property_instance.insulation_floor_area = 100
|
||||
property_instance.roof = {
|
||||
'original_description': None,
|
||||
'clean_description': None,
|
||||
'thermal_transmittance': None,
|
||||
'thermal_transmittance_unit': None,
|
||||
'is_pitched': True, 'is_roof_room': False, 'is_loft': False, 'is_flat': False, 'is_thatched': False,
|
||||
'is_at_rafters': False, 'is_assumed': True, 'has_dwelling_above': False, 'is_valid': True,
|
||||
'insulation_thickness': 'none', 'roof_thermal_transmittance': None, 'roof_insulation_thickness': None
|
||||
}
|
||||
property_instance.already_installed = []
|
||||
|
||||
roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials)
|
||||
roof_recommender.recommend(phase=0)
|
||||
|
||||
assert not roof_recommender.recommendations
|
||||
|
||||
def test_loft_insulation_recommendation_no_insulation(self):
|
||||
epc_record = EPCRecord()
|
||||
epc_record.prepared_epc = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue