diff --git a/apps/edr-freight-api/src/common/booking-guards.ts b/apps/edr-freight-api/src/common/booking-guards.ts index f9eab4d39..68bbdcba4 100644 --- a/apps/edr-freight-api/src/common/booking-guards.ts +++ b/apps/edr-freight-api/src/common/booking-guards.ts @@ -75,7 +75,7 @@ export const TrainSchedulingView = () => BookingStaff(FREIGHT_PERMS.trainScheduling.view); // Granular train-scheduling actions replace the retired coarse manage: -// create a schedule, update (assign/consist/loading/finalize/dispatch/arrive…), +// create a schedule, update (assign/consist/finalize/dispatch/arrive…), // cancel a schedule, reschedule (+ maintenance), and manage global rules. export const TrainSchedulingCreate = () => BookingStaff(FREIGHT_PERMS.trainScheduling.create); @@ -83,6 +83,18 @@ export const TrainSchedulingCreate = () => export const TrainSchedulingUpdate = () => BookingStaff(FREIGHT_PERMS.trainScheduling.update); +/** + * Confirm a booking's cargo loaded/unloaded at a yard — carved out of the + * coarse `update` so it can be granted independently of general schedule + * editing. Same two keys gate import, export, and intercity movements alike: + * the generic per-booking route and the intercity-specific one both use them. + */ +export const TrainSchedulingLoad = () => + BookingStaff(FREIGHT_PERMS.trainScheduling.load); + +export const TrainSchedulingUnload = () => + BookingStaff(FREIGHT_PERMS.trainScheduling.unload); + export const TrainSchedulingCancel = () => BookingStaff(FREIGHT_PERMS.trainScheduling.cancel); diff --git a/apps/edr-freight-api/src/modules/train-scheduling/controllers/train-scheduling.controller.ts b/apps/edr-freight-api/src/modules/train-scheduling/controllers/train-scheduling.controller.ts index 6afcf9380..03eb5ad88 100644 --- a/apps/edr-freight-api/src/modules/train-scheduling/controllers/train-scheduling.controller.ts +++ b/apps/edr-freight-api/src/modules/train-scheduling/controllers/train-scheduling.controller.ts @@ -16,7 +16,9 @@ import { TrainSchedulingCancel, TrainSchedulingCreate, TrainSchedulingEditTrainNumber, + TrainSchedulingLoad, TrainSchedulingReschedule, + TrainSchedulingUnload, TrainSchedulingRulesManage, TrainSchedulingUpdate, TrainSchedulingView, @@ -598,7 +600,7 @@ export class TrainSchedulingController { } @Post("schedules/:id/bookings/:bookingId/load") - @TrainSchedulingUpdate() + @TrainSchedulingLoad() @ApiOperation({ summary: "Confirm a booking's cargo loaded at its origin yard (any direction; train must be at that yard)", @@ -611,7 +613,7 @@ export class TrainSchedulingController { } @Post("schedules/:id/bookings/:bookingId/unload") - @TrainSchedulingUpdate() + @TrainSchedulingUnload() @ApiOperation({ summary: "Confirm a booking's cargo unloaded at its destination yard — per-booking arrival, may precede the train's final arrival", @@ -624,7 +626,7 @@ export class TrainSchedulingController { } @Post("schedules/:id/intercity/:bookingId/load") - @TrainSchedulingUpdate() + @TrainSchedulingLoad() @ApiOperation({ summary: "Confirm intercity cargo loaded (train must be at the booking's origin yard)", }) @@ -636,7 +638,7 @@ export class TrainSchedulingController { } @Post("schedules/:id/intercity/:bookingId/unload") - @TrainSchedulingUpdate() + @TrainSchedulingUnload() @ApiOperation({ summary: "Confirm intercity cargo unloaded at the booking's destination yard (completes the booking)", 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 5fde44f2d..8204ee2d3 100644 --- a/apps/edr-freight-api/src/seed/freight-permissions.registry.ts +++ b/apps/edr-freight-api/src/seed/freight-permissions.registry.ts @@ -1469,6 +1469,20 @@ export const SCHEDULING_EXTRA_PERMISSIONS: FreightPermissionSeed[] = [ "edr_freight_app:train_scheduling:rules_manage", "Manage global scheduling rules", ), + // Carved out of the coarse `update` — confirming a booking's cargo loaded/ + // unloaded at a yard, across import, export, and intercity movements alike + // (the same schedules/:id/bookings/:bookingId/{load,unload} + intercity + // routes serve all three directions). + perm( + "a2a00001-0001-4000-8000-000000000006", + "edr_freight_app:train_scheduling:load", + "Confirm cargo loaded (import, export, intercity)", + ), + perm( + "a2a00001-0001-4000-8000-000000000007", + "edr_freight_app:train_scheduling:unload", + "Confirm cargo unloaded (import, export, intercity)", + ), ]; // L. Administration & settings (split from the coarse admin umbrella) @@ -1996,6 +2010,15 @@ export const FREIGHT_PERMS = { cancel: "edr_freight_app:train_scheduling:cancel", reschedule: "edr_freight_app:train_scheduling:reschedule", rulesManage: "edr_freight_app:train_scheduling:rules_manage", + /** + * Confirm a booking's cargo loaded/unloaded at a yard — carved out of the + * coarse `update` so load/unload can be granted independently of general + * schedule editing. Covers import, export, and intercity alike: the + * generic per-booking route and the intercity-specific one both gate on + * these same two keys. + */ + load: "edr_freight_app:train_scheduling:load", + unload: "edr_freight_app:train_scheduling:unload", dispatch: "edr_freight_app:train_scheduling:dispatch", markPaid: "edr_freight_app:train_scheduling:mark_paid", expireBooking: "edr_freight_app:train_scheduling:expire_booking", @@ -2602,6 +2625,8 @@ export const ROLE_PERMISSION_PRESETS = { FREIGHT_PERMS.trainScheduling.view, FREIGHT_PERMS.trainScheduling.create, FREIGHT_PERMS.trainScheduling.update, + FREIGHT_PERMS.trainScheduling.load, + FREIGHT_PERMS.trainScheduling.unload, FREIGHT_PERMS.trainScheduling.cancel, FREIGHT_PERMS.trainScheduling.reschedule, FREIGHT_PERMS.trainScheduling.rulesManage, @@ -2822,6 +2847,8 @@ export const POSITION_PERMISSION_PRESETS = { FREIGHT_PERMS.trainScheduling.view, FREIGHT_PERMS.trainScheduling.create, FREIGHT_PERMS.trainScheduling.update, + FREIGHT_PERMS.trainScheduling.load, + FREIGHT_PERMS.trainScheduling.unload, FREIGHT_PERMS.trainScheduling.cancel, FREIGHT_PERMS.trainScheduling.reschedule, FREIGHT_PERMS.trainScheduling.rulesManage,