From d1be7c28427b3d2be7a14e72c641acb7a9e3811c Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 09:32:50 +0000 Subject: [PATCH 01/11] =?UTF-8?q?Prefer=20the=20newer=20of=20a=20stored=20?= =?UTF-8?q?survey=20and=20a=20fetched=20gov=20cert=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- applications/modelling_e2e/handler.py | 9 +++++ .../modelling_e2e/test_handler.py | 37 ++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/applications/modelling_e2e/handler.py b/applications/modelling_e2e/handler.py index 3442cb362..e0c31ca37 100644 --- a/applications/modelling_e2e/handler.py +++ b/applications/modelling_e2e/handler.py @@ -387,6 +387,15 @@ def _dedupe_skipped( return unique +def _newer_lodged( + stored: Optional[EpcPropertyData], fetched: Optional[EpcPropertyData] +) -> tuple[Optional[EpcPropertyData], bool]: + """ADR-0001 Recency Tie-Break over the two lodged sources. Returns + (chosen, chosen_is_fetched) — the bool gates the EPC save, so a stored EPC + that wins is never re-persisted.""" + raise NotImplementedError + + def _predict_epc( *, property_id: int, diff --git a/tests/applications/modelling_e2e/test_handler.py b/tests/applications/modelling_e2e/test_handler.py index b51f784a7..e2396e0c9 100644 --- a/tests/applications/modelling_e2e/test_handler.py +++ b/tests/applications/modelling_e2e/test_handler.py @@ -7,7 +7,11 @@ is needed. One test per distinct behaviour path. from __future__ import annotations +import dataclasses +import json from contextlib import ExitStack +from datetime import date +from pathlib import Path from typing import Any, Iterator, Optional from unittest.mock import MagicMock, call, patch from uuid import UUID, uuid4 @@ -18,6 +22,8 @@ from pydantic import ValidationError from applications.modelling_e2e.modelling_e2e_trigger_body import ( ModellingE2ETriggerBody, ) +from datatypes.epc.domain.epc_property_data import EpcPropertyData +from datatypes.epc.domain.mapper import EpcPropertyDataMapper from domain.tasks.subtasks import SubTask from repositories.epc.epc_postgres_repository import EpcSaveRequest @@ -1403,9 +1409,38 @@ def test_cohort_cache_prevents_duplicate_candidates_for_calls() -> None: # --------------------------------------------------------------------------- -# refetch_epc flag +# Recency Tie-Break between the two lodged sources (ADR-0001) # --------------------------------------------------------------------------- +_JSON_SAMPLES = Path(__file__).resolve().parents[3] / "backend/epc_api/json_samples" + + +def _lodged_epc(inspection: str) -> EpcPropertyData: + """A real lodged EPC surveyed on `inspection` — the tie-break reads only + inspection_date, but a real cert keeps the test honest about the type.""" + raw: dict[str, Any] = json.loads( + (_JSON_SAMPLES / "RdSAP-Schema-21.0.0" / "epc.json").read_text() + ) + epc = EpcPropertyDataMapper.from_api_response(raw) + return dataclasses.replace(epc, inspection_date=date.fromisoformat(inspection)) + + +def test_stored_survey_newer_than_gov_cert_wins_the_tie_break() -> None: + """The bug in #1589: a newer stored survey (e.g. PasHub site notes) must beat + an older gov-register cert, and must not be flagged for re-persisting.""" + # Arrange + from applications.modelling_e2e.handler import _newer_lodged + + stored = _lodged_epc("2026-05-01") + fetched = _lodged_epc("2023-12-01") + + # Act + chosen, chosen_is_fetched = _newer_lodged(stored, fetched) + + # Assert + assert chosen is stored + assert chosen_is_fetched is False + def test_refetch_epc_false_with_stored_epc_skips_api_call() -> None: """refetch_epc=False + stored lodged EPC present: EpcClientService.get_by_uprn From ec584fc84cab9c147788ef35f13a2085259247f4 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 09:33:06 +0000 Subject: [PATCH 02/11] =?UTF-8?q?Prefer=20the=20newer=20of=20a=20stored=20?= =?UTF-8?q?survey=20and=20a=20fetched=20gov=20cert=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- applications/modelling_e2e/handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/modelling_e2e/handler.py b/applications/modelling_e2e/handler.py index e0c31ca37..bbf88b5bc 100644 --- a/applications/modelling_e2e/handler.py +++ b/applications/modelling_e2e/handler.py @@ -393,7 +393,7 @@ def _newer_lodged( """ADR-0001 Recency Tie-Break over the two lodged sources. Returns (chosen, chosen_is_fetched) — the bool gates the EPC save, so a stored EPC that wins is never re-persisted.""" - raise NotImplementedError + return stored, False def _predict_epc( From 22bd0eadbe1bc8cf47c5a06d734eed0ca63fe520 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 09:33:28 +0000 Subject: [PATCH 03/11] =?UTF-8?q?Use=20the=20fetched=20gov=20cert=20when?= =?UTF-8?q?=20it=20is=20the=20newer=20assessment=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/applications/modelling_e2e/test_handler.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/applications/modelling_e2e/test_handler.py b/tests/applications/modelling_e2e/test_handler.py index e2396e0c9..18a887864 100644 --- a/tests/applications/modelling_e2e/test_handler.py +++ b/tests/applications/modelling_e2e/test_handler.py @@ -1442,6 +1442,22 @@ def test_stored_survey_newer_than_gov_cert_wins_the_tie_break() -> None: assert chosen_is_fetched is False +def test_gov_cert_newer_than_stored_survey_wins_and_is_flagged_for_saving() -> None: + """A genuinely fresher gov cert still wins, and is flagged new so it persists.""" + # Arrange + from applications.modelling_e2e.handler import _newer_lodged + + stored = _lodged_epc("2023-12-01") + fetched = _lodged_epc("2026-05-01") + + # Act + chosen, chosen_is_fetched = _newer_lodged(stored, fetched) + + # Assert + assert chosen is fetched + assert chosen_is_fetched is True + + def test_refetch_epc_false_with_stored_epc_skips_api_call() -> None: """refetch_epc=False + stored lodged EPC present: EpcClientService.get_by_uprn is never called; the stored EPC is used and reaches run_modelling.""" From dd1ea99c3d9dda7ad969c693ba1a932ed4b967db Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 09:34:37 +0000 Subject: [PATCH 04/11] =?UTF-8?q?Use=20the=20fetched=20gov=20cert=20when?= =?UTF-8?q?=20it=20is=20the=20newer=20assessment=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- applications/modelling_e2e/handler.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/applications/modelling_e2e/handler.py b/applications/modelling_e2e/handler.py index bbf88b5bc..8ff4497bd 100644 --- a/applications/modelling_e2e/handler.py +++ b/applications/modelling_e2e/handler.py @@ -393,6 +393,8 @@ def _newer_lodged( """ADR-0001 Recency Tie-Break over the two lodged sources. Returns (chosen, chosen_is_fetched) — the bool gates the EPC save, so a stored EPC that wins is never re-persisted.""" + if fetched is not None and fetched.inspection_date > stored.inspection_date: + return fetched, True return stored, False From 3a76bd0f7c0e7399486bb50131bd97206e71a99d Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 09:35:01 +0000 Subject: [PATCH 05/11] =?UTF-8?q?Use=20the=20fetched=20gov=20cert=20when?= =?UTF-8?q?=20nothing=20is=20stored=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/applications/modelling_e2e/test_handler.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/applications/modelling_e2e/test_handler.py b/tests/applications/modelling_e2e/test_handler.py index 18a887864..eb3e943c6 100644 --- a/tests/applications/modelling_e2e/test_handler.py +++ b/tests/applications/modelling_e2e/test_handler.py @@ -1458,6 +1458,21 @@ def test_gov_cert_newer_than_stored_survey_wins_and_is_flagged_for_saving() -> N assert chosen_is_fetched is True +def test_gov_cert_is_used_when_nothing_is_stored() -> None: + """Only the gov cert exists: it is the assessment, and it must be persisted.""" + # Arrange + from applications.modelling_e2e.handler import _newer_lodged + + fetched = _lodged_epc("2023-12-01") + + # Act + chosen, chosen_is_fetched = _newer_lodged(None, fetched) + + # Assert + assert chosen is fetched + assert chosen_is_fetched is True + + def test_refetch_epc_false_with_stored_epc_skips_api_call() -> None: """refetch_epc=False + stored lodged EPC present: EpcClientService.get_by_uprn is never called; the stored EPC is used and reaches run_modelling.""" From aeae322a4e67789839a909e508265f673c11f977 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 09:35:19 +0000 Subject: [PATCH 06/11] =?UTF-8?q?Use=20the=20fetched=20gov=20cert=20when?= =?UTF-8?q?=20nothing=20is=20stored=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- applications/modelling_e2e/handler.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/applications/modelling_e2e/handler.py b/applications/modelling_e2e/handler.py index 8ff4497bd..208b5ae7c 100644 --- a/applications/modelling_e2e/handler.py +++ b/applications/modelling_e2e/handler.py @@ -393,7 +393,11 @@ def _newer_lodged( """ADR-0001 Recency Tie-Break over the two lodged sources. Returns (chosen, chosen_is_fetched) — the bool gates the EPC save, so a stored EPC that wins is never re-persisted.""" - if fetched is not None and fetched.inspection_date > stored.inspection_date: + if fetched is None: + return stored, False + if stored is None: + return fetched, True + if fetched.inspection_date > stored.inspection_date: return fetched, True return stored, False From 04f72e2d320dfc3fa1bb8e4258e743264dcb1b85 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 09:36:21 +0000 Subject: [PATCH 07/11] =?UTF-8?q?Keep=20the=20stored=20survey=20when=20the?= =?UTF-8?q?=20register=20has=20no=20cert=20or=20ties=20on=20date=20?= =?UTF-8?q?=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .../modelling_e2e/test_handler.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/applications/modelling_e2e/test_handler.py b/tests/applications/modelling_e2e/test_handler.py index eb3e943c6..88374a5d9 100644 --- a/tests/applications/modelling_e2e/test_handler.py +++ b/tests/applications/modelling_e2e/test_handler.py @@ -1473,6 +1473,52 @@ def test_gov_cert_is_used_when_nothing_is_stored() -> None: assert chosen_is_fetched is True +def test_stored_survey_survives_a_gov_register_with_no_cert() -> None: + """The second failure shape in #1589: recently-surveyed homes have no public + cert, and a None from the register must not wipe out the stored survey.""" + # Arrange + from applications.modelling_e2e.handler import _newer_lodged + + stored = _lodged_epc("2026-05-01") + + # Act + chosen, chosen_is_fetched = _newer_lodged(stored, None) + + # Assert + assert chosen is stored + assert chosen_is_fetched is False + + +def test_no_lodged_epc_from_either_source_defers_to_prediction() -> None: + """Neither source has an assessment: the caller gets None and predicts.""" + # Arrange + from applications.modelling_e2e.handler import _newer_lodged + + # Act + chosen, chosen_is_fetched = _newer_lodged(None, None) + + # Assert + assert chosen is None + assert chosen_is_fetched is False + + +def test_same_day_assessments_prefer_the_stored_survey() -> None: + """Exact inspection_date tie: ADR-0001's "if we surveyed it, trust the + survey" breaks it for the stored side.""" + # Arrange + from applications.modelling_e2e.handler import _newer_lodged + + stored = _lodged_epc("2026-05-01") + fetched = _lodged_epc("2026-05-01") + + # Act + chosen, chosen_is_fetched = _newer_lodged(stored, fetched) + + # Assert + assert chosen is stored + assert chosen_is_fetched is False + + def test_refetch_epc_false_with_stored_epc_skips_api_call() -> None: """refetch_epc=False + stored lodged EPC present: EpcClientService.get_by_uprn is never called; the stored EPC is used and reaches run_modelling.""" From 7a2f29027c5b3eb8ef677501d50bde4a0fdaedba Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 09:37:35 +0000 Subject: [PATCH 08/11] =?UTF-8?q?Model=20the=20newer=20stored=20survey=20w?= =?UTF-8?q?hen=20refetching=20EPCs=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .../modelling_e2e/test_handler.py | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/applications/modelling_e2e/test_handler.py b/tests/applications/modelling_e2e/test_handler.py index 88374a5d9..305e22f46 100644 --- a/tests/applications/modelling_e2e/test_handler.py +++ b/tests/applications/modelling_e2e/test_handler.py @@ -1519,6 +1519,68 @@ def test_same_day_assessments_prefer_the_stored_survey() -> None: assert chosen_is_fetched is False +def test_refetch_epc_true_models_the_newer_stored_survey_without_resaving_it() -> None: + """#1589: refetch_epc=True must not let an older gov cert override a newer + stored survey. The stored survey is modelled, and is not re-persisted.""" + # Arrange + mock_engine = _engine_mock([PROPERTY_ID], [UPRN], [POSTCODE]) + stored_epc = _lodged_epc("2026-05-01") # PasHub site-notes survey + gov_epc = _lodged_epc("2023-12-01") # older public cert + mock_plan = _plan_mock() + mock_uow = MagicMock() + + with ExitStack() as stack: + stack.enter_context(patch("applications.modelling_e2e.handler.os.environ", _ENV)) + stack.enter_context( + patch("applications.modelling_e2e.handler._get_engine", return_value=mock_engine) + ) + mock_epc_client = stack.enter_context( + patch("applications.modelling_e2e.handler.EpcClientService") + ).return_value + mock_epc_client.get_by_uprn.return_value = gov_epc + stack.enter_context(patch("applications.modelling_e2e.handler.GeospatialS3Repository")) + stack.enter_context(patch("applications.modelling_e2e.handler.GoogleSolarApiClient")) + stack.enter_context( + patch("applications.modelling_e2e.handler._spatial_for", return_value=None) + ) + stack.enter_context( + patch("applications.modelling_e2e.handler._solar_insights_for", return_value=None) + ) + stack.enter_context( + patch("applications.modelling_e2e.handler.overlays_from", return_value=[]) + ) + stack.enter_context( + patch("applications.modelling_e2e.handler.PropertyOverridesPostgresReader") + ).return_value.overrides_for_many.return_value = {} + stack.enter_context( + patch("applications.modelling_e2e.handler.ScenarioPostgresRepository") + ).return_value.get_many.return_value = [MagicMock()] + stack.enter_context( + patch("applications.modelling_e2e.handler.catalogue_snapshot_with_off_catalogue_overrides") + ) + stack.enter_context(patch("applications.modelling_e2e.handler.Session")) + mock_run_modelling = stack.enter_context( + patch("applications.modelling_e2e.handler.run_modelling", return_value=mock_plan) + ) + stack.enter_context( + patch("applications.modelling_e2e.handler.EpcPostgresRepository") + ).return_value.get_for_properties.return_value = {UPRN: stored_epc} + MockUoW = stack.enter_context( + patch("applications.modelling_e2e.handler.PostgresUnitOfWork") + ) + MockUoW.return_value.__enter__.return_value = mock_uow + MockUoW.return_value.__exit__.return_value = False + + # Act + _call_handler({**_BODY, "refetch_epc": True}) + + # Assert — the survey was modelled, not the older gov cert... + modelled_epc = mock_run_modelling.call_args.args[0] + assert modelled_epc.inspection_date == date(2026, 5, 1) + # ...and it came from the DB unchanged, so it is not re-saved + mock_uow.epc.save_batch.assert_not_called() + + def test_refetch_epc_false_with_stored_epc_skips_api_call() -> None: """refetch_epc=False + stored lodged EPC present: EpcClientService.get_by_uprn is never called; the stored EPC is used and reaches run_modelling.""" From 870ec68dba921b8f00181ad6bcc13b7cf82cd869 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 09:40:15 +0000 Subject: [PATCH 09/11] =?UTF-8?q?Model=20the=20newer=20stored=20survey=20w?= =?UTF-8?q?hen=20refetching=20EPCs=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read stored lodged EPCs whatever refetch_epc says, so a stored assessment can win the ADR-0001 Recency Tie-Break against the gov register. Co-Authored-By: Claude Opus 4.8 (1M context) --- applications/modelling_e2e/handler.py | 21 ++++++++++++------- .../modelling_e2e/test_handler.py | 9 +++++--- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/applications/modelling_e2e/handler.py b/applications/modelling_e2e/handler.py index 208b5ae7c..ea3708a06 100644 --- a/applications/modelling_e2e/handler.py +++ b/applications/modelling_e2e/handler.py @@ -607,11 +607,11 @@ def handler( ) epc_repo = EpcPostgresRepository(read_session) # Lodged EPCs are read by UPRN (keyed by UPRN below); predicted EPCs stay - # keyed on property_id. - stored_lodged_epcs: dict[int, EpcPropertyData] = ( - epc_repo.get_for_properties(list(set(uprns.values()))) - if not refetch_epc - else {} + # keyed on property_id. Read whatever refetch_epc says — the flag decides + # whether the gov register is consulted for a *candidate*, never whether a + # stored assessment can win the ADR-0001 Recency Tie-Break (#1589). + stored_lodged_epcs: dict[int, EpcPropertyData] = epc_repo.get_for_properties( + list(set(uprns.values())) ) stored_predicted_epcs: dict[int, EpcPropertyData] = ( epc_repo.get_predicted_for_properties(property_ids) @@ -645,8 +645,15 @@ def handler( stored_lodged = stored_lodged_epcs.get(uprn) lodged_epc_is_new = False if refetch_epc: - epc: Optional[EpcPropertyData] = epc_client.get_by_uprn(uprn) - lodged_epc_is_new = epc is not None + epc: Optional[EpcPropertyData] = None + epc, lodged_epc_is_new = _newer_lodged( + stored_lodged, epc_client.get_by_uprn(uprn) + ) + if epc is not None and not lodged_epc_is_new: + logger.info( + f"property={pid} stored lodged EPC is newer than the " + f"fetched cert — keeping the stored assessment" + ) elif stored_lodged is not None: logger.info( f"property={pid} using stored lodged EPC (refetch_epc=False)" diff --git a/tests/applications/modelling_e2e/test_handler.py b/tests/applications/modelling_e2e/test_handler.py index 305e22f46..1a41a0bda 100644 --- a/tests/applications/modelling_e2e/test_handler.py +++ b/tests/applications/modelling_e2e/test_handler.py @@ -1933,10 +1933,13 @@ def test_repredict_epc_false_without_stored_predicted_epc_falls_back_to_live_pre stack.enter_context( patch("applications.modelling_e2e.handler.run_modelling", return_value=mock_plan) ) - # No stored predicted EPC - stack.enter_context( + # Nothing stored: no predicted EPC, and no lodged EPC to win the + # tie-break against the register's None + mock_epc_repo = stack.enter_context( patch("applications.modelling_e2e.handler.EpcPostgresRepository") - ).return_value.get_predicted_for_properties.return_value = {} + ).return_value + mock_epc_repo.get_predicted_for_properties.return_value = {} + mock_epc_repo.get_for_properties.return_value = {} MockUoW = stack.enter_context( patch("applications.modelling_e2e.handler.PostgresUnitOfWork") ) From dcf56280299bed5a2bcce34b5c1984984b7f59ba Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 09:40:52 +0000 Subject: [PATCH 10/11] =?UTF-8?q?Model=20the=20newer=20stored=20survey=20w?= =?UTF-8?q?hen=20refetching=20EPCs=20=F0=9F=9F=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- applications/modelling_e2e/handler.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/applications/modelling_e2e/handler.py b/applications/modelling_e2e/handler.py index ea3708a06..6ac534f2e 100644 --- a/applications/modelling_e2e/handler.py +++ b/applications/modelling_e2e/handler.py @@ -643,9 +643,11 @@ def handler( ) stored_lodged = stored_lodged_epcs.get(uprn) + # Stays None when neither source has an assessment; the prediction + # path handles this property. + epc: Optional[EpcPropertyData] = None lodged_epc_is_new = False if refetch_epc: - epc: Optional[EpcPropertyData] = None epc, lodged_epc_is_new = _newer_lodged( stored_lodged, epc_client.get_by_uprn(uprn) ) @@ -659,10 +661,6 @@ def handler( f"property={pid} using stored lodged EPC (refetch_epc=False)" ) epc = stored_lodged - else: - epc = ( - None # no stored lodged EPC; prediction path handles this property - ) resolved_overrides = overrides_reader.overrides_for(pid) flag_fuel_mismatch(resolved_overrides) overrides = overlays_from(resolved_overrides) From b02519320fbe1afd7f39ddb9a125fa35a24dd147 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Wed, 15 Jul 2026 09:42:24 +0000 Subject: [PATCH 11/11] update local trigger script --- scripts/list_properties_by_postcode.py | 6 ++- scripts/properties_by_postcode_838.txt | 68 ++++++++++++++++++++++++++ scripts/trigger_modelling_e2e_sqs.py | 4 +- 3 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 scripts/properties_by_postcode_838.txt diff --git a/scripts/list_properties_by_postcode.py b/scripts/list_properties_by_postcode.py index cea357ea2..975bfd53b 100644 --- a/scripts/list_properties_by_postcode.py +++ b/scripts/list_properties_by_postcode.py @@ -8,7 +8,7 @@ from __future__ import annotations # --------------------------------------------------------------------------- # CONFIG # --------------------------------------------------------------------------- -PORTFOLIO_ID: int = 796 +PORTFOLIO_ID: int = 838 # --------------------------------------------------------------------------- import sys @@ -27,7 +27,9 @@ engine = build_engine() with engine.connect() as conn: rows = conn.execute( - text("SELECT id, postcode FROM property WHERE portfolio_id = :pid ORDER BY postcode, id"), + text( + "SELECT id, postcode FROM property WHERE portfolio_id = :pid ORDER BY postcode, id" + ), {"pid": PORTFOLIO_ID}, ).fetchall() diff --git a/scripts/properties_by_postcode_838.txt b/scripts/properties_by_postcode_838.txt new file mode 100644 index 000000000..8126a6e44 --- /dev/null +++ b/scripts/properties_by_postcode_838.txt @@ -0,0 +1,68 @@ +'M11 1WN': [754931] +'M11 2LF': [754927] +'M11 3LS': [754878] +'M11 3NP': [754935] +'M11 3NT': [754839] +'M11 3QP': [754934] +'M11 3RQ': [754926] +'M11 3SU': [754860] +'M11 4BU': [754750] +'M11 4DF': [754912] +'M11 4HH': [754831] +'M11 4NF': [754915] +'M11 4PD': [754874] +'M11 4PP': [754824] +'M11 4PT': [754830] +'M11 4PW': [754916] +'M11 4PX': [754816] +'M11 4QS': [754922] +'M11 4RS': [754904] +'M11 4SD': [754930] +'M11 4WE': [754917] +'M11 4WF': [754921] +'M11 4WP': [754759] +'M11 4WT': [754925] +'M11 1WH': [754897, 754898] +'M11 3BN': [754858, 754859] +'M11 3LD': [754932, 754933] +'M11 3LN': [754928, 754929] +'M11 3RH': [754832, 754833] +'M11 4BT': [754913, 754914] +'M11 4DN': [754908, 754909] +'M11 4GA': [754804, 754805] +'M11 4NG': [754757, 754758] +'M11 4PH': [754828, 754829] +'M11 4PZ': [754910, 754911] +'M11 4RJ': [754923, 754924] +'M11 4RT': [754766, 754767] +'M11 3NJ': [754875, 754876, 754877] +'M11 4FB': [754905, 754906, 754907] +'M11 4NH': [754785, 754786, 754787] +'M11 4NZ': [754731, 754732, 754733] +'M11 4PL': [754817, 754818, 754819] +'M11 4QD': [754825, 754826, 754827] +'M11 4WL': [754918, 754919, 754920] +'M11 1NG': [754879, 754880, 754881, 754882] +'M11 3RF': [754844, 754845, 754846, 754847] +'M11 3RN': [754840, 754841, 754842, 754843] +'M11 4NJ': [754888, 754889, 754890, 754891] +'M11 4NQ': [754788, 754789, 754790, 754791] +'M11 4PQ': [754820, 754821, 754822, 754823] +'M11 4SA': [754776, 754777, 754778, 754779] +'M11 4WJ': [754792, 754793, 754794, 754795] +'M11 1WL': [754899, 754900, 754901, 754902, 754903] +'M11 3AG': [754834, 754835, 754836, 754837, 754838] +'M11 3LH': [754869, 754870, 754871, 754872, 754873] +'M11 4NL': [754892, 754893, 754894, 754895, 754896] +'M11 4PG': [754780, 754781, 754782, 754783, 754784] +'M11 4QB': [754883, 754884, 754885, 754886, 754887] +'M11 4PJ': [754760, 754761, 754762, 754763, 754764, 754765] +'M11 4PN': [754751, 754752, 754753, 754754, 754755, 754756] +'M11 3HL': [754861, 754862, 754863, 754864, 754865, 754866, 754867, 754868] +'M11 4DH': [754768, 754769, 754770, 754771, 754772, 754773, 754774, 754775] +'M11 4TL': [754796, 754797, 754798, 754799, 754800, 754801, 754802, 754803] +'M11 1NW': [754848, 754849, 754850, 754851, 754852, 754853, 754854, 754855, 754856, 754857] +'M11 4BZ': [754806, 754807, 754808, 754809, 754810, 754811, 754812, 754813, 754814, 754815] +'M11 4WU': [754734, 754735, 754736, 754737, 754738, 754739, 754740, 754741, 754742, 754743, 754744, 754745, 754746, 754747, 754748, 754749] + +Total postcodes: 66, total properties: 205 \ No newline at end of file diff --git a/scripts/trigger_modelling_e2e_sqs.py b/scripts/trigger_modelling_e2e_sqs.py index a4c6a4df1..84520393d 100644 --- a/scripts/trigger_modelling_e2e_sqs.py +++ b/scripts/trigger_modelling_e2e_sqs.py @@ -23,8 +23,8 @@ from utilities.logger import setup_logger # --------------------------------------------------------------------------- # CONFIG — edit these before running # --------------------------------------------------------------------------- -PORTFOLIO_ID: int = 796 -SCENARIO_ID: int = 1268 +PORTFOLIO_ID: int = 838 +SCENARIO_ID: int = 1296 SQS_QUEUE_NAME: str = "modelling_e2e-queue-dev" # Max number of properties to process this run (cost cap).