mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 21:08:12 +00:00
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>
53 lines
1.8 KiB
TypeScript
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);
|
|
});
|
|
});
|