From 60c69c478640ba47915ac312807a54d7052abb34 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 7 May 2026 12:43:45 +0000 Subject: [PATCH] =?UTF-8?q?match=20address=20string=20to=20magicplan=20pla?= =?UTF-8?q?n=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/magic_plan/address_matcher.py | 47 +++++++++++++++++++ .../magic_plan/tests/test_address_matcher.py | 16 ++++--- 2 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 backend/magic_plan/address_matcher.py diff --git a/backend/magic_plan/address_matcher.py b/backend/magic_plan/address_matcher.py new file mode 100644 index 00000000..043358c0 --- /dev/null +++ b/backend/magic_plan/address_matcher.py @@ -0,0 +1,47 @@ +import re + +from datatypes.magicplan.api.response import PlanSummary + +_UK_POSTCODE_RE = re.compile( + r"[A-Z]{1,2}\d[A-Z\d]?\s*\d[A-Z]{2}", re.IGNORECASE +) + + +def _extract_postcode(address: str) -> str | None: + match = _UK_POSTCODE_RE.search(address) + if match is None: + return None + return match.group().replace(" ", "").upper() + + +def _normalize_postcode(postcode: str) -> str: + return postcode.replace(" ", "").upper() + + +def find_matching_plan(plans: list[PlanSummary], address: str) -> PlanSummary | None: + postcode = _extract_postcode(address) + if postcode is None: + return None + + address_lower = address.lower() + + for plan in plans: + if plan.address is None: + continue + + plan_postcode = plan.address.postal_code + if plan_postcode is None: + continue + + if _normalize_postcode(plan_postcode) != postcode: + continue + + street_parts = [ + p for p in [plan.address.street_number, plan.address.street] if p + ] + plan_street = " ".join(street_parts).lower() + + if plan_street and plan_street in address_lower: + return plan + + return None diff --git a/backend/magic_plan/tests/test_address_matcher.py b/backend/magic_plan/tests/test_address_matcher.py index 2ee1f687..347a49ef 100644 --- a/backend/magic_plan/tests/test_address_matcher.py +++ b/backend/magic_plan/tests/test_address_matcher.py @@ -1,6 +1,4 @@ -import pytest - -from datatypes.magicplan.api.response import Address, PlanSummary +from datatypes.magicplan.api.response import PlanSummary from backend.magic_plan.address_matcher import find_matching_plan, _extract_postcode @@ -49,8 +47,12 @@ def test_extract_postcode_none_for_empty_string() -> None: # --- find_matching_plan --- -PLAN_A = _make_plan("plan-a", street="Laburnum Way", street_number="2", postal_code="BR2 8BZ") -PLAN_B = _make_plan("plan-b", street="Station Road", street_number="11", postal_code="BR1 3LP") +PLAN_A = _make_plan( + "plan-a", street="Laburnum Way", street_number="2", postal_code="BR2 8BZ" +) +PLAN_B = _make_plan( + "plan-b", street="Station Road", street_number="11", postal_code="BR1 3LP" +) def test_find_matching_plan_returns_match() -> None: @@ -100,7 +102,9 @@ def test_find_matching_plan_postcode_with_no_space_in_address() -> None: def test_find_matching_plan_plan_postcode_with_no_space() -> None: # Arrange - plan has postcode without space - plan = _make_plan("plan-c", street="Laburnum Way", street_number="2", postal_code="BR28BZ") + plan = _make_plan( + "plan-c", street="Laburnum Way", street_number="2", postal_code="BR28BZ" + ) # Act result = find_matching_plan([plan], "2 Laburnum Way Bromley BR2 8BZ") # Assert