"""入库单 / 出库单 Pydantic schemas""" from __future__ import annotations from datetime import date, datetime from decimal import Decimal from typing import Optional from pydantic import BaseModel, Field class BrandOption(BaseModel): brand_id: str = Field(alias="brandId") brand_name: str = Field(alias="brandName") model_config = {"populate_by_name": True} class BrandQtyItem(BaseModel): brand_id: str = Field(default="", alias="brandId") brand_name: Optional[str] = Field(default=None, alias="brandName") qty: Decimal = Field(..., ge=0) model_config = {"populate_by_name": True} class IoOrderItemRead(BaseModel): id: str order_id: str = Field(alias="orderId") plan_product_id: str = Field(alias="planProductId") product_id: Optional[str] = Field(default=None, alias="productId") product_name: Optional[str] = Field(default=None, alias="productName") alias_name: Optional[str] = Field(default=None, alias="aliasName") brand_summary: Optional[str] = Field(default=None, alias="brandSummary") brand_mode: Optional[str] = Field(default=None, alias="brandMode") brand_id: Optional[str] = Field(default=None, alias="brandId") brand_name: Optional[str] = Field(default=None, alias="brandName") brand_options: Optional[list[BrandOption]] = Field(default=None, alias="brandOptions") brand_qtys: Optional[list[BrandQtyItem]] = Field(default=None, alias="brandQtys") specification: Optional[str] = None unit: Optional[str] = None plan_qty: Optional[Decimal] = Field(default=None, alias="planQty") actual_qty: Optional[Decimal] = Field(default=None, alias="actualQty") qty_source: Optional[str] = Field(default=None, alias="qtySource") product_no: Optional[str] = Field(default=None, alias="productNo") category_name: Optional[str] = Field(default=None, alias="categoryName") package_spec: Optional[str] = Field(default=None, alias="packageSpec") delivery_method: Optional[str] = Field(default=None, alias="deliveryMethod") remark: Optional[str] = None unit_label: Optional[str] = Field(default=None, alias="unitLabel") model_config = {"populate_by_name": True} class IoOrderItemPatch(BaseModel): id: str actual_qty: Decimal = Field(alias="actualQty") brand_qtys: Optional[list[BrandQtyItem]] = Field(default=None, alias="brandQtys") model_config = {"populate_by_name": True} class IoOrderPatch(BaseModel): status: Optional[str] = None site_feedback_remark: Optional[str] = Field(default=None, alias="siteFeedbackRemark") site_feedback_images: Optional[list[str]] = Field(default=None, alias="siteFeedbackImages") remark: Optional[str] = None items: Optional[list[IoOrderItemPatch]] = None model_config = {"populate_by_name": True} class IoOrderRead(BaseModel): id: str order_no: str = Field(alias="orderNo") plan_id: str = Field(alias="planId") transport_id: str = Field(alias="transportId") status: str partner_company: Optional[str] = Field(default=None, alias="partnerCompany") vehicle_no: Optional[str] = Field(default=None, alias="vehicleNo") plan_no: Optional[str] = Field(default=None, alias="planNo") plan_date: Optional[date] = Field(default=None, alias="planDate") site_access_token: Optional[str] = Field(default=None, alias="siteAccessToken") site_url: Optional[str] = Field(default=None, alias="siteUrl") site_feedback_remark: Optional[str] = Field(default=None, alias="siteFeedbackRemark") site_feedback_images: list[str] = Field(default_factory=list, alias="siteFeedbackImages") site_feedback_time: Optional[datetime] = Field(default=None, alias="siteFeedbackTime") site_first_submitted_at: Optional[datetime] = Field(default=None, alias="siteFirstSubmittedAt") remark: Optional[str] = None product_summary: Optional[str] = Field(default=None, alias="productSummary") actual_qty_total: Optional[float] = Field(default=None, alias="actualQtyTotal") kind: str items: list[IoOrderItemRead] = Field(default_factory=list) business_type: Optional[str] = Field(default=None, alias="businessType") plan_remark: Optional[str] = Field(default=None, alias="planRemark") pickup_address: Optional[str] = Field(default=None, alias="pickupAddress") pickup_lng: Optional[float] = Field(default=None, alias="pickupLng") pickup_lat: Optional[float] = Field(default=None, alias="pickupLat") pickup_time: Optional[datetime] = Field(default=None, alias="pickupTime") pickup_contact: Optional[str] = Field(default=None, alias="pickupContact") pickup_notes: Optional[str] = Field(default=None, alias="pickupNotes") destination_name: Optional[str] = Field(default=None, alias="destinationName") destination_address: Optional[str] = Field(default=None, alias="destinationAddress") destination_lng: Optional[float] = Field(default=None, alias="destinationLng") destination_lat: Optional[float] = Field(default=None, alias="destinationLat") delivery_time: Optional[datetime] = Field(default=None, alias="deliveryTime") delivery_contact: Optional[str] = Field(default=None, alias="deliveryContact") destination_notes: Optional[str] = Field(default=None, alias="destinationNotes") create_time: Optional[datetime] = Field(default=None, alias="createTime") update_time: Optional[datetime] = Field(default=None, alias="updateTime") model_config = {"populate_by_name": True} class IoOrderListResponse(BaseModel): total: int list: list[IoOrderRead] class PublicIoOrderItemFeedback(BaseModel): id: str actual_qty: Decimal = Field(alias="actualQty") brand_qtys: Optional[list[BrandQtyItem]] = Field(default=None, alias="brandQtys") model_config = {"populate_by_name": True} class PublicIoOrderStopProductFeedback(BaseModel): stop_product_id: str = Field(alias="stopProductId") actual_qty: Decimal = Field(alias="actualQty") brand_qtys: Optional[list[BrandQtyItem]] = Field(default=None, alias="brandQtys") model_config = {"populate_by_name": True} class PublicIoOrderStopFeedback(BaseModel): stop_type: str = Field(alias="stopType") stop_id: str = Field(alias="stopId") attachment_urls: list[str] = Field(default_factory=list, alias="attachmentUrls") products: list[PublicIoOrderStopProductFeedback] = Field(default_factory=list) model_config = {"populate_by_name": True} class PublicIoOrderFeedback(BaseModel): status: str remark: Optional[str] = None images: list[str] = Field(default_factory=list) items: list[PublicIoOrderItemFeedback] = Field(default_factory=list) stops: list[PublicIoOrderStopFeedback] = Field(default_factory=list) model_config = {"populate_by_name": True} class PublicIoOrderHistoryProductRead(BaseModel): product_name: str = Field(alias="productName") model: Optional[str] = None package_spec: Optional[str] = Field(default=None, alias="packageSpec") quantity: Optional[Decimal] = None unit: Optional[str] = None model_config = {"populate_by_name": True} class PublicIoOrderHistoryRecordRead(BaseModel): kind: str = Field(description="inbound | outbound") order_id: str = Field(alias="orderId") order_no: str = Field(alias="orderNo") plan_id: Optional[str] = Field(default=None, alias="planId") plan_no: Optional[str] = Field(default=None, alias="planNo") plan_date: Optional[date] = Field(default=None, alias="planDate") partner_company: Optional[str] = Field(default=None, alias="partnerCompany") supplier_name: Optional[str] = Field(default=None, alias="supplierName") customer_name: Optional[str] = Field(default=None, alias="customerName") vehicle_no: Optional[str] = Field(default=None, alias="vehicleNo") pickup_time: Optional[datetime] = Field(default=None, alias="pickupTime") delivery_time: Optional[datetime] = Field(default=None, alias="deliveryTime") pickup_address: Optional[str] = Field(default=None, alias="pickupAddress") destination_address: Optional[str] = Field(default=None, alias="destinationAddress") products: list[PublicIoOrderHistoryProductRead] = Field(default_factory=list) site_access_token: Optional[str] = Field(default=None, alias="siteAccessToken") site_url: Optional[str] = Field(default=None, alias="siteUrl") status: Optional[str] = None order_voided: bool = Field(default=False, alias="orderVoided") plan_archived: bool = Field(default=False, alias="planArchived") status_label: str = Field(default="进行中", alias="statusLabel") model_config = {"populate_by_name": True} class PublicIoOrderHistoryPageRead(BaseModel): date: str keyword: Optional[str] = None page: int = 1 page_size: int = Field(default=20, alias="pageSize") total: int = 0 records: list[PublicIoOrderHistoryRecordRead] = Field(default_factory=list) model_config = {"populate_by_name": True}