From 70fd417c4a5d4a4e886cbf2b720379e7c195dc8f Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 12 Feb 2026 15:04:02 +0000 Subject: [PATCH] =?UTF-8?q?Check=20whether=20plan=20with=20EPC=20goal=20is?= =?UTF-8?q?=20compliant=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/domain/classes/plan.py | 5 +- backend/app/domain/records/plan_record.py | 1 - .../tests/test_plan_is_compliant.py | 73 +++++++++++++++++++ pytest.ini | 2 +- 4 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 backend/categorisation/tests/test_plan_is_compliant.py diff --git a/backend/app/domain/classes/plan.py b/backend/app/domain/classes/plan.py index 3540c603..76aba958 100644 --- a/backend/app/domain/classes/plan.py +++ b/backend/app/domain/classes/plan.py @@ -23,7 +23,6 @@ class Plan: record = PlanRecord( property_id=plan_model.property_id, portfolio_id=plan_model.portfolio_id, - scenario_id=plan_model.scenario_id, created_at=plan_model.created_at, is_default=plan_model.is_default, valuation_increase_lower_bound=plan_model.valuation_increase_lower_bound, @@ -45,5 +44,9 @@ class Plan: ) return cls(record=record, scenario=scenario, id=plan_model.id) + @property + def is_compliant(self) -> bool: + raise NotImplementedError + def set_default(self, value: bool) -> None: self.record = replace(self.record, is_default=value) diff --git a/backend/app/domain/records/plan_record.py b/backend/app/domain/records/plan_record.py index dee7cb4b..2df7a7c6 100644 --- a/backend/app/domain/records/plan_record.py +++ b/backend/app/domain/records/plan_record.py @@ -10,7 +10,6 @@ from backend.app.db.models.recommendations import PlanTypeEnum class PlanRecord: property_id: int portfolio_id: int - scenario_id: Optional[int] created_at: datetime is_default: bool diff --git a/backend/categorisation/tests/test_plan_is_compliant.py b/backend/categorisation/tests/test_plan_is_compliant.py new file mode 100644 index 00000000..41fb1b85 --- /dev/null +++ b/backend/categorisation/tests/test_plan_is_compliant.py @@ -0,0 +1,73 @@ +from typing import Callable +import pytest +from datetime import datetime + +from backend.app.domain.classes.plan import Plan +from backend.app.domain.classes.scenario import Scenario +from backend.app.domain.records.plan_record import PlanRecord +from backend.app.domain.records.scenario_record import ScenarioRecord +from backend.app.db.models.portfolio import Epc + + +@pytest.fixture +def created_at_datetime() -> datetime: + return datetime.now() + + +@pytest.fixture +def epc_c_scenario(created_at_datetime: datetime) -> "Scenario": + # arrange + scenario_record = ScenarioRecord( + name="EPC C", + created_at=created_at_datetime, + housing_type="", + goal="EPC", + goal_value="C", + trigger_file_path="", + multi_plan=False, + is_default=False, + ) + return Scenario(record=scenario_record, id=1) + + +@pytest.fixture +def plan_factory( + epc_c_scenario: "Scenario", created_at_datetime: datetime +) -> Callable[[int, "Epc"], "Plan"]: + # returns a function to create plans with different attributes + def _create_plan(post_sap_points: int, post_epc_rating: "Epc") -> "Plan": + plan_record = PlanRecord( + property_id=1, + portfolio_id=1, + created_at=created_at_datetime, + is_default=False, + post_sap_points=post_sap_points, + post_epc_rating=post_epc_rating, + ) + return Plan(record=plan_record, scenario=epc_c_scenario, id=1) + + return _create_plan + + +@pytest.mark.parametrize( + "post_sap_points, post_epc_rating, expected_compliance", + [ + (75, Epc.C, True), + (100, Epc.A, True), + (60, Epc.D, False), + ], +) +def test_scenario_goal_is_epc_c( + plan_factory: Callable[[int, "Epc"], "Plan"], + post_sap_points: int, + post_epc_rating: "Epc", + expected_compliance: bool, +) -> None: + # arrange + plan = plan_factory(post_sap_points, post_epc_rating) + + # act + actual_compliance: bool = plan.is_compliant + + # assert + assert actual_compliance == expected_compliance diff --git a/pytest.ini b/pytest.ini index ee203d46..9c9f8234 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,4 +1,4 @@ [pytest] pythonpath = . addopts = --cov-report term-missing --cov=etl/epc --cov=recommendations --cov=backend --cov=etl/epc_clean --cov=etl/spatial -testpaths = recommendations/tests backend/tests etl/epc/tests etl/epc_clean/tests etl/spatial/tests backend/condition/tests backend/address2UPRN/tests backend/onboarders/tests +testpaths = recommendations/tests backend/tests etl/epc/tests etl/epc_clean/tests etl/spatial/tests backend/condition/tests backend/address2UPRN/tests backend/onboarders/tests backend/categorisation/tests