const EDR_FREIGHT_APP_KEY = 'edr_freight_app'; export type FreightPermissionSeed = { id: string; key: string; name: { am: string; en: string }; applicationKey: string; }; export const RULE_ENGINE_RESOURCE_SLUGS = [ 'cargo-types', 'container-types', 'wagon-types', 'service-types', 'yards', 'shipping-lines', 'weight-limit-rules', 'priority-configs', 'rates', 'approval-rules', ] as const; export type RuleEngineResourceSlug = (typeof RULE_ENGINE_RESOURCE_SLUGS)[number]; const slugToResourceKey = (slug: RuleEngineResourceSlug): string => slug.replace(/-/g, '_'); const perm = ( id: string, key: string, en: string, ): FreightPermissionSeed => ({ id, key, name: { am: en, en }, applicationKey: EDR_FREIGHT_APP_KEY, }); export const BOOKING_PERMISSIONS: FreightPermissionSeed[] = [ perm('a1000001-0001-4000-8000-000000000001', 'edr_freight_app:bookings:view', 'View bookings'), perm('a1000001-0001-4000-8000-000000000002', 'edr_freight_app:bookings:staff_accept', 'Accept booking intake'), perm('a1000001-0001-4000-8000-000000000003', 'edr_freight_app:bookings:request_changes', 'Request booking changes'), perm('a1000001-0001-4000-8000-000000000004', 'edr_freight_app:bookings:reject', 'Reject booking submission'), perm('a1000001-0001-4000-8000-000000000005', 'edr_freight_app:bookings:approve_line_staff', 'Approve as line staff'), perm('a1000001-0001-4000-8000-000000000006', 'edr_freight_app:bookings:approve_director', 'Approve as director'), perm('a1000001-0001-4000-8000-000000000007', 'edr_freight_app:bookings:approve_ceo', 'Approve as CEO'), perm('a1000001-0001-4000-8000-000000000008', 'edr_freight_app:bookings:reject_approval', 'Reject at approval step'), perm('a1000001-0001-4000-8000-000000000009', 'edr_freight_app:bookings:generate_contract', 'Generate contract'), perm('a1000001-0001-4000-8000-00000000000a', 'edr_freight_app:bookings:sign_staff', 'Staff contract signature'), perm('a1000001-0001-4000-8000-00000000000b', 'edr_freight_app:bookings:payment_pnr', 'Generate PNR'), perm('a1000001-0001-4000-8000-00000000000c', 'edr_freight_app:bookings:payment_verify', 'Verify payment'), perm('a1000001-0001-4000-8000-00000000000d', 'edr_freight_app:bookings:operations', 'Booking operations'), perm('a1000001-0001-4000-8000-00000000000e', 'edr_freight_app:bookings:cancel', 'Cancel booking'), perm('a1000001-0001-4000-8000-000000000023', 'edr_freight_app:bookings:clearance_view', 'View customs-clearance queue'), perm('a1000001-0001-4000-8000-000000000020', 'edr_freight_app:bookings:review_documents', 'Review clearance documents'), perm('a1000001-0001-4000-8000-000000000021', 'edr_freight_app:bookings:upload_clearance_output', 'Upload customs output documents'), perm('a1000001-0001-4000-8000-000000000022', 'edr_freight_app:bookings:finalize_clearance', 'Finalize document clearance'), perm('a1000001-0001-4000-8000-00000000000f', 'edr_freight_app:train_scheduling:view', 'View train scheduling'), perm('a1000001-0001-4000-8000-000000000010', 'edr_freight_app:train_scheduling:manage', 'Manage train scheduling'), 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'), ]; /** * Contract-phase permissions (contract–booking separation). Mirror the booking * approval/sign/clearance permissions but scoped to the new contracts module. */ export const CONTRACT_PERMISSIONS: FreightPermissionSeed[] = [ perm('a3000001-0001-4000-8000-000000000001', 'edr_freight_app:contracts:view', 'View contracts'), perm('a3000001-0001-4000-8000-000000000002', 'edr_freight_app:contracts:staff_accept', 'Accept contract intake'), perm('a3000001-0001-4000-8000-000000000003', 'edr_freight_app:contracts:request_changes', 'Request contract changes'), perm('a3000001-0001-4000-8000-000000000004', 'edr_freight_app:contracts:reject', 'Reject contract'), perm('a3000001-0001-4000-8000-000000000005', 'edr_freight_app:contracts:approve_line_staff', 'Approve contract as line staff'), perm('a3000001-0001-4000-8000-000000000006', 'edr_freight_app:contracts:approve_director', 'Approve contract as director'), perm('a3000001-0001-4000-8000-000000000007', 'edr_freight_app:contracts:approve_ceo', 'Approve contract as CEO'), perm('a3000001-0001-4000-8000-000000000008', 'edr_freight_app:contracts:generate_contract', 'Generate contract document'), perm('a3000001-0001-4000-8000-000000000009', 'edr_freight_app:contracts:sign_staff', 'Staff contract signature'), perm('a3000001-0001-4000-8000-00000000000a', 'edr_freight_app:contracts:clearance_review', 'Review pre-booking clearance docs'), perm('a3000001-0001-4000-8000-00000000000b', 'edr_freight_app:contracts:finalize_clearance', 'Finalize pre-booking clearance'), perm('a3000001-0001-4000-8000-00000000000c', 'edr_freight_app:contracts:create_booking', 'GL ET create booking under contract'), perm('a3000001-0001-4000-8000-00000000000d', 'edr_freight_app:contracts:ops_clearance_review', 'Operations review of self-clearance docs (Path A)'), ]; const RULE_ENGINE_PERMISSION_IDS: Record = { 'cargo-types': { view: 'b2000001-0001-4000-8000-000000000001', manage: 'b2000001-0001-4000-8000-000000000002' }, 'container-types': { view: 'b2000001-0001-4000-8000-000000000003', manage: 'b2000001-0001-4000-8000-000000000004' }, 'wagon-types': { view: 'b2000001-0001-4000-8000-000000000015', manage: 'b2000001-0001-4000-8000-000000000016' }, 'service-types': { view: 'b2000001-0001-4000-8000-000000000005', manage: 'b2000001-0001-4000-8000-000000000006' }, yards: { view: 'b2000001-0001-4000-8000-000000000007', manage: 'b2000001-0001-4000-8000-000000000008' }, 'shipping-lines': { view: 'b2000001-0001-4000-8000-000000000009', manage: 'b2000001-0001-4000-8000-00000000000a' }, 'weight-limit-rules': { view: 'b2000001-0001-4000-8000-00000000000b', manage: 'b2000001-0001-4000-8000-00000000000c' }, 'priority-configs': { view: 'b2000001-0001-4000-8000-00000000000f', manage: 'b2000001-0001-4000-8000-000000000010' }, rates: { view: 'b2000001-0001-4000-8000-000000000011', manage: 'b2000001-0001-4000-8000-000000000012' }, 'approval-rules': { view: 'b2000001-0001-4000-8000-000000000013', manage: 'b2000001-0001-4000-8000-000000000014' }, }; export const RULE_ENGINE_PERMISSIONS: FreightPermissionSeed[] = RULE_ENGINE_RESOURCE_SLUGS.flatMap( (slug) => { const resource = slugToResourceKey(slug); const ids = RULE_ENGINE_PERMISSION_IDS[slug]; return [ perm(ids.view, `edr_freight_app:rule_engine:${resource}:view`, `View ${slug}`), perm(ids.manage, `edr_freight_app:rule_engine:${resource}:manage`, `Manage ${slug}`), ]; }, ); export const BOOKING_RULE_ENGINE_PERMISSIONS = [ ...BOOKING_PERMISSIONS, ...CONTRACT_PERMISSIONS, ...RULE_ENGINE_PERMISSIONS, ]; export const BOOKING_RULE_ENGINE_PERMISSION_KEYS = BOOKING_RULE_ENGINE_PERMISSIONS.map( (p) => p.key, ); export const FREIGHT_PERMS = { bookings: { view: 'edr_freight_app:bookings:view', 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', }, trainScheduling: { view: 'edr_freight_app:train_scheduling:view', manage: 'edr_freight_app:train_scheduling:manage', }, fleet: { view: 'edr_freight_app:fleet:view', manage: 'edr_freight_app:fleet:manage', }, admin: 'edr_freight_app:admin', ruleEngine: { view: (slug: RuleEngineResourceSlug) => `edr_freight_app:rule_engine:${slugToResourceKey(slug)}:view`, manage: (slug: RuleEngineResourceSlug) => `edr_freight_app:rule_engine:${slugToResourceKey(slug)}:manage`, }, } as const; const allRuleEngineViewKeys = () => RULE_ENGINE_RESOURCE_SLUGS.map((s) => FREIGHT_PERMS.ruleEngine.view(s)); export const ROLE_PERMISSION_PRESETS = { // Marketing / line staff: drives a booking from intake through line-staff // approval and contract generation/signing — i.e. until the contract is ready // and signed. No director/CEO approval, no scheduling, no operations. lineStaff: [ FREIGHT_PERMS.bookings.view, FREIGHT_PERMS.bookings.staffAccept, FREIGHT_PERMS.bookings.requestChanges, FREIGHT_PERMS.bookings.reject, FREIGHT_PERMS.bookings.approveLineStaff, FREIGHT_PERMS.bookings.rejectApproval, FREIGHT_PERMS.bookings.cancel, FREIGHT_PERMS.contracts.view, FREIGHT_PERMS.contracts.staffAccept, FREIGHT_PERMS.contracts.requestChanges, FREIGHT_PERMS.contracts.reject, FREIGHT_PERMS.contracts.approveLineStaff, ...allRuleEngineViewKeys(), ], // Operations Officer: train scheduling + wagon allocation + transit/complete // + fleet management (wagons, trains, locomotives, routes, containers, cargo). operationsOfficer: [ FREIGHT_PERMS.bookings.view, FREIGHT_PERMS.bookings.operations, FREIGHT_PERMS.trainScheduling.view, FREIGHT_PERMS.trainScheduling.manage, FREIGHT_PERMS.fleet.view, FREIGHT_PERMS.fleet.manage, // Path A (no customs): Operations reviews the customer's self-clearance docs // on the contract before the customer may create a shipment booking. FREIGHT_PERMS.contracts.view, FREIGHT_PERMS.contracts.opsClearanceReview, ...allRuleEngineViewKeys(), ], director: [ FREIGHT_PERMS.bookings.view, FREIGHT_PERMS.bookings.approveDirector, FREIGHT_PERMS.bookings.rejectApproval, FREIGHT_PERMS.bookings.generateContract, FREIGHT_PERMS.contracts.view, FREIGHT_PERMS.contracts.approveDirector, FREIGHT_PERMS.contracts.generateContract, ...allRuleEngineViewKeys(), ], ceo: [ FREIGHT_PERMS.bookings.view, FREIGHT_PERMS.bookings.approveCeo, FREIGHT_PERMS.bookings.rejectApproval, FREIGHT_PERMS.contracts.view, FREIGHT_PERMS.contracts.approveCeo, ...allRuleEngineViewKeys(), ], finance: [FREIGHT_PERMS.bookings.view], // Global Logistics: manages ONLY the customs-clearance queue. Scoped out of // the general booking-request list (no bookings:view) — instead a dedicated // clearance:view permission lists the clearance bookings. Reviews customer // clearance documents, uploads customs output documents, and finalizes the // clearance gate. // GL Ethiopia (edr_gl_ethiopia): reviews pre-booking clearance docs on the // contract, uploads ET output docs, finalizes clearance, and EXCLUSIVELY creates // the booking under a customs contract (Path B). Also runs post-booking ET // milestones + the legacy booking-clearance permissions during migration. glEthiopia: [ FREIGHT_PERMS.contracts.view, FREIGHT_PERMS.contracts.clearanceReview, FREIGHT_PERMS.contracts.finalizeClearance, FREIGHT_PERMS.contracts.createBooking, FREIGHT_PERMS.bookings.clearanceView, FREIGHT_PERMS.bookings.reviewDocuments, FREIGHT_PERMS.bookings.uploadClearanceOutput, FREIGHT_PERMS.bookings.finalizeClearance, FREIGHT_PERMS.bookings.operations, ], // GL Djibouti (edr_gl_djibouti): DO/RO collection, gatepass, loading milestones, // damage reports. Read-only on the contract; no booking creation. glDjibouti: [ FREIGHT_PERMS.contracts.view, FREIGHT_PERMS.bookings.clearanceView, FREIGHT_PERMS.bookings.uploadClearanceOutput, FREIGHT_PERMS.bookings.operations, ], // Marketing handles intake through contract (same as line staff here) and, // for non-customs bookings, reviews/finalizes the customer's clearance // documents from the booking detail (customs bookings go to Global Logistics). marketing: [ FREIGHT_PERMS.bookings.view, FREIGHT_PERMS.bookings.staffAccept, FREIGHT_PERMS.bookings.requestChanges, FREIGHT_PERMS.bookings.reject, FREIGHT_PERMS.bookings.approveLineStaff, FREIGHT_PERMS.bookings.rejectApproval, FREIGHT_PERMS.bookings.cancel, FREIGHT_PERMS.bookings.generateContract, FREIGHT_PERMS.bookings.signStaff, FREIGHT_PERMS.bookings.reviewDocuments, FREIGHT_PERMS.bookings.finalizeClearance, FREIGHT_PERMS.contracts.view, FREIGHT_PERMS.contracts.staffAccept, FREIGHT_PERMS.contracts.requestChanges, FREIGHT_PERMS.contracts.reject, FREIGHT_PERMS.contracts.approveLineStaff, FREIGHT_PERMS.contracts.generateContract, FREIGHT_PERMS.contracts.signStaff, ], orgManager: [...BOOKING_RULE_ENGINE_PERMISSION_KEYS], } as const; 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', }));