mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-27 23:35:01 +00:00
Flag a void property at the front of the deal's booking information 🟥
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a2c2681c18
commit
f742795434
5 changed files with 48 additions and 6 deletions
|
|
@ -264,7 +264,7 @@ class HubspotClient:
|
|||
"number_of_attempts",
|
||||
"outcome_notes",
|
||||
"booking_status",
|
||||
"extra_booking_information",
|
||||
"notes_for_surveyor",
|
||||
"project_code",
|
||||
"major_condition_issue_description",
|
||||
"major_condition_issue_photos",
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class HubspotDealDiffer:
|
|||
"project_code": "project_code",
|
||||
"outcome_notes": "outcome_notes",
|
||||
"booking_status": "booking_status",
|
||||
"extra_booking_information": "extra_booking_information",
|
||||
"notes_for_surveyor": "notes_for_surveyor",
|
||||
"major_condition_issue_description": "major_condition_issue_description",
|
||||
"major_condition_issue_photos": "major_condition_issue_photos",
|
||||
"coordination_status__stage_1_": "coordination_status",
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
from typing import Any, Dict, Optional, cast
|
||||
|
||||
from hubspot.client import Client # type: ignore[reportMissingTypeStubs]
|
||||
from hubspot.crm.deals import SimplePublicObjectInput # type: ignore[reportMissingTypeStubs]
|
||||
|
||||
|
|
@ -15,6 +17,15 @@ class HubspotDealPropertiesClient:
|
|||
def __init__(self, sdk_client: Client) -> None:
|
||||
self._client: Client = sdk_client
|
||||
|
||||
def read_deal_property(self, deal_id: str, property_name: str) -> Optional[str]:
|
||||
"""The property's current value, or None when it is unset.
|
||||
|
||||
Read live rather than from the scraped snapshot: callers that rewrite
|
||||
a property whole (HubSpot has no append) would otherwise overwrite
|
||||
edits made since the last scrape.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def write_deal_property(
|
||||
self, deal_id: str, property_name: str, value: str
|
||||
) -> None:
|
||||
|
|
|
|||
|
|
@ -25,10 +25,14 @@ from infrastructure.hubspot.errors import HubspotRequestError
|
|||
# property ID is fixed externally, the domain and database call it job_no.
|
||||
JOB_NO_DEAL_PROPERTY = "client_booking_reference"
|
||||
|
||||
# The note left on a deal whose place Abri reports as having no live tenancy.
|
||||
# Worded as what Abri said rather than as a conclusion about the property: the
|
||||
# same signal would arrive for a place_ref the deal should never have carried.
|
||||
VOID_PROPERTY_NOTE = "Abri reports no live tenancy for this property."
|
||||
# The HubSpot deal property behind "Extra booking information"; the property
|
||||
# ID is fixed externally, and the surveyor-facing label is what users see.
|
||||
NOTES_FOR_SURVEYOR_DEAL_PROPERTY = "notes_for_surveyor"
|
||||
|
||||
# Prepended to that property when Abri reports the place as having no live
|
||||
# tenancy, so a surveyor sees it first. Doubles as the idempotency marker: a
|
||||
# note already carrying it is left alone, so redelivery never stacks markers.
|
||||
VOID_MARKER = "Void ||"
|
||||
|
||||
|
||||
def _vulnerability_description(tenant: Tenant) -> Optional[str]:
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import requests
|
|||
from hubspot.crm.associations.v4 import AssociationSpec # type: ignore[reportMissingTypeStubs]
|
||||
from hubspot.crm.contacts import ApiException as ContactsApiException # type: ignore[reportMissingTypeStubs]
|
||||
from hubspot.crm.contacts import SimplePublicObjectInputForCreate # type: ignore[reportMissingTypeStubs]
|
||||
from hubspot.crm.deals import SimplePublicObjectInput as DealPropertyInput # type: ignore[reportMissingTypeStubs]
|
||||
|
||||
from domain.abri.models import AbriRequestRejected, PlaceRef
|
||||
from infrastructure.hubspot.deal_contacts_client import HubspotDealContactsClient
|
||||
|
|
@ -561,3 +562,29 @@ def test_sync_tenant_data_reports_the_property_void_and_creates_no_contacts(
|
|||
# Assert
|
||||
assert result == PropertyReportedVoid(place_ref=PLACE_REF)
|
||||
assert sdk_client.crm.contacts.mock_calls == []
|
||||
|
||||
|
||||
def test_a_void_property_is_flagged_at_the_front_of_the_deals_booking_information(
|
||||
orchestrator: AbriOrchestrator,
|
||||
mock_session: MagicMock,
|
||||
sdk_client: MagicMock,
|
||||
) -> None:
|
||||
# Arrange: a surveyor must see the property is empty before whatever the
|
||||
# coordinator already wrote for them.
|
||||
mock_session.post.return_value.content = _load_fixture(
|
||||
"abri_relay_getscstenantdata_notenancyfound_response.xml"
|
||||
)
|
||||
sdk_client.crm.deals.basic_api.get_by_id.return_value.properties = {
|
||||
"notes_for_surveyor": "Key safe code 1234"
|
||||
}
|
||||
|
||||
# Act
|
||||
orchestrator.sync_tenant_data(PLACE_REF, deal_id=DEAL_ID)
|
||||
|
||||
# Assert
|
||||
sdk_client.crm.deals.basic_api.update.assert_called_once_with(
|
||||
DEAL_ID,
|
||||
simple_public_object_input=DealPropertyInput(
|
||||
properties={"notes_for_surveyor": "Void || Key safe code 1234"}
|
||||
),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue