61 lines
2.4 KiB
Python
61 lines
2.4 KiB
Python
"""手工派车日历输入,只接收可写业务字段。"""
|
|
import re
|
|
from datetime import date
|
|
from typing import Optional
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
|
|
|
|
|
class CreateBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True, extra="forbid", str_strip_whitespace=True)
|
|
|
|
dispatch_date: date = Field(..., alias="dispatchDate", description="派车日期,范围 1900-01-01 至 2100-12-31")
|
|
vehicle_id: str = Field(..., alias="vehicleId", min_length=1, max_length=64)
|
|
product_id: str = Field(..., alias="productId", min_length=1, max_length=64)
|
|
origin: str = Field(default="", max_length=255)
|
|
destination: str = Field(default="", max_length=255)
|
|
quantity: Optional[str] = Field(default=None, max_length=16, description="数量文本,单位吨,最多两位小数;不参与汇总")
|
|
calendar_kind: str = Field(default="acid", alias="calendarKind", min_length=1, max_length=16)
|
|
remark: Optional[str] = Field(default=None, max_length=500)
|
|
|
|
@field_validator("dispatch_date", mode="before")
|
|
@classmethod
|
|
def validate_date_format(cls, value):
|
|
if not isinstance(value, str) or not re.fullmatch(r"[0-9]{4}-[0-9]{2}-[0-9]{2}", value):
|
|
raise ValueError("派车日期须为 YYYY-MM-DD")
|
|
return value
|
|
|
|
|
|
@field_validator("dispatch_date")
|
|
@classmethod
|
|
def validate_date_range(cls, value: date) -> date:
|
|
# Pydantic 2.5 的 date ge/le 会生成不合法的 OpenAPI 数字范围约束。
|
|
if not date(1900, 1, 1) <= value <= date(2100, 12, 31):
|
|
raise ValueError("派车日期须在 1900-01-01 至 2100-12-31 范围内")
|
|
return value
|
|
|
|
@field_validator("quantity", mode="before")
|
|
@classmethod
|
|
def validate_quantity(cls, value):
|
|
if value is None:
|
|
return None
|
|
if not isinstance(value, str):
|
|
raise ValueError("数量须为文本")
|
|
text = value.strip()
|
|
if not text:
|
|
return None
|
|
if not re.fullmatch(r"\d{1,12}(\.\d{1,2})?", text):
|
|
raise ValueError("数量须为数字,最多两位小数")
|
|
return text
|
|
|
|
@field_validator("calendar_kind")
|
|
@classmethod
|
|
def validate_calendar_kind(cls, value: str) -> str:
|
|
if value not in ("acid", "alkali", "other", "site"):
|
|
raise ValueError("日历类型须为 acid、alkali、other 或 site")
|
|
return value
|
|
|
|
|
|
class UpdateBody(CreateBody):
|
|
"""PUT 提交完整表单。"""
|