Files
shanxia2.0/backend/app/schemas/pl/quota_cert.py
T

122 lines
5.4 KiB
Python

"""证件档案写入契约:只接收可写字段,遗漏与清空严格区分。"""
from datetime import date
from decimal import Decimal
from typing import List, Literal, Optional
from pydantic import BaseModel, ConfigDict, Field, field_validator
def camel(name: str) -> str:
first, *parts = name.split('_')
return first + ''.join(p.title() for p in parts)
class InputBody(BaseModel):
model_config = ConfigDict(alias_generator=camel, populate_by_name=True, extra='forbid')
class CertFields(InputBody):
cert_no: Optional[str] = Field(None, min_length=1, max_length=100)
issue_date: Optional[date] = None
product_name_on_cert: Optional[str] = Field(None, min_length=1, max_length=200)
total_qty: Optional[Decimal] = Field(None, ge=0, max_digits=18, decimal_places=6, allow_inf_nan=False)
quantity_unit: Optional[str] = Field(None, min_length=1, max_length=32)
valid_from: Optional[date] = None
valid_to: Optional[date] = None
valid_use_text: Optional[str] = Field(None, min_length=1, max_length=32)
entry_mode: Optional[Literal['manual', 'image_parse']] = None
attachment_urls: Optional[str] = None
status: Optional[Literal['draft', 'suspended', 'void']] = None
remark: Optional[str] = Field(None, max_length=1000)
order_num: Optional[int] = None
@field_validator('valid_use_text')
@classmethod
def validate_use_text(cls, value):
if value is not None and not value.strip():
raise ValueError('有效次数原文不能为空')
return value
class PurchaseCertUpdate(CertFields):
buyer_name: Optional[str] = Field(None, max_length=255)
buyer_address: Optional[str] = Field(None, max_length=1000)
buyer_legal_representative: Optional[str] = Field(None, max_length=100)
buyer_phone: Optional[str] = Field(None, max_length=100)
seller_name: Optional[str] = Field(None, max_length=255)
seller_address: Optional[str] = Field(None, max_length=1000)
seller_legal_representative: Optional[str] = Field(None, max_length=100)
seller_phone: Optional[str] = Field(None, max_length=100)
purchase_purpose: Optional[str] = Field(None, max_length=1000)
class PurchaseCertCreate(PurchaseCertUpdate):
cert_no: str = Field(min_length=1, max_length=100)
product_name_on_cert: str = Field(min_length=1, max_length=200)
total_qty: Decimal = Field(ge=0, max_digits=18, decimal_places=6, allow_inf_nan=False)
quantity_unit: str = Field(min_length=1, max_length=32)
valid_use_text: str = Field(min_length=1, max_length=32)
buyer_name: str = Field(min_length=1, max_length=255)
seller_name: str = Field(min_length=1, max_length=255)
entry_mode: Literal['manual', 'image_parse'] = 'manual'
class PurchaseReference(InputBody):
id: Optional[str] = None
reference_type: Literal['purchase_permit', 'purchase_filing', 'export_permit', 'unknown']
reference_no: str = Field(min_length=1, max_length=100)
purchase_cert_id: Optional[str] = None
remark: Optional[str] = Field(None, max_length=1000)
order_num: Optional[int] = None
class TransportCertUpdate(CertFields):
shipper_name: Optional[str] = Field(None, max_length=255)
shipper_address: Optional[str] = Field(None, max_length=1000)
shipper_legal_representative: Optional[str] = Field(None, max_length=100)
shipper_phone: Optional[str] = Field(None, max_length=100)
packaging_text: Optional[str] = Field(None, max_length=255)
carrier_name: Optional[str] = Field(None, max_length=255)
carrier_address_phone: Optional[str] = Field(None, max_length=1200)
transport_mode: Optional[str] = Field(None, max_length=100)
vehicle_numbers_json: Optional[List[str]] = None
route_text: Optional[str] = None
consignee_name: Optional[str] = Field(None, max_length=255)
applicant_name: Optional[str] = Field(None, max_length=255)
purchase_refs: Optional[List[PurchaseReference]] = None
class TransportCertCreate(TransportCertUpdate):
cert_no: str = Field(min_length=1, max_length=100)
product_name_on_cert: str = Field(min_length=1, max_length=200)
total_qty: Decimal = Field(ge=0, max_digits=18, decimal_places=6, allow_inf_nan=False)
quantity_unit: str = Field(min_length=1, max_length=32)
valid_use_text: str = Field(min_length=1, max_length=32)
shipper_name: str = Field(min_length=1, max_length=255)
vehicle_numbers_json: List[str] = Field(default_factory=list)
entry_mode: Literal['manual', 'image_parse'] = 'manual'
class CertConfirmBody(InputBody):
operation_id: str = Field(min_length=1, max_length=64)
used_qty: Decimal = Field(ge=0, max_digits=18, decimal_places=6, allow_inf_nan=False)
single_use_consumed: bool
reason: str = Field(min_length=1, max_length=1000)
evidence_urls: Optional[str] = None
source_note: Optional[str] = Field(None, max_length=1000)
class CertVerifyBody(InputBody):
operation_id: str = Field(min_length=1, max_length=64)
reason: str = Field(min_length=1, max_length=1000)
evidence_urls: Optional[str] = None
source_note: Optional[str] = Field(None, max_length=1000)
class CertTotalAdjustBody(InputBody):
operation_id: str = Field(min_length=1, max_length=64)
total_qty: Decimal = Field(ge=0, max_digits=18, decimal_places=6, allow_inf_nan=False)
reason: str = Field(min_length=1, max_length=1000)
source_note: str = Field('', max_length=1000)
evidence_urls: str = Field('', max_length=2000)