refactor(backend): 仓储层散参数收敛为查询 DTO

仓储层的 list_*/count_* 此前以 keyword/status/offset/limit 四五个散参数
传参,调用点重复铺开、易漏传且不可扩展;按项目「参数 >4 封装 DTO」的
约定统一收敛为各模块的 Query 对象(如 RoleQuery、BusinessQuery),
服务层与测试调用同步调整,行为不变。

- repositories 层查询方法签名改为 (session, query),分页与筛选条件
  由 Query 承载,_apply_filters 同步收口
- schemas 层补齐各模块 Query 模型(approval/business_role/report 等)
- services 层调用点同步改为传 Query
- tests 随之调整;新增用例:待办角色流转(财务通过后领导出现待办)、
  参数预览顺序稳定

验证:全量 pytest 900 passed(11:08);单元 526 passed;ruff check 绿。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
liuwenxinandClaude Code committed 2026-10-22 19:43:20 +08:00
1 parent c48d24ab6d
commit 5ece9f6dab
45 files changed
+1045 -1028

No files matched your search

+9 -30
View File
@@ -103,10 +103,7 @@ def _person_row(row: PerformanceLedger, role_names: dict[str, str]) -> dict:
def _role_names(session) -> dict[str, str]:
"""岗位编码 → 名称一次查询(明细与部门行共用,避免 N+1)。"""
return {
r.role_code: r.role_name
for r in session.execute(select(BusinessRole)).scalars()
}
return {r.role_code: r.role_name for r in session.execute(select(BusinessRole)).scalars()}
def _dec(value) -> Decimal | None:
@@ -178,11 +175,7 @@ def department_summary(session, query) -> dict:
extra_ids = {
target
for pid in adjustments
if (
target := _adjustment_target(
pid, member_map, manager_of, manager_role, include_mp
)
)
if (target := _adjustment_target(pid, member_map, manager_of, manager_role, include_mp))
is not None
} - set(manager_ids)
if extra_ids:
@@ -193,9 +186,7 @@ def department_summary(session, query) -> dict:
for team in teams_all
if query.manager_id is None or team["manager_id"] == query.manager_id
]
unassigned_all = _unassigned_rows(
member_map, manager_of, manager_role, adjustments, include_mp
)
unassigned_all = _unassigned_rows(member_map, manager_of, manager_role, adjustments, include_mp)
# 「仅看某经理团队」时未分配桶不随展示:全公司无经理人员与该团队无关
unassigned = [] if query.manager_id is not None else unassigned_all
company_share_amount = _company_share(company_base, share.company_pct)
@@ -335,9 +326,7 @@ def _reconciliation(
(m["adjust_net"] for team in teams for m in team["members"]), Decimal("0")
) + sum((row["adjust_net"] for row in unassigned), Decimal("0"))
team_base_total = sum((team["team_base"] for team in teams), Decimal("0"))
unassigned_performance = sum(
(row["performance_sum"] for row in unassigned), Decimal("0")
)
unassigned_performance = sum((row["performance_sum"] for row in unassigned), Decimal("0"))
payable_total = (
team_member_payable + unassigned_payable + aggregate_payable_total + adjust_net_total
)
@@ -378,9 +367,7 @@ def _reconciliation(
def _team_share(team_base: Decimal, team_pct: Fraction) -> Decimal:
"""12.5% 团队分成:全公司部分传 0,仅取 team_pct 项。"""
return manager_team_share(
team_base, Decimal("0"), team_pct=team_pct, company_pct=Fraction(0)
)
return manager_team_share(team_base, Decimal("0"), team_pct=team_pct, company_pct=Fraction(0))
def _company_share(company_base: Decimal, company_pct: Fraction) -> Decimal:
@@ -483,12 +470,8 @@ def _team_relations(
referenced = {p.manager_id for p in people if p.manager_id is not None}
missing = referenced - seed
if missing:
people.extend(
session.execute(select(Personnel).where(Personnel.id.in_(missing))).scalars()
)
role_by_id = {
r.id: r.role_code for r in session.execute(select(BusinessRole)).scalars()
}
people.extend(session.execute(select(Personnel).where(Personnel.id.in_(missing))).scalars())
role_by_id = {r.id: r.role_code for r in session.execute(select(BusinessRole)).scalars()}
manager_of = {p.id: p.manager_id for p in people}
manager_role = {p.id: role_by_id.get(p.business_role_id, "") for p in people}
person_info = {
@@ -619,9 +602,7 @@ def _member_rows(
)
)
personal_in_team = (
pid == manager_id
and include_manager_personal
and member["has_manager_personal"]
pid == manager_id and include_manager_personal and member["has_manager_personal"]
)
if personal_in_team:
rows.append(
@@ -893,9 +874,7 @@ def _group_rows(rows) -> list[dict]:
def payment_detail(session, query) -> dict:
"""区间下钻分页(bucket 未注册 → 400)。"""
bucket = _bucket_by_code(query.bucket)
rows = report_repository.list_payment_detail(
session, query, bucket, offset=query.offset, limit=query.page_size
)
rows = report_repository.list_payment_detail(session, query, bucket)
return {
"list": [_payment_row(r) for r in rows],
"total": report_repository.count_payment_detail(session, query, bucket),