"""订单调整 API""" from typing import Optional, List from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.orm import Session from pydantic import BaseModel, Field from app.core.database import get_db from app.core.auth import get_current_user from app.core.response import success_response, error_response from app.crud.order_adjust import order_adjust_crud from app.schemas.order_adjust import AdjustType router = APIRouter(prefix="/api/web/admin/order-adjust", tags=["订单调整"]) class CreateAdjustRequest(BaseModel): """创建调整请求""" order_id: str = Field(..., description="订单ID") order_item_id: Optional[str] = Field(None, description="订单项ID") adjust_type: str = Field(..., description="调整类型: reduce-减量, delete-删除, substitute-替代") before_quantity: float = Field(..., description="调整前数量") after_quantity: float = Field(..., description="调整后数量") before_amount: float = Field(..., description="调整前金额") after_amount: float = Field(..., description="调整后金额") reason: str = Field(..., min_length=1, max_length=500, description="调整原因") substitute_product_id: Optional[str] = Field(None, description="替代商品ID") class AdjustResponse(BaseModel): """调整记录响应""" id: str order_id: str order_item_id: Optional[str] adjust_type: str adjust_type_text: str before_quantity: float after_quantity: float before_amount: float after_amount: float difference_amount: float reason: str substitute_product_id: Optional[str] operator_id: str operator_name: str create_at: str create_name: str class Config: from_attributes = True def adjust_to_response(adjust) -> dict: """将调整记录转换为响应格式""" adjust_type_map = { "reduce": "减量", "delete": "删除", "substitute": "替代" } return { "id": adjust.id, "orderId": adjust.order_id, "orderItemId": adjust.order_item_id, "adjustType": adjust.adjust_type, "adjustTypeText": adjust_type_map.get(adjust.adjust_type, adjust.adjust_type), "beforeQuantity": float(adjust.before_quantity or 0), "afterQuantity": float(adjust.after_quantity or 0), "beforeAmount": float(adjust.before_amount or 0), "afterAmount": float(adjust.after_amount or 0), "differenceAmount": float(adjust.difference_amount or 0), "reason": adjust.reason, "substituteProductId": adjust.substitute_product_id, "operatorId": adjust.operator_id, "operatorName": adjust.operator_name, "createAt": str(adjust.create_at) if adjust.create_at else "", "createName": adjust.create_name or "" } @router.post("/create", response_model=dict) def create_adjust( request: CreateAdjustRequest, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """创建订单调整记录""" try: # 验证调整类型 valid_types = ["reduce", "delete", "substitute"] if request.adjust_type not in valid_types: return error_response(400, f"无效的调整类型,支持的类型: {', '.join(valid_types)}") # 验证调整数量 if request.after_quantity < 0: return error_response(400, "调整后数量不能为负数") # 验证金额 if request.after_amount < 0: return error_response(400, "调整后金额不能为负数") # 创建调整记录 adjust = order_adjust_crud.create_adjust( db=db, order_id=request.order_id, order_item_id=request.order_item_id, adjust_type=request.adjust_type, before_quantity=request.before_quantity, after_quantity=request.after_quantity, before_amount=request.before_amount, after_amount=request.after_amount, reason=request.reason, operator_id=current_user.get("user_id", ""), operator_name=current_user.get("real_name", current_user.get("username", "")), substitute_product_id=request.substitute_product_id ) return success_response({ "id": adjust.id, "message": "订单调整记录已创建" }) except Exception as e: return error_response(500, f"创建调整记录失败: {str(e)}") @router.get("/list/{order_id}", response_model=dict) def get_order_adjusts_by_order( order_id: str, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """获取指定订单的所有调整记录""" try: adjusts = order_adjust_crud.get_by_order(db, order_id) return success_response({ "list": [adjust_to_response(a) for a in adjusts], "total": len(adjusts), "totalAmount": order_adjust_crud.get_total_adjust_amount(db, order_id) }) except Exception as e: return error_response(500, f"获取调整记录失败: {str(e)}") @router.post("/list", response_model=dict) def get_order_adjust_list( page: int = 1, pageSize: int = 10, keyword: Optional[str] = None, adjustType: Optional[str] = None, startDate: Optional[str] = None, endDate: Optional[str] = None, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """获取订单调整列表(支持分页和搜索)""" try: adjusts, total = order_adjust_crud.get_list( db=db, page=page, pageSize=pageSize, keyword=keyword, adjust_type=adjustType, start_date=startDate, end_date=endDate ) return success_response({ "list": [adjust_to_response(a) for a in adjusts], "total": total, "page": page, "pageSize": pageSize }) except Exception as e: return error_response(500, f"获取调整记录列表失败: {str(e)}") @router.get("/detail/{adjust_id}", response_model=dict) def get_adjust_detail( adjust_id: str, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """获取调整记录详情""" try: adjust = order_adjust_crud.get(db, adjust_id) if not adjust: return error_response(404, "调整记录不存在") if adjust.is_del == 1: return error_response(404, "调整记录已删除") return success_response(adjust_to_response(adjust)) except Exception as e: return error_response(500, f"获取调整记录详情失败: {str(e)}") @router.delete("/{adjust_id}", response_model=dict) def delete_adjust( adjust_id: str, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """删除调整记录(仅管理员可操作)""" try: # 检查权限 if current_user.get("role") != "admin": return error_response(403, "仅管理员可删除调整记录") adjust = order_adjust_crud.get(db, adjust_id) if not adjust: return error_response(404, "调整记录不存在") # 软删除 order_adjust_crud.delete(db, adjust_id) # 创建历史记录 order_adjust_crud.create_adjust_history( db=db, original_record=adjust, operator_id=current_user.get("user_id", ""), operator_name=current_user.get("real_name", current_user.get("username", "")) ) return success_response({"message": "删除成功"}) except Exception as e: return error_response(500, f"删除调整记录失败: {str(e)}") @router.get("/statistics/{order_id}", response_model=dict) def get_adjust_statistics( order_id: str, db: Session = Depends(get_db), current_user: dict = Depends(get_current_user) ): """获取订单调整统计""" try: adjusts = order_adjust_crud.get_by_order(db, order_id) # 按类型统计 reduce_count = sum(1 for a in adjusts if a.adjust_type == "reduce") delete_count = sum(1 for a in adjusts if a.adjust_type == "delete") substitute_count = sum(1 for a in adjusts if a.adjust_type == "substitute") total_refund = sum( abs(a.difference_amount or 0) for a in adjusts if a.difference_amount and a.difference_amount > 0 ) return success_response({ "totalCount": len(adjusts), "reduceCount": reduce_count, "deleteCount": delete_count, "substituteCount": substitute_count, "totalRefund": total_refund }) except Exception as e: return error_response(500, f"获取统计信息失败: {str(e)}")