from fastapi import APIRouter, Depends from sqlalchemy.orm import Session from typing import List, Optional from app.models.order import ( ShippingOrderDB, ShippingOrderPackageDB, OrderCreate, OrderInfo, OrderPackageInfo, generate_order_id, OrderPriceCalculateRequest, OrderPriceInfo, OrderStatus, OrderCancel, OrderComplete ) from app.models.database import get_db from app.api.deps import get_current_user, get_deliveryman_user from app.models.user import UserDB,UserRole from app.core.response import success_response, error_response, ResponseModel from app.models.coupon import UserCouponDB, CouponStatus from datetime import datetime, timezone from app.core.config import settings from app.models.address import AddressDB from sqlalchemy.orm import joinedload from app.models.community import CommunityDB from app.models.community_building import CommunityBuildingDB from app.models.station import StationDB router = APIRouter() @router.post("/", response_model=ResponseModel) async def create_shipping_order( order: OrderCreate, db: Session = Depends(get_db), current_user: UserDB = Depends(get_current_user) ): """创建配送订单""" # 生成订单号 orderid = generate_order_id() # 计算订单价格 package_count = sum( len(package.pickup_codes.split(',')) for package in order.price_request.packages if package.pickup_codes ) # 计算原始金额 original_amount = settings.ORDER_BASE_PRICE if package_count > settings.ORDER_EXTRA_PACKAGE_THRESHOLD: extra_packages = package_count - settings.ORDER_EXTRA_PACKAGE_THRESHOLD original_amount += extra_packages * settings.ORDER_EXTRA_PACKAGE_PRICE # 计算优惠券折扣 coupon_discount = 0 coupon_id = None # 查询用户优惠券 user_coupon = db.query(UserCouponDB).filter( UserCouponDB.user_id == current_user.userid, UserCouponDB.status == CouponStatus.UNUSED, UserCouponDB.expire_time > datetime.now(timezone.utc) ).first() if user_coupon: coupon_discount = user_coupon.coupon_amount coupon_id = user_coupon.id # 更新优惠券状态 user_coupon.status = CouponStatus.USED # 计算最终金额 final_amount = max(0, original_amount - coupon_discount) # 创建订单 db_order = ShippingOrderDB( orderid=orderid, userid=current_user.userid, addressid=order.addressid, package_count=package_count, original_amount=original_amount, coupon_discount_amount=coupon_discount, coupon_id=coupon_id, final_amount=final_amount, delivery_method=order.delivery_method ) db.add(db_order) # 创建订单包裹 for package in order.price_request.packages: db_package = ShippingOrderPackageDB( orderid=orderid, station_id=package.station_id, pickup_codes=package.pickup_codes ) db.add(db_package) try: db.commit() db.refresh(db_order) # 查询包裹信息 packages = db.query(ShippingOrderPackageDB).filter( ShippingOrderPackageDB.orderid == orderid ).all() return success_response( message="订单创建成功", data={ "order": OrderInfo.model_validate(db_order), "packages": [OrderPackageInfo.model_validate(p) for p in packages] } ) except Exception as e: db.rollback() return error_response(code=500, message=f"订单创建失败: {str(e)}") @router.get("/{orderid}", response_model=ResponseModel) async def get_order_detail( orderid: str, db: Session = Depends(get_db), current_user: UserDB = Depends(get_current_user) ): """获取订单详情""" # 使用 join 查询获取订单和相关地址信息 order = db.query( ShippingOrderDB, AddressDB.name.label('address_name'), AddressDB.phone.label('address_phone'), AddressDB.address_detail.label('address_detail'), CommunityBuildingDB.building_name.label('building_name'), CommunityDB.name.label('community_name') ).join( AddressDB, ShippingOrderDB.addressid == AddressDB.id ).join( CommunityBuildingDB, AddressDB.community_building_id == CommunityBuildingDB.id ).join( CommunityDB, CommunityBuildingDB.community_id == CommunityDB.id ).filter( ShippingOrderDB.orderid == orderid ).first() if not order: return error_response(code=404, message="订单不存在") # 检查权限 if order.ShippingOrderDB.userid != current_user.userid and UserRole.ADMIN not in current_user.roles: return error_response(code=403, message="无权查看此订单") # 查询包裹信息,包含驿站名称 packages = db.query( ShippingOrderPackageDB, StationDB.name.label('station_name') ).join( StationDB, ShippingOrderPackageDB.station_id == StationDB.id ).filter( ShippingOrderPackageDB.orderid == orderid ).all() # 构建响应数据 order_data = { "orderid": order.ShippingOrderDB.orderid, "userid": order.ShippingOrderDB.userid, "addressid": order.ShippingOrderDB.addressid, "package_count": order.ShippingOrderDB.package_count, "original_amount": order.ShippingOrderDB.original_amount, "coupon_discount_amount": order.ShippingOrderDB.coupon_discount_amount, "coupon_id": order.ShippingOrderDB.coupon_id, "final_amount": order.ShippingOrderDB.final_amount, "status": order.ShippingOrderDB.status, "complete_images": order.ShippingOrderDB.complete_images.split(",") if order.ShippingOrderDB.complete_images else None, "create_time": order.ShippingOrderDB.create_time, "delivery_method": order.ShippingOrderDB.delivery_method, "deliveryman_user_id": order.ShippingOrderDB.deliveryman_user_id, # 地址相关信息 "address_name": order.address_name, "address_phone": order.address_phone, "address_detail": order.address_detail, "building_name": order.building_name, "community_name": order.community_name } # 构建包裹信息,包含驿站名称 package_list = [{ "id": p.ShippingOrderPackageDB.id, "orderid": p.ShippingOrderPackageDB.orderid, "station_id": p.ShippingOrderPackageDB.station_id, "station_name": p.station_name, "pickup_codes": p.ShippingOrderPackageDB.pickup_codes, "create_time": p.ShippingOrderPackageDB.create_time } for p in packages] return success_response(data={ "order": order_data, "packages": package_list }) @router.get("/", response_model=ResponseModel) async def get_user_orders( skip: int = 0, limit: int = 10, db: Session = Depends(get_db), current_user: UserDB = Depends(get_current_user) ): """获取用户的订单列表""" orders = db.query(ShippingOrderDB).filter( ShippingOrderDB.userid == current_user.userid ).order_by( ShippingOrderDB.create_time.desc() ).offset(skip).limit(limit).all() return success_response(data=[OrderInfo.model_validate(o) for o in orders]) @router.post("/calculate-price", response_model=ResponseModel) async def calculate_order_price( request: OrderPriceCalculateRequest, db: Session = Depends(get_db), current_user: UserDB = Depends(get_current_user) ): """计算订单价格""" # 计算所有包裹中的取件码总数 package_count = sum( len(package.pickup_codes.split(',')) for package in request.packages if package.pickup_codes ) # 计算原始金额 original_amount = settings.ORDER_BASE_PRICE if package_count > settings.ORDER_EXTRA_PACKAGE_THRESHOLD: extra_packages = package_count - settings.ORDER_EXTRA_PACKAGE_THRESHOLD original_amount += extra_packages * settings.ORDER_EXTRA_PACKAGE_PRICE # 计算优惠券折扣 coupon_discount = 0 used_coupon_id = None # 查询用户所有可用的优惠券 available_coupons = db.query(UserCouponDB).filter( UserCouponDB.user_id == current_user.userid, UserCouponDB.status == CouponStatus.UNUSED ).order_by( UserCouponDB.coupon_amount.desc() # 优先使用面额大的优惠券 ).all() # 选择最优惠的券 if available_coupons: user_coupon = available_coupons[0] # 取面额最大的优惠券 coupon_discount = user_coupon.coupon_amount used_coupon_id = user_coupon.id # 计算最终金额 final_amount = max(0, original_amount - coupon_discount) price_info = OrderPriceInfo( package_count=package_count, original_amount=original_amount, coupon_discount_amount=coupon_discount, coupon_id=used_coupon_id, final_amount=final_amount ) return success_response(data=price_info) @router.post("/{orderid}/cancel", response_model=ResponseModel) async def cancel_order( orderid: str, cancel_data: OrderCancel, db: Session = Depends(get_db), current_user: UserDB = Depends(get_current_user) ): """取消订单""" # 查询订单 order = db.query(ShippingOrderDB).filter( ShippingOrderDB.orderid == orderid, ShippingOrderDB.userid == current_user.userid ).first() if not order: return error_response(code=404, message="订单不存在") # 检查订单状态是否可取消 if order.status not in [OrderStatus.CREATED, OrderStatus.ACCEPTED]: return error_response(code=400, message="当前订单状态不可取消") try: # 更新订单状态、取消原因和取消用户 order.status = OrderStatus.CANCELLED order.cancel_reason = cancel_data.reason order.cancel_user_id = current_user.userid # 记录取消订单的用户ID # 如果使用了优惠券,返还优惠券 if order.coupon_id: coupon = db.query(UserCouponDB).filter( UserCouponDB.id == order.coupon_id ).first() if coupon: coupon.status = CouponStatus.UNUSED db.commit() return success_response( message="订单取消成功", data=OrderInfo.model_validate(order) ) except Exception as e: db.rollback() return error_response(code=500, message=f"取消订单失败: {str(e)}") @router.post("/{orderid}/complete", response_model=ResponseModel) async def complete_order( orderid: str, complete_data: OrderComplete, db: Session = Depends(get_db), current_user: UserDB = Depends(get_current_user) ): """完成订单""" # 查询订单 order = db.query(ShippingOrderDB).filter( ShippingOrderDB.orderid == orderid, ShippingOrderDB.userid == current_user.userid ).first() if not order: return error_response(code=404, message="订单不存在") # 检查订单状态 if order.status != OrderStatus.ACCEPTED: return error_response(code=400, message="只有已接单的订单才能标记为完成") try: # 更新订单状态和完成图片 order.status = OrderStatus.COMPLETED if complete_data.images: order.complete_images = ",".join(complete_data.images) db.commit() return success_response( message="订单已完成", data=OrderInfo.model_validate(order) ) except Exception as e: db.rollback() return error_response(code=500, message=f"完成订单失败: {str(e)}") @router.get("/delivery", response_model=ResponseModel) async def get_delivery_orders( status: Optional[OrderStatus] = None, community_building_id: Optional[int] = None, skip: int = 0, limit: int = 10, db: Session = Depends(get_db), deliveryman: UserDB = Depends(get_deliveryman_user) # 使用已有的配送员权限检查 ): """获取配送订单列表(仅配送员可用) Args: status: 订单状态筛选 community_building_id: 社区楼栋ID筛选 skip: 分页偏移 limit: 每页数量 """ # 基础查询 query = db.query(ShippingOrderDB).join( AddressDB, ShippingOrderDB.addressid == AddressDB.id ) # 添加状态筛选 if status: query = query.filter(ShippingOrderDB.status == status) # 添加社区楼栋筛选 if community_building_id: query = query.filter( AddressDB.community_building_id == community_building_id ) # 获取总数 total = query.count() # 获取分页数据并按创建时间倒序排序 orders = query.order_by( ShippingOrderDB.create_time.desc() ).offset(skip).limit(limit).all() return success_response(data={ "total": total, "items": [OrderInfo.model_validate(o) for o in orders] }) @router.post("/{orderid}/accept", response_model=ResponseModel) async def accept_order( orderid: str, db: Session = Depends(get_db), deliveryman: UserDB = Depends(get_deliveryman_user) ): """接单(仅配送员可用)""" # 查询订单 order = db.query(ShippingOrderDB).filter( ShippingOrderDB.orderid == orderid ).first() if not order: return error_response(code=404, message="订单不存在") # 检查订单状态 if order.status != OrderStatus.CREATED: return error_response(code=400, message="只能接待新创建的订单") # 检查订单是否已被接单 if order.deliveryman_user_id is not None: return error_response(code=400, message="订单已被其他配送员接单") try: # 更新订单状态和配送员ID order.status = OrderStatus.ACCEPTED order.deliveryman_user_id = deliveryman.userid db.commit() return success_response( message="接单成功", data=OrderInfo.model_validate(order) ) except Exception as e: db.rollback() return error_response(code=500, message=f"接单失败: {str(e)}")