From 1fdd5e3c4c1e0f87da7a57961d7962b8665f5c52 Mon Sep 17 00:00:00 2001 From: Nathnael Date: Mon, 6 Jul 2026 14:10:44 +0000 Subject: [PATCH] feat: add permissions --- .../src/seed/freight-permissions.registry.ts | 452 +++++++++++++++++- .../backoffice/src/lib/permissions.ts | 243 ++++++++++ 2 files changed, 690 insertions(+), 5 deletions(-) diff --git a/apps/edr-freight-api/src/seed/freight-permissions.registry.ts b/apps/edr-freight-api/src/seed/freight-permissions.registry.ts index d70cb5fb4..d4d85e84c 100644 --- a/apps/edr-freight-api/src/seed/freight-permissions.registry.ts +++ b/apps/edr-freight-api/src/seed/freight-permissions.registry.ts @@ -60,6 +60,7 @@ export const BOOKING_PERMISSIONS: FreightPermissionSeed[] = [ perm('a1000001-0001-4000-8000-000000000011', 'edr_freight_app:fleet:view', 'View fleet'), perm('a1000001-0001-4000-8000-000000000012', 'edr_freight_app:fleet:manage', 'Manage fleet'), perm('a1000001-0001-4000-8000-000000000013', 'edr_freight_app:admin', 'Freight administration'), + perm('a1000001-0001-4000-8000-000000000024', 'edr_freight_app:bookings:create', 'Create booking'), ]; /** @@ -117,11 +118,209 @@ export const GAP_CONTROLLER_PERMISSIONS: FreightPermissionSeed[] = [ perm('c1000001-0001-4000-8000-000000000001', 'edr_freight_app:allocation:manage', 'Allocate containers to vehicles'), ]; +/** + * Advanced backoffice resources — full CRUD + workflow-action keys. + * See docs/rbac/freight-backoffice-permissions.md. Additive only: the existing + * bookings/contracts/rule-engine/allocation keys above are unchanged. + */ + +// C. Customers +export const CUSTOMER_PERMISSIONS: FreightPermissionSeed[] = [ + perm('d1a00001-0001-4000-8000-000000000001', 'edr_freight_app:customers:view', 'View customers'), + perm('d1a00001-0001-4000-8000-000000000002', 'edr_freight_app:customers:create', 'Create customer'), + perm('d1a00001-0001-4000-8000-000000000003', 'edr_freight_app:customers:update', 'Update customer'), + perm('d1a00001-0001-4000-8000-000000000004', 'edr_freight_app:customers:deactivate', 'Deactivate customer'), + perm('d1a00001-0001-4000-8000-000000000005', 'edr_freight_app:customers:verify', 'Verify customer (KYC/Fayda)'), +]; + +// D. Finance — payments + invoices +export const FINANCE_PERMISSIONS: FreightPermissionSeed[] = [ + perm('d2a00001-0001-4000-8000-000000000001', 'edr_freight_app:payments:view', 'View payments'), + perm('d2a00001-0001-4000-8000-000000000002', 'edr_freight_app:payments:verify', 'Verify/settle payment'), + perm('d2a00001-0001-4000-8000-000000000003', 'edr_freight_app:payments:refund', 'Refund payment'), + perm('d2b00001-0001-4000-8000-000000000001', 'edr_freight_app:invoices:view', 'View invoices'), + perm('d2b00001-0001-4000-8000-000000000002', 'edr_freight_app:invoices:create', 'Generate invoice'), + perm('d2b00001-0001-4000-8000-000000000003', 'edr_freight_app:invoices:cancel', 'Cancel invoice'), + perm('d2b00001-0001-4000-8000-000000000004', 'edr_freight_app:invoices:export', 'Download invoice document'), +]; + +// E. First / last mile operations +export const MILE_PERMISSIONS: FreightPermissionSeed[] = [ + perm('d3a00001-0001-4000-8000-000000000001', 'edr_freight_app:first_mile:view', 'View first-mile'), + perm('d3a00001-0001-4000-8000-000000000002', 'edr_freight_app:first_mile:accept', 'Accept first-mile request'), + perm('d3a00001-0001-4000-8000-000000000003', 'edr_freight_app:first_mile:create', 'Create first-mile'), + perm('d3a00001-0001-4000-8000-000000000004', 'edr_freight_app:first_mile:update', 'Update first-mile'), + perm('d3a00001-0001-4000-8000-000000000005', 'edr_freight_app:first_mile:delete', 'Delete first-mile'), + perm('d3a00001-0001-4000-8000-000000000006', 'edr_freight_app:first_mile:assign_vehicles', 'Assign first-mile vehicles'), + perm('d3a00001-0001-4000-8000-000000000007', 'edr_freight_app:first_mile:set_distances', 'Set first-mile distances'), + perm('d3a00001-0001-4000-8000-000000000008', 'edr_freight_app:first_mile:generate_invoice', 'Generate first-mile invoice'), + perm('d3b00001-0001-4000-8000-000000000001', 'edr_freight_app:last_mile:view', 'View last-mile'), + perm('d3b00001-0001-4000-8000-000000000002', 'edr_freight_app:last_mile:accept', 'Accept last-mile request'), + perm('d3b00001-0001-4000-8000-000000000003', 'edr_freight_app:last_mile:create', 'Create last-mile'), + perm('d3b00001-0001-4000-8000-000000000004', 'edr_freight_app:last_mile:update', 'Update last-mile'), + perm('d3b00001-0001-4000-8000-000000000005', 'edr_freight_app:last_mile:delete', 'Delete last-mile'), + perm('d3b00001-0001-4000-8000-000000000006', 'edr_freight_app:last_mile:assign_vehicles', 'Assign last-mile vehicles'), + perm('d3b00001-0001-4000-8000-000000000007', 'edr_freight_app:last_mile:set_distances', 'Set last-mile distances'), + perm('d3b00001-0001-4000-8000-000000000008', 'edr_freight_app:last_mile:generate_invoice', 'Generate last-mile invoice'), +]; + +// F. Fleet — rail assets (splits the flat fleet:view/manage) +export const FLEET_RAIL_PERMISSIONS: FreightPermissionSeed[] = [ + perm('e1a00001-0001-4000-8000-000000000001', 'edr_freight_app:locomotives:view', 'View locomotives'), + perm('e1a00001-0001-4000-8000-000000000002', 'edr_freight_app:locomotives:create', 'Create locomotive'), + perm('e1a00001-0001-4000-8000-000000000003', 'edr_freight_app:locomotives:update', 'Update locomotive'), + perm('e1a00001-0001-4000-8000-000000000004', 'edr_freight_app:locomotives:delete', 'Delete locomotive'), + perm('e1b00001-0001-4000-8000-000000000001', 'edr_freight_app:wagons:view', 'View wagons'), + perm('e1b00001-0001-4000-8000-000000000002', 'edr_freight_app:wagons:create', 'Create wagon'), + perm('e1b00001-0001-4000-8000-000000000003', 'edr_freight_app:wagons:update', 'Update wagon'), + perm('e1b00001-0001-4000-8000-000000000004', 'edr_freight_app:wagons:delete', 'Delete wagon'), + perm('e1c00001-0001-4000-8000-000000000001', 'edr_freight_app:trains:view', 'View trains'), + perm('e1c00001-0001-4000-8000-000000000002', 'edr_freight_app:trains:create', 'Create train'), + perm('e1c00001-0001-4000-8000-000000000003', 'edr_freight_app:trains:update', 'Update train'), + perm('e1c00001-0001-4000-8000-000000000004', 'edr_freight_app:trains:delete', 'Delete train'), + perm('e1c00001-0001-4000-8000-000000000005', 'edr_freight_app:trains:assign_wagons', 'Assign wagons to train'), + perm('e1d00001-0001-4000-8000-000000000001', 'edr_freight_app:routes:view', 'View routes'), + perm('e1d00001-0001-4000-8000-000000000002', 'edr_freight_app:routes:create', 'Create route'), + perm('e1d00001-0001-4000-8000-000000000003', 'edr_freight_app:routes:update', 'Update route'), + perm('e1d00001-0001-4000-8000-000000000004', 'edr_freight_app:routes:delete', 'Delete route'), + perm('e1e00001-0001-4000-8000-000000000001', 'edr_freight_app:containers:view', 'View containers'), + perm('e1e00001-0001-4000-8000-000000000002', 'edr_freight_app:containers:create', 'Create container'), + perm('e1e00001-0001-4000-8000-000000000003', 'edr_freight_app:containers:update', 'Update container'), + perm('e1e00001-0001-4000-8000-000000000004', 'edr_freight_app:containers:delete', 'Delete container'), + perm('e1f00001-0001-4000-8000-000000000001', 'edr_freight_app:cargoes:view', 'View cargoes'), + perm('e1f00001-0001-4000-8000-000000000002', 'edr_freight_app:cargoes:create', 'Create cargo'), + perm('e1f00001-0001-4000-8000-000000000003', 'edr_freight_app:cargoes:update', 'Update cargo'), + perm('e1f00001-0001-4000-8000-000000000004', 'edr_freight_app:cargoes:delete', 'Delete cargo'), +]; + +// G. Fleet — road & telemetry +export const FLEET_ROAD_PERMISSIONS: FreightPermissionSeed[] = [ + perm('e2a00001-0001-4000-8000-000000000001', 'edr_freight_app:vehicles:view', 'View vehicles'), + perm('e2a00001-0001-4000-8000-000000000002', 'edr_freight_app:vehicles:create', 'Create vehicle'), + perm('e2a00001-0001-4000-8000-000000000003', 'edr_freight_app:vehicles:update', 'Update vehicle'), + perm('e2a00001-0001-4000-8000-000000000004', 'edr_freight_app:vehicles:delete', 'Delete vehicle'), + perm('e2b00001-0001-4000-8000-000000000001', 'edr_freight_app:drivers:view', 'View drivers'), + perm('e2b00001-0001-4000-8000-000000000002', 'edr_freight_app:drivers:create', 'Create driver'), + perm('e2b00001-0001-4000-8000-000000000003', 'edr_freight_app:drivers:update', 'Update driver'), + perm('e2b00001-0001-4000-8000-000000000004', 'edr_freight_app:drivers:delete', 'Delete driver'), + perm('e2c00001-0001-4000-8000-000000000001', 'edr_freight_app:tracking:view', 'Track vehicles'), + perm('e2d00001-0001-4000-8000-000000000001', 'edr_freight_app:fuel:view', 'View fuel purchases'), + perm('e2d00001-0001-4000-8000-000000000002', 'edr_freight_app:fuel:create', 'Create fuel purchase'), + perm('e2d00001-0001-4000-8000-000000000003', 'edr_freight_app:fuel:update', 'Update fuel purchase'), + perm('e2d00001-0001-4000-8000-000000000004', 'edr_freight_app:fuel:delete', 'Delete fuel purchase'), + perm('e2d00001-0001-4000-8000-000000000005', 'edr_freight_app:fuel:approve', 'Approve fuel purchase'), + perm('e2e00001-0001-4000-8000-000000000001', 'edr_freight_app:maintenance:view', 'View maintenance'), + perm('e2e00001-0001-4000-8000-000000000002', 'edr_freight_app:maintenance:create', 'Create maintenance'), + perm('e2e00001-0001-4000-8000-000000000003', 'edr_freight_app:maintenance:update', 'Update maintenance'), + perm('e2e00001-0001-4000-8000-000000000004', 'edr_freight_app:maintenance:delete', 'Delete maintenance'), + perm('e2e00001-0001-4000-8000-000000000005', 'edr_freight_app:maintenance:complete', 'Complete maintenance'), + perm('e2f00001-0001-4000-8000-000000000001', 'edr_freight_app:fleet_reports:view', 'View fleet financial reports'), + perm('e2f00001-0001-4000-8000-000000000002', 'edr_freight_app:fleet_reports:export', 'Export fleet financial reports'), + perm('e2000001-0001-4000-8000-000000000001', 'edr_freight_app:fleet_dashboard:view', 'View fleet dashboard'), +]; + +// H. Warehouse management +export const WAREHOUSE_PERMISSIONS: FreightPermissionSeed[] = [ + perm('f1000001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_dashboard:view', 'View warehouse dashboard'), + perm('f1a00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouses:view', 'View warehouses'), + perm('f1a00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouses:create', 'Create warehouse'), + perm('f1a00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouses:update', 'Update warehouse'), + perm('f1a00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouses:delete', 'Delete warehouse'), + perm('f1b00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_yards:view', 'View warehouse yards'), + perm('f1b00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_yards:create', 'Create warehouse yard'), + perm('f1b00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_yards:update', 'Update warehouse yard'), + perm('f1b00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouse_yards:delete', 'Delete warehouse yard'), + perm('f1c00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_zones:view', 'View warehouse zones'), + perm('f1c00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_zones:create', 'Create warehouse zone'), + perm('f1c00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_zones:update', 'Update warehouse zone'), + perm('f1d00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_allocation_rules:view', 'View allocation rules'), + perm('f1d00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_allocation_rules:create', 'Create allocation rule'), + perm('f1d00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_allocation_rules:update', 'Update allocation rule'), + perm('f1d00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouse_allocation_rules:delete', 'Delete allocation rule'), + perm('f1e00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_fee_rules:view', 'View fee rules'), + perm('f1e00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_fee_rules:create', 'Create fee rule'), + perm('f1e00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_fee_rules:update', 'Update fee rule'), + perm('f1e00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouse_fee_rules:delete', 'Delete fee rule'), + perm('f1f00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_inspection_reports:view', 'View inspection reports'), + perm('f1f00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_inspection_reports:create', 'Create inspection report'), + perm('f1f00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_inspection_reports:update', 'Update inspection report'), +]; + +// I. Port & terminal — inventory movement + interchange + fee invoices +export const PORT_TERMINAL_PERMISSIONS: FreightPermissionSeed[] = [ + perm('f2a00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_inventory:view', 'View terminal inventory'), + perm('f2a00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_inventory:receive', 'Receive inventory'), + perm('f2a00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_inventory:move', 'Move/store/reserve inventory'), + perm('f2a00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouse_inventory:load', 'Load inventory'), + perm('f2a00001-0001-4000-8000-000000000005', 'edr_freight_app:warehouse_inventory:unload', 'Unload inventory'), + perm('f2a00001-0001-4000-8000-000000000006', 'edr_freight_app:warehouse_inventory:dispatch', 'Dispatch inventory'), + perm('f2a00001-0001-4000-8000-000000000007', 'edr_freight_app:warehouse_inventory:gate_pass', 'Gate-clearance inventory'), + perm('f2a00001-0001-4000-8000-000000000008', 'edr_freight_app:warehouse_inventory:release', 'Release inventory'), + perm('f2a00001-0001-4000-8000-000000000009', 'edr_freight_app:warehouse_inventory:deliver', 'Deliver inventory'), + perm('f2a00001-0001-4000-8000-00000000000a', 'edr_freight_app:warehouse_inventory:inspect', 'Inspect inventory'), + perm('f2b00001-0001-4000-8000-000000000001', 'edr_freight_app:interchange_documents:view', 'View interchange documents'), + perm('f2b00001-0001-4000-8000-000000000002', 'edr_freight_app:interchange_documents:generate', 'Generate interchange document'), + perm('f2b00001-0001-4000-8000-000000000003', 'edr_freight_app:interchange_documents:acknowledge', 'Acknowledge interchange document'), + perm('f2b00001-0001-4000-8000-000000000004', 'edr_freight_app:interchange_documents:dispute', 'Dispute interchange document'), + perm('f2b00001-0001-4000-8000-000000000005', 'edr_freight_app:interchange_documents:cancel', 'Cancel interchange document'), + perm('f2c00001-0001-4000-8000-000000000001', 'edr_freight_app:warehouse_fee_invoices:view', 'View warehouse fee invoices'), + perm('f2c00001-0001-4000-8000-000000000002', 'edr_freight_app:warehouse_fee_invoices:generate', 'Generate warehouse fee invoice'), + perm('f2c00001-0001-4000-8000-000000000003', 'edr_freight_app:warehouse_fee_invoices:cancel', 'Cancel warehouse fee invoice'), + perm('f2c00001-0001-4000-8000-000000000004', 'edr_freight_app:warehouse_fee_invoices:pay', 'Pay warehouse fee invoice'), +]; + +// E'. Train-scheduling finer actions (augment existing view/manage) +export const SCHEDULING_EXTRA_PERMISSIONS: FreightPermissionSeed[] = [ + perm('a2a00001-0001-4000-8000-000000000001', 'edr_freight_app:train_scheduling:create', 'Create train schedule'), + perm('a2a00001-0001-4000-8000-000000000002', 'edr_freight_app:train_scheduling:update', 'Update train schedule'), + perm('a2a00001-0001-4000-8000-000000000003', 'edr_freight_app:train_scheduling:cancel', 'Cancel train schedule'), + perm('a2a00001-0001-4000-8000-000000000004', 'edr_freight_app:train_scheduling:reschedule', 'Reschedule train'), + perm('a2a00001-0001-4000-8000-000000000005', 'edr_freight_app:train_scheduling:rules_manage', 'Manage global scheduling rules'), +]; + +// L. Administration & settings (split from the coarse admin umbrella) +export const CONFIG_SETTINGS_PERMISSIONS: FreightPermissionSeed[] = [ + perm('b3a00001-0001-4000-8000-000000000001', 'edr_freight_app:config:contract_validity:view', 'View contract validity periods'), + perm('b3a00001-0001-4000-8000-000000000002', 'edr_freight_app:config:contract_validity:manage', 'Manage contract validity periods'), + perm('b4a00001-0001-4000-8000-000000000001', 'edr_freight_app:settings:file_upload:view', 'View file-upload settings'), + perm('b4a00001-0001-4000-8000-000000000002', 'edr_freight_app:settings:file_upload:manage', 'Manage file-upload settings'), + perm('b4b00001-0001-4000-8000-000000000001', 'edr_freight_app:settings:dropdown:view', 'View dropdown settings'), + perm('b4b00001-0001-4000-8000-000000000002', 'edr_freight_app:settings:dropdown:manage', 'Manage dropdown settings'), +]; + +// M. Staff / IAM admin — NEW keys only. The employee_registration / role_assignment +// / hierarchy_* / position_types:view keys are seeded separately in edr-freight.seed.ts. +export const STAFF_IAM_PERMISSIONS: FreightPermissionSeed[] = [ + perm('c2a00001-0001-4000-8000-000000000001', 'edr_freight_app:staff:roles:view', 'View roles'), + perm('c2a00001-0001-4000-8000-000000000002', 'edr_freight_app:staff:roles:create', 'Create role'), + perm('c2a00001-0001-4000-8000-000000000003', 'edr_freight_app:staff:roles:update', 'Update role'), + perm('c2a00001-0001-4000-8000-000000000004', 'edr_freight_app:staff:roles:delete', 'Delete role'), + perm('c2b00001-0001-4000-8000-000000000001', 'edr_freight_app:staff:permissions:view', 'View permission assignments'), + perm('c2b00001-0001-4000-8000-000000000002', 'edr_freight_app:staff:permissions:assign', 'Assign permissions'), + perm('c2c00001-0001-4000-8000-000000000001', 'edr_freight_app:position_types:create', 'Create position type'), + perm('c2c00001-0001-4000-8000-000000000002', 'edr_freight_app:position_types:update', 'Update position type'), + perm('c2c00001-0001-4000-8000-000000000003', 'edr_freight_app:position_types:delete', 'Delete position type'), +]; + +export const ADVANCED_BACKOFFICE_PERMISSIONS: FreightPermissionSeed[] = [ + ...CUSTOMER_PERMISSIONS, + ...FINANCE_PERMISSIONS, + ...MILE_PERMISSIONS, + ...FLEET_RAIL_PERMISSIONS, + ...FLEET_ROAD_PERMISSIONS, + ...WAREHOUSE_PERMISSIONS, + ...PORT_TERMINAL_PERMISSIONS, + ...SCHEDULING_EXTRA_PERMISSIONS, + ...CONFIG_SETTINGS_PERMISSIONS, + ...STAFF_IAM_PERMISSIONS, +]; + export const BOOKING_RULE_ENGINE_PERMISSIONS = [ ...BOOKING_PERMISSIONS, ...CONTRACT_PERMISSIONS, ...RULE_ENGINE_PERMISSIONS, ...GAP_CONTROLLER_PERMISSIONS, + ...ADVANCED_BACKOFFICE_PERMISSIONS, ]; export const BOOKING_RULE_ENGINE_PERMISSION_KEYS = BOOKING_RULE_ENGINE_PERMISSIONS.map( @@ -131,6 +330,7 @@ export const BOOKING_RULE_ENGINE_PERMISSION_KEYS = BOOKING_RULE_ENGINE_PERMISSIO 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', @@ -168,6 +368,11 @@ export const FREIGHT_PERMS = { 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', @@ -183,6 +388,244 @@ export const FREIGHT_PERMS = { 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', + }, + 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', + }, + 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', + }, + 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', + }, + // Seeded in edr-freight.seed.ts (EDR_FREIGHT_PERMISSIONS) — surfaced here for gating. + 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 allRuleEngineViewKeys = () => @@ -326,12 +769,11 @@ export const POSITION_PERMISSION_PRESETS = { ]), } as const; +/** Derive the module bucket from the resource segment of a permission key. */ +const moduleOf = (key: string): string => key.split(':')[1] ?? 'other'; + export const PERMISSIONS_CATALOG = BOOKING_RULE_ENGINE_PERMISSIONS.map((p) => ({ key: p.key, label: p.name.en, - module: p.key.includes(':bookings:') - ? 'bookings' - : p.key.includes(':contracts:') - ? 'contracts' - : 'rule_engine', + module: moduleOf(p.key), })); diff --git a/apps/edr-freight-web/backoffice/src/lib/permissions.ts b/apps/edr-freight-web/backoffice/src/lib/permissions.ts index 0abb91e99..c8bfa7c84 100644 --- a/apps/edr-freight-web/backoffice/src/lib/permissions.ts +++ b/apps/edr-freight-web/backoffice/src/lib/permissions.ts @@ -4,6 +4,7 @@ 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", @@ -41,6 +42,11 @@ export const FREIGHT_PERMS = { 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", @@ -50,6 +56,243 @@ export const FREIGHT_PERMS = { 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", + }, + 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", + }, + 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", + }, + 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 =>