Log an Abri job only when both survey date and surveyor complete the pair 🟥

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Daniel Roth 2026-07-24 15:40:20 +00:00
parent f477e6dc7d
commit 84822c3228

View file

@ -40,9 +40,71 @@ def make_new_deal(**overrides: str) -> Dict[str, str]:
# ==========================
def test_a_first_confirmed_survey_date_builds_a_log_job_message() -> None:
# Arrange
old_deal = make_old_deal(project_code=ABRI_PROJECT_CODE, confirmed_survey_date=None)
def test_a_surveyor_landing_after_the_date_completes_the_pair_and_logs() -> None:
# Arrange: the date was already set; the surveyor lands second, completing
# the pair, so the job is logged (not amended) whichever field lands last.
old_deal = make_old_deal(
project_code=ABRI_PROJECT_CODE,
confirmed_survey_date=datetime(2026, 6, 24, tzinfo=timezone.utc),
confirmed_survey_time="14:30",
third_party_surveyor_identifier=None,
)
new_deal = make_new_deal(
confirmed_survey_date="2026-06-24",
confirmed_survey_time="14:30",
third_party_surveyor_identifier="THIRDPARTY",
)
# Act
message = HubspotDealDiffer.check_abri_triggers_and_construct_message(
hubspot_deal_id=DEAL_ID,
new_deal=new_deal,
new_project=None,
new_listing=LISTING,
old_deal=old_deal,
)
# Assert
assert message is not None
assert message["flows"] == ["log_job"]
def test_a_date_landing_after_the_surveyor_completes_the_pair_and_logs() -> None:
# Arrange: the surveyor was already set; the date lands second, completing
# the pair, so the job is logged — field ordering does not matter.
old_deal = make_old_deal(
project_code=ABRI_PROJECT_CODE,
confirmed_survey_date=None,
third_party_surveyor_identifier="THIRDPARTY",
)
new_deal = make_new_deal(
confirmed_survey_date="2026-06-24",
confirmed_survey_time="14:30",
third_party_surveyor_identifier="THIRDPARTY",
)
# Act
message = HubspotDealDiffer.check_abri_triggers_and_construct_message(
hubspot_deal_id=DEAL_ID,
new_deal=new_deal,
new_project=None,
new_listing=LISTING,
old_deal=old_deal,
)
# Assert
assert message is not None
assert message["flows"] == ["log_job"]
def test_a_lone_survey_date_without_a_surveyor_fires_nothing() -> None:
# Arrange: only the date lands; the pair is incomplete, so the job is not
# logged (the resource requirement is kept) and nothing is amended.
old_deal = make_old_deal(
project_code=ABRI_PROJECT_CODE,
confirmed_survey_date=None,
third_party_surveyor_identifier=None,
)
new_deal = make_new_deal(
confirmed_survey_date="2026-06-24", confirmed_survey_time="14:30"
)
@ -57,17 +119,88 @@ def test_a_first_confirmed_survey_date_builds_a_log_job_message() -> None:
)
# Assert
assert message == {
"hubspot_deal_id": DEAL_ID,
"flows": ["log_job"],
"place_ref": "1007165",
"deal_name": "49 Admers Crescent",
"confirmed_survey_date": "2026-06-24",
"confirmed_survey_time": "14:30",
"last_submission_date": None,
"outcome": None,
"third_party_surveyor_identifier": None,
}
assert message is None
def test_a_lone_surveyor_without_a_survey_date_fires_nothing() -> None:
# Arrange: only the surveyor lands; the pair is incomplete, so nothing fires.
old_deal = make_old_deal(
project_code=ABRI_PROJECT_CODE,
confirmed_survey_date=None,
third_party_surveyor_identifier=None,
)
new_deal = make_new_deal(third_party_surveyor_identifier="THIRDPARTY")
# Act
message = HubspotDealDiffer.check_abri_triggers_and_construct_message(
hubspot_deal_id=DEAL_ID,
new_deal=new_deal,
new_project=None,
new_listing=LISTING,
old_deal=old_deal,
)
# Assert
assert message is None
def test_a_pair_already_complete_before_does_not_re_log() -> None:
# Arrange: both fields were already set and nothing changed, so the log
# must not fire a second time.
old_deal = make_old_deal(
project_code=ABRI_PROJECT_CODE,
confirmed_survey_date=datetime(2026, 6, 24, tzinfo=timezone.utc),
confirmed_survey_time="14:30",
third_party_surveyor_identifier="THIRDPARTY",
)
new_deal = make_new_deal(
confirmed_survey_date="2026-06-24",
confirmed_survey_time="14:30",
third_party_surveyor_identifier="THIRDPARTY",
)
# Act
message = HubspotDealDiffer.check_abri_triggers_and_construct_message(
hubspot_deal_id=DEAL_ID,
new_deal=new_deal,
new_project=None,
new_listing=LISTING,
old_deal=old_deal,
)
# Assert
assert message is None
def test_a_deal_that_already_has_a_client_booking_reference_is_never_logged() -> None:
# Arrange: the pair completes this scrape, but the deal already carries a
# Job Number, so the job exists and must not be logged again.
old_deal = make_old_deal(
project_code=ABRI_PROJECT_CODE,
confirmed_survey_date=datetime(2026, 6, 24, tzinfo=timezone.utc),
confirmed_survey_time="14:30",
third_party_surveyor_identifier=None,
client_booking_reference="AD0226519",
)
new_deal = make_new_deal(
confirmed_survey_date="2026-06-24",
confirmed_survey_time="14:30",
third_party_surveyor_identifier="THIRDPARTY",
client_booking_reference="AD0226519",
)
# Act
message = HubspotDealDiffer.check_abri_triggers_and_construct_message(
hubspot_deal_id=DEAL_ID,
new_deal=new_deal,
new_project=None,
new_listing=LISTING,
old_deal=old_deal,
)
# Assert
assert message is not None
assert "log_job" not in message["flows"]
def test_the_message_carries_the_deals_third_party_surveyor_identifier() -> None:
@ -384,8 +517,15 @@ def test_a_deal_crossing_into_abandonment_builds_an_abandon_job_message() -> Non
def test_a_missing_listing_still_builds_the_message_without_a_place_ref() -> None:
# Arrange: validation in the abri lambda is the visibility surface for
# a fired flow that lacks its place_ref; the scraper still sends.
old_deal = make_old_deal(project_code=ABRI_PROJECT_CODE, confirmed_survey_date=None)
new_deal = make_new_deal(confirmed_survey_date="2026-06-24")
old_deal = make_old_deal(
project_code=ABRI_PROJECT_CODE,
confirmed_survey_date=None,
third_party_surveyor_identifier=None,
)
new_deal = make_new_deal(
confirmed_survey_date="2026-06-24",
third_party_surveyor_identifier="THIRDPARTY",
)
# Act
message = HubspotDealDiffer.check_abri_triggers_and_construct_message(