/** The booking fields that decide who hauls the road legs. */ export interface MileHaulageRow { tradeDirection: string | null; /** `first_mile_pickup_address` — set when the customer asked EDR to collect. */ firstMile: string | null; /** `last_mile_delivery_address` — set when the customer asked EDR to deliver. */ lastMile: string | null; } /** * Whether the customer bought the EDR road leg that matters for their direction: * delivery at the end of an import, collection at the start of an export. A * DOMESTIC booking can use either, so either one counts. * * The address is the signal because it is the only per-booking record of the * choice. `service_types.includes_first_mile` / `includes_last_mile` cannot be * used — every service type ships with both set to true, so reading them would * mean every booking uses EDR haulage and none could ever self-haul. */ export function usesEdrMileService(booking: MileHaulageRow): boolean { const hasFirstMile = Boolean(booking.firstMile?.trim()); const hasLastMile = Boolean(booking.lastMile?.trim()); switch (booking.tradeDirection) { case 'IMPORT': return hasLastMile; case 'EXPORT': return hasFirstMile; default: return hasFirstMile || hasLastMile; } } /** * EDR haulage and a customer's own truck are alternatives, never both. Whichever * side is being set up, it has to reject the other — a guard on only one side * lets the two paths open on the same booking, each unaware of the other. */ export const SELF_HAUL_CONFLICT_MESSAGE = 'This booking is delivered by the customer’s own truck — an EDR mile leg cannot also be assigned.'; export const EDR_HAULAGE_CONFLICT_MESSAGE = 'Customer truck assignment is only allowed when first/last mile delivery is not selected'; /** * The road legs are chosen on the contract. A booking whose contract bought * neither has no business in the first/last-mile queues at all. */ export const NO_MILE_SERVICE_MESSAGE = 'This booking did not select first/last mile delivery on its contract, so it cannot be assigned an EDR mile leg.';