From 2512d428a1172930869df8380c3f219fc51a98ae Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Tue, 7 Jul 2026 15:38:10 +0000 Subject: [PATCH] =?UTF-8?q?Map=20a=20HubSpot=20outcome=20to=20an=20abandon?= =?UTF-8?q?ment=20reason=20code=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 --- domain/abri/abandonment.py | 13 +++++++++++++ tests/domain/abri/test_abandonment.py | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 domain/abri/abandonment.py create mode 100644 tests/domain/abri/test_abandonment.py diff --git a/domain/abri/abandonment.py b/domain/abri/abandonment.py new file mode 100644 index 000000000..b91a25c6f --- /dev/null +++ b/domain/abri/abandonment.py @@ -0,0 +1,13 @@ +from typing import Optional + +from domain.abri.models import AbandonReason + + +def abandon_reason_for_outcome(outcome: Optional[str]) -> AbandonReason: + """The OpenHousing abandonment reason code for a HubSpot deal outcome. + + The single mapping point from HubSpot's outcome to a coded reason. For now + every outcome maps to CARDED; the real outcome-to-code table is a follow-up + (needs Abri's code list), and swapping it in is a one-place change here. + """ + raise NotImplementedError diff --git a/tests/domain/abri/test_abandonment.py b/tests/domain/abri/test_abandonment.py new file mode 100644 index 000000000..4c0cda5f1 --- /dev/null +++ b/tests/domain/abri/test_abandonment.py @@ -0,0 +1,20 @@ +from typing import Optional + +import pytest + +from domain.abri.abandonment import abandon_reason_for_outcome +from domain.abri.models import AbandonReason + + +@pytest.mark.parametrize( + "outcome", + ["no answer", "cancelled", "no show", "tenant refusal", "not viable", None], +) +def test_every_outcome_currently_maps_to_the_carded_reason( + outcome: Optional[str], +) -> None: + # Act + reason = abandon_reason_for_outcome(outcome) + + # Assert + assert reason == AbandonReason.CARDED