From 490c8946d721725b16a90d40903ff667757b86cb Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 18 Feb 2026 17:11:00 +0000 Subject: [PATCH] Unset existing default before setting new one --- .../db/functions/recommendations_functions.py | 34 +++++++++++++++++++ .../local_handler/invoke_local_lambda.py | 2 +- backend/categorisation/processor.py | 16 +++++++-- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/backend/app/db/functions/recommendations_functions.py b/backend/app/db/functions/recommendations_functions.py index d4c3fcb9..3af9fd29 100644 --- a/backend/app/db/functions/recommendations_functions.py +++ b/backend/app/db/functions/recommendations_functions.py @@ -646,6 +646,40 @@ def get_scenario(scenario_id: int) -> Optional[ScenarioModel]: return session_any.exec(stmt).scalar_one_or_none() +def get_default_plan_ids_for_property(property_id: int) -> List[int]: + # This should in reality always return exactly 1 ID, but there's currently + # no database constraint to enforce that, so account for 0 or >1 + stmt = select(PlanModel.id).where( + PlanModel.property_id == property_id and PlanModel.is_default + ) + with db_read_session() as session: + session_any: Any = session # Typehint as Any to satisfy Pylance... + return session_any.exec(stmt).scalars().all() + + +def set_plan_and_scenario_default(plan_id: int, default: bool) -> bool: + with db_session() as session: + plan: PlanModel = session.get(PlanModel, plan_id) + if not plan: + return False + + scenario_id = plan.scenario_id + + plan_mapper: Mapper[Any] = inspect(PlanModel) + scenario_mapper: Mapper[Any] = inspect(ScenarioModel) + + plan_mappings: List[Dict[str, Any]] = [{"id": plan.id, "is_default": default}] + scenario_mappings: List[Dict[str, Any]] = [ + {"id": scenario_id, "is_default": default} + ] + + session.bulk_update_mappings(plan_mapper, plan_mappings) + session.bulk_update_mappings(scenario_mapper, scenario_mappings) + session.commit() + + return True + + def bulk_update_plans( plan_models: List[PlanModel], scenario_models: List[ScenarioModel], diff --git a/backend/categorisation/local_handler/invoke_local_lambda.py b/backend/categorisation/local_handler/invoke_local_lambda.py index 9eb5adda..23e5fda2 100644 --- a/backend/categorisation/local_handler/invoke_local_lambda.py +++ b/backend/categorisation/local_handler/invoke_local_lambda.py @@ -10,7 +10,7 @@ payload = { "body": json.dumps( { "portfolio_id": 556, - "plans_to_consider": [], + "plans_to_consider": [1589319, 1589320], "plan_priority_order": [], } ) diff --git a/backend/categorisation/processor.py b/backend/categorisation/processor.py index b7ddfc62..b07f1c3b 100644 --- a/backend/categorisation/processor.py +++ b/backend/categorisation/processor.py @@ -3,9 +3,11 @@ from typing import Dict, List, Optional from backend.app.db.functions.recommendations_functions import ( bulk_update_plans, + get_default_plan_ids_for_property, get_plans_by_ids, get_plans_by_portfolio_id, get_scenarios_by_portfolio_id, + set_plan_and_scenario_default, ) from backend.app.db.models.recommendations import PlanModel, ScenarioModel from backend.app.domain.classes.plan import Plan @@ -26,15 +28,23 @@ def process_portfolio( plans_by_property: Dict[int, List[Plan]] = _group_plans_by_property(plans) - for uprn, property_plans in plans_by_property.items(): + for property_id, property_plans in plans_by_property.items(): if not property_plans: - raise ValueError(f"No plans for property {uprn}") + raise ValueError(f"No plans for property {property_id}") cheapest_plan = choose_cheapest_relevant_plan( property_plans, plan_priority_order ) - _update_default_flags(property_plans, cheapest_plan) + + # Unset existing default(s) in case they are outside the plans to consider + default_plan_ids: List[int] = get_default_plan_ids_for_property(property_id) + for id in default_plan_ids: + set_plan_and_scenario_default(id, False) + + _update_default_flags( + property_plans, cheapest_plan + ) # TODO: we have already unset existing default(s), so this method can probably be a bit simpler now def choose_cheapest_relevant_plan(