feat(P15A-1,P15A-5): 解耦请假审批权限

这个提交包含在:
2026-03-07 07:15:33 +08:00
父节点 637fd24d8e
当前提交 03c5a78485
共修改 10 个文件,包含 230 行新增和 46 行删除
@@ -0,0 +1,37 @@
const {
hasPermission,
resolveEntityPermission,
resolvePermissionsForRoles,
} = require("../../../src/constants/permissions");
describe("Permission Constants", () => {
it("grants leave self-service permissions to employee roles", () => {
const employeePermissions = resolvePermissionsForRoles(["employee"]);
expect(employeePermissions).toEqual(
expect.arrayContaining(["leave.create", "leave.view_own", "leave.submit"]),
);
});
it("grants leave approval only to configured approver roles", () => {
expect(hasPermission(resolvePermissionsForRoles(["manager"]), "leave.approve")).toBe(true);
expect(hasPermission(resolvePermissionsForRoles(["ceo"]), "leave.approve")).toBe(true);
expect(hasPermission(resolvePermissionsForRoles(["finance"]), "leave.approve")).toBe(false);
expect(hasPermission(resolvePermissionsForRoles(["finance_mgr"]), "leave.approve")).toBe(false);
expect(hasPermission(resolvePermissionsForRoles(["hr"]), "leave.approve")).toBe(false);
});
it("grants hr leave view-all and manage permissions", () => {
const hrPermissions = resolvePermissionsForRoles(["hr"]);
expect(hrPermissions).toEqual(expect.arrayContaining(["leave.view_all", "leave.manage"]));
});
it("maps workflow entities to correct permission codes", () => {
expect(resolveEntityPermission("reimbursement", "approve")).toBe("expense.approve");
expect(resolveEntityPermission("reimbursement", "transfer")).toBe("expense.transfer");
expect(resolveEntityPermission("leave", "approve")).toBe("leave.approve");
expect(resolveEntityPermission("leave", "submit")).toBe("leave.submit");
expect(resolveEntityPermission("unknown", "approve")).toBe(null);
});
});
@@ -0,0 +1,53 @@
const workflowRoutes = require("../../../src/routes/workflow");
describe("Workflow Route Permissions", () => {
const { listAllowedActionsForTask } = workflowRoutes.__testables;
it("allows leave approvers to act on leave tasks", () => {
const actions = listAllowedActionsForTask(
{ employee: { permissionCodes: ["leave.approve"] } },
{
status: "pending",
workflow_instance: { entity_type: "leave" },
},
true,
);
expect(actions).toEqual(["approve", "reject", "return"]);
});
it("does not allow expense approvers to act on leave tasks without leave.approve", () => {
const actions = listAllowedActionsForTask(
{ employee: { permissionCodes: ["expense.approve"] } },
{
status: "pending",
workflow_instance: { entity_type: "leave" },
},
true,
);
expect(actions).toEqual([]);
});
it("keeps transfer action limited to reimbursement tasks", () => {
const reimbursementActions = listAllowedActionsForTask(
{ employee: { permissionCodes: ["expense.approve", "expense.transfer"] } },
{
status: "pending",
workflow_instance: { entity_type: "reimbursement" },
},
true,
);
const leaveActions = listAllowedActionsForTask(
{ employee: { permissionCodes: ["leave.approve", "expense.transfer"] } },
{
status: "pending",
workflow_instance: { entity_type: "leave" },
},
true,
);
expect(reimbursementActions).toContain("transfer");
expect(leaveActions).not.toContain("transfer");
});
});