覆盖所有模块: - api 层:17 个路由文件,每个接口标注用途、参数、返回值、权限 - services 层:18 个服务文件,每个方法标注作用、参数、返回值、调用方 - repositories 层:13 个仓储文件,每个方法标注查询逻辑和被调用方 - schemas 层:11 个请求/响应体文件,每个字段标注业务含义 - core 层:config、security、exceptions、responses、error_codes - models 层:19 个 ORM 模型类,每个表标注业务含义和关联关系 - scripts:bootstrap_data、smoke_check - migrations:env.py 和版本迁移文件 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
303 lines
15 KiB
Python
303 lines
15 KiB
Python
"""
|
||
订单管理路由模块
|
||
|
||
职责:
|
||
处理订单的全生命周期管理接口,URL 前缀为 /api/orders。
|
||
包括:订单列表查询、创建、更新、详情查看、提交、取消、
|
||
状态变更、审批、撤销审批、供应商文本发送与确认。
|
||
"""
|
||
from fastapi import APIRouter, Depends, Query
|
||
from sqlalchemy.orm import Session
|
||
|
||
from backend.app.api.deps import get_order_service, require_permissions, require_roles
|
||
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,
|
||
ChangeOrderStatusRequest,
|
||
ConfirmSupplierTextRequest,
|
||
CreateOrderRequest,
|
||
SupplierTextRequest,
|
||
UpdateOrderRequest,
|
||
)
|
||
from backend.app.services.order_service import OrderService
|
||
|
||
router = APIRouter(prefix="/api/orders", tags=["orders"])
|
||
|
||
|
||
@router.get("")
|
||
def list_orders(
|
||
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")), # 权限鉴权:订单查看
|
||
) -> dict:
|
||
"""分页查询订单列表
|
||
|
||
用途:根据多维度筛选条件获取订单列表,支持按订单号、状态、客户、业务员、工厂、来源、时间范围筛选。
|
||
请求参数:Query 参数组合筛选 + 分页参数。
|
||
返回值:分页订单列表,包含 total、page_no、page_size、list。
|
||
权限要求:业务员/经理/管理员,且需 order:list 权限。
|
||
"""
|
||
orders = order_service.list_orders(
|
||
session,
|
||
order_service.normalize_list_filters(
|
||
{
|
||
"order_no": order_no,
|
||
"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,
|
||
"page_no": page_no,
|
||
"page_size": page_size,
|
||
},
|
||
current_user,
|
||
),
|
||
current_user=current_user,
|
||
)
|
||
return success_payload(
|
||
{
|
||
"total": len(orders),
|
||
"page_no": page_no,
|
||
"page_size": page_size,
|
||
"list": orders,
|
||
}
|
||
)
|
||
|
||
|
||
@router.post("")
|
||
def create_order(
|
||
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")), # 权限鉴权:订单创建
|
||
) -> dict:
|
||
"""创建新订单
|
||
|
||
用途:新建一个订单,需包含至少一条订单明细。
|
||
请求参数:CreateOrderRequest(客户信息、明细列表 items 等)。
|
||
返回值:创建成功后的订单信息。
|
||
权限要求:业务员(salesman)或管理员(admin),且需 order:create 权限。
|
||
"""
|
||
if not payload.items:
|
||
raise AppException(code=ErrorCode.PARAM_ERROR, message="订单明细不能为空", status_code=400)
|
||
order = order_service.create_order(payload.model_dump(), session, current_user)
|
||
return success_payload(order)
|
||
|
||
|
||
@router.put("/{order_id}")
|
||
def update_order(
|
||
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")), # 权限鉴权:订单更新
|
||
) -> dict:
|
||
"""更新订单信息
|
||
|
||
用途:修改已有订单的基本信息和明细,需包含至少一条订单明细。
|
||
请求参数:order_id(路径参数)+ UpdateOrderRequest(更新字段)。
|
||
返回值:更新后的订单信息。
|
||
权限要求:业务员(salesman)或管理员(admin),且需 order:update 权限。
|
||
"""
|
||
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)
|
||
|
||
|
||
@router.get("/{order_id}")
|
||
def get_order(
|
||
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")), # 权限鉴权:订单查看
|
||
) -> dict:
|
||
"""查询订单详情
|
||
|
||
用途:根据订单 ID 获取单个订单的完整信息(含明细、状态历史等)。
|
||
请求参数:order_id - 订单 ID(路径参数)。
|
||
返回值:订单详情信息。
|
||
权限要求:业务员/经理/管理员,且需 order:list 权限。
|
||
"""
|
||
order = order_service.get_order(order_id, session, current_user)
|
||
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(
|
||
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")), # 权限鉴权:订单提交
|
||
) -> dict:
|
||
"""提交订单
|
||
|
||
用途:将草稿状态的订单提交审批,进入审批流程。
|
||
请求参数:order_id - 订单 ID(路径参数)。
|
||
返回值:提交后的订单信息。
|
||
权限要求:业务员(salesman)或管理员(admin),且需 order:submit 权限。
|
||
"""
|
||
order = order_service.submit_order(order_id, session, current_user)
|
||
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(
|
||
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")), # 权限鉴权:订单查看
|
||
) -> dict:
|
||
"""取消订单
|
||
|
||
用途:取消一个未完成的订单,需提供取消原因。
|
||
请求参数:order_id(路径参数)+ CancelOrderRequest(取消原因)。
|
||
返回值:取消后的订单信息。
|
||
权限要求:业务员(salesman)或管理员(admin),且需 order:list 权限。
|
||
"""
|
||
order = order_service.cancel_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)
|
||
|
||
|
||
@router.post("/{order_id}/status")
|
||
def change_order_status(
|
||
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")), # 权限鉴权:物流任务创建
|
||
) -> dict:
|
||
"""变更订单状态
|
||
|
||
用途:手动变更订单的当前状态(如发货、完成等),需经理或管理员操作。
|
||
请求参数:order_id(路径参数)+ ChangeOrderStatusRequest(目标状态)。
|
||
返回值:状态变更后的订单信息。
|
||
权限要求:经理(manager)或管理员(admin),且需 logistics:task:create 权限。
|
||
"""
|
||
order = order_service.change_order_status(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)
|
||
|
||
|
||
@router.post("/{order_id}/approve")
|
||
def approve_order(
|
||
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")), # 权限鉴权:订单审批
|
||
) -> dict:
|
||
"""审批订单
|
||
|
||
用途:对已提交的订单进行审批通过操作。
|
||
请求参数:order_id(路径参数)+ ApproveOrderRequest(审批意见)。
|
||
返回值:审批后的订单信息。
|
||
权限要求:经理(manager)或管理员(admin),且需 order:approve 权限。
|
||
"""
|
||
order = order_service.approve_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)
|
||
|
||
|
||
@router.post("/{order_id}/cancel-approve")
|
||
def cancel_approve_order(
|
||
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")), # 权限鉴权:撤销审批
|
||
) -> dict:
|
||
"""撤销订单审批
|
||
|
||
用途:撤销已通过的订单审批,将订单回退到待审批状态。
|
||
请求参数:order_id(路径参数)+ ApproveOrderRequest(撤销原因)。
|
||
返回值:撤销审批后的订单信息。
|
||
权限要求:经理(manager)或管理员(admin),且需 order:cancel-approve 权限。
|
||
"""
|
||
order = order_service.cancel_approve_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)
|
||
|
||
|
||
@router.post("/{order_id}/supplier-text")
|
||
def supplier_text(
|
||
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")), # 权限鉴权:供应商文本
|
||
) -> dict:
|
||
"""生成/发送供应商文本
|
||
|
||
用途:根据订单信息生成供应商沟通文本,供内部确认后发送给供应商。
|
||
请求参数:order_id(路径参数)+ SupplierTextRequest(文本参数)。
|
||
返回值:包含供应商文本内容的订单信息。
|
||
权限要求:经理(manager)或管理员(admin),且需 order:supplier-text 权限。
|
||
"""
|
||
order = order_service.get_supplier_text(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)
|
||
|
||
|
||
@router.post("/{order_id}/supplier-text/confirm")
|
||
def confirm_supplier_text(
|
||
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")), # 权限鉴权:供应商文本
|
||
) -> dict:
|
||
"""确认供应商文本
|
||
|
||
用途:确认已生成的供应商沟通文本,触发实际发送流程。
|
||
请求参数:order_id(路径参数)+ ConfirmSupplierTextRequest(确认内容)。
|
||
返回值:确认后的订单信息。
|
||
权限要求:经理(manager)或管理员(admin),且需 order:supplier-text 权限。
|
||
"""
|
||
order = order_service.confirm_supplier_text(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)
|