From 015db4275b0adf8432388d025c10168814a6d6ef Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 7 Jul 2026 16:08:30 +0000 Subject: [PATCH] =?UTF-8?q?The=20plan=20repository=20reports=20which=20pro?= =?UTF-8?q?perties=20already=20have=20a=20default=20plan=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- repositories/plan/plan_postgres_repository.py | 3 +++ repositories/plan/plan_repository.py | 8 +++++++ tests/orchestration/fakes.py | 5 +++++ .../plan/test_plan_postgres_repository.py | 21 +++++++++++++++++++ 4 files changed, 37 insertions(+) diff --git a/repositories/plan/plan_postgres_repository.py b/repositories/plan/plan_postgres_repository.py index e81e90844..c2685ace4 100644 --- a/repositories/plan/plan_postgres_repository.py +++ b/repositories/plan/plan_postgres_repository.py @@ -45,6 +45,9 @@ class PlanPostgresRepository(PlanRepository): [PlanSaveRequest(plan, property_id=property_id, scenario_id=scenario_id, portfolio_id=portfolio_id, is_default=is_default)] )[0] + def property_ids_with_default_plans(self, property_ids: list[int]) -> set[int]: + raise NotImplementedError + def save_batch(self, requests: list[PlanSaveRequest]) -> list[int]: """Persist all Plans in three statements regardless of batch size. diff --git a/repositories/plan/plan_repository.py b/repositories/plan/plan_repository.py index 6fdc16d63..149a88618 100644 --- a/repositories/plan/plan_repository.py +++ b/repositories/plan/plan_repository.py @@ -54,3 +54,11 @@ class PlanRepository(ABC): UPDATE only when at least one request has ``is_default=True``. Keeps prior Plans as history (ADR-0017).""" ... + + @abstractmethod + def property_ids_with_default_plans(self, property_ids: list[int]) -> set[int]: + """The subset of ``property_ids`` that already have a default Plan. + A property outside this set is receiving its first Plan, which becomes + its default whatever the Scenario says (the legacy ``p.is_new`` rule — + readers need one default Plan per property).""" + ... diff --git a/tests/orchestration/fakes.py b/tests/orchestration/fakes.py index d5fe016a8..52f409693 100644 --- a/tests/orchestration/fakes.py +++ b/tests/orchestration/fakes.py @@ -240,6 +240,11 @@ class FakePlanRepository(PlanRepository): for r in requests ] + def property_ids_with_default_plans(self, property_ids: list[int]) -> set[int]: + # The fake store does not track defaults; every property reads as + # first-time (no default yet). + return set() + class _UnsetProductRepo(ProductRepository): """Default for a `FakeUnitOfWork` built without a catalogue — raises if a diff --git a/tests/repositories/plan/test_plan_postgres_repository.py b/tests/repositories/plan/test_plan_postgres_repository.py index 200c38d6b..2d3fb7473 100644 --- a/tests/repositories/plan/test_plan_postgres_repository.py +++ b/tests/repositories/plan/test_plan_postgres_repository.py @@ -206,3 +206,24 @@ def test_rerun_as_non_default_does_not_demote_the_prior_default( assert len(plan_rows) == 2 assert by_id[first_id].is_default is True + + +def test_reports_which_properties_already_have_a_default_plan( + db_engine: Engine, +) -> None: + # Arrange — property 20 has a default Plan, 21 only a non-default one, + # 22 has no Plans at all + with Session(db_engine) as session: + repo = PlanPostgresRepository(session) + repo.save(_plan(), property_id=20, scenario_id=7, portfolio_id=1, is_default=True) + repo.save(_plan(), property_id=21, scenario_id=7, portfolio_id=1, is_default=False) + session.commit() + + # Act + with Session(db_engine) as session: + have_default = PlanPostgresRepository(session).property_ids_with_default_plans( + [20, 21, 22] + ) + + # Assert — only the property with a default Plan is reported + assert have_default == {20}