mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-22 08:48:38 +00:00
232 lines
6.6 KiB
Python
232 lines
6.6 KiB
Python
from datetime import datetime, timezone
|
|
from typing import Any, Dict
|
|
import uuid
|
|
|
|
from backend.app.db.models.hubspot_deal_data import HubspotDealData
|
|
from etl.hubspot.abri_flow_triggers import check_for_abri_triggers_and_construct_message
|
|
|
|
BASE_TIME = datetime(2025, 12, 1, 12, 0, 0)
|
|
|
|
ABRI_PROJECT_CODE = "[Abri Stock Condition - Privately Funded - 062026 - 1247536318670]"
|
|
|
|
DEAL_ID = "9876543210"
|
|
|
|
LISTING = {"listing_id": "55", "owner_property_id": "1007165", "national_uprn": "1"}
|
|
|
|
|
|
def make_old_deal(**overrides: Any) -> HubspotDealData:
|
|
return HubspotDealData(
|
|
id=overrides.get("id", uuid.uuid4()),
|
|
deal_id=DEAL_ID,
|
|
created_at=BASE_TIME,
|
|
updated_at=BASE_TIME,
|
|
**{k: v for k, v in overrides.items() if k != "id"},
|
|
)
|
|
|
|
|
|
def make_new_deal(**overrides: str) -> Dict[str, str]:
|
|
return {
|
|
"hs_object_id": DEAL_ID,
|
|
"dealname": "49 Admers Crescent",
|
|
"project_code": ABRI_PROJECT_CODE,
|
|
**overrides,
|
|
}
|
|
|
|
|
|
# ==========================
|
|
# SINGLE-FLOW FIRING
|
|
# ==========================
|
|
|
|
|
|
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)
|
|
new_deal = make_new_deal(
|
|
confirmed_survey_date="2026-06-24", confirmed_survey_time="14:30"
|
|
)
|
|
|
|
# Act
|
|
message = check_for_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 == {
|
|
"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",
|
|
}
|
|
|
|
|
|
def test_a_changed_confirmed_survey_date_builds_an_amend_job_message() -> None:
|
|
# Arrange
|
|
old_deal = make_old_deal(
|
|
project_code=ABRI_PROJECT_CODE,
|
|
confirmed_survey_date=datetime(2026, 6, 18, tzinfo=timezone.utc),
|
|
)
|
|
new_deal = make_new_deal(
|
|
confirmed_survey_date="2026-06-24", confirmed_survey_time="14:30"
|
|
)
|
|
|
|
# Act
|
|
message = check_for_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"] == ["amend_job"]
|
|
assert message["confirmed_survey_date"] == "2026-06-24"
|
|
|
|
|
|
def test_a_first_expected_commencement_date_builds_a_tenant_sync_message() -> None:
|
|
# Arrange
|
|
old_deal = make_old_deal(
|
|
project_code=ABRI_PROJECT_CODE, expected_commencement_date=None
|
|
)
|
|
new_deal = make_new_deal(expected_commencement_date="2026-07-01")
|
|
|
|
# Act
|
|
message = check_for_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"] == ["sync_tenant_data"]
|
|
assert message["place_ref"] == "1007165"
|
|
|
|
|
|
# ==========================
|
|
# ONE MESSAGE PER SCRAPE
|
|
# ==========================
|
|
|
|
|
|
def test_several_flows_firing_in_one_scrape_share_one_message() -> None:
|
|
# Arrange: date changed and commencement date first set together.
|
|
old_deal = make_old_deal(
|
|
project_code=ABRI_PROJECT_CODE,
|
|
confirmed_survey_date=datetime(2026, 6, 18, tzinfo=timezone.utc),
|
|
expected_commencement_date=None,
|
|
)
|
|
new_deal = make_new_deal(
|
|
confirmed_survey_date="2026-06-24",
|
|
confirmed_survey_time="14:30",
|
|
expected_commencement_date="2026-07-01",
|
|
)
|
|
|
|
# Act
|
|
message = check_for_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"] == ["amend_job", "sync_tenant_data"]
|
|
|
|
|
|
# ==========================
|
|
# NOTHING FIRES
|
|
# ==========================
|
|
|
|
|
|
def test_no_message_when_no_abri_trigger_fires() -> None:
|
|
# Arrange: something changed, but nothing Abri cares about.
|
|
old_deal = make_old_deal(project_code=ABRI_PROJECT_CODE, outcome=None)
|
|
new_deal = make_new_deal(outcome="left voicemail")
|
|
|
|
# Act
|
|
message = check_for_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_no_message_for_a_non_abri_deal() -> None:
|
|
# Arrange: a survey date first set, but on another project's deal.
|
|
old_deal = make_old_deal(project_code="Other", confirmed_survey_date=None)
|
|
new_deal = make_new_deal(project_code="Other", confirmed_survey_date="2026-06-24")
|
|
|
|
# Act
|
|
message = check_for_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_abandonment_alone_stays_unwired_and_builds_no_message() -> None:
|
|
# Arrange: the abandonment predicate would fire, but CancelJob does not
|
|
# exist yet, so no flow may be dispatched for it.
|
|
old_deal = make_old_deal(
|
|
project_code=ABRI_PROJECT_CODE, number_of_attempts="2", outcome=None
|
|
)
|
|
new_deal = make_new_deal(number_of_attempts="3", outcome="no answer")
|
|
|
|
# Act
|
|
message = check_for_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
|
|
|
|
|
|
# ==========================
|
|
# PAYLOAD ROBUSTNESS
|
|
# ==========================
|
|
|
|
|
|
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")
|
|
|
|
# Act
|
|
message = check_for_abri_triggers_and_construct_message(
|
|
hubspot_deal_id=DEAL_ID,
|
|
new_deal=new_deal,
|
|
new_project=None,
|
|
new_listing=None,
|
|
old_deal=old_deal,
|
|
)
|
|
|
|
# Assert
|
|
assert message is not None
|
|
assert message["place_ref"] is None
|
|
assert message["confirmed_survey_time"] is None
|