PayrollManagementSystem/backend/app/services/authorization_policy.py
liuwenxin 1e53792ad6 feat(T+): 完成数据贯通与自动接入闭环
打通 T+ 快照、业务、发货、回款和核算准备链路,保留来源差异并提供待补状态。
新增业务自动接入任务、跨平台读取服务托管、权限复核、来源关联和前端核对页面。
补充迁移、隔离集成测试、浏览器模拟验收及角色授权边界修复。
2026-11-05 18:47:13 +08:00

95 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""每个受保护接口必须映射权限;未登记接口默认拒绝。"""
RESOURCE_MODULES = {
"base.personnel": "base:personnel", "base.products": "base:products",
"base.customers": "base:customers", "business.businesses": "business:businesses",
"business.shipments": "business:shipments", "business.receipts": "business:receipts",
"business.ratings": "business:ratings", "system.users": "system:users",
"system.roles": "system:roles", "system.business_roles": "system:business_roles",
"system.logs": "system:logs", "system.settings": "system:settings",
"system.monitor": "system:monitor",
}
REPORT_MODULES = {
"personal-detail": "reports:personal", "department-summary": "reports:department",
"business-stats": "reports:business", "payment-stats": "reports:payments",
}
PUBLIC_ENDPOINTS = {("auth", "get_captcha"), ("auth", "login"),
("system.settings", "get_settings_public"), ("system.settings", "get_logo_public")}
LOGIN_ENDPOINTS = {("auth", "me"), ("auth", "logout")}
def permission_for(module, name, method, *, params=None, body=None):
"""返回目录操作码;None 表示没有登记,空串仅用于显式登录态接口。"""
params, body = params or {}, body or {}
if (module, name) in PUBLIC_ENDPOINTS | LOGIN_ENDPOINTS:
return ""
if module == "dashboard":
return "dashboard:view"
if module == "system.authorization":
resource = "system:users" if name in ("user_authorization", "preview", "save_user") else "system:roles"
return resource + (":view" if method == "GET" or name == "preview" else ":update")
if module == "metadata":
return "" # 此端点按请求的参照资源执行独立的关联功能校验。
if module == "base.business_roles":
return "" # 下拉只返回选项;由端点校验人员查看/维护能力。
if module in RESOURCE_MODULES:
resource = RESOURCE_MODULES[module]
if module == "base.products" and name in ("extraction_preview", "extraction_apply", "restore_source"):
return resource + (":create" if name == "extraction_apply" else ":update" if name == "restore_source" else ":view")
if method == "GET":
return resource + ":view"
special = {"set_status": "status", "change_status": "status", "reset_password": "password",
"confirm_receipt": "confirm",
"replace_regions": "regions", "replace_plans": "plans", "rate_customer": "rating",
"change_ownership": "ownership", "batch_ownership": "ownership", "upload_logo": "update"}
action = special.get(name) or {"POST": "create", "PUT": "update", "DELETE": "delete"}.get(method)
return resource + ":" + action if action else None
if module == "system.params":
action = "view" if method == "GET" else {"submit_change": "update", "withdraw_batch": "withdraw", "preview": "preview"}.get(name)
if name == "export_changes":
action = "export"
return "system:params:" + action if action else None
if module == "system.coefficients":
return "system:params:" + ({"save": "update", "export": "export", "import_preview": "preview"}.get(name, "view"))
if module == "system.calc_templates":
return "system:params:" + ("view" if method == "GET" else "update")
if module == "system.monitor":
return "system:monitor:" + ("export" if name == "diagnostic" else "view")
if module == "system.tplus":
return "tplus:" + ("view" if method == "GET" else "retry" if name == "retry" else "collect")
if module == "system.tplus_workbench":
if name.startswith("business_sync_"):
return "tplus:view" if method == "GET" else "tplus:import"
if name == "work_report":
return "tplus:export"
if method == "GET":
return "tplus:view"
if name in ("save_fact", "save_correction_pair"):
return "tplus:facts"
if name == "create_work":
return "tplus:import" if body.get("kind") in ("MASTER_APPLY", "BUSINESS_APPLY") else "tplus:preview"
if module in ("payroll", "calc"):
if name == "probation_adjustment":
return "adjustments:create"
if name in ("probation_export", "salary_export"):
return "reports:personal:export"
if method == "GET":
return "payroll:view"
return "adjustments:create" if name == "adjustment" else "payroll:prepare" if name == "save_input" else "payroll:calculate"
if module == "settlements":
if name in ("create_adjustment", "list_adjustments"):
return "adjustments:" + ("view" if method == "GET" else "create")
return "settlements:" + ("view" if method == "GET" else "generate" if name == "generate" else "submit")
if module == "system.approvals":
return "approvals:view" # 节点动作由服务层根据当前节点检查 finance/leader。
if module == "reports":
code = params.get("code") if name == "export_report" else {
"personal_detail": "personal-detail", "department_summary": "department-summary",
"business_stats": "business-stats", "payment_stats": "payment-stats",
"payment_detail": "payment-stats", "payment_day_buckets": "payment-stats",
}.get(name)
resource = REPORT_MODULES.get(code)
return resource + (":export" if name == "export_report" else ":view") if resource else None
return None