62 lines
2.7 KiB
Python
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
|