From 1c75b446306884dfc1b1fe9d6e48dab4d6c4634a Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 2 Jul 2026 16:47:07 +0000 Subject: [PATCH 01/10] =?UTF-8?q?Abri=20survey=20amendment=20trigger=20fir?= =?UTF-8?q?es=20when=20the=20confirmed=20survey=20date=20changes=20on=20an?= =?UTF-8?q?=20Abri=20condition=20deal=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 --- etl/hubspot/hubspot_deal_differ.py | 8 +++++ etl/hubspot/tests/test_hubspot_deal_differ.py | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/etl/hubspot/hubspot_deal_differ.py b/etl/hubspot/hubspot_deal_differ.py index 68b075182..fc49d02c9 100644 --- a/etl/hubspot/hubspot_deal_differ.py +++ b/etl/hubspot/hubspot_deal_differ.py @@ -187,6 +187,14 @@ class HubspotDealDiffer: return parse_hs_date(new_deal.get("confirmed_survey_date")) is not None + @staticmethod + def check_for_abri_survey_amendment( + new_deal: Dict[str, str], + new_project: Optional[ProjectData], + old_deal: HubspotDealData, + ) -> bool: + raise NotImplementedError + @staticmethod def _is_abri_condition_deal( new_deal: Dict[str, str], new_project: Optional[ProjectData] diff --git a/etl/hubspot/tests/test_hubspot_deal_differ.py b/etl/hubspot/tests/test_hubspot_deal_differ.py index a072b175f..c57fcbe07 100644 --- a/etl/hubspot/tests/test_hubspot_deal_differ.py +++ b/etl/hubspot/tests/test_hubspot_deal_differ.py @@ -548,6 +548,37 @@ def test_abri_survey_creation__non_abri_project_id_with_abri_code__returns_false assert result is False +# =================================== +# ABRI SURVEY AMENDMENT TRIGGER TESTS +# =================================== + + +def test_abri_survey_amendment__date_changed_on_abri_deal__returns_true() -> None: + deal_id = uuid.uuid4() + + # Arrange + old_deal = make_old_deal( + id=deal_id, + project_code="Abri Condition", + confirmed_survey_date=datetime(2026, 7, 1, tzinfo=timezone.utc), + ) + new_deal = make_new_deal( + deal_id, + project_code="Abri Condition", + confirmed_survey_date="2026-07-15", + ) + + # Act + result = HubspotDealDiffer.check_for_abri_survey_amendment( + new_deal=new_deal, + new_project=None, + old_deal=old_deal, + ) + + # Assert + assert result is True + + # ======================= # DB UPDATE TRIGGER TESTS # ======================= From dbbb12fa54c91f47784d9d6ddb8764c1209c6673 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 2 Jul 2026 16:47:29 +0000 Subject: [PATCH 02/10] =?UTF-8?q?Abri=20survey=20amendment=20trigger=20fir?= =?UTF-8?q?es=20when=20the=20confirmed=20survey=20date=20changes=20on=20an?= =?UTF-8?q?=20Abri=20condition=20deal=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- etl/hubspot/hubspot_deal_differ.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etl/hubspot/hubspot_deal_differ.py b/etl/hubspot/hubspot_deal_differ.py index fc49d02c9..c521ff843 100644 --- a/etl/hubspot/hubspot_deal_differ.py +++ b/etl/hubspot/hubspot_deal_differ.py @@ -193,7 +193,7 @@ class HubspotDealDiffer: new_project: Optional[ProjectData], old_deal: HubspotDealData, ) -> bool: - raise NotImplementedError + return True @staticmethod def _is_abri_condition_deal( From 16b25c4b54dba0daa8a174fc1959495771548943 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 2 Jul 2026 16:47:51 +0000 Subject: [PATCH 03/10] =?UTF-8?q?Abri=20survey=20amendment=20trigger=20ign?= =?UTF-8?q?ores=20deals=20that=20are=20not=20Abri=20condition=20deals=20?= =?UTF-8?q?=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 --- etl/hubspot/tests/test_hubspot_deal_differ.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/etl/hubspot/tests/test_hubspot_deal_differ.py b/etl/hubspot/tests/test_hubspot_deal_differ.py index c57fcbe07..eaa2940d3 100644 --- a/etl/hubspot/tests/test_hubspot_deal_differ.py +++ b/etl/hubspot/tests/test_hubspot_deal_differ.py @@ -579,6 +579,32 @@ def test_abri_survey_amendment__date_changed_on_abri_deal__returns_true() -> Non assert result is True +def test_abri_survey_amendment__non_abri_deal__returns_false() -> None: + deal_id = uuid.uuid4() + + # Arrange + old_deal = make_old_deal( + id=deal_id, + project_code="Southern Retrofit", + confirmed_survey_date=datetime(2026, 7, 1, tzinfo=timezone.utc), + ) + new_deal = make_new_deal( + deal_id, + project_code="Southern Retrofit", + confirmed_survey_date="2026-07-15", + ) + + # Act + result = HubspotDealDiffer.check_for_abri_survey_amendment( + new_deal=new_deal, + new_project=None, + old_deal=old_deal, + ) + + # Assert + assert result is False + + # ======================= # DB UPDATE TRIGGER TESTS # ======================= From 7bfd26476ebd5d789fdd66ea2975563230fa36b5 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 2 Jul 2026 16:48:26 +0000 Subject: [PATCH 04/10] =?UTF-8?q?Abri=20survey=20amendment=20trigger=20ign?= =?UTF-8?q?ores=20deals=20that=20are=20not=20Abri=20condition=20deals=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 Fable 5 --- etl/hubspot/hubspot_deal_differ.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etl/hubspot/hubspot_deal_differ.py b/etl/hubspot/hubspot_deal_differ.py index c521ff843..b2f38c0f3 100644 --- a/etl/hubspot/hubspot_deal_differ.py +++ b/etl/hubspot/hubspot_deal_differ.py @@ -193,7 +193,7 @@ class HubspotDealDiffer: new_project: Optional[ProjectData], old_deal: HubspotDealData, ) -> bool: - return True + return HubspotDealDiffer._is_abri_condition_deal(new_deal, new_project) @staticmethod def _is_abri_condition_deal( From fce9d305895db6abb9f276797659af7ee22f81c3 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 2 Jul 2026 16:48:53 +0000 Subject: [PATCH 05/10] =?UTF-8?q?Abri=20survey=20amendment=20trigger=20sta?= =?UTF-8?q?ys=20quiet=20when=20the=20survey=20date=20and=20time=20are=20un?= =?UTF-8?q?changed=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 --- etl/hubspot/tests/test_hubspot_deal_differ.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/etl/hubspot/tests/test_hubspot_deal_differ.py b/etl/hubspot/tests/test_hubspot_deal_differ.py index eaa2940d3..9c581da89 100644 --- a/etl/hubspot/tests/test_hubspot_deal_differ.py +++ b/etl/hubspot/tests/test_hubspot_deal_differ.py @@ -605,6 +605,34 @@ def test_abri_survey_amendment__non_abri_deal__returns_false() -> None: assert result is False +def test_abri_survey_amendment__date_and_time_unchanged__returns_false() -> None: + deal_id = uuid.uuid4() + + # Arrange + old_deal = make_old_deal( + id=deal_id, + project_code="Abri Condition", + confirmed_survey_date=datetime(2026, 7, 15, tzinfo=timezone.utc), + confirmed_survey_time="09:30", + ) + new_deal = make_new_deal( + deal_id, + project_code="Abri Condition", + confirmed_survey_date="2026-07-15", + confirmed_survey_time="09:30", + ) + + # Act + result = HubspotDealDiffer.check_for_abri_survey_amendment( + new_deal=new_deal, + new_project=None, + old_deal=old_deal, + ) + + # Assert + assert result is False + + # ======================= # DB UPDATE TRIGGER TESTS # ======================= From bf344e1b5832c7f42a35b0705cf9903282a1a57a Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 2 Jul 2026 16:49:19 +0000 Subject: [PATCH 06/10] =?UTF-8?q?Abri=20survey=20amendment=20trigger=20sta?= =?UTF-8?q?ys=20quiet=20when=20the=20survey=20date=20and=20time=20are=20un?= =?UTF-8?q?changed=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- etl/hubspot/hubspot_deal_differ.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/etl/hubspot/hubspot_deal_differ.py b/etl/hubspot/hubspot_deal_differ.py index b2f38c0f3..9a94ed4fb 100644 --- a/etl/hubspot/hubspot_deal_differ.py +++ b/etl/hubspot/hubspot_deal_differ.py @@ -193,7 +193,11 @@ class HubspotDealDiffer: new_project: Optional[ProjectData], old_deal: HubspotDealData, ) -> bool: - return HubspotDealDiffer._is_abri_condition_deal(new_deal, new_project) + if not HubspotDealDiffer._is_abri_condition_deal(new_deal, new_project): + return False + + new_survey_date = parse_hs_date(new_deal.get("confirmed_survey_date")) + return old_deal.confirmed_survey_date != new_survey_date @staticmethod def _is_abri_condition_deal( From 8c5d1a27fff2a7212efc47cce16663fb7c920ae1 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 2 Jul 2026 16:50:53 +0000 Subject: [PATCH 07/10] =?UTF-8?q?Abri=20survey=20amendment=20trigger=20fir?= =?UTF-8?q?es=20when=20the=20confirmed=20survey=20time=20changes=20on=20an?= =?UTF-8?q?=20Abri=20condition=20deal=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 --- etl/hubspot/tests/test_hubspot_deal_differ.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/etl/hubspot/tests/test_hubspot_deal_differ.py b/etl/hubspot/tests/test_hubspot_deal_differ.py index 9c581da89..2cdc0cd5c 100644 --- a/etl/hubspot/tests/test_hubspot_deal_differ.py +++ b/etl/hubspot/tests/test_hubspot_deal_differ.py @@ -633,6 +633,34 @@ def test_abri_survey_amendment__date_and_time_unchanged__returns_false() -> None assert result is False +def test_abri_survey_amendment__time_changed_on_abri_deal__returns_true() -> None: + deal_id = uuid.uuid4() + + # Arrange + old_deal = make_old_deal( + id=deal_id, + project_code="Abri Condition", + confirmed_survey_date=datetime(2026, 7, 15, tzinfo=timezone.utc), + confirmed_survey_time="09:30", + ) + new_deal = make_new_deal( + deal_id, + project_code="Abri Condition", + confirmed_survey_date="2026-07-15", + confirmed_survey_time="14:00", + ) + + # Act + result = HubspotDealDiffer.check_for_abri_survey_amendment( + new_deal=new_deal, + new_project=None, + old_deal=old_deal, + ) + + # Assert + assert result is True + + # ======================= # DB UPDATE TRIGGER TESTS # ======================= From 597cd1c83f737a3d6c0364f97b666682fd73d896 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 2 Jul 2026 16:52:00 +0000 Subject: [PATCH 08/10] =?UTF-8?q?Abri=20survey=20amendment=20trigger=20fir?= =?UTF-8?q?es=20when=20the=20confirmed=20survey=20time=20changes=20on=20an?= =?UTF-8?q?=20Abri=20condition=20deal=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- etl/hubspot/hubspot_deal_differ.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/etl/hubspot/hubspot_deal_differ.py b/etl/hubspot/hubspot_deal_differ.py index 9a94ed4fb..8e11efa52 100644 --- a/etl/hubspot/hubspot_deal_differ.py +++ b/etl/hubspot/hubspot_deal_differ.py @@ -197,7 +197,10 @@ class HubspotDealDiffer: return False new_survey_date = parse_hs_date(new_deal.get("confirmed_survey_date")) - return old_deal.confirmed_survey_date != new_survey_date + if old_deal.confirmed_survey_date != new_survey_date: + return True + + return old_deal.confirmed_survey_time != new_deal.get("confirmed_survey_time") @staticmethod def _is_abri_condition_deal( From 1529544c191a326aacd64c0da86883231085c65a Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 2 Jul 2026 16:52:26 +0000 Subject: [PATCH 09/10] =?UTF-8?q?Abri=20survey=20amendment=20trigger=20def?= =?UTF-8?q?ers=20first-time=20survey=20dates=20to=20the=20creation=20trigg?= =?UTF-8?q?er=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 --- etl/hubspot/tests/test_hubspot_deal_differ.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/etl/hubspot/tests/test_hubspot_deal_differ.py b/etl/hubspot/tests/test_hubspot_deal_differ.py index 2cdc0cd5c..544242623 100644 --- a/etl/hubspot/tests/test_hubspot_deal_differ.py +++ b/etl/hubspot/tests/test_hubspot_deal_differ.py @@ -661,6 +661,32 @@ def test_abri_survey_amendment__time_changed_on_abri_deal__returns_true() -> Non assert result is True +def test_abri_survey_amendment__date_first_set_on_abri_deal__returns_false() -> None: + deal_id = uuid.uuid4() + + # Arrange + old_deal = make_old_deal( + id=deal_id, + project_code="Abri Condition", + confirmed_survey_date=None, + ) + new_deal = make_new_deal( + deal_id, + project_code="Abri Condition", + confirmed_survey_date="2026-07-15", + ) + + # Act + result = HubspotDealDiffer.check_for_abri_survey_amendment( + new_deal=new_deal, + new_project=None, + old_deal=old_deal, + ) + + # Assert + assert result is False + + # ======================= # DB UPDATE TRIGGER TESTS # ======================= From 60146f0c30f1777879bc4c23cc152e28dcdff5df Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 2 Jul 2026 16:52:49 +0000 Subject: [PATCH 10/10] =?UTF-8?q?Abri=20survey=20amendment=20trigger=20def?= =?UTF-8?q?ers=20first-time=20survey=20dates=20to=20the=20creation=20trigg?= =?UTF-8?q?er=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- etl/hubspot/hubspot_deal_differ.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/etl/hubspot/hubspot_deal_differ.py b/etl/hubspot/hubspot_deal_differ.py index 8e11efa52..c4e9c0148 100644 --- a/etl/hubspot/hubspot_deal_differ.py +++ b/etl/hubspot/hubspot_deal_differ.py @@ -196,6 +196,10 @@ class HubspotDealDiffer: if not HubspotDealDiffer._is_abri_condition_deal(new_deal, new_project): return False + # A first-time survey date is a creation, not an amendment. + if old_deal.confirmed_survey_date is None: + return False + new_survey_date = parse_hs_date(new_deal.get("confirmed_survey_date")) if old_deal.confirmed_survey_date != new_survey_date: return True