"""绩效核算接口(M3 ④):台账查询与单笔核算触发。 核算动作 = 把回款固化为台账行(每笔回款仅一次;重算走独立入口并授权)。 准入:读=登录即可;写(核算/重算/批量)=管理员与营销后勤 (权限清单待澄清 #6,答复后细化)。 """ from typing import Annotated from fastapi import APIRouter, Depends, Path, Query from app.api.deps import DbSession, RequestMetaDep, require_roles from app.core.constants import ROLE_ADMIN, ROLE_MARKETING_OPS from app.core.response import ApiResponse, PageResult, ok from app.models import User from app.schemas.calc import CalcReceiptOut, LedgerOut, LedgerQuery from app.services import calc_service router = APIRouter(prefix="/calc", tags=["绩效工资 · 绩效核算"]) _CalcWriter = Annotated[User, Depends(require_roles(ROLE_ADMIN, ROLE_MARKETING_OPS))] @router.get("/ledger", response_model=ApiResponse[PageResult[LedgerOut]], summary="绩效台账") def list_ledger( session: DbSession, query: Annotated[LedgerQuery, Query()], ) -> ApiResponse[PageResult[LedgerOut]]: """分页查询绩效核算台账(默认仅生效行,可筛选历史版本)。""" return ok(calc_service.list_ledger_page(session, query)) @router.get("/ledger/{ledger_id}", response_model=ApiResponse[LedgerOut], summary="台账详情") def get_ledger( session: DbSession, ledger_id: Annotated[int, Path(ge=1)], ) -> ApiResponse[LedgerOut]: """台账行详情(含计算快照)。""" return ok(calc_service.get_ledger(session, ledger_id)) @router.post( "/receipts/{receipt_id}/calc", response_model=ApiResponse[CalcReceiptOut], summary="核算回款", ) def calc_receipt( receipt_id: Annotated[int, Path(ge=1)], session: DbSession, current_user: _CalcWriter, meta: RequestMetaDep, ) -> ApiResponse[CalcReceiptOut]: """把回款固化为台账行(每笔回款仅一次;业务级一次性计提,重复回款仅登记进度)。""" return ok( calc_service.calc_receipt(session, receipt_id, operator=current_user, meta=meta), message="核算完成", )