mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 16:28:12 +00:00
fix issue and add consolidation
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import { Booking } from '../bookings/entities/booking.entity';
|
||||
import { BookingBatchService } from './booking-batch.service';
|
||||
import { WagonStockLedger } from './wagon-stock-ledger.util';
|
||||
|
||||
/**
|
||||
* smartBulkNeed math in isolation: the private helpers it touches
|
||||
* (allowedDimsWithTypes) read only their arguments, so a bare prototype
|
||||
* instance is enough — no Nest wiring.
|
||||
*/
|
||||
describe('BookingBatchService.smartBulkNeed', () => {
|
||||
const service = Object.create(BookingBatchService.prototype) as BookingBatchService;
|
||||
const call = (
|
||||
booking: Booking,
|
||||
stock: WagonStockLedger,
|
||||
rank: Map<string, number>,
|
||||
) =>
|
||||
(
|
||||
service as unknown as {
|
||||
smartBulkNeed: (
|
||||
b: Booking,
|
||||
d: unknown,
|
||||
s: WagonStockLedger,
|
||||
l: { fromEdge: number; toEdge: number },
|
||||
r: Map<string, number>,
|
||||
) => { need: { wagons: number }; perType: Array<{ wagonTypeId: string; wagons: number }> } | null;
|
||||
}
|
||||
).smartBulkNeed(booking, wagonDims, stock, { fromEdge: 0, toEdge: 1 }, rank);
|
||||
|
||||
const nw5 = { id: 'wt-nw5', capacityTons: 70 };
|
||||
const pw2 = { id: 'wt-pw2', capacityTons: 70 };
|
||||
const perishable = {
|
||||
id: 'cargo-perishable',
|
||||
wagonTypes: [nw5, pw2],
|
||||
tonsPerWagonMap: { [nw5.id]: 30, [pw2.id]: 20 },
|
||||
};
|
||||
const wagonDims = {
|
||||
container: { lengthMeters: 14, tareWeightTons: 24, capacityTons: 70 },
|
||||
bulk: { lengthMeters: 14, tareWeightTons: 24, capacityTons: 70 },
|
||||
byWagonTypeId: new Map([
|
||||
[nw5.id, { lengthMeters: 14, tareWeightTons: 24, capacityTons: 70 }],
|
||||
[pw2.id, { lengthMeters: 14, tareWeightTons: 24, capacityTons: 70 }],
|
||||
]),
|
||||
};
|
||||
const booking = (tons: number): Booking =>
|
||||
({
|
||||
id: 'b1',
|
||||
reference: 'b1',
|
||||
freightType: 'BULK',
|
||||
cargoTotalWeightVgm: tons,
|
||||
cargoTypeId: perishable.id,
|
||||
cargoType: perishable,
|
||||
bookingContainers: [],
|
||||
}) as unknown as Booking;
|
||||
// Containers compete for NW5 → NW5 rank 2, PW2 rank 1.
|
||||
const contested = new Map([
|
||||
[nw5.id, 2],
|
||||
[pw2.id, 1],
|
||||
]);
|
||||
|
||||
it('seats 695T as 10 PW2 (20T) + 17 NW5 (30T) = 27 wagons, PW2 first', () => {
|
||||
const stock = new WagonStockLedger(
|
||||
new Map([
|
||||
[nw5.id, 18],
|
||||
[pw2.id, 10],
|
||||
]),
|
||||
1,
|
||||
);
|
||||
const smart = call(booking(695), stock, contested);
|
||||
expect(smart).not.toBeNull();
|
||||
expect(smart!.need.wagons).toBe(27);
|
||||
expect(smart!.perType).toEqual([
|
||||
{ wagonTypeId: pw2.id, wagons: 10 },
|
||||
{ wagonTypeId: nw5.id, wagons: 17 },
|
||||
]);
|
||||
});
|
||||
|
||||
it('returns null when the free stock cannot seat the whole booking', () => {
|
||||
const stock = new WagonStockLedger(
|
||||
new Map([
|
||||
[nw5.id, 5],
|
||||
[pw2.id, 10],
|
||||
]),
|
||||
1,
|
||||
);
|
||||
// 10×20 + 5×30 = 350T < 695T.
|
||||
expect(call(booking(695), stock, contested)).toBeNull();
|
||||
});
|
||||
|
||||
it('uncontested types fall back to biggest per-cargo take (fewest wagons)', () => {
|
||||
const stock = new WagonStockLedger(
|
||||
new Map([
|
||||
[nw5.id, 10],
|
||||
[pw2.id, 10],
|
||||
]),
|
||||
1,
|
||||
);
|
||||
const even = new Map([
|
||||
[nw5.id, 1],
|
||||
[pw2.id, 1],
|
||||
]);
|
||||
const smart = call(booking(60), stock, even);
|
||||
expect(smart!.perType).toEqual([{ wagonTypeId: nw5.id, wagons: 2 }]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user