feat(核算)!: 添加 T+ 正式核算与采集托管

补齐源快照、资料预演、正式导入及工资核算的依赖链路。
新增版本化输入、逐段 FIFO、生成锁和结构化当月调整,
并提供默认关闭的周期采集、有限重试及 Windows 托管。

原始客户资料、私有配置及首页改动不纳入本次提交。

BREAKING CHANGE: 升级前需应用新增迁移,并通过
PAYROLL_MAKER_USER_ID 绑定实际工资制作人,否则业务只读。
旧单批次核算默认关闭;历史兼容需显式启用
PAYROLL_ALLOW_LEGACY_CALCULATION。生产启用和真实金额待验收。
This commit is contained in:
liuwenxin committed 2026-11-02 09:42:53 +08:00
1 parent 1b074576fe
commit 108bf87225
154 files changed
+9515 -645

No files matched your search

+6 -6
View File
@@ -9,7 +9,7 @@ from typing import Annotated
from fastapi import APIRouter, Depends, Path, Query
from app.api.deps import DbSession, RequestMetaDep, get_current_user
from app.api.deps import DbSession, PayrollWriter, RequestMetaDep, get_current_user
from app.core.response import ApiResponse, PageQuery, PageResult, ok
from app.models import User
from app.schemas.business import (
@@ -45,7 +45,7 @@ def list_businesses(
@router.post("", response_model=ApiResponse[BusinessOut], summary="创建业务")
def create_business(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
payload: BusinessCreateIn,
meta: RequestMetaDep,
) -> ApiResponse[BusinessOut]:
@@ -69,7 +69,7 @@ def get_business(
@router.put("/{business_id}", response_model=ApiResponse[BusinessOut], summary="编辑业务")
def update_business(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
business_id: Annotated[int, Path(ge=1)],
payload: BusinessUpdateIn,
meta: RequestMetaDep,
@@ -86,7 +86,7 @@ def update_business(
@router.delete("/{business_id}", response_model=ApiResponse[None], summary="删除业务")
def delete_business(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
business_id: Annotated[int, Path(ge=1)],
meta: RequestMetaDep,
) -> ApiResponse[None]:
@@ -98,7 +98,7 @@ def delete_business(
@router.put("/{business_id}/status", response_model=ApiResponse[BusinessOut], summary="状态流转")
def change_status(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
business_id: Annotated[int, Path(ge=1)],
payload: BusinessStatusIn,
meta: RequestMetaDep,
@@ -115,7 +115,7 @@ def change_status(
@router.put("/{business_id}/ownership", response_model=ApiResponse[BusinessOut], summary="调整归属")
def change_ownership(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
business_id: Annotated[int, Path(ge=1)],
payload: BusinessOwnershipIn,
meta: RequestMetaDep,
+4 -4
View File
@@ -13,7 +13,7 @@ from typing import Annotated
from fastapi import APIRouter, Depends, Path
from app.api.deps import DbSession, RequestMetaDep, get_current_user
from app.api.deps import DbSession, PayrollWriter, RequestMetaDep, get_current_user
from app.core.response import ApiResponse, ok
from app.models import User
from app.schemas.rating import RatingGradeCreateIn, RatingGradeOut, RatingGradeUpdateIn
@@ -36,7 +36,7 @@ def list_grades(
@router.post("", response_model=ApiResponse[RatingGradeOut], summary="新增评级等级")
def create_grade(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
payload: RatingGradeCreateIn,
meta: RequestMetaDep,
) -> ApiResponse[RatingGradeOut]:
@@ -50,7 +50,7 @@ def create_grade(
@router.put("/{grade_id}", response_model=ApiResponse[RatingGradeOut], summary="编辑评级等级")
def update_grade(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
grade_id: Annotated[int, Path(ge=1)],
payload: RatingGradeUpdateIn,
meta: RequestMetaDep,
@@ -65,7 +65,7 @@ def update_grade(
@router.delete("/{grade_id}", response_model=ApiResponse[None], summary="删除评级等级")
def delete_grade(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
grade_id: Annotated[int, Path(ge=1)],
meta: RequestMetaDep,
) -> ApiResponse[None]:
+4 -4
View File
@@ -9,7 +9,7 @@ from typing import Annotated
from fastapi import APIRouter, Depends, Path, Query
from app.api.deps import DbSession, RequestMetaDep, get_current_user
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.receipt import (
@@ -39,7 +39,7 @@ def list_receipts(
@router.post("", response_model=ApiResponse[ReceiptOut], summary="新增回款")
def create_receipt(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
payload: ReceiptCreateIn,
meta: RequestMetaDep,
) -> ApiResponse[ReceiptOut]:
@@ -63,7 +63,7 @@ def get_receipt(
@router.put("/{receipt_id}", response_model=ApiResponse[ReceiptOut], summary="编辑回款")
def update_receipt(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
receipt_id: Annotated[int, Path(ge=1)],
payload: ReceiptUpdateIn,
meta: RequestMetaDep,
@@ -80,7 +80,7 @@ def update_receipt(
@router.delete("/{receipt_id}", response_model=ApiResponse[None], summary="删除回款")
def delete_receipt(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
receipt_id: Annotated[int, Path(ge=1)],
meta: RequestMetaDep,
) -> ApiResponse[None]:
+4 -4
View File
@@ -8,7 +8,7 @@ from typing import Annotated
from fastapi import APIRouter, Depends, Path, Query
from app.api.deps import DbSession, RequestMetaDep, get_current_user
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 (
@@ -39,7 +39,7 @@ def list_shipments(
@router.post("", response_model=ApiResponse[ShipmentOut], summary="创建发货单")
def create_shipment(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
payload: ShipmentCreateIn,
meta: RequestMetaDep,
) -> ApiResponse[ShipmentOut]:
@@ -63,7 +63,7 @@ def get_shipment(
@router.put("/{shipment_id}", response_model=ApiResponse[ShipmentOut], summary="编辑发货单")
def update_shipment(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
shipment_id: Annotated[int, Path(ge=1)],
payload: ShipmentUpdateIn,
meta: RequestMetaDep,
@@ -80,7 +80,7 @@ def update_shipment(
@router.delete("/{shipment_id}", response_model=ApiResponse[None], summary="删除发货单")
def delete_shipment(
session: DbSession,
current_user: CurrentUser,
current_user: PayrollWriter,
shipment_id: Annotated[int, Path(ge=1)],
meta: RequestMetaDep,
) -> ApiResponse[None]: