mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
fix(train-scheduling): scope the not-loaded dispatch guard to EXPORT only
The guard fired on every dispatch. Loading out of an origin warehouse is an export concept — import cargo isn't loaded from a warehouse, so its warehouse inventory says nothing about what's aboard and the check would have blocked legitimate import dispatches. Derive the route direction (reusing deriveTradeDirection, as the warehouse loading queue does) and return early for anything that isn't EXPORT. Import and domestic behave exactly as before. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2031,16 +2031,37 @@ export class TrainSchedulingService {
|
||||
}
|
||||
|
||||
/**
|
||||
* A train must not leave carrying nothing while its cargo sits in the shed.
|
||||
* Blocks dispatch when a booking allocated to this train has warehouse
|
||||
* inventory that never made it onto a wagon (received / stored / ready but not
|
||||
* LOADED). Either load it from the warehouse Load-to-Train queue, or drop the
|
||||
* booking's wagon allocation so it travels on a later train.
|
||||
* EXPORT ONLY. An export train must not leave carrying nothing while its cargo
|
||||
* sits in the shed: the goods are received into the origin warehouse, GRN'd and
|
||||
* loaded onto the wagons allocated to the booking, so anything still in the
|
||||
* warehouse at dispatch is being left behind. Blocks dispatch when an allocated
|
||||
* booking has warehouse inventory that never made it onto a wagon (received /
|
||||
* stored / ready but not LOADED) — either load it from the Load-to-Train queue,
|
||||
* or drop the booking's wagon allocation so it rides a later train.
|
||||
*
|
||||
* Import/domestic are untouched: their cargo isn't loaded out of an origin
|
||||
* warehouse, so warehouse inventory says nothing about what's aboard.
|
||||
*
|
||||
* Bookings with no warehouse inventory at all are NOT blocked — allocating a
|
||||
* wagon before the goods arrive is normal planning; they simply aren't aboard.
|
||||
*/
|
||||
private async assertAllocatedCargoLoaded(scheduleId: string): Promise<void> {
|
||||
const [route]: Array<{ originCountry: string | null; destinationCountry: string | null }> =
|
||||
await this.dataSource.query(
|
||||
`SELECT oy.country AS "originCountry", dy.country AS "destinationCountry"
|
||||
FROM freight.train_schedules ts
|
||||
LEFT JOIN freight.yards oy ON oy.id = ts.origin_station_id
|
||||
LEFT JOIN freight.yards dy ON dy.id = ts.destination_station_id
|
||||
WHERE ts.id = $1 AND ts.deleted_at IS NULL`,
|
||||
[scheduleId],
|
||||
);
|
||||
if (!route) return;
|
||||
const direction = deriveTradeDirection(
|
||||
{ country: route.originCountry },
|
||||
{ country: route.destinationCountry },
|
||||
);
|
||||
if (direction !== 'EXPORT') return;
|
||||
|
||||
const rows: Array<{ reference: string | null; status: string }> = await this.dataSource.query(
|
||||
`WITH ${SCHEDULE_BOOKINGS_CTE}
|
||||
SELECT DISTINCT b.reference AS "reference", inv.status AS "status"
|
||||
@@ -2070,7 +2091,7 @@ export class TrainSchedulingService {
|
||||
throw new BadRequestException('Only SCHEDULED trains can be dispatched');
|
||||
}
|
||||
await this.assertImportDjiboutiMayDepart(schedule);
|
||||
// Don't leave received cargo behind on the platform.
|
||||
// Export only: don't leave received cargo behind in the warehouse.
|
||||
await this.assertAllocatedCargoLoaded(scheduleId);
|
||||
// A locomotive may sit on many future schedules, but it can only pull one train
|
||||
// at a time — block dispatch while any set locomotive is out on a dispatched train.
|
||||
|
||||
Reference in New Issue
Block a user