diff --git a/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts b/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts index 86e37451e..be6a8ea10 100644 --- a/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts +++ b/apps/edr-freight-api/src/modules/train-scheduling/train-scheduling.service.ts @@ -1207,8 +1207,10 @@ export class TrainSchedulingService { const schedule = await this.getImportDjiboutiSchedule(scheduleId); const operation = await this.getOrCreateImportDjiboutiOperation(scheduleId); this.assertImportDjiboutiGatepassGranted(operation); - if (!operation.loadedOnTrainAt) { - throw new BadRequestException('Import train cannot depart Djibouti before loading is confirmed'); + if (!operation.loadedOnTrainAt && !(await this.hasLoadedBooking(schedule.id))) { + throw new BadRequestException( + 'Import train cannot depart Djibouti before at least one booking is loaded', + ); } if (schedule.status === TrainScheduleStatusEnum.Scheduled) { @@ -1586,11 +1588,28 @@ export class TrainSchedulingService { where: { trainScheduleId: schedule.id }, }); this.assertImportDjiboutiGatepassGranted(operation); - if (!operation?.loadedOnTrainAt) { - throw new BadRequestException('Import train cannot depart Djibouti before loading is confirmed'); + // A train dispatches once loading is confirmed at the train level OR at least + // one booking on it is marked LOADED — it never waits for every booking. + if (!operation?.loadedOnTrainAt && !(await this.hasLoadedBooking(schedule.id))) { + throw new BadRequestException( + 'Import train cannot depart Djibouti before at least one booking is loaded', + ); } } + /** True when at least one booking on the schedule is confirmed LOADED. */ + private async hasLoadedBooking(scheduleId: string): Promise { + const [row]: Array<{ loaded: string }> = await this.dataSource.query( + `SELECT COUNT(*) AS loaded + FROM freight.train_schedule_bookings + WHERE train_schedule_id = $1 + AND loading_status = $2 + AND deleted_at IS NULL`, + [scheduleId, LoadingStatus.Loaded], + ); + return Number(row?.loaded ?? 0) > 0; + } + private async getImportDjiboutiSchedule(scheduleId: string): Promise { const schedule = await this.getDjiboutiGatepassSchedule(scheduleId); if (!this.isImportDjiboutiSchedule(schedule)) {