handling ambiguous cases for sloping ceiling vs loft insulation

This commit is contained in:
Khalim Conn-Kowlessar 2026-01-28 09:32:32 +00:00
parent 79ef0805c3
commit 81fc264afe
2 changed files with 73 additions and 3 deletions

View file

@ -122,12 +122,16 @@ class RoofRecommendations:
@staticmethod
def is_sloping_ceiling_appropriate(
is_pitched: bool, is_loft: bool, is_assumed: bool, has_sloping_ceiling_recommendation: bool,
primary_roof_is_sloped: bool, insulation_thickness: str
is_pitched: bool, is_loft: bool, is_assumed: bool,
is_flat: bool,
has_sloping_ceiling_recommendation: bool,
primary_roof_is_sloped: bool, insulation_thickness: str,
has_loft_insulation_recommendation: bool
) -> bool:
"""
:param is_pitched: Boolean - indicates whether or not the roof is pitched
:param is_flat: Boolean - indicates whether or not the roof is flat
:param is_loft: Boolean - indicates whether or not the roof is described as a loft
:param is_assumed: Boolean - indiates if the assessment of the roof is assumed or actually confirmed
:param has_sloping_ceiling_recommendation: Boolean - indicates if the property has a sloping ceiling
@ -135,6 +139,7 @@ class RoofRecommendations:
:param primary_roof_is_sloped: Boolean - indicates if the primary room is described a sloped (as opposed to
an extension)
:param insulation_thickness: String - insulation thickness of the roof
:param has_loft_insulation_recommendation: Boolean - indicates whether or not there
:return:
"""
# We need to check:
@ -166,6 +171,11 @@ class RoofRecommendations:
if has_suitable_features and needs_recommendation:
return True
# In this case, we have an assumed pitched roof with average or below average insulation
# but a sloping ceiling insulation without loft
if has_sloping_ceiling_recommendation and not has_loft_insulation_recommendation and not is_flat:
return True
return False
@staticmethod
@ -504,6 +514,7 @@ class RoofRecommendations:
has_loft_insulation_recommendation = any(x["type"] == "loft_insulation" for x in non_invasive_recommendations)
has_flat_roof_recommendation = any(x["type"] == "flat_roof_insulation" for x in non_invasive_recommendations)
has_room_roof_recommendation = any(x["type"] == "room_roof_insulation" for x in non_invasive_recommendations)
# Very naive condition
primary_roof_is_sloped = self._is_primary_roof_sloped(
is_pitched=is_pitched, is_loft=is_loft, is_assumed=is_assumed
)

View file

@ -1,7 +1,6 @@
import pytest
from unittest.mock import Mock
from backend.Property import Property
from etl.customers.immo.pilot.asset_list import non_invasive_recommendations
from etl.epc.Record import EPCRecord
from recommendations.RoofRecommendations import RoofRecommendations
from recommendations.tests.test_data.materials import materials
@ -711,3 +710,63 @@ class TestRoofRecommendations:
assert len(roof_recommender.recommendations) == 3
# should all be loft insulation recommendations
assert all(rec["type"] == "loft_insulation" for rec in roof_recommender.recommendations)
def sloping_ceiling_limited_insulation(self):
property_instance = Mock(
id=0,
roof={
"original_description": 'Pitched, limited insulation (assumed)',
'clean_description': 'Pitched, limited insulation',
'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': 'below average'
},
roof_area=35,
data={"county": None, "local-authority-label": "Manchester"},
already_installed=[],
find_my_epc_components=[
{'component_name': 'Wall', 'description': 'Cavity wall, as built, no insulation (assumed)',
'efficiency': 'poor', 'appearance_index': 0},
{'component_name': 'Roof', 'description': 'Pitched, limited insulation (assumed)',
'efficiency': 'Very poor', 'appearance_index': 0},
{'component_name': 'Window', 'description': 'Fully double glazed', 'efficiency': 'Average',
'appearance_index': 0},
{'component_name': 'Main heating', 'description': 'Boiler and radiators, mains gas',
'efficiency': 'Good', 'appearance_index': 0},
{'component_name': 'Main heating control', 'description': 'TRVs and bypass',
'efficiency': 'Average', 'appearance_index': 0},
{'component_name': 'Hot water', 'description': 'From main system', 'efficiency': 'Good',
'appearance_index': 0},
{'component_name': 'Lighting', 'description': 'Low energy lighting in all fixed outlets',
'efficiency': 'Very good', 'appearance_index': 0},
{'component_name': 'Floor', 'description': '(another dwelling below)', 'efficiency': 'N/A',
'appearance_index': 0},
{'component_name': 'Secondary heating', 'description': 'None', 'efficiency': 'N/A',
'appearance_index': 0}
],
age_band="B",
non_invasive_recommendations=[
{'type': 'sloping_ceiling_insulation', 'sap_points': 2, 'survey': True},
{'type': 'flat_roof_insulation', 'sap_points': 2, 'survey': True},
],
)
# We expect a sloping ceiling insulation recommendation
roof_recommender = RoofRecommendations(property_instance=property_instance, materials=materials)
assert not roof_recommender.recommendations
roof_recommender.recommend(phase=0)
assert len(roof_recommender.recommendations) == 1
assert roof_recommender.recommendations[0]["type"] == "sloping_ceiling_insulation"
assert roof_recommender.recommendations[0]["measure_type"] == "sloping_ceiling_insulation"
assert roof_recommender.recommendations[0]["description"] == \
"Insulate sloping ceilings at the rafters and re-decorate"
assert roof_recommender.recommendations[0]["simulation_config"] == {
'roof_insulation_thickness_ending': 'average',
'roof_thermal_transmittance_ending': 0.5,
'roof_energy_eff_ending': 'Average'
}
assert roof_recommender.recommendations[0]["description_simulation"] == {
'roof-description': 'Pitched, insulated', 'roof-energy-eff': 'Average'
}