Source code for cadrumo.application.workflow.review_models
"""Canonical workflow event and review-record contracts."""from__future__importannotationsfromdatetimeimportdatetimefrompydanticimportBaseModel,Field,field_validatorfrom...core.errors.hierarchyimportpydantic_validation_boundaryfrom...core.identity.bucketimportBucketIdfrom...core.identity.hex_idsimportInvoiceIdfrom...core.identity.transaction_idsimportTransactionIdfrom...core.modelsimportSTRICT_FROZEN_CONFIGas_STRICT_FROZENfrom...core.time.clockimportnowasutc_nowfrom...core.time.utcimportvalidate_utc_awarefrom...domain.contribuyente.normaliseimportnormalise_key
[docs]classWorkflowEvent(BaseModel):"""One operator-visible event emitted by a mutating workflow verb. Events are appended to :attr:`~application.workflow.state_models.WorkflowState.bucket_events` so the operator can audit which actions ran, when, and against which object. ``action`` names the verb (e.g. ``"profile.created"``); ``reason`` carries a free-form human-readable annotation; ``bucket_id`` and ``object_id`` are optional pointers to the affected resource. """model_config=_STRICT_FROZENaction:str=Field(min_length=1)reason:str=""bucket_id:BucketId|None=Noneobject_id:str|None=Noneat:datetime=Field(default_factory=utc_now)@field_validator("at")@classmethod@pydantic_validation_boundarydef_instant_is_utc(cls,value:datetime)->datetime:"""Reject an event instant that is naive or not UTC. These records serialise as JSON, which preserves the offset, so the canonical contract is enforceable at the model boundary. """returnvalidate_utc_aware(value)@field_validator("action","reason")@classmethoddef_trim_text(cls,value:str)->str:returnvalue.strip()@field_validator("bucket_id","object_id")@classmethoddef_trim_optional_text(cls,value:str|None)->str|None:ifvalueisNone:returnNonetrimmed=value.strip()returntrimmedorNone
[docs]classLedgerReviewRecord(BaseModel):"""Workflow attention annotation for one persisted transaction. Durable transaction facts are not stored here. Classification, category, business percentage, tax fields, evidence references, skip/final-disposition state, and corrections live on the bucket-scoped transaction catalogue. """model_config=_STRICT_FROZENtransaction_id:TransactionIdhistory:tuple[WorkflowEvent,...]=()updated_at:datetime=Field(default_factory=utc_now)@field_validator("updated_at")@classmethod@pydantic_validation_boundarydef_instant_is_utc(cls,value:datetime)->datetime:"""Reject a review-update instant that is naive or not UTC. These records serialise as JSON, which preserves the offset, so the canonical contract is enforceable at the model boundary. """returnvalidate_utc_aware(value)
[docs]classInvoiceReviewRecord(BaseModel):"""Workflow annotations for one persisted invoice."""model_config=_STRICT_FROZENinvoice_id:InvoiceIdfields:dict[str,str]=Field(default_factory=dict)history:tuple[WorkflowEvent,...]=()updated_at:datetime=Field(default_factory=utc_now)@field_validator("updated_at")@classmethod@pydantic_validation_boundarydef_instant_is_utc(cls,value:datetime)->datetime:"""Reject a review-update instant that is naive or not UTC. These records serialise as JSON, which preserves the offset, so the canonical contract is enforceable at the model boundary. """returnvalidate_utc_aware(value)@field_validator("fields")@classmethoddef_normalise_fields(cls,value:dict[str,str])->dict[str,str]:return{normalise_key(str(key)):str(raw).strip()forkey,rawinvalue.items()}