From e8b7a569ff2daca125fd830da926575704fe66e9 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 26 Jan 2026 13:25:15 +0000 Subject: [PATCH] working on rir insulation| --- .idea/copilot.data.migration.ask.xml | 6 ++ .idea/copilot.data.migration.edit.xml | 6 ++ recommendations/RoofRecommendations.py | 113 +++++++++++++++++++------ 3 files changed, 100 insertions(+), 25 deletions(-) create mode 100644 .idea/copilot.data.migration.ask.xml create mode 100644 .idea/copilot.data.migration.edit.xml diff --git a/.idea/copilot.data.migration.ask.xml b/.idea/copilot.data.migration.ask.xml new file mode 100644 index 00000000..7ef04e2e --- /dev/null +++ b/.idea/copilot.data.migration.ask.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/copilot.data.migration.edit.xml b/.idea/copilot.data.migration.edit.xml new file mode 100644 index 00000000..8648f940 --- /dev/null +++ b/.idea/copilot.data.migration.edit.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/recommendations/RoofRecommendations.py b/recommendations/RoofRecommendations.py index 1d6fe06c..6625aeb0 100644 --- a/recommendations/RoofRecommendations.py +++ b/recommendations/RoofRecommendations.py @@ -170,7 +170,13 @@ class RoofRecommendations: @staticmethod def is_loft_insulation_appropriate( - non_invasive_recommendations, measures, is_pitched, is_at_rafters, rir_over_loft + measures: List, + is_pitched: bool, + is_at_rafters: bool, + rir_over_loft: bool, + is_assumed: bool, + has_loft_insulation_recommendation: bool, + has_sloping_ceiling_recommendation: bool ) -> bool: """ Determine if loft insulation is appropriate @@ -179,36 +185,59 @@ class RoofRecommendations: :param is_pitched: Boolean - indicates whether or not the roof is pitched :param is_at_rafters: Boolean - indicates whether or not the loft insulation is at rafters :param rir_over_loft: Boolean - indicates whether or not there we should be doing RIR insulation + :param is_assumed: Boolean - indicates whether or not the roof insulation status is assumed + :param has_loft_insulation_recommendation: Boolean - indicates whether or not there + is a loft insulation non-invasive recommendation + :param has_sloping_ceiling_recommendation: Boolean - indicates whether or not there + is a sloping ceiling non-invasive recommendation :return: """ has_li_in_measures = "loft_insulation" in measures - has_li_non_invasive_recommendation = any( - x["type"] == "loft_insulation" for x in non_invasive_recommendations - ) - return has_li_non_invasive_recommendation or ( + # Key business logic: + # If we have a pitched roof, no insulation, it's not assumed and we have a sloping ceiling recommendation, + # we do NOT recommend loft insulation + if is_pitched and not is_assumed and has_sloping_ceiling_recommendation: + return False + + return has_loft_insulation_recommendation or ( is_pitched and has_li_in_measures and not is_at_rafters ) and not rir_over_loft @staticmethod def is_flat_roof_insulation_appropriate( - is_flat: bool, measures: List, non_invasive_recommendations: List + is_flat: bool, measures: List, has_flat_roof_recommendation: bool ) -> bool: """ Determine if flat roof insulation is appropriate :param is_flat: Boolean - indicates whether or not the roof is flat :param measures: List - list of measures - :param non_invasive_recommendations: List - list of non-invasive recommendations - :return: + :param has_flat_roof_recommendation: Boolean - indicates whether or not there is a flat roof non-invasive + recommendation + :return: Boolean """ flat_roof_in_measures = "flat_roof_insulation" in measures - flat_roof_non_invasive_rec = has_li_non_invasive_recommendation = any( - x["type"] == "flat_roof_insulation" for x in non_invasive_recommendations - ) - return (is_flat and flat_roof_in_measures) or flat_roof_non_invasive_rec + return (is_flat and flat_roof_in_measures) or has_flat_roof_recommendation + + @staticmethod + def is_room_roof_insulation_appropriate( + is_room_roof, measures, rir_over_loft, has_room_roof_recommendation + ): + """ + Determine if room roof insulation is appropriate + :param is_room_roof: Boolean - indicates whether or not the roof is a room roof + :param measures: List - list of measures + :param rir_over_loft: Boolean - indicates whether or not there we should be doing RIR insulation + :param has_room_roof_recommendation: Boolean - indicates whether or not there is a room roof non-invasive + recommendation + :return: + """ + return is_room_roof and ("room_roof_insulation" in measures) or ( + has_room_roof_recommendation or rir_over_loft + ) def _does_roof_need_recommendation(self, measures: List | None = None, u_value: float | None = None): """ @@ -243,6 +272,28 @@ class RoofRecommendations: ): return False + @staticmethod + def _is_primary_roof_sloped( + is_pitched: bool, is_loft: bool, is_assumed: bool + ): + """ + Determine if the primary roof is sloped + :param is_pitched: bool - is the roof pitched + :param is_loft: bool - is the roof a loft + :param is_assumed: bool - is the roof insulation status assumed + :return: + """ + # Conditions for this to be true + # Case 1 + # In the property roof description (primary roof) + # 1) Pitched Roof + # 2) Uninsulated + # 3) Not assumed + if is_pitched and not is_loft and not is_assumed: + return True + + return False + def recommend(self, phase: int, measures: List | None = None, default_u_values: bool = False): """ Main method to recommend roof insulation measures @@ -290,14 +341,21 @@ class RoofRecommendations: is_loft = self.property.roof["is_loft"] is_assumed = self.property.roof["is_assumed"] is_at_rafters = self.property.roof["is_at_rafters"] + is_flat = self.property.roof["is_flat"] + is_room_roof = self.property.roof["is_roof_room"] + has_sloping_ceiling_recommendation = any( x["type"] == "sloping_ceiling_insulation" for x in non_invasive_recommendations ) - primary_roof_is_sloped = False # TODO + 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) + primary_roof_is_sloped = self._is_primary_roof_sloped( + is_pitched=is_pitched, is_loft=is_loft, is_assumed=is_assumed + ) rir_over_loft = ( - is_pitched and - self.property.roof["insulation_thickness"] == "none" and + is_pitched and self.property.roof["insulation_thickness"] == "none" and "room_in_roof_insulation" in [x["type"] for x in non_invasive_recommendations] ) @@ -308,8 +366,19 @@ class RoofRecommendations: ) needs_loft_insulation = self.is_loft_insulation_appropriate( - non_invasive_recommendations=non_invasive_recommendations, measures=measures, - is_pitched=is_pitched, is_at_rafters=is_at_rafters, rir_over_loft=rir_over_loft + measures=measures, is_pitched=is_pitched, is_at_rafters=is_at_rafters, + rir_over_loft=rir_over_loft, has_loft_insulation_recommendation=has_loft_insulation_recommendation, + is_assumed=is_assumed, has_sloping_ceiling_recommendation=has_sloping_ceiling_recommendation + ) + + needs_flat_roof_insulation = self.is_flat_roof_insulation_appropriate( + is_flat=is_flat, measures=measures, has_flat_roof_recommendation=has_flat_roof_recommendation + ) + needs_rir_insulation = self.is_room_roof_insulation_appropriate( + is_room_roof=is_room_roof, + measures=measures, + rir_over_loft=rir_over_loft, + has_room_roof_recommendation=has_room_roof_recommendation ) ################################################## @@ -327,10 +396,7 @@ class RoofRecommendations: ) return - if ( - (self.property.roof["is_flat"] and "flat_roof_insulation" in measures) or - "flat_roof_insulation" in [x["type"] for x in non_invasive_recommendations] - ): + if needs_flat_roof_insulation: self.recommend_roof_insulation( u_value=u_value, insulation_thickness=0, @@ -343,10 +409,7 @@ class RoofRecommendations: # There are cases where the property might have a room roof as the second roof, but we have a recommendation for # it, so we allow this override - if self.property.roof["is_roof_room"] and ("room_roof_insulation" in measures) or ( - "room_roof_insulation" in [x["type"] for x in non_invasive_recommendations] or - rir_over_loft - ): + if needs_rir_insulation: self.recommend_room_roof_insulation(u_value, phase, default_u_values) return