mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
cater for goal_value being NULL 🟥
This commit is contained in:
parent
70fd417c4a
commit
080000123f
6 changed files with 54 additions and 37 deletions
|
|
@ -32,7 +32,7 @@ class PortfolioStatus(enum.Enum):
|
|||
NEEDS_REVIEW = "needs review"
|
||||
|
||||
|
||||
class PortfolioGoal(enum.Enum):
|
||||
class PortfolioGoal(enum.Enum): # TODO: Move to domain?
|
||||
VALUATION_IMPROVEMENT = "Valuation Improvement"
|
||||
INCREASING_EPC = "Increasing EPC"
|
||||
REDUCING_CO2_EMISSIONS = "Reducing CO2 emissions"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ from sqlalchemy.orm import declarative_base, Mapped, mapped_column
|
|||
from sqlalchemy.sql import func
|
||||
from datetime import datetime
|
||||
|
||||
from backend.app.db.models.portfolio import Portfolio, PropertyModel
|
||||
from backend.app.db.models.portfolio import Portfolio, PortfolioGoal, PropertyModel
|
||||
from backend.app.db.models.materials import Material
|
||||
from backend.app.db.models.portfolio import Epc
|
||||
from datatypes.enums import QuantityUnits
|
||||
|
|
@ -152,8 +152,8 @@ class ScenarioModel(Base):
|
|||
BigInteger, ForeignKey(Portfolio.id), nullable=False
|
||||
)
|
||||
housing_type: Mapped[str] = mapped_column(String, nullable=False)
|
||||
goal: Mapped[str] = mapped_column(String, nullable=False)
|
||||
goal_value: Mapped[str] = mapped_column(String, nullable=False)
|
||||
goal: Mapped[PortfolioGoal] = mapped_column(Enum(PortfolioGoal), nullable=False)
|
||||
goal_value: Mapped[Optional[str]] = mapped_column(String, nullable=False)
|
||||
trigger_file_path: Mapped[str] = mapped_column(String, nullable=False)
|
||||
already_installed_file_path: Mapped[Optional[str]] = mapped_column(String)
|
||||
patches_file_path: Mapped[Optional[str]] = mapped_column(String)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
|||
from dataclasses import replace
|
||||
from typing import Optional
|
||||
|
||||
from backend.app.db.models.portfolio import PortfolioGoal
|
||||
from backend.app.db.models.recommendations import PlanModel
|
||||
from backend.app.domain.classes.scenario import Scenario
|
||||
from backend.app.domain.records.plan_record import PlanRecord
|
||||
|
|
@ -48,5 +49,14 @@ class Plan:
|
|||
def is_compliant(self) -> bool:
|
||||
raise NotImplementedError
|
||||
|
||||
goal: PortfolioGoal = self.scenario.record.goal
|
||||
goal_value: str = self.scenario.record.goal_value
|
||||
|
||||
match goal:
|
||||
case PortfolioGoal.INCREASING_EPC:
|
||||
return True
|
||||
case _:
|
||||
raise NotImplementedError
|
||||
|
||||
def set_default(self, value: bool) -> None:
|
||||
self.record = replace(self.record, is_default=value)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ from backend.app.domain.records.scenario_record import ScenarioRecord
|
|||
class Scenario:
|
||||
def __init__(self, record: ScenarioRecord, id: Optional[int] = None):
|
||||
self.id = id
|
||||
self._record = record
|
||||
self.record = record
|
||||
|
||||
@classmethod
|
||||
def from_sqlalchemy(cls, scenario_model: ScenarioModel) -> Scenario:
|
||||
|
|
@ -55,4 +55,4 @@ class Scenario:
|
|||
return cls(record, scenario_model.id)
|
||||
|
||||
def set_default(self, value: bool) -> None:
|
||||
self._record = replace(self._record, is_default=value)
|
||||
self.record = replace(self.record, is_default=value)
|
||||
|
|
|
|||
|
|
@ -2,14 +2,15 @@ from dataclasses import dataclass
|
|||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from backend.app.db.models.portfolio import PortfolioGoal
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ScenarioRecord:
|
||||
name: str
|
||||
created_at: datetime
|
||||
housing_type: str
|
||||
goal: str
|
||||
goal_value: str
|
||||
goal: PortfolioGoal
|
||||
trigger_file_path: str
|
||||
multi_plan: bool
|
||||
is_default: bool
|
||||
|
|
@ -19,6 +20,7 @@ class ScenarioRecord:
|
|||
non_invasive_recommendations_file_path: Optional[str] = None
|
||||
exclusions: Optional[str] = None
|
||||
|
||||
goal_value: Optional[str] = None
|
||||
cost: Optional[float] = None
|
||||
contingency: Optional[float] = None
|
||||
funding: Optional[float] = None
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from typing import Callable
|
||||
from typing import Callable, Optional
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
|
||||
|
|
@ -6,7 +6,7 @@ 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
|
||||
from backend.app.db.models.portfolio import Epc, PortfolioGoal
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
@ -14,28 +14,17 @@ 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":
|
||||
created_at_datetime: datetime,
|
||||
) -> Callable[[int, "Epc", "Scenario"], "Plan"]:
|
||||
"""
|
||||
Returns a factory function to create plans with different attributes and scenarios.
|
||||
"""
|
||||
|
||||
def _create_plan(
|
||||
post_sap_points: int, post_epc_rating: "Epc", scenario: "Scenario"
|
||||
) -> "Plan":
|
||||
plan_record = PlanRecord(
|
||||
property_id=1,
|
||||
portfolio_id=1,
|
||||
|
|
@ -44,27 +33,43 @@ def plan_factory(
|
|||
post_sap_points=post_sap_points,
|
||||
post_epc_rating=post_epc_rating,
|
||||
)
|
||||
return Plan(record=plan_record, scenario=epc_c_scenario, id=1)
|
||||
return Plan(record=plan_record, scenario=scenario, id=1)
|
||||
|
||||
return _create_plan
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"post_sap_points, post_epc_rating, expected_compliance",
|
||||
"scenario_name, goal_value, post_sap_points, post_epc_rating, expected_compliance",
|
||||
[
|
||||
(75, Epc.C, True),
|
||||
(100, Epc.A, True),
|
||||
(60, Epc.D, False),
|
||||
("EPC C", "C", 75, Epc.C, True),
|
||||
("EPC A", "A", 100, Epc.A, True),
|
||||
("EPC D", "D", 60, Epc.D, False),
|
||||
("Achieve EPC B", None, 100, Epc.A, True),
|
||||
("Achieve EPC B", None, 60, Epc.D, False),
|
||||
],
|
||||
)
|
||||
def test_scenario_goal_is_epc_c(
|
||||
plan_factory: Callable[[int, "Epc"], "Plan"],
|
||||
plan_factory: Callable[[int, "Epc", "Scenario"], "Plan"],
|
||||
scenario_name: str,
|
||||
goal_value: Optional[str],
|
||||
post_sap_points: int,
|
||||
post_epc_rating: "Epc",
|
||||
expected_compliance: bool,
|
||||
) -> None:
|
||||
# arrange
|
||||
plan = plan_factory(post_sap_points, post_epc_rating)
|
||||
scenario_record = ScenarioRecord(
|
||||
name=scenario_name,
|
||||
created_at=datetime.now(),
|
||||
housing_type="",
|
||||
goal=PortfolioGoal.INCREASING_EPC,
|
||||
goal_value=goal_value,
|
||||
trigger_file_path="",
|
||||
multi_plan=False,
|
||||
is_default=False,
|
||||
)
|
||||
scenario = Scenario(record=scenario_record, id=1)
|
||||
|
||||
plan = plan_factory(post_sap_points, post_epc_rating, scenario)
|
||||
|
||||
# act
|
||||
actual_compliance: bool = plan.is_compliant
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue