Files
X-Financial/server/src/app/schemas/risk_disposition.py
2026-07-16 15:34:58 +08:00

97 lines
2.9 KiB
Python

from __future__ import annotations
from datetime import datetime
from typing import Any, Literal
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
RiskDispositionAction = Literal[
"confirm",
"false_positive",
"request_supplement",
"start_remediation",
"resolve",
"request_waiver",
]
RiskAdjudication = Literal["unreviewed", "confirmed", "false_positive"]
RiskLifecycleStatus = Literal[
"open",
"supplement_requested",
"remediation_in_progress",
"waiver_requested",
"resolved",
]
class RiskDispositionActionCreate(BaseModel):
action: RiskDispositionAction
expected_version: int = Field(ge=0)
request_id: str = Field(min_length=8, max_length=120)
comment: str | None = Field(default=None, max_length=1000)
assignee: str | None = Field(default=None, max_length=120)
due_at: datetime | None = None
resolution: str | None = Field(default=None, max_length=2000)
@field_validator("request_id", "comment", "assignee", "resolution", mode="before")
@classmethod
def normalize_text(cls, value: Any) -> Any:
if value is None:
return None
normalized = str(value).strip()
return normalized or None
@model_validator(mode="after")
def validate_action_fields(self) -> RiskDispositionActionCreate:
if self.action == "resolve" and not self.resolution:
raise ValueError("resolve 动作必须填写 resolution")
if self.action in {"false_positive", "request_supplement", "request_waiver"} and not (
self.comment
):
raise ValueError(f"{self.action} 动作必须填写 comment")
if self.action in {"confirm", "false_positive"} and any(
value is not None for value in (self.assignee, self.due_at, self.resolution)
):
raise ValueError("裁决动作不能同时修改负责人、截止时间或解决说明")
return self
class RiskDispositionEventRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: str
tenant_id: str
disposition_id: str
observation_id: str
version: int
action: RiskDispositionAction
actor_id: str
actor_name: str
request_id: str
comment: str | None
before_json: dict[str, Any]
after_json: dict[str, Any]
created_at: datetime
class RiskDispositionRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: str
tenant_id: str
observation_id: str
adjudication: RiskAdjudication
lifecycle_status: RiskLifecycleStatus
version: int
assignee: str | None
due_at: datetime | None
resolution: str | None
created_at: datetime
updated_at: datetime
events: list[RiskDispositionEventRead] = Field(default_factory=list)
class RiskDispositionMutationRead(BaseModel):
disposition: RiskDispositionRead
event: RiskDispositionEventRead
replayed: bool = False