补充业务详情指导成本入口、来源版本和历史封存保护,接入月份锁并完善权限复核。 同步接入读取服务运行状态到页面,补充前端控制、回归测试和服务端只读连接授权校验。 定向隔离测试:89 项通过,1 条既有 Starlette 弃用警告。
110 lines
4.0 KiB
Python
110 lines
4.0 KiB
Python
"""来源业务的人工分类资料。"""
|
|
|
|
from decimal import Decimal, InvalidOperation
|
|
from typing import Literal
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
|
|
from app.core.response import PageQuery
|
|
|
|
|
|
class SalesRelationQuery(PageQuery):
|
|
shipment_page: int = Field(default=1, ge=1, le=10000)
|
|
order_page: int = Field(default=1, ge=1, le=10000)
|
|
|
|
|
|
class SourceDocumentsQuery(PageQuery):
|
|
entity: str | None = Field(default=None, max_length=32)
|
|
|
|
|
|
class SourcePriceConfirmIn(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
revision: str = Field(pattern=r"^[0-9a-f]{64}$")
|
|
evidence: str = Field(min_length=1, max_length=500)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_evidence(self):
|
|
self.evidence = self.evidence.strip()
|
|
if not self.evidence:
|
|
raise ValueError("核对依据不能为空")
|
|
return self
|
|
|
|
|
|
class GuidanceConfirmIn(BaseModel):
|
|
"""从业务发货明细登记对应发货月份的单位指导成本。"""
|
|
|
|
model_config = ConfigDict(extra="forbid")
|
|
shipment_item_id: int = Field(ge=1)
|
|
amount: str = Field(min_length=1, max_length=32)
|
|
evidence: str = Field(min_length=1, max_length=500)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_values(self):
|
|
self.evidence = self.evidence.strip()
|
|
if not self.evidence:
|
|
raise ValueError("核对依据不能为空")
|
|
try:
|
|
value = Decimal(self.amount)
|
|
except (InvalidOperation, TypeError, ValueError):
|
|
raise ValueError("指导成本必须为有效数字") from None
|
|
if not value.is_finite() or value < 0 or value.as_tuple().exponent < -4:
|
|
raise ValueError("指导成本最多保留4位小数且不能为负数")
|
|
return self
|
|
|
|
|
|
class SourceProductCategory(BaseModel):
|
|
product_id: int = Field(ge=1)
|
|
category: Literal["municipal_water", "rail_transit"]
|
|
|
|
|
|
class SourceMaterialsIn(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
customer_type: Literal["personal", "manager_personal", "enterprise"] | None = None
|
|
products: list[SourceProductCategory] = Field(default_factory=list, max_length=200)
|
|
|
|
@model_validator(mode="after")
|
|
def unique_products(self):
|
|
if len({p.product_id for p in self.products}) != len(self.products):
|
|
raise ValueError("产品不能重复")
|
|
if self.customer_type is None and not self.products:
|
|
raise ValueError("请选择要补充的分类")
|
|
return self
|
|
|
|
|
|
class SalesRelationConfirmIn(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
item_id: int = Field(ge=1)
|
|
shipment_document_id: int = Field(ge=1)
|
|
order_document_id: int | None = Field(default=None, ge=1)
|
|
disposition: Literal["ORDER", "INDEPENDENT"]
|
|
item_revision: str = Field(pattern=r"^[0-9a-f]{64}$")
|
|
shipment_revision: str = Field(pattern=r"^[0-9a-f]{64}$")
|
|
order_revision: str | None = Field(default=None, pattern=r"^[0-9a-f]{64}$")
|
|
expected_version: int = Field(default=0, ge=0)
|
|
evidence: str = Field(min_length=1, max_length=500)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_relation(self):
|
|
self.evidence = self.evidence.strip()
|
|
if not self.evidence:
|
|
raise ValueError("确认依据不能为空")
|
|
if self.disposition == "ORDER" and (self.order_document_id is None or self.order_revision is None):
|
|
raise ValueError("请选择并核对订单明细")
|
|
if self.disposition == "INDEPENDENT" and (self.order_document_id is not None or self.order_revision is not None):
|
|
raise ValueError("独立发货不应指定订单明细")
|
|
return self
|
|
|
|
|
|
class SalesRelationReleaseIn(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
item_id: int = Field(ge=1)
|
|
expected_version: int = Field(ge=1)
|
|
evidence: str = Field(min_length=1, max_length=500)
|
|
|
|
@model_validator(mode="after")
|
|
def validate_evidence(self):
|
|
self.evidence = self.evidence.strip()
|
|
if not self.evidence:
|
|
raise ValueError("撤销依据不能为空")
|
|
return self
|