from datetime import datetime from typing import Optional, List from sqlalchemy import Column, String, Integer, Float, DateTime, ForeignKey, Enum from sqlalchemy.sql import func from pydantic import BaseModel, Field from .database import Base import enum class OrderStatus(str, enum.Enum): CREATED = "created" # 已下单 ACCEPTED = "accepted" # 已接单 UNPAID = "unpaid" # 未支付 COMPLETED = "completed" # 已完成 CANCELLED = "cancelled" # 已取消 class DeliveryMethod(str, enum.Enum): DELIVERY_TO_DOOR = "delivery_to_door" # 放在门口 DELIVERY_TO_ROOM = "delivery_to_room" # 投递到家 # 数据库模型 class ShippingOrderDB(Base): __tablename__ = "shipping_orders" orderid = Column(String(32), primary_key=True) userid = Column(Integer, ForeignKey("users.userid"), index=True) addressid = Column(Integer, ForeignKey("delivery_addresses.id"), index=True) package_count = Column(Integer, nullable=False) original_amount = Column(Float, nullable=False) coupon_discount_amount = Column(Float, default=0) coupon_id = Column(Integer, ForeignKey("user_coupons.id"), nullable=True) final_amount = Column(Float, nullable=False) status = Column(Enum(OrderStatus), nullable=False, default=OrderStatus.CREATED) cancel_reason = Column(String(200), nullable=True) # 取消原因 complete_images = Column(String(1000), nullable=True) # 完成订单的图片URL,多个URL用逗号分隔 create_time = Column(DateTime(timezone=True), server_default=func.now()) delivery_method = Column(Enum(DeliveryMethod), nullable=False, default=DeliveryMethod.DELIVERY_TO_DOOR) class ShippingOrderPackageDB(Base): __tablename__ = "shipping_order_packages" id = Column(Integer, primary_key=True, autoincrement=True) orderid = Column(String(32), ForeignKey("shipping_orders.orderid"), index=True) station_id = Column(Integer, ForeignKey("stations.id"), index=True) pickup_codes = Column(String(100), nullable=False) create_time = Column(DateTime(timezone=True), server_default=func.now()) # Pydantic 模型 class OrderPackage(BaseModel): station_id: int pickup_codes: str = Field(..., max_length=100) class OrderCreate(BaseModel): addressid: int package_count: int = Field(..., gt=0) original_amount: float = Field(..., ge=0) coupon_id: Optional[int] = None packages: List[OrderPackage] delivery_method: DeliveryMethod = Field(default=DeliveryMethod.DELIVERY_TO_DOOR) class OrderInfo(BaseModel): orderid: str userid: int addressid: int package_count: int original_amount: float coupon_discount_amount: float coupon_id: Optional[int] final_amount: float status: OrderStatus complete_images: Optional[List[str]] = None create_time: datetime delivery_method: DeliveryMethod def __init__(self, **data): super().__init__(**data) # 将逗号分隔的图片URL字符串转换为列表 if self.complete_images and isinstance(self.complete_images, str): self.complete_images = self.complete_images.split(",") class Config: from_attributes = True class OrderPackageInfo(BaseModel): id: int orderid: str station_id: int pickup_codes: str create_time: datetime class Config: from_attributes = True def generate_order_id() -> str: """生成订单号:日期+时间戳""" now = datetime.now() # 生成8位日期 + 6位序号,共14位 date_str = now.strftime('%Y%m%d') # 8位日期 # 生成6位序号(毫秒级时间戳后6位) timestamp = str(int(now.timestamp() * 1000))[-6:] return f"{date_str}{timestamp}" class OrderPriceCalculateRequest(BaseModel): packages: List[OrderPackage] class OrderPriceInfo(BaseModel): package_count: int original_amount: float coupon_discount_amount: float coupon_id: Optional[int] = None final_amount: float # 添加取消订单请求模型 class OrderCancel(BaseModel): reason: str = Field(..., max_length=200, description="取消原因") # 完成订单请求模型 class OrderComplete(BaseModel): images: Optional[List[str]] = Field(None, max_items=5) # 最多5张图片,可选