implement intercity booking management and booking window websocket integration

This commit is contained in:
Marshal
2026-07-06 13:28:21 +00:00
parent 907f4edc0a
commit fed5f2f43f
46 changed files with 1772 additions and 101 deletions

View File

@@ -1,20 +1,33 @@
import type { ScheduleTradeDirection } from '@edr/types';
import { YardCountry, type ScheduleTradeDirection } from '@edr/types';
type YardLike = { country?: string | null };
/** Derive booking/schedule trade direction from origin and destination yard countries. */
/**
* Derive trade direction from origin and destination yard countries.
* Ethiopia → Djibouti = EXPORT, Djibouti → Ethiopia = IMPORT, same country =
* DOMESTIC (shown as "Intercity"; scheduling/contracts reject it for now).
* Comparison is strict against the YardCountry enum values the yards table is
* constrained to; the trim/case fold only shields legacy rows.
*/
export function deriveTradeDirection(
originYard: YardLike,
destinationYard: YardLike,
): ScheduleTradeDirection {
const originCountry = originYard.country?.trim().toLowerCase();
const destinationCountry = destinationYard.country?.trim().toLowerCase();
const origin = normalizeCountry(originYard.country);
const destination = normalizeCountry(destinationYard.country);
if (originCountry === 'djibouti') {
if (origin === YardCountry.DJIBOUTI && destination === YardCountry.ETHIOPIA) {
return 'IMPORT';
}
if (destinationCountry === 'djibouti' && originCountry !== 'djibouti') {
if (origin === YardCountry.ETHIOPIA && destination === YardCountry.DJIBOUTI) {
return 'EXPORT';
}
return 'DOMESTIC';
}
function normalizeCountry(country: string | null | undefined): YardCountry | null {
const folded = country?.trim().toLowerCase();
if (folded === YardCountry.ETHIOPIA.toLowerCase()) return YardCountry.ETHIOPIA;
if (folded === YardCountry.DJIBOUTI.toLowerCase()) return YardCountry.DJIBOUTI;
return null;
}