const EXPENSE_SELF_SERVICE_PERMISSIONS = [ "expense.create", "expense.view_own", "expense.edit_own", "expense.delete_own", "expense.submit", "expense.withdraw", "invoice.upload", "invoice.view_own", "expense.proxy_manage", ] as const; const LEAVE_SELF_SERVICE_PERMISSIONS = [ "leave.create", "leave.view_own", "leave.submit", ] as const; const ATTENDANCE_SELF_SERVICE_PERMISSIONS = [ "attendance.create", "attendance.view_own", "attendance.submit", ] as const; const PROCUREMENT_SELF_SERVICE_PERMISSIONS = [ "procurement.create", "procurement.view_own", "procurement.submit", ] as const; const ASSET_SELF_SERVICE_PERMISSIONS = ["asset.view_own"] as const; const PROJECT_SELF_SERVICE_PERMISSIONS = ["project.view_own"] as const; const MASTERDATA_VIEW_PERMISSIONS = ["masterdata.view"] as const; const MASTERDATA_MANAGE_PERMISSIONS = ["masterdata.manage"] as const; const EMPLOYEE_BASE_PERMISSIONS = [ ...EXPENSE_SELF_SERVICE_PERMISSIONS, ...LEAVE_SELF_SERVICE_PERMISSIONS, ...ATTENDANCE_SELF_SERVICE_PERMISSIONS, ...PROJECT_SELF_SERVICE_PERMISSIONS, ] as const; const ROLE_PERMISSIONS: Record = { employee: [ ...EMPLOYEE_BASE_PERMISSIONS, ...PROCUREMENT_SELF_SERVICE_PERMISSIONS, ...ASSET_SELF_SERVICE_PERMISSIONS, ], manager: [ ...EMPLOYEE_BASE_PERMISSIONS, ...PROCUREMENT_SELF_SERVICE_PERMISSIONS, "expense.approve", "expense.transfer", "expense.view_all", "leave.approve", "leave.view_all", "attendance.approve", "attendance.view_all", "procurement.approve", "procurement.view_all", "asset.view_all", "report.dashboard.view", "project.view_all", "project.manage", "budget.view", "budget.manage", "payment.batch.review", ], ceo: [ ...EMPLOYEE_BASE_PERMISSIONS, ...PROCUREMENT_SELF_SERVICE_PERMISSIONS, ...MASTERDATA_VIEW_PERMISSIONS, "expense.approve", "expense.transfer", "expense.view_all", "leave.approve", "leave.view_all", "attendance.approve", "attendance.view_all", "procurement.approve", "procurement.view_all", "asset.view_all", "report.dashboard.view", "budget.view", "payment.batch.review", ], finance: [ ...EMPLOYEE_BASE_PERMISSIONS, ...MASTERDATA_VIEW_PERMISSIONS, "invoice.manage", "invoice.verify", "report.dashboard.view", "budget.view", "expense.approve", "expense.finance.pay", "payment.batch.manage", "expense.view_all", "procurement.view_all", "asset.view_all", "attendance.view_all", "employee.bank.read", "payroll.manage", ], finance_mgr: [ ...EMPLOYEE_BASE_PERMISSIONS, ...MASTERDATA_MANAGE_PERMISSIONS, "invoice.manage", "invoice.verify", "report.dashboard.view", "budget.view", "budget.manage", "integration.manage", "notification.channel.manage", "ai.assist", "expense.approve", "expense.finance.pay", "payment.batch.manage", "expense.view_all", "expense.finance.override_duplicate", "procurement.view_all", "procurement.manage", "asset.view_all", "asset.manage", "asset.inventory", "system.settings", "system.audit.view", "payment.batch.manage", "risk.review.manage", "project.view_all", "attendance.view_all", "attendance.manage", "attendance.sync", "payroll.manage", "employee.bank.read", ], administration: [ "expense.proxy_submit", ...EMPLOYEE_BASE_PERMISSIONS, "procurement.view_all", "procurement.manage", "asset.view_all", "asset.manage", "asset.transfer", "project.view_all", "project.manage", "attendance.view_all", "attendance.manage", ], hr: [ ...LEAVE_SELF_SERVICE_PERMISSIONS, ...ATTENDANCE_SELF_SERVICE_PERMISSIONS, "leave.view_all", "leave.manage", "attendance.approve", "attendance.view_all", "attendance.manage", "attendance.sync", "system.users", "system.users_sensitive", "system.accounts.manage", "system.roles.manage", "employee.bank.manage", "employee.identity.manage", "employee.contract.manage", "expense.view_all", "report.dashboard.view", ], system_admin: [ ...EMPLOYEE_BASE_PERMISSIONS, ...PROCUREMENT_SELF_SERVICE_PERMISSIONS, ...ASSET_SELF_SERVICE_PERMISSIONS, "system.accounts.manage", "system.roles.manage", "system.settings", "integration.manage", "notification.channel.manage", "system.audit.view", ], admin: ["*"], }; export const BUSINESS_APPROVAL_PERMISSIONS = [ "expense.approve", "leave.approve", "attendance.approve", "procurement.approve", "travel.approve", ] as const; const BUSINESS_APPROVER_ROLE_CODES = ["manager", "ceo", "finance", "finance_mgr", "hr"] as const; const FINANCE_ROLE_CODES = ["finance", "finance_mgr"] as const; const FINANCE_PORTAL_PERMISSIONS = ["payment.batch.manage", "risk.review.manage", "expense.finance.pay"] as const; function rolePermissions(roleCode: string): readonly string[] { return ROLE_PERMISSIONS[roleCode] ?? []; } export function resolvePermissionsForRoles(roleCodes: string[]) { const permissions = new Set(); for (const roleCode of roleCodes) { for (const permission of rolePermissions(roleCode)) { permissions.add(permission); } } return Array.from(permissions); } export function hasPermission(permissionCodes: string[], permissionCode: string) { return permissionCodes.includes("*") || permissionCodes.includes(permissionCode); } export function hasAnyPermission(permissionCodes: string[], candidates: string[]) { if (candidates.length === 0) { return true; } return candidates.some((candidate) => hasPermission(permissionCodes, candidate)); } export function hasBusinessApproverRole(roleCodes: string[] | undefined, permissionCodes: string[]) { const hasBusinessRole = (roleCodes ?? []).some((roleCode) => (BUSINESS_APPROVER_ROLE_CODES as readonly string[]).includes(roleCode), ); return hasBusinessRole && hasAnyPermission(permissionCodes, [...BUSINESS_APPROVAL_PERMISSIONS]); } export function hasFinanceRole(roleCodes: string[] | undefined, permissionCodes: string[]) { const hasRole = (roleCodes ?? []).some((roleCode) => (FINANCE_ROLE_CODES as readonly string[]).includes(roleCode) || roleCode === "admin"); return hasRole && hasAnyPermission(permissionCodes, [...FINANCE_PORTAL_PERMISSIONS]); } export function isManagerRole(permissionCodes: string[]) { if (hasPermission(permissionCodes, "*") || hasPermission(permissionCodes, "system.users")) { return true; } return permissionCodes.some( (permission) => permission.endsWith(".approve") || (permission.endsWith(".manage") && !permission.endsWith(".view_all")), ); }