import type { AuthUser } from "@/auth/types"; import type { RuleEngineResourceSlug } from "@/types/rule-engine"; export const FREIGHT_PERMS = { bookings: { view: "edr_freight_app:bookings:view", create: "edr_freight_app:bookings:create", clearanceView: "edr_freight_app:bookings:clearance_view", staffAccept: "edr_freight_app:bookings:staff_accept", requestChanges: "edr_freight_app:bookings:request_changes", reject: "edr_freight_app:bookings:reject", approveLineStaff: "edr_freight_app:bookings:approve_line_staff", approveDirector: "edr_freight_app:bookings:approve_director", approveCeo: "edr_freight_app:bookings:approve_ceo", rejectApproval: "edr_freight_app:bookings:reject_approval", generateContract: "edr_freight_app:bookings:generate_contract", signStaff: "edr_freight_app:bookings:sign_staff", operations: "edr_freight_app:bookings:operations", cancel: "edr_freight_app:bookings:cancel", reviewDocuments: "edr_freight_app:bookings:review_documents", uploadClearanceOutput: "edr_freight_app:bookings:upload_clearance_output", finalizeClearance: "edr_freight_app:bookings:finalize_clearance", }, contracts: { view: "edr_freight_app:contracts:view", staffAccept: "edr_freight_app:contracts:staff_accept", requestChanges: "edr_freight_app:contracts:request_changes", reject: "edr_freight_app:contracts:reject", approveLineStaff: "edr_freight_app:contracts:approve_line_staff", approveDirector: "edr_freight_app:contracts:approve_director", approveCeo: "edr_freight_app:contracts:approve_ceo", generateContract: "edr_freight_app:contracts:generate_contract", signStaff: "edr_freight_app:contracts:sign_staff", clearanceReview: "edr_freight_app:contracts:clearance_review", finalizeClearance: "edr_freight_app:contracts:finalize_clearance", createBooking: "edr_freight_app:contracts:create_booking", opsClearanceReview: "edr_freight_app:contracts:ops_clearance_review", clearanceDutyAdvise: "edr_freight_app:contracts:clearance_duty_advise", clearanceEtActions: "edr_freight_app:contracts:clearance_et_actions", clearanceDjActions: "edr_freight_app:contracts:clearance_dj_actions", }, trainScheduling: { view: "edr_freight_app:train_scheduling:view", manage: "edr_freight_app:train_scheduling:manage", create: "edr_freight_app:train_scheduling:create", update: "edr_freight_app:train_scheduling:update", cancel: "edr_freight_app:train_scheduling:cancel", reschedule: "edr_freight_app:train_scheduling:reschedule", rulesManage: "edr_freight_app:train_scheduling:rules_manage", }, fleet: { view: "edr_freight_app:fleet:view", manage: "edr_freight_app:fleet:manage", }, admin: "edr_freight_app:admin", allocation: { manage: "edr_freight_app:allocation:manage", }, customers: { view: "edr_freight_app:customers:view", create: "edr_freight_app:customers:create", update: "edr_freight_app:customers:update", deactivate: "edr_freight_app:customers:deactivate", verify: "edr_freight_app:customers:verify", resetPassword: "edr_freight_app:customers:reset-password", }, payments: { view: "edr_freight_app:payments:view", verify: "edr_freight_app:payments:verify", refund: "edr_freight_app:payments:refund", }, invoices: { view: "edr_freight_app:invoices:view", create: "edr_freight_app:invoices:create", cancel: "edr_freight_app:invoices:cancel", export: "edr_freight_app:invoices:export", }, firstMile: { view: "edr_freight_app:first_mile:view", accept: "edr_freight_app:first_mile:accept", create: "edr_freight_app:first_mile:create", update: "edr_freight_app:first_mile:update", delete: "edr_freight_app:first_mile:delete", assignVehicles: "edr_freight_app:first_mile:assign_vehicles", setDistances: "edr_freight_app:first_mile:set_distances", generateInvoice: "edr_freight_app:first_mile:generate_invoice", }, lastMile: { view: "edr_freight_app:last_mile:view", accept: "edr_freight_app:last_mile:accept", create: "edr_freight_app:last_mile:create", update: "edr_freight_app:last_mile:update", delete: "edr_freight_app:last_mile:delete", assignVehicles: "edr_freight_app:last_mile:assign_vehicles", setDistances: "edr_freight_app:last_mile:set_distances", generateInvoice: "edr_freight_app:last_mile:generate_invoice", }, locomotives: { view: "edr_freight_app:locomotives:view", create: "edr_freight_app:locomotives:create", update: "edr_freight_app:locomotives:update", delete: "edr_freight_app:locomotives:delete", }, wagons: { view: "edr_freight_app:wagons:view", create: "edr_freight_app:wagons:create", update: "edr_freight_app:wagons:update", delete: "edr_freight_app:wagons:delete", transferRequest: "edr_freight_app:wagons:transfer_request", transferFulfill: "edr_freight_app:wagons:transfer_fulfill", transferHistoryAll: "edr_freight_app:wagons:transfer_history_all", }, trains: { view: "edr_freight_app:trains:view", create: "edr_freight_app:trains:create", update: "edr_freight_app:trains:update", delete: "edr_freight_app:trains:delete", assignWagons: "edr_freight_app:trains:assign_wagons", }, routes: { view: "edr_freight_app:routes:view", create: "edr_freight_app:routes:create", update: "edr_freight_app:routes:update", delete: "edr_freight_app:routes:delete", }, containers: { view: "edr_freight_app:containers:view", create: "edr_freight_app:containers:create", update: "edr_freight_app:containers:update", delete: "edr_freight_app:containers:delete", }, cargoes: { view: "edr_freight_app:cargoes:view", create: "edr_freight_app:cargoes:create", update: "edr_freight_app:cargoes:update", delete: "edr_freight_app:cargoes:delete", }, vehicles: { view: "edr_freight_app:vehicles:view", create: "edr_freight_app:vehicles:create", update: "edr_freight_app:vehicles:update", delete: "edr_freight_app:vehicles:delete", }, drivers: { view: "edr_freight_app:drivers:view", create: "edr_freight_app:drivers:create", update: "edr_freight_app:drivers:update", delete: "edr_freight_app:drivers:delete", }, tracking: { view: "edr_freight_app:tracking:view", manage: "edr_freight_app:tracking:manage", }, fuel: { view: "edr_freight_app:fuel:view", create: "edr_freight_app:fuel:create", update: "edr_freight_app:fuel:update", delete: "edr_freight_app:fuel:delete", approve: "edr_freight_app:fuel:approve", }, maintenance: { view: "edr_freight_app:maintenance:view", create: "edr_freight_app:maintenance:create", update: "edr_freight_app:maintenance:update", delete: "edr_freight_app:maintenance:delete", complete: "edr_freight_app:maintenance:complete", }, fleetReports: { view: "edr_freight_app:fleet_reports:view", export: "edr_freight_app:fleet_reports:export", }, fleetDashboard: { view: "edr_freight_app:fleet_dashboard:view", }, warehouseDashboard: { view: "edr_freight_app:warehouse_dashboard:view", }, warehouses: { view: "edr_freight_app:warehouses:view", create: "edr_freight_app:warehouses:create", update: "edr_freight_app:warehouses:update", delete: "edr_freight_app:warehouses:delete", }, warehouseYards: { view: "edr_freight_app:warehouse_yards:view", create: "edr_freight_app:warehouse_yards:create", update: "edr_freight_app:warehouse_yards:update", delete: "edr_freight_app:warehouse_yards:delete", }, warehouseZones: { view: "edr_freight_app:warehouse_zones:view", create: "edr_freight_app:warehouse_zones:create", update: "edr_freight_app:warehouse_zones:update", }, warehouseAllocationRules: { view: "edr_freight_app:warehouse_allocation_rules:view", create: "edr_freight_app:warehouse_allocation_rules:create", update: "edr_freight_app:warehouse_allocation_rules:update", delete: "edr_freight_app:warehouse_allocation_rules:delete", }, warehouseFeeRules: { view: "edr_freight_app:warehouse_fee_rules:view", create: "edr_freight_app:warehouse_fee_rules:create", update: "edr_freight_app:warehouse_fee_rules:update", delete: "edr_freight_app:warehouse_fee_rules:delete", }, warehouseInspectionReports: { view: "edr_freight_app:warehouse_inspection_reports:view", create: "edr_freight_app:warehouse_inspection_reports:create", update: "edr_freight_app:warehouse_inspection_reports:update", }, warehouseInventory: { view: "edr_freight_app:warehouse_inventory:view", receive: "edr_freight_app:warehouse_inventory:receive", move: "edr_freight_app:warehouse_inventory:move", load: "edr_freight_app:warehouse_inventory:load", unload: "edr_freight_app:warehouse_inventory:unload", dispatch: "edr_freight_app:warehouse_inventory:dispatch", gatePass: "edr_freight_app:warehouse_inventory:gate_pass", release: "edr_freight_app:warehouse_inventory:release", deliver: "edr_freight_app:warehouse_inventory:deliver", inspect: "edr_freight_app:warehouse_inventory:inspect", }, interchangeDocuments: { view: "edr_freight_app:interchange_documents:view", generate: "edr_freight_app:interchange_documents:generate", acknowledge: "edr_freight_app:interchange_documents:acknowledge", dispute: "edr_freight_app:interchange_documents:dispute", cancel: "edr_freight_app:interchange_documents:cancel", }, warehouseFeeInvoices: { view: "edr_freight_app:warehouse_fee_invoices:view", generate: "edr_freight_app:warehouse_fee_invoices:generate", cancel: "edr_freight_app:warehouse_fee_invoices:cancel", pay: "edr_freight_app:warehouse_fee_invoices:pay", }, config: { contractValidity: { view: "edr_freight_app:config:contract_validity:view", manage: "edr_freight_app:config:contract_validity:manage", }, }, settings: { fileUpload: { view: "edr_freight_app:settings:file_upload:view", manage: "edr_freight_app:settings:file_upload:manage", }, dropdown: { view: "edr_freight_app:settings:dropdown:view", manage: "edr_freight_app:settings:dropdown:manage", }, }, staff: { roles: { view: "edr_freight_app:staff:roles:view", create: "edr_freight_app:staff:roles:create", update: "edr_freight_app:staff:roles:update", delete: "edr_freight_app:staff:roles:delete", }, permissions: { view: "edr_freight_app:staff:permissions:view", assign: "edr_freight_app:staff:permissions:assign", }, employeeRegistration: { view: "edr_freight_app:employee_registration:view", create: "edr_freight_app:employee_registration:create", update: "edr_freight_app:employee_registration:update", activate: "edr_freight_app:employee_registration:activate", deactivate: "edr_freight_app:employee_registration:deactivate", }, roleAssignment: { view: "edr_freight_app:role_assignment:view", assign: "edr_freight_app:role_assignment:assign", replace: "edr_freight_app:role_assignment:replace", }, hierarchyUnits: { view: "edr_freight_app:hierarchy_units:view", create: "edr_freight_app:hierarchy_units:create", update: "edr_freight_app:hierarchy_units:update", delete: "edr_freight_app:hierarchy_units:delete", }, hierarchyPositions: { view: "edr_freight_app:hierarchy_positions:view", create: "edr_freight_app:hierarchy_positions:create", update: "edr_freight_app:hierarchy_positions:update", delete: "edr_freight_app:hierarchy_positions:delete", changeParent: "edr_freight_app:hierarchy_positions:change_parent", }, hierarchyEmployeeAssignment: { view: "edr_freight_app:hierarchy_employee_assignment:view", invite: "edr_freight_app:hierarchy_employee_assignment:invite", assign: "edr_freight_app:hierarchy_employee_assignment:assign", }, positionTypes: { view: "edr_freight_app:position_types:view", create: "edr_freight_app:position_types:create", update: "edr_freight_app:position_types:update", delete: "edr_freight_app:position_types:delete", }, }, } as const; const slugToResourceKey = (slug: RuleEngineResourceSlug): string => slug.replace(/-/g, "_"); export function getPermissionKeys(user: AuthUser | null | undefined): string[] { if (!user) return []; if (user.permissionKeys?.length) return user.permissionKeys; const keys = new Set(); for (const p of user.permissions ?? []) { if (p.key) keys.add(p.key); } for (const emp of user.employee ?? []) { for (const pos of emp.positions ?? []) { for (const p of pos.permissions ?? []) { if (p.key) keys.add(p.key); } } } return [...keys]; } /** * Position keys held by the user (e.g. "ethiopian_gl", "djibouti_gl"). * Tolerates IAM payload shape variants: the key flat on the employee position, * nested under `position.key`, or the GL modeled as a role instead. */ export function getPositionKeys(user: AuthUser | null | undefined): string[] { if (!user) return []; const keys = new Set(); for (const emp of user.employee ?? []) { for (const pos of emp.positions ?? []) { if (pos.key) keys.add(pos.key); if (pos.position?.key) keys.add(pos.position.key); } } for (const role of user.roles ?? []) { if (role.key) keys.add(role.key); } return [...keys]; } export function hasPosition( user: AuthUser | null | undefined, positionKey: string, ): boolean { return getPositionKeys(user).includes(positionKey); } export const POSITION_KEYS = { ethiopianGl: "ethiopian_gl", djiboutiGl: "djibouti_gl", } as const; export function isEthiopianGl(user: AuthUser | null | undefined): boolean { return hasPosition(user, POSITION_KEYS.ethiopianGl); } export function isDjiboutiGl(user: AuthUser | null | undefined): boolean { return hasPosition(user, POSITION_KEYS.djiboutiGl); } export function isSuperAdmin(user: AuthUser | null | undefined): boolean { if (user?.isSuperAdmin) return true; return Boolean(user?.roles?.some((r) => r.key === "super_admin")); } /** Org-level admins may act on any approval step in the chain. */ export function isOrganizationAdmin( user: AuthUser | null | undefined, ): boolean { return Boolean(user?.roles?.some((r) => r.key === "organization_admin")); } export function isFreightApprovalAdmin( user: AuthUser | null | undefined, ): boolean { return isSuperAdmin(user) || isOrganizationAdmin(user); } export function hasPermission( user: AuthUser | null | undefined, key: string, ): boolean { if (!user) return false; if (isSuperAdmin(user)) return true; return getPermissionKeys(user).includes(key); } export function canAccessBookings(user: AuthUser | null | undefined): boolean { return hasPermission(user, FREIGHT_PERMS.bookings.view); } export function canAccessContracts(user: AuthUser | null | undefined): boolean { return hasPermission(user, FREIGHT_PERMS.contracts.view); } /** Can review the GL Ethiopia pre-booking contract clearance queue (Path B). */ export function canReviewContractClearance( user: AuthUser | null | undefined, ): boolean { return hasPermission(user, FREIGHT_PERMS.contracts.clearanceReview); } /** GL Ethiopia: can create a booking under a cleared contract (Path B). */ export function canCreateContractBooking( user: AuthUser | null | undefined, ): boolean { return hasPermission(user, FREIGHT_PERMS.contracts.createBooking); } /** Operations: can review the Path A self-clearance queue (non-customs). */ export function canReviewSelfClearance( user: AuthUser | null | undefined, ): boolean { return hasPermission(user, FREIGHT_PERMS.contracts.opsClearanceReview); } /** Can see/manage the customs document-clearance queue (Global Logistics). */ export function canViewClearance(user: AuthUser | null | undefined): boolean { return hasPermission(user, FREIGHT_PERMS.bookings.reviewDocuments); } export function canViewScheduling(user: AuthUser | null | undefined): boolean { return hasPermission(user, FREIGHT_PERMS.trainScheduling.view); } export function canManageScheduling(user: AuthUser | null | undefined): boolean { return hasPermission(user, FREIGHT_PERMS.trainScheduling.manage); } export function canViewFleet(user: AuthUser | null | undefined): boolean { return hasPermission(user, FREIGHT_PERMS.fleet.view); } export function isFreightAdmin(user: AuthUser | null | undefined): boolean { return hasPermission(user, FREIGHT_PERMS.admin); } export function ruleEngineViewKey(slug: RuleEngineResourceSlug): string { return `edr_freight_app:rule_engine:${slugToResourceKey(slug)}:view`; } export function ruleEngineManageKey(slug: RuleEngineResourceSlug): string { return `edr_freight_app:rule_engine:${slugToResourceKey(slug)}:manage`; } export function canAccessRuleEngineResource( user: AuthUser | null | undefined, slug: RuleEngineResourceSlug, mode: "view" | "manage", ): boolean { const key = mode === "manage" ? ruleEngineManageKey(slug) : ruleEngineViewKey(slug); return hasPermission(user, key); } export function canAccessAnyRuleEngineView( user: AuthUser | null | undefined, slugs: RuleEngineResourceSlug[], ): boolean { return slugs.some((slug) => canAccessRuleEngineResource(user, slug, "view")); }