dingdanquanliucheng/backend/app/schemas/orders.py
wsb1224 a39bd4bc09 新增订单管理页批量匹配物流功能,支持文本/表格截图/快递面单三种模式
- 文本粘贴:正则解析"快递公司+单号+收件人"多行文本
- 物流表格截图:OCR识别后用LLM提取快递单号和收件人
- 快递面单照片:复用快递100面单OCR接口识别单号
- 按customer_name精确匹配订单,同名时展开选择
- 已有单号标记提示,确认后覆盖
- 含唯一性检查、审计日志、缓存清理

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-24 18:16:57 +08:00

346 lines
8.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
订单模块请求模型
定义订单管理相关的请求体数据模型,供 orders 路由使用。
包含订单查询、创建、更新、取消、审批以及供应商对账等操作的请求体。
"""
from pydantic import BaseModel, Field
class OrderListQuery(BaseModel):
"""订单列表查询参数模型。被 GET /api/orders 路由使用。"""
order_no: str | None = None
"""订单编号,模糊匹配"""
order_status: str | None = None
"""订单状态筛选"""
customer_name: str | None = None
"""客户名称,模糊匹配"""
customer_mobile: str | None = None
"""客户手机号,模糊匹配"""
salesman_id: int | None = None
"""业务员 ID 筛选"""
factory_id: int | None = None
"""工厂 ID 筛选"""
order_source: str | None = None
"""订单来源筛选"""
start_time: str | None = None
"""查询起始时间ISO 格式)"""
end_time: str | None = None
"""查询截止时间ISO 格式)"""
page_no: int = 1
"""页码,从 1 开始"""
page_size: int = 20
"""每页条数"""
class OrderItemPayload(BaseModel):
"""订单商品明细载荷,用于创建/更新订单时携带商品行项。"""
product_id: int | None = None
"""产品 ID可选新建时可能尚未关联"""
product_name: str
"""产品名称"""
specification: str
"""规格"""
unit: str
"""单位"""
quantity: float = Field(gt=0)
"""数量,必须大于 0"""
sale_price: float = Field(ge=0)
"""销售单价"""
cost_price: float = Field(ge=0)
"""成本单价"""
rebate_amount: float = Field(default=0, ge=0)
"""返利金额"""
freight_amount: float = Field(default=0, ge=0)
"""运费"""
tax_amount: float = Field(default=0, ge=0)
"""税额"""
other_fee_amount: float = Field(default=0, ge=0)
"""其他费用"""
remark: str | None = None
"""备注"""
demand_specification: str | None = None
"""需求规格"""
# 报价引擎快照字段
pricing_type: str | None = None
"""报价类型(创建订单时从报价引擎快照而来)"""
length_m: float | None = None
"""长度(米),报价快照"""
width_m: float | None = None
"""宽度(米),报价快照"""
area_sqm: float | None = None
"""面积(平方米),报价快照"""
surcharge_detail: str | None = None
"""附加费明细JSON 字符串"""
processing_detail: str | None = None
"""加工费明细JSON 字符串"""
supplier_id: int | None = None
"""供应商 ID报价快照"""
supplier_model: str | None = None
"""供应商型号,报价快照"""
price_tier: str | None = None
"""价格档位,报价快照"""
class CreateOrderRequest(BaseModel):
"""创建订单请求体。被 POST /api/orders 路由使用。"""
customer_name: str
"""客户名称"""
customer_mobile: str
"""客户联系电话"""
customer_address: str | None = None
"""配送地址"""
order_source: str | None = None
"""订单来源"""
delivery_type: str | None = None
"""配送方式"""
factory_id: int | None = None
"""生产工厂 ID"""
contract_amount: float = Field(default=0, ge=0)
"""合同金额(客户应付总额)"""
commission_amount: float = Field(default=0, ge=0)
"""佣金金额"""
rebate_total: float = Field(default=0, ge=0)
"""返利合计"""
freight_total: float = Field(default=0, ge=0)
"""运费合计"""
tax_total: float = Field(default=0, ge=0)
"""税额合计"""
other_fee_total: float = Field(default=0, ge=0)
"""其他费用合计"""
payment_method: str | None = None
"""收款渠道"""
tax_amount: float = Field(default=0, ge=0)
"""含税金额"""
need_invoice: int = Field(default=0, ge=0)
"""是否需要发票0=否1=是)"""
order_type: str | None = None
"""订单类型industry=工业订单daily=日用品订单)"""
self_delivery: int = Field(default=0, ge=0)
"""是否自发0=否1=是)"""
tracking_number: str | None = None
"""快递单号(自发时填写)"""
customer_demand: str | None = None
"""客户需求描述"""
remark: str | None = None
"""备注"""
items: list[OrderItemPayload] = Field(default_factory=list)
"""订单商品明细列表"""
class UpdateOrderRequest(BaseModel):
"""更新订单请求体。被 PUT /api/orders/{id} 路由使用。"""
customer_name: str
"""客户名称"""
customer_mobile: str
"""客户联系电话"""
customer_address: str | None = None
"""配送地址"""
order_source: str | None = None
"""订单来源"""
delivery_type: str | None = None
"""配送方式"""
factory_id: int | None = None
"""生产工厂 ID"""
contract_amount: float = Field(default=0, ge=0)
"""合同金额(客户应付总额)"""
commission_amount: float = Field(default=0, ge=0)
"""佣金金额"""
rebate_total: float = Field(default=0, ge=0)
"""返利合计"""
freight_total: float = Field(default=0, ge=0)
"""运费合计"""
tax_total: float = Field(default=0, ge=0)
"""税额合计"""
other_fee_total: float = Field(default=0, ge=0)
"""其他费用合计"""
payment_method: str | None = None
"""收款渠道"""
tax_amount: float = Field(default=0, ge=0)
"""含税金额"""
need_invoice: int = Field(default=0, ge=0)
"""是否需要发票0=否1=是)"""
order_type: str | None = None
"""订单类型industry=工业订单daily=日用品订单)"""
self_delivery: int = Field(default=0, ge=0)
"""是否自发0=否1=是)"""
tracking_number: str | None = None
"""快递单号(自发时填写)"""
customer_demand: str | None = None
"""客户需求描述"""
remark: str | None = None
"""备注"""
items: list[OrderItemPayload] = Field(default_factory=list)
"""订单商品明细列表(全量替换)"""
class CancelOrderRequest(BaseModel):
"""取消订单请求体。被 POST /api/orders/{id}/cancel 路由使用。"""
cancel_reason: str
"""取消原因"""
cancel_opinion: str | None = None
"""取消审批意见"""
class ApproveOrderRequest(BaseModel):
"""审批订单请求体。被 POST /api/orders/{id}/approve 路由使用。"""
approve_result: str
"""审批结果(如 approved / rejected"""
approve_opinion: str | None = None
"""审批意见"""
class SupplierTextRequest(BaseModel):
"""获取供应商对账文本请求体。被 POST /api/orders/supplier-text 路由使用。"""
supplier_id: int
"""供应商 ID"""
class ConfirmSupplierTextRequest(BaseModel):
"""确认供应商对账文本请求体。被 POST /api/orders/supplier-text/confirm 路由使用。"""
supplier_id: int
"""供应商 ID"""
text_content: str
"""对账文本内容"""
remark: str | None = None
"""备注"""
class ChangeOrderStatusRequest(BaseModel):
"""变更订单状态请求体。被 POST /api/orders/{id}/status 路由使用。"""
target_status: str
"""目标状态"""
remark: str | None = None
"""备注"""
class UpdateOrderTrackingRequest(BaseModel):
"""修改自发订单快递单号请求体。被 PUT /api/orders/{id}/tracking 路由使用。"""
tracking_number: str
"""快递单号"""
remark: str | None = None
class LogisticsMatchItem(BaseModel):
"""批量匹配物流条目。"""
tracking_number: str
"""快递单号"""
express_company: str | None = None
"""快递公司"""
recipient_name: str | None = None
"""收件人姓名(面单场景可能为空)"""
order_id: int | None = None
"""用户确认后填入的目标订单 ID"""
class BatchMatchLogisticsRequest(BaseModel):
"""批量匹配物流请求体。被 POST /api/orders/batch-match-logistics 路由使用。"""
mode: str
"""模式text文本粘贴| image_table物流表格截图| express_images快递面单照片"""
text: str | None = None
"""mode=text 时的文本内容"""
image_urls: list[str] = Field(default_factory=list)
"""mode=image_table 或 express_images 时的图片 URL 列表"""
class BatchMatchConfirmRequest(BaseModel):
"""批量匹配确认请求体。被 POST /api/orders/batch-match-logistics/confirm 路由使用。"""
matches: list[LogisticsMatchItem] = Field(min_length=1)
"""用户确认后的匹配列表,至少一条"""