Model/applications/abri/abri_trigger_request.py
Daniel Roth 8daaa0974d A trigger message validates the fields each fired Abri flow needs 🟩
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 10:05:25 +00:00

44 lines
1.5 KiB
Python

"""The message contract between the HubSpot scraper and the abri lambda.
One message per scrape, naming every Abri flow that fired plus the deal
fields those flows need. A message missing a field its flow needs fails
validation — the resulting failed task / DLQ entry is the agreed
visibility surface.
"""
from datetime import date
from typing import Dict, List, Literal, Optional, Tuple
from pydantic import BaseModel, ConfigDict, Field, model_validator
AbriFlow = Literal["amend_job", "log_job", "sync_tenant_data"]
# The deal fields each flow reads; hubspot_deal_id is always required.
_FIELDS_BY_FLOW: Dict[AbriFlow, Tuple[str, ...]] = {
"amend_job": ("confirmed_survey_date",),
"log_job": ("place_ref", "deal_name", "confirmed_survey_date"),
"sync_tenant_data": ("place_ref",),
}
class AbriTriggerRequest(BaseModel):
model_config = ConfigDict(extra="ignore")
hubspot_deal_id: str
flows: List[AbriFlow] = Field(min_length=1)
place_ref: Optional[str] = None
deal_name: Optional[str] = None
confirmed_survey_date: Optional[date] = None
confirmed_survey_time: Optional[str] = None
@model_validator(mode="after")
def _each_fired_flow_has_its_fields(self) -> "AbriTriggerRequest":
missing = [
f"flow {flow} requires {field}"
for flow in self.flows
for field in _FIELDS_BY_FLOW[flow]
if getattr(self, field) is None
]
if missing:
raise ValueError("; ".join(missing))
return self