"""发货管理接口(需求 2.2.2)。 校验规则(状态门槛、行金额固化、双重汇总回写、删除保护)见 `shipment_service` 模块 docstring;业务数据属业务操作,登录即可访问。 """ from typing import Annotated from fastapi import APIRouter, Depends, Path, Query from app.api.deps import DbSession, RequestMetaDep, get_current_user from app.core.response import ApiResponse, PageResult, ok from app.models import User from app.schemas.shipment import ( ShipmentCreateIn, ShipmentDetailOut, ShipmentOut, ShipmentQuery, ShipmentUpdateIn, ) from app.services import shipment_service # 基础数据是业务操作:登录即可,不要求管理员(区别于系统管理的 AdminUser) CurrentUser = Annotated[User, Depends(get_current_user)] router = APIRouter(prefix="/shipments", tags=["发货管理"]) @router.get("", response_model=ApiResponse[PageResult[ShipmentOut]], summary="发货单列表") def list_shipments( session: DbSession, _: CurrentUser, query: Annotated[ShipmentQuery, Query()], ) -> ApiResponse[PageResult[ShipmentOut]]: """分页查询发货单(附业务编号),可按业务/发货日期范围筛选。""" return ok(shipment_service.list_shipments(session, query)) @router.post("", response_model=ApiResponse[ShipmentOut], summary="创建发货单") def create_shipment( session: DbSession, current_user: CurrentUser, payload: ShipmentCreateIn, meta: RequestMetaDep, ) -> ApiResponse[ShipmentOut]: """创建发货单(明细 ≥1)。业务须处于执行中;锁业务行后生成 SH 编号。""" return ok( shipment_service.create_shipment(session, payload, operator=current_user, meta=meta), message="发货单已创建", ) @router.get("/{shipment_id}", response_model=ApiResponse[ShipmentDetailOut], summary="发货单详情") def get_shipment( session: DbSession, _: CurrentUser, shipment_id: Annotated[int, Path(ge=1)], ) -> ApiResponse[ShipmentDetailOut]: """发货单详情,附产品明细行,供编辑抽屉一次回显。""" return ok(shipment_service.get_detail(session, shipment_id)) @router.put("/{shipment_id}", response_model=ApiResponse[ShipmentOut], summary="编辑发货单") def update_shipment( session: DbSession, current_user: CurrentUser, shipment_id: Annotated[int, Path(ge=1)], payload: ShipmentUpdateIn, meta: RequestMetaDep, ) -> ApiResponse[ShipmentOut]: """编辑发货单(明细全量替换并重算汇总)。终态业务的发货单禁改。""" return ok( shipment_service.update_shipment( session, shipment_id, payload, operator=current_user, meta=meta ), message="已保存", ) @router.delete("/{shipment_id}", response_model=ApiResponse[None], summary="删除发货单") def delete_shipment( session: DbSession, current_user: CurrentUser, shipment_id: Annotated[int, Path(ge=1)], meta: RequestMetaDep, ) -> ApiResponse[None]: """删除发货单(连带明细行并回写业务汇总)。被回款批次指定时禁删。""" shipment_service.delete_shipment(session, shipment_id, operator=current_user, meta=meta) return ok(message="发货单已删除")