补齐源快照、资料预演、正式导入及工资核算的依赖链路。 新增版本化输入、逐段 FIFO、生成锁和结构化当月调整, 并提供默认关闭的周期采集、有限重试及 Windows 托管。 原始客户资料、私有配置及首页改动不纳入本次提交。 BREAKING CHANGE: 升级前需应用新增迁移,并通过 PAYROLL_MAKER_USER_ID 绑定实际工资制作人,否则业务只读。 旧单批次核算默认关闭;历史兼容需显式启用 PAYROLL_ALLOW_LEGACY_CALCULATION。生产启用和真实金额待验收。
90 lines
3.2 KiB
Python
90 lines
3.2 KiB
Python
"""发货管理接口(需求 2.2.2)。
|
|
|
|
校验规则(状态门槛、行金额固化、双重汇总回写、删除保护)见
|
|
`shipment_service` 模块 docstring;业务数据属业务操作,登录即可访问。
|
|
"""
|
|
|
|
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, Depends, Path, Query
|
|
|
|
from app.api.deps import DbSession, PayrollWriter, 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: PayrollWriter,
|
|
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: PayrollWriter,
|
|
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: PayrollWriter,
|
|
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="发货单已删除")
|