feat(核算)!: 添加 T+ 正式核算与采集托管
补齐源快照、资料预演、正式导入及工资核算的依赖链路。 新增版本化输入、逐段 FIFO、生成锁和结构化当月调整, 并提供默认关闭的周期采集、有限重试及 Windows 托管。 原始客户资料、私有配置及首页改动不纳入本次提交。 BREAKING CHANGE: 升级前需应用新增迁移,并通过 PAYROLL_MAKER_USER_ID 绑定实际工资制作人,否则业务只读。 旧单批次核算默认关闭;历史兼容需显式启用 PAYROLL_ALLOW_LEGACY_CALCULATION。生产启用和真实金额待验收。
This commit is contained in:
1 parent
1b074576fe
commit
108bf87225
154 files changed
+9515
-645
No files matched your search
@@ -19,6 +19,7 @@
|
||||
评级用例会删改种子构造重叠/相邻场景,恢复保证跨文件幂等
|
||||
"""
|
||||
|
||||
import os
|
||||
import uuid
|
||||
from decimal import Decimal
|
||||
from pathlib import Path
|
||||
@@ -81,7 +82,12 @@ def _purge_test_data() -> None:
|
||||
``t\\_%`` 中的下划线做了转义 —— 不转义时 `_` 是 LIKE 的单字符通配,
|
||||
会把 tn... 这类无关账号一并卷入。
|
||||
"""
|
||||
from app.core.config import get_settings
|
||||
from tests.isolation import ensure_test_database
|
||||
|
||||
ensure_test_database(get_settings().mysql_database, os.environ.get("PAYROLL_TEST_DATABASE"))
|
||||
factory = get_session_factory()
|
||||
ensure_test_database(factory.kw["bind"].url.database, os.environ.get("PAYROLL_TEST_DATABASE"))
|
||||
with factory() as session:
|
||||
users = list(
|
||||
session.execute(select(User.id, User.username).where(User.username.like("t\\_%"))).all()
|
||||
@@ -104,6 +110,11 @@ def _purge_test_data() -> None:
|
||||
# ---- M3-core:核算台账 / 月结 / 调整单(必须先于回款/业务/人员删除——
|
||||
# ledger.receipt_id/personnel_id/settlement_id 外键 RESTRICT 会挡住后面
|
||||
# 的单据与人员清理;仅测试写入,全量清)----
|
||||
from app.models import PayrollAllocation, PayrollInput, PayrollMonth, TPlusAutomationState
|
||||
session.execute(delete(TPlusAutomationState))
|
||||
session.execute(delete(PayrollAllocation))
|
||||
session.execute(delete(PayrollInput))
|
||||
session.execute(delete(PayrollMonth))
|
||||
session.execute(delete(PerformanceLedger))
|
||||
session.execute(delete(SettlementItem))
|
||||
session.execute(delete(MonthlySettlement))
|
||||
@@ -216,6 +227,11 @@ def _purge_test_data() -> None:
|
||||
@pytest.fixture(autouse=True)
|
||||
def _purge_after_each_test():
|
||||
"""每个集成用例结束后兜底清理,避免残留影响后续用例的计数断言。"""
|
||||
from app.core.config import get_settings
|
||||
from tests.isolation import ensure_test_database
|
||||
|
||||
ensure_test_database(get_settings().mysql_database, os.environ.get("PAYROLL_TEST_DATABASE"))
|
||||
ensure_test_database(get_session_factory().kw["bind"].url.database, os.environ.get("PAYROLL_TEST_DATABASE"))
|
||||
yield
|
||||
_purge_test_data()
|
||||
|
||||
@@ -311,9 +327,11 @@ def make_role():
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def admin(make_user, auth_headers) -> dict:
|
||||
def admin(make_user, auth_headers, monkeypatch) -> dict:
|
||||
"""管理员账号(含请求头)。"""
|
||||
user = make_user([ROLE_ADMIN])
|
||||
from app.core.config import get_settings
|
||||
monkeypatch.setattr(get_settings(), "payroll_maker_user_id", user["id"])
|
||||
user["headers"] = auth_headers(user)
|
||||
return user
|
||||
|
||||
@@ -357,3 +375,18 @@ def tplus_tasks(monkeypatch):
|
||||
db.execute(delete(TPlusSyncError).where(TPlusSyncError.batch_no.in_(numbers)))
|
||||
db.execute(delete(TPlusSyncBatch).where(TPlusSyncBatch.batch_no.in_(numbers)))
|
||||
db.commit()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def legacy_calculation(monkeypatch):
|
||||
"""明确启用旧引擎兼容回归;生产和正式工资测试默认关闭。"""
|
||||
from app.core.config import get_settings
|
||||
monkeypatch.setattr(get_settings(), "payroll_allow_legacy_calculation", True)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def writer(normal, admin, monkeypatch):
|
||||
"""指定一个普通角色账号为工资制作人,证明身份授权与管理员角色无关。"""
|
||||
from app.core.config import get_settings
|
||||
monkeypatch.setattr(get_settings(), "payroll_maker_user_id", normal["id"])
|
||||
return normal
|
||||
Reference in new issue
Block a user