import { Booking } from './entities/booking.entity'; /** * Resolves which seeded clearance FileUploadSetting applies to a booking, from * its trade direction, freight type and whether its service includes customs. * Mirrors the codes seeded in file-upload-settings.seeder.ts. */ type Op = 'import' | 'export'; type Freight = 'container' | 'bulk'; /** * The single (admin-configured) document set intercity shipments upload. * DOMESTIC has no customs, so one shared set serves every intercity booking — * ONE_TIME and GENERAL alike, collected per booking and reviewed by Operations. */ export const INTERCITY_DOCUMENTS_SETTING_CODE = 'intercity_documents'; /** * The document set a shipping line uploads on a booking it initiated. * * Shipping lines book without a contract, so none of the trade-direction / * freight / customs matrix below applies to them — this one admin-configured * set is what Operations reviews before the booking may be completed. */ export const SHIPPING_LINE_DOCUMENTS_SETTING_CODE = 'shipping_line_booking_documents'; /** Trade direction → clearance operation. DOMESTIC has no customs clearance. */ function operationFor(tradeDirection: string): Op | null { if (tradeDirection === 'IMPORT') return 'import'; if (tradeDirection === 'EXPORT') return 'export'; return null; // DOMESTIC / intercity — no customs operation } function freightFor(freightType: string): Freight { return freightType === 'BULK' ? 'bulk' : 'container'; } /** The customer-input clearance setting code, or null when no gate applies. */ export function clearanceSettingCode( tradeDirection: string, freightType: string, includesCustoms: boolean, ): string | null { // Intercity: no customs, but the admin-configured intercity document set is // still collected and ops-reviewed before the shipment may board a train. if (tradeDirection === 'DOMESTIC') return INTERCITY_DOCUMENTS_SETTING_CODE; const op = operationFor(tradeDirection); if (!op) return null; const freight = freightFor(freightType); // 4 import + 4 export cases (bulk/container × with/without customs) — each // booking resolves to its own clearance_{op}_{freight}_{with|without}_customs // set, independent of any contract-level clearance codes. if (!includesCustoms) { return `clearance_${op}_${freight}_without_customs`; } return `clearance_${op}_${freight}_with_customs`; } /** The GL-output (customs output) setting code, keyed on op + freight. */ export function clearanceOutputSettingCode( tradeDirection: string, freightType: string, includesCustoms: boolean, ): string | null { if (!includesCustoms) return null; const op = operationFor(tradeDirection); if (!op) return null; const freight = freightFor(freightType); return `clearance_output_${op}_${freight}`; } /** Convenience: resolve both codes for a loaded booking (with its serviceType). */ export function clearanceCodesForBooking(booking: Booking): { inputCode: string | null; outputCode: string | null; includesCustoms: boolean; } { // Shipping-line bookings resolve to their own single set and never reach the // matrix below: they have no contract, and their trade direction / freight // type are placeholders until the booking is completed, so the customer codes // would resolve to a set that was never meant for them. Keyed off the owner // column, which is NULL on every customer booking — so no customer booking // can take this branch. if (booking.shippingLineCompanyId) { return { inputCode: SHIPPING_LINE_DOCUMENTS_SETTING_CODE, outputCode: null, includesCustoms: false, }; } // Customs applies when EITHER the service type bundles it OR the booking was // created with customsClearingEnabled (copied from the contract). Contract // bookings carry customsClearingEnabled even when the serviceType relation // isn't loaded / has includesCustoms=false — without this the per-booking // clearance grid would resolve empty. const includesCustoms = Boolean(booking.serviceType?.includesCustoms) || Boolean(booking.customsClearingEnabled); return { inputCode: clearanceSettingCode( booking.tradeDirection, booking.freightType, includesCustoms, ), outputCode: clearanceOutputSettingCode( booking.tradeDirection, booking.freightType, includesCustoms, ), includesCustoms, }; }