62 lines
2.7 KiB
Python

"""Validated external assessment inputs; no caller-supplied scores or roles."""
from datetime import date
from typing import Annotated, Literal
from pydantic import ConfigDict, Field, StringConstraints, field_validator, model_validator
from app.schemas.common import ApiSchema
class IntegrationSchema(ApiSchema):
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
class IntegrationOperator(IntegrationSchema):
dingtalk_union_id: str | None = Field(default=None, min_length=1, max_length=64)
external_user_id: str | None = Field(default=None, min_length=1, max_length=128)
dingtalk_user_id: str | None = Field(default=None, min_length=1, max_length=50)
employee_no: str | None = Field(default=None, max_length=64)
name: str | None = Field(default=None, max_length=50)
@model_validator(mode="after")
def identity_source(self):
if bool(self.dingtalk_union_id) == bool(self.external_user_id):
raise ValueError("dingtalkUnionId 和 externalUserId 必须且只能提供一个")
if self.external_user_id and self.dingtalk_user_id:
raise ValueError("外部账号模式不能同时提供 dingtalkUserId")
return self
class IntegrationProduct(IntegrationSchema):
subject_id: str = Field(min_length=1, max_length=128)
product_name: str | None = Field(default=None, max_length=200)
product_category: str = Field(min_length=1, max_length=100)
specification: str | None = Field(default=None, max_length=100)
material_type: str = Field(min_length=1, max_length=200)
supplier: str | None = Field(default=None, max_length=300)
factory: str | None = Field(default=None, max_length=300)
stage_new: Literal["需求发现", "产品立项", "产品开发", "量产上市", "产品生命管理"] | None = None
defect_level: Literal["A", "B", "C"] | None = None
description: str | None = Field(default=None, max_length=2000)
as_of_date: date | None = None
@field_validator("as_of_date", mode="before")
@classmethod
def iso_date(cls, value): # noqa: ANN001
if value is not None and (not isinstance(value, str) or len(value) != 10):
raise ValueError("asOfDate 必须为 YYYY-MM-DD")
if value is not None and date.fromisoformat(value).year < 1900:
raise ValueError("asOfDate 不早于 1900-01-01")
return value
RequestId = Annotated[str, StringConstraints(min_length=1, max_length=128, pattern=r"^[A-Za-z0-9_.:-]+$")]
class IntegrationRiskRequest(IntegrationSchema):
request_id: RequestId
source_system: str = Field(min_length=1, max_length=64, pattern=r"^[A-Za-z0-9_-]+$")
operator: IntegrationOperator
assessment: IntegrationProduct