fix(report): 报表统计修复批次——对账口径、导出审计与月份校验

- 部门汇总全公司 5% 按每位有台账聚合行的营销经理各计一次,
  团队应发小计取聚合额 + 调整净额;与月结 total_payable 对拍
  (有调整单时 + adjust_net_total),分列舍入差单列
- 人员归属按行类型拆分(普通/经理个人户/仅调整单),调整单全量并入,
  团队与未分配不重复;按经理筛选只汇总展示团队
- 导出改单 sheet 分块签字稿,审计覆盖取数与超限;筛选页眉 ID→名称
- 月份校验抽 core/month,报表/月结/调整单非法月份统一 400;
  岗位只读选项供财务/领导筛选
- 前端修复:部门下钻带入筛选、回款多桶独立状态、打印截断判定、
  summary 请求序号保护

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
liuwenxinandClaude Code committed 2026-10-20 09:44:43 +08:00
1 parent 294d99a0d3
commit ebb3a92f25
21 files changed
+2377 -287

No files matched your search

+211
View File
@@ -209,3 +209,214 @@ class TestExcel模板:
]
text = _sheet_text(_build("business-stats", rows))
assert "已完成" in text
def _member(
personnel_id: int,
name: str,
*,
kind: str = "regular",
performance: str = "0.00",
payable: str = "0.00",
adjust: str = "0.00",
reason: str | None = None,
) -> dict:
return {
"personnel_id": personnel_id,
"personnel_name": name,
"role_code": "salesperson",
"is_probation": 0,
"member_kind": kind,
"unassigned_reason": reason,
"performance_sum": Decimal(performance),
"payable_sum": Decimal(payable),
"adjust_extra": Decimal(adjust),
"adjust_deduct": Decimal("0"),
"adjust_net": Decimal(adjust),
"net_total": Decimal(payable) + Decimal(adjust),
"ledger_ids": [],
}
def _department_data(
team_text: str = "12.5",
company_text: str = "5",
*,
second_has_aggregate: bool = False,
) -> dict:
"""一份含成员、零成员团队与未分配人员的部门汇总出参。
``second_has_aggregate`` 打开后两位经理都有月结聚合行,用于验证
全公司 5% 按人数累计(零成员团队默认不发 5%)。
"""
second_aggregate = Decimal("600.00") if second_has_aggregate else Decimal("0")
share_count = 2 if second_has_aggregate else 1
aggregate_total = Decimal("1850.00") + second_aggregate
payable_total = Decimal("10000.00") + Decimal("2000.00") + aggregate_total
return {
"settlement_month": "2026-10",
"params": {
"team_text": team_text,
"company_text": company_text,
"manager_personal_included": 0,
"params_as_of": "2026-10-31",
},
"teams": [
{
"manager_id": 1,
"manager_name": "张经理",
"manager_status": 1,
"member_count": 1,
"team_base": Decimal("10000.00"),
"team_share_amount": Decimal("1250.00"),
"company_share_amount": Decimal("600.00"),
"has_aggregate": True,
"aggregate_amount": Decimal("1850.00"),
"team_subtotal": Decimal("1850.00"),
"company_base_ratio": Decimal("0.8333"),
"adjust_extra": Decimal("0"),
"adjust_deduct": Decimal("0"),
"adjust_net": Decimal("0"),
"net_total": Decimal("1850.00"),
"frozen_amount": None,
"aggregate_ledger_id": None,
"members": [
_member(
2,
"李业务",
performance="10000.00",
payable="10000.00",
)
],
},
{
"manager_id": 3,
"manager_name": "王经理",
"manager_status": 1,
"member_count": 0,
"team_base": Decimal("0"),
"team_share_amount": Decimal("0"),
"company_share_amount": second_aggregate,
"has_aggregate": second_has_aggregate,
"aggregate_amount": second_aggregate,
"team_subtotal": second_aggregate,
"company_base_ratio": Decimal("0"),
"adjust_extra": Decimal("0"),
"adjust_deduct": Decimal("0"),
"adjust_net": Decimal("0"),
"net_total": second_aggregate,
"frozen_amount": None,
"aggregate_ledger_id": None,
"members": [],
},
],
"unassigned": [
_member(
4,
"赵未分配",
performance="2000.00",
payable="2000.00",
reason="无经理或上级非营销经理",
)
],
"company": {
"team_base_total": Decimal("10000.00"),
"company_base": Decimal("12000.00"),
"company_share_pct": company_text,
"company_share_amount": Decimal("600.00"),
"company_share_count": share_count,
"company_share_total": Decimal("600.00") * share_count,
},
"reconciliation": {
"team_member_payable_total": Decimal("10000.00"),
"unassigned_payable_total": Decimal("2000.00"),
"team_share_total": Decimal("1250.00"),
"company_share_total": Decimal("600.00") * share_count,
"aggregate_payable_total": aggregate_total,
"aggregate_rounding_diff": Decimal("0"),
"adjust_net_total": Decimal("0"),
"payable_total": payable_total,
"team_base_total": Decimal("10000.00"),
"unassigned_performance_total": Decimal("2000.00"),
"other_team_base": Decimal("0"),
"other_team_member_payable_total": Decimal("0"),
"other_team_share_total": Decimal("0"),
"other_team_company_share_total": Decimal("0"),
"other_team_aggregate_total": Decimal("0"),
"other_adjust_net_total": Decimal("0"),
"company_base": Decimal("12000.00"),
},
"totals": {},
}
def _build_department(data: dict) -> bytes:
return report_export.build_workbook(
code="department-summary",
title="部门绩效工资汇总表",
filters="统计月份 2026-10",
rows=[],
summary=None,
buckets=None,
department=data,
template_version="V1.2",
operator_name="admin",
company_name="衍水集团",
)
class Test部门汇总签字稿:
"""签字稿少了团队分成/5% 块/未分配/零成员团队,合计就会小于应发。"""
def test_五块顺序完整(self):
text = _sheet_text(_build_department(_department_data()))
titles = [
"一、团队分成汇总",
"二、全公司分成(每位有聚合行",
"三、对账汇总",
"四、团队成员明细",
"五、未分配人员明细",
]
positions = [text.index(title) for title in titles]
assert positions == sorted(positions), "签字稿块顺序错乱"
assert "财务复核" in text and "领导签字" in text
def test_零成员团队与未分配行存在(self):
text = _sheet_text(_build_department(_department_data()))
assert "王经理" in text
assert "赵未分配" in text
assert "无经理或上级非营销经理" in text
def test_全公司分成按计入次数累计(self):
"""两位有聚合行的经理各计一次 5%;零成员团队不产生分成。"""
one = _department_data()
text = _sheet_text(_build_department(one))
assert text.count("全公司分成(每位有聚合行") == 1
assert "共 1 次" in text
assert "13850" in text
two = _department_data(second_has_aggregate=True)
text = _sheet_text(_build_department(two))
assert "共 2 次" in text
# 团队成员应付 10000 + 未分配 2000 + 聚合 2450
assert "14450" in text
def test_应发合计取对账口径(self):
text = _sheet_text(_build_department(_department_data()))
assert "应发合计" in text
# Excel 数值单元格读回为 int/float,金额断言只看数值本身
assert "13850" in text
def test_聚合行舍入差单列(self):
data = _department_data()
data["reconciliation"]["aggregate_rounding_diff"] = Decimal("-0.02")
text = _sheet_text(_build_department(data))
assert "聚合行舍入差" in text
assert "-0.02" in text
def test_比例标题参数化(self):
text = _sheet_text(_build_department(_department_data("20", "6")))
assert "团队分成(20%)" in text
assert "6%" in text
assert "12.5%" not in text
assert "5%" not in text.replace("6%", "")