import { BadRequestException, ConflictException } from '@nestjs/common'; import { assertBulkTonnageRemains, assertTruckCountWithinContainers, assertTruckLoad, remainingBulkTons, } from './truck-load.util'; /** * One physical rule, shared by customer self-haul and EDR last-mile. It used to * be written out three times (addTruck, updateTruck, departTruck) plus a fourth * in LastMileService. */ describe('assertTruckLoad', () => { const booking = ['ABCD1234567', 'ABCD7654321', 'WXYZ1111111']; it('accepts two 20ft containers on one truck', () => { expect(() => assertTruckLoad({ containers: ['ABCD1234567', 'ABCD7654321'], bookingContainers: booking, sizes: ['20ft', '20ft'], }), ).not.toThrow(); }); it('accepts a single 40ft container', () => { expect(() => assertTruckLoad({ containers: ['ABCD1234567'], bookingContainers: booking, sizes: ['40ft'], }), ).not.toThrow(); }); it('rejects a 40ft sharing the truck — it fills the bed', () => { expect(() => assertTruckLoad({ containers: ['ABCD1234567', 'ABCD7654321'], bookingContainers: booking, sizes: ['40ft', '20ft'], }), ).toThrow(BadRequestException); }); it('rejects more than two containers', () => { expect(() => assertTruckLoad({ containers: ['ABCD1234567', 'ABCD7654321', 'WXYZ1111111'], bookingContainers: booking, sizes: ['20ft', '20ft', '20ft'], }), ).toThrow(BadRequestException); }); it('rejects a container that is not on the booking', () => { expect(() => assertTruckLoad({ containers: ['ZZZZ9999999'], bookingContainers: booking, sizes: ['20ft'], }), ).toThrow(BadRequestException); }); it('rejects a container already riding another truck', () => { expect(() => assertTruckLoad({ containers: ['ABCD1234567'], bookingContainers: booking, sizes: ['20ft'], assignedElsewhere: ['ABCD1234567'], }), ).toThrow(ConflictException); }); it('skips membership checks when the booking has no containers (bulk)', () => { expect(() => assertTruckLoad({ containers: [], bookingContainers: [], sizes: [] }), ).not.toThrow(); }); it('still caps the count when the booking has no containers', () => { expect(() => assertTruckLoad({ containers: ['A', 'B', 'C'], bookingContainers: [], sizes: [], }), ).toThrow(BadRequestException); }); }); describe('assertBulkTonnageRemains', () => { it('allows another truck while tonnage is left', () => { expect(() => assertBulkTonnageRemains(100, 40)).not.toThrow(); }); it('rejects a truck once the booking is fully hauled', () => { expect(() => assertBulkTonnageRemains(100, 0)).toThrow(BadRequestException); }); it('does not cap a booking with no declared weight', () => { // Nothing to draw down against — capping here would block every truck. expect(() => assertBulkTonnageRemains(0, 0)).not.toThrow(); }); }); describe('remainingBulkTons', () => { const dataSourceReturning = (totalTons: string, hauledTons: string) => ({ query: jest.fn().mockResolvedValue([{ totalTons, hauledTons }]) }) as never; it('counts trucks from both haulage paths against the declared weight', async () => { const result = await remainingBulkTons(dataSourceReturning('100', '60'), 'b-1'); expect(result).toEqual({ totalTons: 100, hauledTons: 60, remainingTons: 40, complete: false, }); }); it('is complete once everything is hauled', async () => { const result = await remainingBulkTons(dataSourceReturning('100', '100'), 'b-1'); expect(result.remainingTons).toBe(0); expect(result.complete).toBe(true); }); it('never reports negative tonnage when trucks overshoot', async () => { const result = await remainingBulkTons(dataSourceReturning('100', '104'), 'b-1'); expect(result.remainingTons).toBe(0); expect(result.complete).toBe(true); }); it('is not complete for a booking with no declared weight', async () => { const result = await remainingBulkTons(dataSourceReturning('0', '0'), 'b-1'); expect(result.complete).toBe(false); }); }); describe('assertTruckCountWithinContainers', () => { it('allows one truck per container', () => { expect(() => assertTruckCountWithinContainers(3, 3)).not.toThrow(); }); it('rejects more trucks than containers', () => { expect(() => assertTruckCountWithinContainers(4, 3)).toThrow(BadRequestException); }); it('does not cap a bulk booking, which has no container count', () => { expect(() => assertTruckCountWithinContainers(9, 0)).not.toThrow(); }); });