Files
edr-platform/apps/edr-freight-api/src/modules/bookings/container-pairing.util.spec.ts
Marshal 35cb20da0b feat: implement 20ft container weight-pairing validation
- Added ContainerValidationService to handle 20ft weight-pairing logic.
- Introduced validate20ftWeightPairing utility function to check weight differences.
- Updated BookingPricingService to include overweight line details and pairing errors in price response.
- Enhanced BookingTransitionService to reject submissions with unpairable 20ft containers.
- Created ShipmentValidation interface for pre-submit validation of container contracts.
- Integrated shipment validation into the contract booking process, providing warnings for overweight containers and hard blocks for pairing errors.
- Updated front-end components to display validation results and prevent submission when errors are present.
2026-07-03 09:26:27 +00:00

56 lines
2.1 KiB
TypeScript

import { validate20ftWeightPairing } from './container-pairing.util';
describe('validate20ftWeightPairing', () => {
const MAX_DIFF = 10;
it('passes when a balanced pairing exists (adjacent diffs within cap)', () => {
// sorted: 8, 15, 18, 24 → pairs (8,15) diff 7, (18,24) diff 6 — both ≤ 10.
const units = [
{ label: 'A', grossWeightTons: 24 },
{ label: 'B', grossWeightTons: 8 },
{ label: 'C', grossWeightTons: 18 },
{ label: 'D', grossWeightTons: 15 },
];
expect(validate20ftWeightPairing(units, MAX_DIFF)).toEqual([]);
});
it('flags a pair whose weight difference exceeds the cap', () => {
// sorted: 5, 25 → single pair diff 20 > 10.
const units = [
{ label: 'HEAVY', grossWeightTons: 25 },
{ label: 'LIGHT', grossWeightTons: 5 },
];
const result = validate20ftWeightPairing(units, MAX_DIFF);
expect(result).toHaveLength(1);
expect(result[0].labels).toEqual(['LIGHT', 'HEAVY']);
expect(result[0].diffTons).toBe(20);
});
it('allows an odd leftover unit (goes to consolidation, not a violation)', () => {
// sorted: 10, 12, 30 → pair (10,12) diff 2 ok; 30 is the odd leftover.
const units = [
{ label: 'A', grossWeightTons: 10 },
{ label: 'B', grossWeightTons: 12 },
{ label: 'C', grossWeightTons: 30 },
];
expect(validate20ftWeightPairing(units, MAX_DIFF)).toEqual([]);
});
it('adjacent-by-weight pairing succeeds where a naive input order would fail', () => {
// Input order (20, 12, 22, 10) naively pairs (20,12)=8 and (22,10)=12 (fail),
// but sorted (10,12,20,22) pairs (10,12)=2 and (20,22)=2 — valid, so no violation.
const units = [
{ label: 'A', grossWeightTons: 20 },
{ label: 'B', grossWeightTons: 12 },
{ label: 'C', grossWeightTons: 22 },
{ label: 'D', grossWeightTons: 10 },
];
expect(validate20ftWeightPairing(units, MAX_DIFF)).toEqual([]);
});
it('returns nothing for fewer than two units', () => {
expect(validate20ftWeightPairing([{ label: 'A', grossWeightTons: 30 }], MAX_DIFF)).toEqual([]);
expect(validate20ftWeightPairing([], MAX_DIFF)).toEqual([]);
});
});