PayrollManagementSystem/backend/app/services/permission_catalog.py
liuwenxin 1461a8d113 feat(后端): 添加授权体系、系统监控与试用期计提
按 2026-11-02 需求补齐计划交付后端能力:
- 角色授权:权限目录化,接口统一准入校验,未登记默认拒绝;
  管理员判断改为按数据库角色重新判定,防止权限码持有者绕过
- 系统监控:单进程采集资源、请求与异常指标,分钟级聚合,
  阈值配置化;敏感配置增加 repr 保护,Redis 密码 URL 转义
- 试用期计提:按回款日判定并写入快照,年度结清与调整单联动;
  人员模型补试用期、离职日期与工资版本历史字段
- 计提模板:公式骨架受控,页面维护名称与参数绑定
- T+ 采集:自动化配置表与进度查询

内置角色禁停用保护对齐模块注释;核算规则版本提为常量并
补充批量核算失败堆栈日志。

影响范围:后端全部模块、数据库迁移 V22-V28
验证:uv run ruff check 通过;922 个单元测试全部通过;
集成测试因本机 MySQL 数据卷被其他容器锁定暂未运行
2026-11-03 11:20:55 +08:00

80 lines
4.9 KiB
Python

"""权限目录随代码发布;菜单、按钮和 API 共用同一操作码。"""
MODULES = (
("dashboard", "工作台", "首页", ("view",)),
("system:users", "系统管理", "用户管理", ("view", "create", "update", "delete", "status", "password")),
("system:roles", "系统管理", "角色管理", ("view", "create", "update", "delete", "status")),
("system:business_roles", "系统管理", "计提岗位", ("view", "create", "update", "delete", "status")),
("system:params", "系统管理", "计提参数", ("view", "update", "withdraw", "export", "preview")),
("system:settings", "系统管理", "公司信息", ("view", "update")),
("system:logs", "系统管理", "日志查询", ("view",)),
("system:monitor", "系统管理", "系统监控", ("view", "export")),
("base:personnel", "基础资料", "人员管理", ("view", "create", "update", "delete", "status", "regions", "plans")),
("base:products", "基础资料", "产品管理", ("view", "create", "update", "delete", "status")),
("base:customers", "基础资料", "客户管理", ("view", "create", "update", "delete", "rating", "ownership")),
("business:businesses", "业务数据", "业务管理", ("view", "create", "update", "delete", "status", "ownership")),
("business:shipments", "业务数据", "发货管理", ("view", "create", "update", "delete")),
("business:receipts", "业务数据", "回款管理", ("view", "create", "update", "delete")),
("business:ratings", "业务数据", "评级标准", ("view", "create", "update", "delete")),
("tplus", "T+ 对接", "采集与导入", ("view", "collect", "retry", "preview", "import", "facts", "export")),
("payroll", "绩效工资", "正式核算与分配", ("view", "prepare", "calculate", "allocation")),
("settlements", "绩效工资", "月度工资", ("view", "generate", "submit")),
("adjustments", "绩效工资", "工资调整", ("view", "create")),
("approvals", "绩效工资", "审核记录", ("view", "finance", "leader")),
("reports:business", "报表统计", "业务统计", ("view", "export")),
("reports:personal", "报表统计", "个人明细", ("view", "export")),
("reports:department", "报表统计", "部门汇总", ("view", "export")),
("reports:payments", "报表统计", "回款统计", ("view", "export")),
)
ACTION_NAMES = {
"view": "查看", "create": "新增", "update": "编辑", "delete": "删除",
"status": "变更状态", "password": "重置密码", "regions": "维护区域", "plans": "维护计划",
"rating": "客户评级", "ownership": "变更归属", "export": "导出", "preview": "预览",
"withdraw": "撤回参数", "collect": "创建采集", "retry": "重试采集", "import": "执行导入",
"facts": "维护补充资料", "prepare": "准备核算资料", "calculate": "核算与重算",
"allocation": "修改工资分配", "generate": "生成工资", "submit": "提交审核",
"finance": "财务复核", "leader": "领导审核",
}
CATALOG = {
f"{module}:{action}": {
"code": f"{module}:{action}", "module": module, "group": group,
"module_name": name, "name": ACTION_NAMES[action], "action": action,
"view_code": f"{module}:view", "admin_only": module in (
"system:users", "system:roles", "system:authorization", "system:monitor"
),
"maker_required": False,
}
for module, group, name, actions in MODULES for action in actions
}
MAKER_ROLE = "payroll_maker"
PAYROLL_WRITE_PERMISSIONS = frozenset(
code for code, item in CATALOG.items()
if item["module"] in ("payroll", "settlements", "adjustments") and item["action"] != "view"
)
MAKER_PERMISSIONS = {
code for code, item in CATALOG.items()
if code in PAYROLL_WRITE_PERMISSIONS or item["module"] in (
"base:personnel", "base:products", "base:customers", "business:businesses",
"business:shipments", "business:receipts", "business:ratings", "tplus",
) or (item["action"] == "view" and item["group"] in ("绩效工资", "报表统计"))
}
USER_PERMISSIONS = {
code for code, item in CATALOG.items()
if item["action"] == "view" and item["group"] in ("基础资料", "业务数据")
}
ROLE_DEFAULTS = {
"admin": set(CATALOG), "user": USER_PERMISSIONS,
"marketing_ops": USER_PERMISSIONS,
"finance": USER_PERMISSIONS | {
code for code, item in CATALOG.items()
if (item["action"] == "view" and item["group"] in ("绩效工资", "报表统计", "工作台"))
or (item["group"] == "报表统计" and item["action"] == "export")
} | {"approvals:finance", "system:params:view", "system:params:preview"},
"leader": USER_PERMISSIONS | {
code for code, item in CATALOG.items()
if (item["action"] == "view" and item["group"] in ("绩效工资", "报表统计", "工作台"))
or (item["group"] == "报表统计" and item["action"] == "export")
} | {"approvals:leader", "system:params:view", "system:params:preview"},
MAKER_ROLE: MAKER_PERMISSIONS,
}