mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
remove reopen delay minutes from global rules and update related types
- Removed the field from and related components. - Updated to reflect the removal of the reopen delay input field. - Modified to include new train number fields: and . - Added interface to manage active schedules with trade direction. - Introduced interface to track wagon shortages in bookings. - Updated logic to ensure consistent UI state representation. - Created migrations to drop the column and add and columns to the table. - Added tests for the new booking window display logic and wagon planning functionality.
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
import { Booking } from '../bookings/entities/booking.entity';
|
||||
import { WagonType } from '../wagon-types/entities/wagon-type.entity';
|
||||
import { planWagonsWithStock } from './wagon-plan-flex.util';
|
||||
|
||||
const nw6: WagonType = {
|
||||
id: 'wt-nw6',
|
||||
code: 'NW6',
|
||||
name: 'Flat Wagon',
|
||||
capacityTons: 70,
|
||||
lengthMeters: 14,
|
||||
supportedLoadTypes: ['CONTAINER'],
|
||||
isActive: true,
|
||||
supportsContainer: true,
|
||||
} as WagonType;
|
||||
|
||||
const cw3: WagonType = {
|
||||
id: 'wt-cw3',
|
||||
code: 'CW3',
|
||||
name: 'Covered Wagon',
|
||||
capacityTons: 60,
|
||||
lengthMeters: 14,
|
||||
supportedLoadTypes: ['BULK'],
|
||||
isActive: true,
|
||||
supportsContainer: false,
|
||||
} as WagonType;
|
||||
|
||||
const containerBooking = (id: string, quantity: number, wagonsRequired: number): Booking =>
|
||||
({
|
||||
id,
|
||||
reference: id,
|
||||
freightType: 'CONTAINER',
|
||||
cargoTotalWeightVgm: quantity * 25,
|
||||
bookingContainers: [
|
||||
{
|
||||
id: `${id}-line-0`,
|
||||
containerTypeId: 'ct-1',
|
||||
quantity,
|
||||
wagonsRequired,
|
||||
vgmPerUnitTons: 25,
|
||||
},
|
||||
],
|
||||
}) as Booking;
|
||||
|
||||
describe('planWagonsWithStock — shortage detail', () => {
|
||||
it('defers with a structured per-type shortage when container stock runs out', () => {
|
||||
const result = planWagonsWithStock({
|
||||
bookings: [containerBooking('BKG-1', 2, 1)],
|
||||
allowed: {
|
||||
byContainerTypeId: new Map([['ct-1', [nw6]]]),
|
||||
byCargoTypeId: new Map(),
|
||||
},
|
||||
stock: {
|
||||
mode: 'YARD',
|
||||
remainingByTypeId: new Map([[nw6.id, 0]]),
|
||||
codesByTypeId: new Map([[nw6.id, nw6.code]]),
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.fitting).toHaveLength(0);
|
||||
expect(result.deferred).toHaveLength(1);
|
||||
const row = result.deferred[0]!;
|
||||
expect(row.reference).toBe('BKG-1');
|
||||
expect(row.reason).toContain('No available NW6 wagon at the yard');
|
||||
expect(row.reason).toContain('short 1');
|
||||
expect(row.shortage).toEqual({
|
||||
wagonTypeCodes: 'NW6',
|
||||
wagonsNeeded: 1,
|
||||
wagonsAvailable: 0,
|
||||
wagonsShort: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('counts the stock the deferred booking actually saw, not its rolled-back usage', () => {
|
||||
// Two wagons needed (2 × 40ft), one in stock: booking rolls back entirely,
|
||||
// the shortage reports 1 available / 1 short.
|
||||
const fortyFooter = containerBooking('BKG-2', 2, 2);
|
||||
fortyFooter.bookingContainers![0]!.containerType = {
|
||||
code: '40GP',
|
||||
sizeFt: 40,
|
||||
wagonsPerUnit: 1,
|
||||
} as never;
|
||||
const result = planWagonsWithStock({
|
||||
bookings: [fortyFooter],
|
||||
allowed: {
|
||||
byContainerTypeId: new Map([['ct-1', [nw6]]]),
|
||||
byCargoTypeId: new Map(),
|
||||
},
|
||||
stock: {
|
||||
mode: 'YARD',
|
||||
remainingByTypeId: new Map([[nw6.id, 1]]),
|
||||
codesByTypeId: new Map([[nw6.id, nw6.code]]),
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.deferred).toHaveLength(1);
|
||||
expect(result.deferred[0]?.shortage).toEqual({
|
||||
wagonTypeCodes: 'NW6',
|
||||
wagonsNeeded: 2,
|
||||
wagonsAvailable: 1,
|
||||
wagonsShort: 1,
|
||||
});
|
||||
// The rolled-back wagon is plannable again for later bookings.
|
||||
expect(result.plan).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('leaves shortage unset for configuration problems', () => {
|
||||
const bulkBooking = {
|
||||
id: 'BKG-3',
|
||||
reference: 'BKG-3',
|
||||
freightType: 'BULK',
|
||||
cargoTotalWeightVgm: 40,
|
||||
cargoTypeId: 'cargo-1',
|
||||
cargoType: { id: 'cargo-1', cargoTypeName: 'Fertilizer' },
|
||||
bookingContainers: [],
|
||||
} as unknown as Booking;
|
||||
|
||||
const result = planWagonsWithStock({
|
||||
bookings: [bulkBooking],
|
||||
allowed: {
|
||||
byContainerTypeId: new Map(),
|
||||
byCargoTypeId: new Map(), // no wagon types configured → config issue
|
||||
},
|
||||
stock: {
|
||||
mode: 'YARD',
|
||||
remainingByTypeId: new Map([[cw3.id, 5]]),
|
||||
codesByTypeId: new Map([[cw3.id, cw3.code]]),
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.configIssues).toHaveLength(1);
|
||||
expect(result.deferred[0]?.shortage).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user