Files
edr-platform/apps/edr-freight-api/src/common/mile-haulage.util.spec.ts
Hagernesh c1c362ab9d fix(mile): only send bookings that bought EDR haulage to the mile queues
The rule that a customer's own truck and an EDR road leg are alternatives
existed on the truck side only (CustomerTruckService.assertSelfHaulPaid).
LastMileService had no counterpart: create checked payment and nothing else,
so any paid booking could be accepted into the queue. A booking took a
customer truck at 06:42 and an EDR last-mile leg with a real EDR truck at
06:47, neither side aware of the other, on a contract that had chosen no
road legs at all.

The road legs are chosen on the contract and copied onto the booking, and
the pickup/delivery address is the only per-booking record of that choice.
service_types cannot serve: every type ships with includes_first_mile and
includes_last_mile set to true, so reading them would mean no booking could
ever self-haul. That same always-true flag had already killed the first-mile
guard, whose `address || serviceType.includesFirstMile` admitted every paid
export booking.

One shared rule now answers it for both sides, so the two halves cannot
drift apart again: last-mile create rejects a booking that chose no road
legs and one already carrying a customer truck; first-mile no longer honours
the service-type flag; the customer-truck guard reads the same helper.

Existing legs are untouched — the guards are on creation, so the one booking
already carrying both needs a human to reconcile it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 08:03:16 +00:00

53 lines
1.8 KiB
TypeScript

import { usesEdrMileService } from './mile-haulage.util';
/**
* The road legs are chosen on the contract and copied onto the booking. EDR
* haulage and a customer's own truck are alternatives, so this one answer gates
* both sides — the customer-truck guard and the mile-queue guard.
*/
describe('usesEdrMileService', () => {
const booking = (over: Partial<Parameters<typeof usesEdrMileService>[0]> = {}) => ({
tradeDirection: 'IMPORT',
firstMile: null,
lastMile: null,
...over,
});
it('an import that chose delivery uses EDR haulage', () => {
expect(usesEdrMileService(booking({ lastMile: 'Bole, Addis Ababa' }))).toBe(true);
});
it('an import that chose nothing does not', () => {
expect(usesEdrMileService(booking())).toBe(false);
});
it('ignores the pickup address on an import — collection is the export leg', () => {
expect(usesEdrMileService(booking({ firstMile: 'Modjo' }))).toBe(false);
});
it('an export that chose collection uses EDR haulage', () => {
expect(
usesEdrMileService(booking({ tradeDirection: 'EXPORT', firstMile: 'Modjo' })),
).toBe(true);
});
it('ignores the delivery address on an export — delivery is the import leg', () => {
expect(
usesEdrMileService(booking({ tradeDirection: 'EXPORT', lastMile: 'Djibouti' })),
).toBe(false);
});
it('a domestic booking counts either leg', () => {
expect(
usesEdrMileService(booking({ tradeDirection: 'DOMESTIC', firstMile: 'Adama' })),
).toBe(true);
expect(
usesEdrMileService(booking({ tradeDirection: 'DOMESTIC', lastMile: 'Dire Dawa' })),
).toBe(true);
});
it('treats a whitespace-only address as no choice', () => {
expect(usesEdrMileService(booking({ lastMile: ' ' }))).toBe(false);
});
});