2026-05-30 07:23:33 +08:00
|
|
|
|
"""
|
|
|
|
|
|
供应商管理路由模块
|
|
|
|
|
|
|
|
|
|
|
|
职责:
|
|
|
|
|
|
处理供应商信息的增删改查接口,URL 前缀为 /api/suppliers。
|
2026-06-02 20:45:00 +08:00
|
|
|
|
包括:供应商列表查询、创建供应商、查看详情、更新供应商信息、删除供应商。
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""
|
2026-06-02 20:45:00 +08:00
|
|
|
|
from fastapi import APIRouter, Body, Depends, Query
|
|
|
|
|
|
from sqlalchemy import func, select
|
2026-05-14 23:28:09 +08:00
|
|
|
|
from sqlalchemy.orm import Session
|
2026-05-14 13:51:06 +08:00
|
|
|
|
|
2026-05-15 12:18:50 +08:00
|
|
|
|
from backend.app.api.deps import get_supplier_service, require_roles
|
|
|
|
|
|
from backend.app.core.error_codes import ErrorCode
|
|
|
|
|
|
from backend.app.core.exceptions import AppException
|
2026-05-14 23:28:09 +08:00
|
|
|
|
from backend.app.db import get_db_session
|
2026-06-02 20:45:00 +08:00
|
|
|
|
from backend.app.models.business import Supplier, SalesOrder
|
2026-05-14 13:51:06 +08:00
|
|
|
|
from backend.app.schemas.common import success_payload
|
2026-05-28 22:59:04 +08:00
|
|
|
|
from backend.app.schemas.suppliers import CreateSupplierRequest, UpdateSupplierRequest
|
2026-05-14 23:28:09 +08:00
|
|
|
|
from backend.app.services.supplier_service import SupplierService
|
2026-05-14 13:51:06 +08:00
|
|
|
|
|
|
|
|
|
|
router = APIRouter(prefix="/api/suppliers", tags=["suppliers"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("")
|
2026-05-14 23:28:09 +08:00
|
|
|
|
def list_suppliers(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
supplier_name: str | None = Query(default=None), # 供应商名称模糊搜索
|
|
|
|
|
|
supplier_type: str | None = Query(default=None), # 供应商类型筛选
|
|
|
|
|
|
status: int | None = Query(default=None), # 供应商状态筛选(启用/停用)
|
|
|
|
|
|
page_no: int = Query(default=1), # 页码,默认第 1 页
|
|
|
|
|
|
page_size: int = Query(default=20), # 每页条数,默认 20 条
|
|
|
|
|
|
supplier_service: SupplierService = Depends(get_supplier_service), # 注入供应商服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("salesman", "manager", "admin")), # 角色鉴权
|
2026-05-14 23:28:09 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""分页查询供应商列表
|
|
|
|
|
|
|
|
|
|
|
|
用途:获取所有供应商信息,支持按名称、类型、状态筛选。
|
|
|
|
|
|
请求参数:Query 参数筛选 + 分页参数。
|
|
|
|
|
|
返回值:分页供应商列表,包含 total、page_no、page_size、list。
|
|
|
|
|
|
权限要求:业务员(salesman)、经理(manager)、管理员(admin)。
|
|
|
|
|
|
"""
|
2026-05-14 23:28:09 +08:00
|
|
|
|
result = supplier_service.list_suppliers(
|
|
|
|
|
|
{"supplier_name": supplier_name, "supplier_type": supplier_type, "status": status},
|
|
|
|
|
|
session,
|
|
|
|
|
|
)
|
|
|
|
|
|
start = max(page_no - 1, 0) * page_size
|
|
|
|
|
|
result["list"] = result["list"][start : start + page_size]
|
|
|
|
|
|
result["page_no"] = page_no
|
|
|
|
|
|
result["page_size"] = page_size
|
|
|
|
|
|
return success_payload(result)
|
2026-05-14 13:51:06 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("")
|
2026-05-14 23:28:09 +08:00
|
|
|
|
def create_supplier(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
payload: CreateSupplierRequest, # 创建供应商的请求体
|
|
|
|
|
|
supplier_service: SupplierService = Depends(get_supplier_service), # 注入供应商服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("manager", "admin")), # 角色鉴权:仅经理/管理员
|
2026-05-14 23:28:09 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""创建新供应商
|
|
|
|
|
|
|
|
|
|
|
|
用途:新增一个供应商记录。
|
|
|
|
|
|
请求参数:CreateSupplierRequest(供应商名称、类型、联系方式等)。
|
|
|
|
|
|
返回值:创建成功后的供应商信息。
|
|
|
|
|
|
权限要求:经理(manager)或管理员(admin)。
|
|
|
|
|
|
"""
|
2026-05-14 23:28:09 +08:00
|
|
|
|
return success_payload(supplier_service.create_supplier(payload.model_dump(), session))
|
2026-05-15 12:18:50 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.get("/{supplier_id}")
|
|
|
|
|
|
def get_supplier(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
supplier_id: int, # 供应商 ID(路径参数)
|
|
|
|
|
|
supplier_service: SupplierService = Depends(get_supplier_service), # 注入供应商服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("salesman", "manager", "admin")), # 角色鉴权
|
2026-05-15 12:18:50 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""查询供应商详情
|
|
|
|
|
|
|
|
|
|
|
|
用途:根据供应商 ID 获取单个供应商的详细信息。
|
|
|
|
|
|
请求参数:supplier_id - 供应商 ID(路径参数)。
|
|
|
|
|
|
返回值:供应商详情信息。
|
|
|
|
|
|
权限要求:业务员(salesman)、经理(manager)、管理员(admin)。
|
|
|
|
|
|
"""
|
2026-05-15 12:18:50 +08:00
|
|
|
|
supplier = supplier_service.get_supplier(supplier_id, session)
|
|
|
|
|
|
if not supplier:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="供应商不存在", status_code=404)
|
|
|
|
|
|
return success_payload(supplier)
|
2026-05-28 22:59:04 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.put("/{supplier_id}")
|
|
|
|
|
|
def update_supplier(
|
2026-05-30 07:23:33 +08:00
|
|
|
|
supplier_id: int, # 供应商 ID(路径参数)
|
|
|
|
|
|
payload: UpdateSupplierRequest, # 更新供应商的请求体
|
|
|
|
|
|
supplier_service: SupplierService = Depends(get_supplier_service), # 注入供应商服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("manager", "admin")), # 角色鉴权:仅经理/管理员
|
2026-05-28 22:59:04 +08:00
|
|
|
|
) -> dict:
|
2026-05-30 07:23:33 +08:00
|
|
|
|
"""更新供应商信息
|
|
|
|
|
|
|
|
|
|
|
|
用途:修改已有供应商的基本信息。
|
|
|
|
|
|
请求参数:supplier_id(路径参数)+ UpdateSupplierRequest(更新字段)。
|
|
|
|
|
|
返回值:更新后的供应商信息。
|
|
|
|
|
|
权限要求:经理(manager)或管理员(admin)。
|
|
|
|
|
|
"""
|
2026-05-28 22:59:04 +08:00
|
|
|
|
result = supplier_service.update_supplier(supplier_id, payload.model_dump(), session)
|
|
|
|
|
|
if not result:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="供应商不存在", status_code=404)
|
|
|
|
|
|
return success_payload(result)
|
2026-06-02 20:45:00 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.delete("/{supplier_id}")
|
|
|
|
|
|
def delete_supplier(
|
|
|
|
|
|
supplier_id: int, # 供应商 ID(路径参数)
|
|
|
|
|
|
supplier_service: SupplierService = Depends(get_supplier_service), # 注入供应商服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("manager", "admin")), # 角色鉴权:仅经理/管理员
|
|
|
|
|
|
) -> dict:
|
|
|
|
|
|
"""软删除供应商
|
|
|
|
|
|
|
|
|
|
|
|
用途:将供应商标记为已删除(deleted=1),不实际删除数据。
|
|
|
|
|
|
请求参数:supplier_id - 供应商 ID(路径参数)。
|
|
|
|
|
|
返回值:删除结果 {"deleted": true}。
|
|
|
|
|
|
权限要求:经理(manager)或管理员(admin)。
|
|
|
|
|
|
"""
|
|
|
|
|
|
supplier = session.execute(
|
|
|
|
|
|
select(Supplier).where(Supplier.id == supplier_id, Supplier.deleted == 0)
|
|
|
|
|
|
).scalar_one_or_none()
|
|
|
|
|
|
if not supplier:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="供应商不存在", status_code=404)
|
|
|
|
|
|
supplier.deleted = 1
|
|
|
|
|
|
session.commit()
|
|
|
|
|
|
return success_payload({"deleted": True})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.delete("/{supplier_id}/permanent")
|
|
|
|
|
|
def permanent_delete_supplier(
|
|
|
|
|
|
supplier_id: int, # 供应商 ID(路径参数)
|
|
|
|
|
|
supplier_service: SupplierService = Depends(get_supplier_service), # 注入供应商服务
|
|
|
|
|
|
session: Session = Depends(get_db_session), # 注入数据库会话
|
|
|
|
|
|
current_user: dict = Depends(require_roles("manager", "admin")), # 角色鉴权:仅经理/管理员
|
|
|
|
|
|
) -> dict:
|
|
|
|
|
|
"""永久删除供应商
|
|
|
|
|
|
|
|
|
|
|
|
用途:彻底删除供应商记录。若存在关联的有效订单则禁止删除。
|
|
|
|
|
|
请求参数:supplier_id - 供应商 ID(路径参数)。
|
|
|
|
|
|
返回值:删除结果 {"deleted": true}。
|
|
|
|
|
|
权限要求:经理(manager)或管理员(admin)。
|
|
|
|
|
|
"""
|
|
|
|
|
|
supplier = session.execute(
|
|
|
|
|
|
select(Supplier).where(Supplier.id == supplier_id, Supplier.deleted == 0)
|
|
|
|
|
|
).scalar_one_or_none()
|
|
|
|
|
|
if not supplier:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="供应商不存在", status_code=404)
|
|
|
|
|
|
order_count = session.execute(
|
|
|
|
|
|
select(func.count(SalesOrder.id)).where(
|
|
|
|
|
|
SalesOrder.factory_id == supplier_id,
|
|
|
|
|
|
SalesOrder.order_status != "cancelled",
|
|
|
|
|
|
)
|
|
|
|
|
|
).scalar()
|
|
|
|
|
|
if order_count > 0:
|
|
|
|
|
|
raise AppException(
|
|
|
|
|
|
code=ErrorCode.PARAM_ERROR,
|
|
|
|
|
|
message="该供应商还有关联订单,无法删除",
|
|
|
|
|
|
status_code=400,
|
|
|
|
|
|
)
|
|
|
|
|
|
session.delete(supplier)
|
|
|
|
|
|
session.commit()
|
|
|
|
|
|
return success_payload({"deleted": True})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@router.post("/batch-delete")
|
|
|
|
|
|
def batch_delete_suppliers(
|
|
|
|
|
|
ids: list[int] = Body(..., embed=True),
|
|
|
|
|
|
permanent: bool = Body(default=False, embed=True),
|
|
|
|
|
|
session: Session = Depends(get_db_session),
|
|
|
|
|
|
current_user: dict = Depends(require_roles("manager", "admin")),
|
|
|
|
|
|
) -> dict:
|
|
|
|
|
|
"""批量删除供应商"""
|
|
|
|
|
|
suppliers = session.execute(
|
|
|
|
|
|
select(Supplier).where(Supplier.id.in_(ids), Supplier.deleted == 0)
|
|
|
|
|
|
).scalars().all()
|
|
|
|
|
|
if not suppliers:
|
|
|
|
|
|
raise AppException(code=ErrorCode.NOT_FOUND, message="未找到可删除的供应商", status_code=404)
|
|
|
|
|
|
if permanent:
|
|
|
|
|
|
sup_ids = [s.id for s in suppliers]
|
|
|
|
|
|
count = session.execute(
|
|
|
|
|
|
select(func.count(SalesOrder.id)).where(
|
|
|
|
|
|
SalesOrder.factory_id.in_(sup_ids), SalesOrder.order_status != "cancelled"
|
|
|
|
|
|
)
|
|
|
|
|
|
).scalar()
|
|
|
|
|
|
if count > 0:
|
|
|
|
|
|
raise AppException(code=ErrorCode.PARAM_ERROR, message="所选供应商还有关联订单,无法删除", status_code=400)
|
|
|
|
|
|
for s in suppliers:
|
|
|
|
|
|
session.delete(s)
|
|
|
|
|
|
else:
|
|
|
|
|
|
for s in suppliers:
|
|
|
|
|
|
s.deleted = 1
|
|
|
|
|
|
session.commit()
|
|
|
|
|
|
return success_payload({"deleted": len(suppliers)})
|