2026-05-30 07:23:33 +08:00
|
|
|
|
"""
|
|
|
|
|
|
订单管理路由模块
|
|
|
|
|
|
|
|
|
|
|
|
职责:
|
|
|
|
|
|
处理订单的全生命周期管理接口,URL 前缀为 /api/orders。
|
|
|
|
|
|
包括:订单列表查询、创建、更新、详情查看、提交、取消、
|
|
|
|
|
|
状态变更、审批、撤销审批、供应商文本发送与确认。
|
|
|
|
|
|
"""
|
2026-05-14 13:51:06 +08:00
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
|
|
|
2026-05-15 13:40:58 +08:00
|
|
|
|
from backend.app.api.deps import get_order_service, require_permissions, require_roles
|
2026-05-14 13:51:06 +08:00
|
|
|
|
from backend.app.core.error_codes import ErrorCode
|
|
|
|
|
|
from backend.app.core.exceptions import AppException
|
|
|
|
|
|
from backend.app.db import get_db_session
|
|
|
|
|
|
from backend.app.schemas.common import success_payload
|
|
|
|
|
|
from backend.app.schemas.orders import (
|
|
|
|
|
|
ApproveOrderRequest,
|
|
|
|
|
|
CancelOrderRequest,
|
2026-05-15 11:31:55 +08:00
|
|
|
|
ChangeOrderStatusRequest,
|
2026-05-14 13:51:06 +08:00
|
|
|
|
ConfirmSupplierTextRequest,
|
|
|
|
|
|
CreateOrderRequest,
|
|
|
|
|
|
SupplierTextRequest,
|
2026-05-19 17:30:35 +08:00
|
|
|
|
UpdateOrderRequest,
|
2026-05-14 13:51:06 +08:00
|
|
|
|
)
|
|
|
|
|
|
from backend.app.services.order_service import OrderService
|
|
|
|
|
|
|
|
|
|
|
|
router = APIRouter(prefix="/api/orders", tags=["orders"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("")
|
|
|
|
|
|
def list_orders(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
order_no: str | None = Query(default=None), # 订单编号模糊搜索
|
|
|
|
|
|
order_status: str | None = Query(default=None), # 订单状态筛选
|
|
|
|
|
|
customer_name: str | None = Query(default=None), # 客户名称模糊搜索
|
|
|
|
|
|
customer_mobile: str | None = Query(default=None), # 客户手机号搜索
|
|
|
|
|
|
salesman_id: int | None = Query(default=None), # 业务员 ID 筛选
|
|
|
|
|
|
factory_id: int | None = Query(default=None), # 工厂 ID 筛选
|
|
|
|
|
|
order_source: str | None = Query(default=None), # 订单来源筛选
|
|
|
|
|
|
start_time: str | None = Query(default=None), # 查询起始时间
|
|
|
|
|
|
end_time: str | None = Query(default=None), # 查询结束时间
|
|
|
|
|
|
page_no: int = Query(default=1), # 页码,默认第 1 页
|
|
|
|
|
|
page_size: int = Query(default=20), # 每页条数,默认 20 条
|
|
|
|
|
|
order_service: OrderService = Depends(get_order_service), # 注入订单服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("salesman", "manager", "admin")), # 角色鉴权
|
|
|
|
|
|
_permission_user: dict = Depends(require_permissions("order:list")), # 权限鉴权:订单查看
|
2026-05-14 13:51:06 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""分页查询订单列表
|
|
|
|
|
|
|
|
|
|
|
|
用途:根据多维度筛选条件获取订单列表,支持按订单号、状态、客户、业务员、工厂、来源、时间范围筛选。
|
|
|
|
|
|
请求参数:Query 参数组合筛选 + 分页参数。
|
|
|
|
|
|
返回值:分页订单列表,包含 total、page_no、page_size、list。
|
|
|
|
|
|
权限要求:业务员/经理/管理员,且需 order:list 权限。
|
|
|
|
|
|
"""
|
2026-05-14 13:51:06 +08:00
|
|
|
|
orders = order_service.list_orders(
|
|
|
|
|
|
session,
|
2026-05-15 12:05:18 +08:00
|
|
|
|
order_service.normalize_list_filters(
|
|
|
|
|
|
{
|
2026-05-14 15:07:53 +08:00
|
|
|
|
"order_no": order_no,
|
2026-05-14 13:51:06 +08:00
|
|
|
|
"order_status": order_status,
|
|
|
|
|
|
"customer_name": customer_name,
|
|
|
|
|
|
"customer_mobile": customer_mobile,
|
|
|
|
|
|
"salesman_id": salesman_id,
|
|
|
|
|
|
"factory_id": factory_id,
|
|
|
|
|
|
"order_source": order_source,
|
|
|
|
|
|
"start_time": start_time,
|
|
|
|
|
|
"end_time": end_time,
|
2026-05-28 22:59:04 +08:00
|
|
|
|
"page_no": page_no,
|
|
|
|
|
|
"page_size": page_size,
|
2026-05-15 12:05:18 +08:00
|
|
|
|
},
|
|
|
|
|
|
current_user,
|
|
|
|
|
|
),
|
2026-05-28 22:59:04 +08:00
|
|
|
|
current_user=current_user,
|
2026-05-14 13:51:06 +08:00
|
|
|
|
)
|
|
|
|
|
|
return success_payload(
|
|
|
|
|
|
{
|
|
|
|
|
|
"total": len(orders),
|
|
|
|
|
|
"page_no": page_no,
|
|
|
|
|
|
"page_size": page_size,
|
2026-05-28 22:59:04 +08:00
|
|
|
|
"list": orders,
|
2026-05-14 13:51:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("")
|
|
|
|
|
|
def create_order(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
payload: CreateOrderRequest, # 创建订单的请求体
|
|
|
|
|
|
order_service: OrderService = Depends(get_order_service), # 注入订单服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("salesman", "admin")), # 角色鉴权:业务员/管理员
|
|
|
|
|
|
_permission_user: dict = Depends(require_permissions("order:create")), # 权限鉴权:订单创建
|
2026-05-14 13:51:06 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""创建新订单
|
|
|
|
|
|
|
|
|
|
|
|
用途:新建一个订单,需包含至少一条订单明细。
|
|
|
|
|
|
请求参数:CreateOrderRequest(客户信息、明细列表 items 等)。
|
|
|
|
|
|
返回值:创建成功后的订单信息。
|
|
|
|
|
|
权限要求:业务员(salesman)或管理员(admin),且需 order:create 权限。
|
|
|
|
|
|
"""
|
2026-05-14 13:51:06 +08:00
|
|
|
|
if not payload.items:
|
|
|
|
|
|
raise AppException(code=ErrorCode.PARAM_ERROR, message="订单明细不能为空", status_code=400)
|
2026-05-15 12:05:18 +08:00
|
|
|
|
order = order_service.create_order(payload.model_dump(), session, current_user)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
return success_payload(order)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-19 17:30:35 +08:00
|
|
|
|
@router.put("/{order_id}")
|
|
|
|
|
|
def update_order(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
order_id: int, # 订单 ID(路径参数)
|
|
|
|
|
|
payload: UpdateOrderRequest, # 更新订单的请求体
|
|
|
|
|
|
order_service: OrderService = Depends(get_order_service), # 注入订单服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("salesman", "admin")), # 角色鉴权:业务员/管理员
|
|
|
|
|
|
_permission_user: dict = Depends(require_permissions("order:update")), # 权限鉴权:订单更新
|
2026-05-19 17:30:35 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""更新订单信息
|
|
|
|
|
|
|
|
|
|
|
|
用途:修改已有订单的基本信息和明细,需包含至少一条订单明细。
|
|
|
|
|
|
请求参数:order_id(路径参数)+ UpdateOrderRequest(更新字段)。
|
|
|
|
|
|
返回值:更新后的订单信息。
|
|
|
|
|
|
权限要求:业务员(salesman)或管理员(admin),且需 order:update 权限。
|
|
|
|
|
|
"""
|
2026-05-19 17:30:35 +08:00
|
|
|
|
if not payload.items:
|
|
|
|
|
|
raise AppException(code=ErrorCode.PARAM_ERROR, message="订单明细不能为空", status_code=400)
|
|
|
|
|
|
order = order_service.update_order(order_id, payload.model_dump(), session, current_user)
|
|
|
|
|
|
if not order:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="订单不存在", status_code=404)
|
|
|
|
|
|
return success_payload(order)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-05-14 13:51:06 +08:00
|
|
|
|
@router.get("/{order_id}")
|
|
|
|
|
|
def get_order(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
order_id: int, # 订单 ID(路径参数)
|
|
|
|
|
|
order_service: OrderService = Depends(get_order_service), # 注入订单服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("salesman", "manager", "admin")), # 角色鉴权
|
|
|
|
|
|
_permission_user: dict = Depends(require_permissions("order:list")), # 权限鉴权:订单查看
|
2026-05-14 13:51:06 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""查询订单详情
|
|
|
|
|
|
|
|
|
|
|
|
用途:根据订单 ID 获取单个订单的完整信息(含明细、状态历史等)。
|
|
|
|
|
|
请求参数:order_id - 订单 ID(路径参数)。
|
|
|
|
|
|
返回值:订单详情信息。
|
|
|
|
|
|
权限要求:业务员/经理/管理员,且需 order:list 权限。
|
|
|
|
|
|
"""
|
2026-05-15 12:05:18 +08:00
|
|
|
|
order = order_service.get_order(order_id, session, current_user)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
if not order:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="订单不存在", status_code=404)
|
|
|
|
|
|
return success_payload(order)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/{order_id}/submit")
|
|
|
|
|
|
def submit_order(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
order_id: int, # 订单 ID(路径参数)
|
|
|
|
|
|
order_service: OrderService = Depends(get_order_service), # 注入订单服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("salesman", "admin")), # 角色鉴权:业务员/管理员
|
|
|
|
|
|
_permission_user: dict = Depends(require_permissions("order:submit")), # 权限鉴权:订单提交
|
2026-05-14 13:51:06 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""提交订单
|
|
|
|
|
|
|
|
|
|
|
|
用途:将草稿状态的订单提交审批,进入审批流程。
|
|
|
|
|
|
请求参数:order_id - 订单 ID(路径参数)。
|
|
|
|
|
|
返回值:提交后的订单信息。
|
|
|
|
|
|
权限要求:业务员(salesman)或管理员(admin),且需 order:submit 权限。
|
|
|
|
|
|
"""
|
2026-05-15 12:05:18 +08:00
|
|
|
|
order = order_service.submit_order(order_id, session, current_user)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
if not order:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="订单不存在", status_code=404)
|
|
|
|
|
|
return success_payload(order)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/{order_id}/cancel")
|
|
|
|
|
|
def cancel_order(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
order_id: int, # 订单 ID(路径参数)
|
|
|
|
|
|
payload: CancelOrderRequest, # 取消原因请求体
|
|
|
|
|
|
order_service: OrderService = Depends(get_order_service), # 注入订单服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("salesman", "admin")), # 角色鉴权:业务员/管理员
|
|
|
|
|
|
_permission_user: dict = Depends(require_permissions("order:list")), # 权限鉴权:订单查看
|
2026-05-14 13:51:06 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""取消订单
|
|
|
|
|
|
|
|
|
|
|
|
用途:取消一个未完成的订单,需提供取消原因。
|
|
|
|
|
|
请求参数:order_id(路径参数)+ CancelOrderRequest(取消原因)。
|
|
|
|
|
|
返回值:取消后的订单信息。
|
|
|
|
|
|
权限要求:业务员(salesman)或管理员(admin),且需 order:list 权限。
|
|
|
|
|
|
"""
|
2026-05-15 12:05:18 +08:00
|
|
|
|
order = order_service.cancel_order(order_id, payload.model_dump(), session, current_user)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
if not order:
|
2026-05-15 11:31:55 +08:00
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="订单不存在", status_code=404)
|
|
|
|
|
|
return success_payload(order)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/{order_id}/status")
|
|
|
|
|
|
def change_order_status(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
order_id: int, # 订单 ID(路径参数)
|
|
|
|
|
|
payload: ChangeOrderStatusRequest, # 状态变更请求体
|
|
|
|
|
|
order_service: OrderService = Depends(get_order_service), # 注入订单服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("manager", "admin")), # 角色鉴权:经理/管理员
|
|
|
|
|
|
_permission_user: dict = Depends(require_permissions("logistics:task:create")), # 权限鉴权:物流任务创建
|
2026-05-15 11:31:55 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""变更订单状态
|
|
|
|
|
|
|
|
|
|
|
|
用途:手动变更订单的当前状态(如发货、完成等),需经理或管理员操作。
|
|
|
|
|
|
请求参数:order_id(路径参数)+ ChangeOrderStatusRequest(目标状态)。
|
|
|
|
|
|
返回值:状态变更后的订单信息。
|
|
|
|
|
|
权限要求:经理(manager)或管理员(admin),且需 logistics:task:create 权限。
|
|
|
|
|
|
"""
|
2026-05-15 12:05:18 +08:00
|
|
|
|
order = order_service.change_order_status(order_id, payload.model_dump(), session, current_user)
|
2026-05-15 11:31:55 +08:00
|
|
|
|
if not order:
|
2026-05-14 13:51:06 +08:00
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="订单不存在", status_code=404)
|
|
|
|
|
|
return success_payload(order)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/{order_id}/approve")
|
|
|
|
|
|
def approve_order(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
order_id: int, # 订单 ID(路径参数)
|
|
|
|
|
|
payload: ApproveOrderRequest, # 审批意见请求体
|
|
|
|
|
|
order_service: OrderService = Depends(get_order_service), # 注入订单服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("manager", "admin")), # 角色鉴权:经理/管理员
|
|
|
|
|
|
_permission_user: dict = Depends(require_permissions("order:approve")), # 权限鉴权:订单审批
|
2026-05-14 13:51:06 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""审批订单
|
|
|
|
|
|
|
|
|
|
|
|
用途:对已提交的订单进行审批通过操作。
|
|
|
|
|
|
请求参数:order_id(路径参数)+ ApproveOrderRequest(审批意见)。
|
|
|
|
|
|
返回值:审批后的订单信息。
|
|
|
|
|
|
权限要求:经理(manager)或管理员(admin),且需 order:approve 权限。
|
|
|
|
|
|
"""
|
2026-05-15 12:05:18 +08:00
|
|
|
|
order = order_service.approve_order(order_id, payload.model_dump(), session, current_user)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
if not order:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="订单不存在", status_code=404)
|
|
|
|
|
|
return success_payload(order)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/{order_id}/cancel-approve")
|
|
|
|
|
|
def cancel_approve_order(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
order_id: int, # 订单 ID(路径参数)
|
|
|
|
|
|
payload: ApproveOrderRequest, # 撤销审批意见请求体
|
|
|
|
|
|
order_service: OrderService = Depends(get_order_service), # 注入订单服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("manager", "admin")), # 角色鉴权:经理/管理员
|
|
|
|
|
|
_permission_user: dict = Depends(require_permissions("order:cancel-approve")), # 权限鉴权:撤销审批
|
2026-05-14 13:51:06 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""撤销订单审批
|
|
|
|
|
|
|
|
|
|
|
|
用途:撤销已通过的订单审批,将订单回退到待审批状态。
|
|
|
|
|
|
请求参数:order_id(路径参数)+ ApproveOrderRequest(撤销原因)。
|
|
|
|
|
|
返回值:撤销审批后的订单信息。
|
|
|
|
|
|
权限要求:经理(manager)或管理员(admin),且需 order:cancel-approve 权限。
|
|
|
|
|
|
"""
|
2026-05-15 12:05:18 +08:00
|
|
|
|
order = order_service.cancel_approve_order(order_id, payload.model_dump(), session, current_user)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
if not order:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="订单不存在", status_code=404)
|
|
|
|
|
|
return success_payload(order)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/{order_id}/supplier-text")
|
|
|
|
|
|
def supplier_text(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
order_id: int, # 订单 ID(路径参数)
|
|
|
|
|
|
payload: SupplierTextRequest, # 供应商文本请求体
|
|
|
|
|
|
order_service: OrderService = Depends(get_order_service), # 注入订单服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("manager", "admin")), # 角色鉴权:经理/管理员
|
|
|
|
|
|
_permission_user: dict = Depends(require_permissions("order:supplier-text")), # 权限鉴权:供应商文本
|
2026-05-14 13:51:06 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""生成/发送供应商文本
|
|
|
|
|
|
|
|
|
|
|
|
用途:根据订单信息生成供应商沟通文本,供内部确认后发送给供应商。
|
|
|
|
|
|
请求参数:order_id(路径参数)+ SupplierTextRequest(文本参数)。
|
|
|
|
|
|
返回值:包含供应商文本内容的订单信息。
|
|
|
|
|
|
权限要求:经理(manager)或管理员(admin),且需 order:supplier-text 权限。
|
|
|
|
|
|
"""
|
2026-05-15 12:05:18 +08:00
|
|
|
|
order = order_service.get_supplier_text(order_id, payload.model_dump(), session, current_user)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
if not order:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="订单不存在", status_code=404)
|
|
|
|
|
|
return success_payload(order)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/{order_id}/supplier-text/confirm")
|
|
|
|
|
|
def confirm_supplier_text(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
order_id: int, # 订单 ID(路径参数)
|
|
|
|
|
|
payload: ConfirmSupplierTextRequest, # 确认文本请求体
|
|
|
|
|
|
order_service: OrderService = Depends(get_order_service), # 注入订单服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("manager", "admin")), # 角色鉴权:经理/管理员
|
|
|
|
|
|
_permission_user: dict = Depends(require_permissions("order:supplier-text")), # 权限鉴权:供应商文本
|
2026-05-14 13:51:06 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""确认供应商文本
|
|
|
|
|
|
|
|
|
|
|
|
用途:确认已生成的供应商沟通文本,触发实际发送流程。
|
|
|
|
|
|
请求参数:order_id(路径参数)+ ConfirmSupplierTextRequest(确认内容)。
|
|
|
|
|
|
返回值:确认后的订单信息。
|
|
|
|
|
|
权限要求:经理(manager)或管理员(admin),且需 order:supplier-text 权限。
|
|
|
|
|
|
"""
|
2026-05-15 12:05:18 +08:00
|
|
|
|
order = order_service.confirm_supplier_text(order_id, payload.model_dump(), session, current_user)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
if not order:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="订单不存在", status_code=404)
|
|
|
|
|
|
return success_payload(order)
|