mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
feat(bookings): Implement data-driven service type selection and configuration
This commit is contained in:
@@ -106,16 +106,10 @@ export default function NewBookingPage() {
|
||||
: Number(data.cargoWeight || 0);
|
||||
|
||||
// ── Reference data lookups ──────────────────────────────────────────
|
||||
const services = referenceData?.service ?? [];
|
||||
const shippingLines = referenceData?.shipping_line ?? [];
|
||||
const cargoTree = referenceData?.cargo_type ?? [];
|
||||
const containerGroups = referenceData?.containers ?? [];
|
||||
|
||||
const findServiceTypeId = (): string => {
|
||||
const code = data.serviceType === "rail" ? "RAIL" : "RAIL_AND_FORWARDING";
|
||||
return services.find((s) => s.code === code)?.id ?? services[0]?.id ?? "";
|
||||
};
|
||||
|
||||
const findShippingLineId = (name: string): string | undefined =>
|
||||
shippingLines.find((l) => l.name === name)?.id;
|
||||
|
||||
@@ -127,32 +121,32 @@ export default function NewBookingPage() {
|
||||
return "";
|
||||
};
|
||||
|
||||
const selectedChild =
|
||||
data.cargoType !== "container" && data.bulkCommoditytype
|
||||
? cargoTree
|
||||
.find((g) => g.code.toLowerCase() === data.freightType)
|
||||
?.children?.find((c) => c.name === data.bulkCommoditytype)
|
||||
: undefined;
|
||||
const bulkChild = cargoTree
|
||||
.flatMap((g) => g.children ?? [])
|
||||
.find((c) => c.id === data.bulkCommoditytype);
|
||||
|
||||
const cargoTypeId = selectedChild?.id;
|
||||
const cargoTypeId =
|
||||
data.cargoType === "bulk" ? data.bulkCommoditytype : undefined;
|
||||
|
||||
const cargoFreeText =
|
||||
data.cargoType === "container"
|
||||
? undefined
|
||||
: selectedChild?.show_free_text_box
|
||||
? data.cargoFreeText
|
||||
: undefined;
|
||||
const cargoFreeText = bulkChild?.show_free_text_box
|
||||
? data.cargoFreeText
|
||||
: undefined;
|
||||
|
||||
const serviceType = referenceData?.service.find(
|
||||
(s) => s.id === data.serviceTypeId,
|
||||
)!;
|
||||
|
||||
// ── Build API payload ───────────────────────────────────────────────
|
||||
const apiPayload: CreateBookingPayload = {
|
||||
scheduledDate: new Date().toISOString(),
|
||||
contractType:
|
||||
data.contractType.toUpperCase() as CreateBookingPayload["contractType"],
|
||||
serviceTypeId: findServiceTypeId(),
|
||||
serviceTypeId: data.serviceTypeId,
|
||||
equipmentReturn:
|
||||
data.equipmentReturn === "with_return"
|
||||
? "WITH_RETURN"
|
||||
: "WITHOUT_RETURN",
|
||||
paymentCurrency: "USD",
|
||||
originYardId: data.originYard,
|
||||
destinationYardId: data.destinationYard,
|
||||
tradeDirection: direction!,
|
||||
@@ -180,10 +174,10 @@ export default function NewBookingPage() {
|
||||
...(data.contractType === "renewal" && data.previousContractRef
|
||||
? { pnrCode: data.previousContractRef }
|
||||
: {}),
|
||||
...(data.serviceType === "rail_forwarding" && data.firstMile.enabled
|
||||
...(serviceType.includesFirstMile && data.firstMile.enabled
|
||||
? { firstMilePickupAddress: data.firstMile.pickUpAddress }
|
||||
: {}),
|
||||
...(data.serviceType === "rail_forwarding" && data.lastMile.enabled
|
||||
...(serviceType.includesLastMile && data.lastMile.enabled
|
||||
? { lastMileDeliveryAddress: data.lastMile.deliveryAddress }
|
||||
: {}),
|
||||
...(data.shippingLine
|
||||
@@ -265,7 +259,9 @@ export default function NewBookingPage() {
|
||||
)}
|
||||
|
||||
{step === 1 && <Step1ContractType form={form} />}
|
||||
{step === 2 && <Step2ServiceType form={form} />}
|
||||
{step === 2 && (
|
||||
<Step2ServiceType referenceData={referenceData} form={form} />
|
||||
)}
|
||||
{step === 3 && (
|
||||
<Step4Route
|
||||
form={form}
|
||||
|
||||
@@ -74,7 +74,7 @@ export const bookingFormSchema = z
|
||||
.object({
|
||||
contractType: z.enum(["new", "renewal"], "Select a contract type."),
|
||||
previousContractRef: z.string(),
|
||||
serviceType: z.enum(["rail", "rail_forwarding"], "Select a service type."),
|
||||
serviceTypeId: z.string("Select a service type."),
|
||||
firstMile: z
|
||||
.object({
|
||||
enabled: z.boolean().default(false),
|
||||
@@ -247,7 +247,7 @@ export const initialBookingFormValues: DeepPartial<BookingFormValues> = {
|
||||
export const stepFields: Record<number, Array<Path<BookingFormValues>>> = {
|
||||
1: ["contractType", "previousContractRef"],
|
||||
2: [
|
||||
"serviceType",
|
||||
"serviceTypeId",
|
||||
"firstMile",
|
||||
"lastMile",
|
||||
"equipmentReturn",
|
||||
|
||||
@@ -1,18 +1,52 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { Controller, type UseFormReturn } from "react-hook-form";
|
||||
import { FileText, Package, Train, Truck } from "lucide-react";
|
||||
import { Badge, Switch, TextInput } from "@mantine/core";
|
||||
import { FileText, Train, Truck } from "lucide-react";
|
||||
import { Switch, TextInput } from "@mantine/core";
|
||||
import { BookingFormInputValues, type BookingFormValues } from "./schema";
|
||||
import { OptionCard, OptionFieldError, StepHeader } from "./shared";
|
||||
|
||||
type BookingForm = UseFormReturn<BookingFormInputValues, any, BookingFormValues>;
|
||||
import type { Freight } from "@edr/types";
|
||||
|
||||
export function Step2ServiceType({ form }: { form: BookingForm }) {
|
||||
const serviceType = form.watch("serviceType");
|
||||
type BookingForm = UseFormReturn<
|
||||
BookingFormInputValues,
|
||||
any,
|
||||
BookingFormValues
|
||||
>;
|
||||
|
||||
export function Step2ServiceType({
|
||||
form,
|
||||
referenceData,
|
||||
}: {
|
||||
form: BookingForm;
|
||||
|
||||
referenceData?: Freight.BookingReferenceData;
|
||||
}) {
|
||||
const serviceTypeId = form.watch("serviceTypeId");
|
||||
const serviceType = referenceData?.service.find(
|
||||
(s) => s.id === serviceTypeId,
|
||||
);
|
||||
|
||||
const { includesCustoms, includesFirstMile, includesLastMile } =
|
||||
serviceType ?? {};
|
||||
const firstMileEnabled = form.watch("firstMile.enabled");
|
||||
const lastMileEnabled = form.watch("lastMile.enabled");
|
||||
|
||||
const prevServiceType = useRef(serviceType);
|
||||
useEffect(() => {
|
||||
form.setValue(
|
||||
"firstMile",
|
||||
{ enabled: false, pickUpAddress: "" },
|
||||
{ shouldValidate: true },
|
||||
);
|
||||
}, [includesFirstMile]);
|
||||
|
||||
useEffect(() => {
|
||||
form.setValue(
|
||||
"lastMile",
|
||||
{ enabled: false, deliveryAddress: "" },
|
||||
{ shouldValidate: true },
|
||||
);
|
||||
}, [includesLastMile]);
|
||||
|
||||
useEffect(() => {
|
||||
const prev = prevServiceType.current;
|
||||
@@ -20,35 +54,12 @@ export function Step2ServiceType({ form }: { form: BookingForm }) {
|
||||
|
||||
if (!prev || prev === serviceType) return;
|
||||
|
||||
if (serviceType === "rail") {
|
||||
form.setValue(
|
||||
"firstMile",
|
||||
{ enabled: false, pickUpAddress: "" },
|
||||
{ shouldDirty: true, shouldValidate: true },
|
||||
);
|
||||
form.setValue(
|
||||
"lastMile",
|
||||
{ enabled: false, deliveryAddress: "" },
|
||||
{ shouldDirty: true, shouldValidate: true },
|
||||
);
|
||||
form.setValue("equipmentReturn", "with_return", { shouldDirty: true });
|
||||
if (!includesCustoms)
|
||||
form.setValue("customsClearingEnabled", false, { shouldDirty: true });
|
||||
} else if (serviceType === "rail_forwarding") {
|
||||
form.setValue(
|
||||
"firstMile",
|
||||
{ enabled: false, pickUpAddress: "" },
|
||||
{ shouldDirty: false, shouldValidate: false },
|
||||
);
|
||||
form.setValue(
|
||||
"lastMile",
|
||||
{ enabled: false, deliveryAddress: "" },
|
||||
{ shouldDirty: false, shouldValidate: false },
|
||||
);
|
||||
}
|
||||
}, [serviceType, form]);
|
||||
|
||||
const showServiceSections = serviceType === "rail_forwarding";
|
||||
}, [serviceTypeId, form]);
|
||||
|
||||
const showServiceSections =
|
||||
includesCustoms || includesFirstMile || includesLastMile;
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<StepHeader
|
||||
@@ -57,44 +68,29 @@ export function Step2ServiceType({ form }: { form: BookingForm }) {
|
||||
/>
|
||||
|
||||
<Controller
|
||||
name="serviceType"
|
||||
name="serviceTypeId"
|
||||
control={form.control}
|
||||
render={({ field, fieldState }) => (
|
||||
<div>
|
||||
<div className="grid gap-3 md:grid-cols-2">
|
||||
<OptionCard
|
||||
selected={serviceType === "rail"}
|
||||
onClick={() => field.onChange("rail")}
|
||||
>
|
||||
<div className="mb-2 flex h-9 w-9 items-center justify-center rounded-lg bg-indigo-100">
|
||||
<Train className="h-4 w-4 text-indigo-600" />
|
||||
</div>
|
||||
<p className="font-semibold">Rail Transport Only</p>
|
||||
<p className="mt-0.5 text-xs text-gray-500">
|
||||
Rail transport along the EDR corridor, with optional
|
||||
first/last mile trucking.
|
||||
</p>
|
||||
<Badge color="indigo" variant="light" mt="xs" size="sm">
|
||||
Option A
|
||||
</Badge>
|
||||
</OptionCard>
|
||||
|
||||
<OptionCard
|
||||
selected={serviceType === "rail_forwarding"}
|
||||
onClick={() => field.onChange("rail_forwarding")}
|
||||
>
|
||||
<div className="mb-2 flex h-9 w-9 items-center justify-center rounded-lg bg-emerald-100">
|
||||
<Package className="h-4 w-4 text-emerald-600" />
|
||||
</div>
|
||||
<p className="font-semibold">Logistics</p>
|
||||
<p className="mt-0.5 text-xs text-gray-500">
|
||||
Rail transport plus documentation, customs liaison, and a
|
||||
dedicated coordinator.
|
||||
</p>
|
||||
<Badge color="edr-green" variant="light" mt="xs" size="sm">
|
||||
Option B
|
||||
</Badge>
|
||||
</OptionCard>
|
||||
{referenceData?.service
|
||||
.filter((s) => s.canBeBookedAlone)
|
||||
.map((s) => {
|
||||
return (
|
||||
<OptionCard
|
||||
selected={field.value === s.id}
|
||||
onClick={() => field.onChange(s.id)}
|
||||
>
|
||||
<div className="mb-2 flex h-9 w-9 items-center justify-center rounded-lg bg-indigo-100">
|
||||
<Train className="h-4 w-4 text-indigo-600" />
|
||||
</div>
|
||||
<p className="font-semibold">{s.serviceName}</p>
|
||||
<p className="mt-0.5 text-xs text-gray-500">
|
||||
{s.description}
|
||||
</p>
|
||||
</OptionCard>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<OptionFieldError error={fieldState.error} />
|
||||
</div>
|
||||
@@ -104,112 +100,120 @@ export function Step2ServiceType({ form }: { form: BookingForm }) {
|
||||
{showServiceSections && (
|
||||
<div className="divide-y divide-gray-200 rounded-xl border border-gray-200">
|
||||
{/* First Mile */}
|
||||
<div className="p-4">
|
||||
<Controller
|
||||
name="firstMile.enabled"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<Truck className="mt-0.5 h-4 w-4 shrink-0 text-gray-400" />
|
||||
<div>
|
||||
<p className="text-sm font-medium">First Mile — Pick-up</p>
|
||||
<p className="mt-0.5 text-xs text-gray-500">
|
||||
Truck pick-up from your premises (Door to Port) to the
|
||||
origin rail yard.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.checked;
|
||||
field.onChange(value);
|
||||
if (!value) {
|
||||
form.setValue("firstMile.pickUpAddress", "", {
|
||||
shouldDirty: true,
|
||||
shouldValidate: true,
|
||||
});
|
||||
}
|
||||
}}
|
||||
color="edr-green"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
{firstMileEnabled && (
|
||||
{includesFirstMile && (
|
||||
<div className="p-4">
|
||||
<Controller
|
||||
name="firstMile.pickUpAddress"
|
||||
name="firstMile.enabled"
|
||||
control={form.control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextInput
|
||||
{...field}
|
||||
mt="sm"
|
||||
placeholder="Pick-up address *"
|
||||
error={fieldState.error?.message}
|
||||
radius="md"
|
||||
/>
|
||||
render={({ field }) => (
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<Truck className="mt-0.5 h-4 w-4 shrink-0 text-gray-400" />
|
||||
<div>
|
||||
<p className="text-sm font-medium">
|
||||
First Mile — Pick-up
|
||||
</p>
|
||||
<p className="mt-0.5 text-xs text-gray-500">
|
||||
Truck pick-up from your premises (Door to Port) to the
|
||||
origin rail yard.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.checked;
|
||||
field.onChange(value);
|
||||
if (!value) {
|
||||
form.setValue("firstMile.pickUpAddress", "", {
|
||||
shouldDirty: true,
|
||||
shouldValidate: true,
|
||||
});
|
||||
}
|
||||
}}
|
||||
color="edr-green"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{firstMileEnabled && (
|
||||
<Controller
|
||||
name="firstMile.pickUpAddress"
|
||||
control={form.control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextInput
|
||||
{...field}
|
||||
mt="sm"
|
||||
placeholder="Pick-up address *"
|
||||
error={fieldState.error?.message}
|
||||
radius="md"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Last Mile */}
|
||||
<div className="p-4">
|
||||
<Controller
|
||||
name="lastMile.enabled"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<Truck className="mt-0.5 h-4 w-4 shrink-0 text-gray-400" />
|
||||
<div>
|
||||
<p className="text-sm font-medium">Last Mile — Delivery</p>
|
||||
<p className="mt-0.5 text-xs text-gray-500">
|
||||
Truck delivery from the destination rail yard to the
|
||||
final address (Port to Door).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.checked;
|
||||
field.onChange(value);
|
||||
if (!value) {
|
||||
form.setValue("lastMile.deliveryAddress", "", {
|
||||
shouldDirty: true,
|
||||
shouldValidate: true,
|
||||
});
|
||||
form.setValue("equipmentReturn", "with_return", {
|
||||
shouldDirty: true,
|
||||
});
|
||||
}
|
||||
}}
|
||||
color="edr-green"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
{lastMileEnabled && (
|
||||
{includesLastMile && (
|
||||
<div className="p-4">
|
||||
<Controller
|
||||
name="lastMile.deliveryAddress"
|
||||
name="lastMile.enabled"
|
||||
control={form.control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextInput
|
||||
{...field}
|
||||
mt="sm"
|
||||
placeholder="Delivery address *"
|
||||
error={fieldState.error?.message}
|
||||
radius="md"
|
||||
/>
|
||||
render={({ field }) => (
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<Truck className="mt-0.5 h-4 w-4 shrink-0 text-gray-400" />
|
||||
<div>
|
||||
<p className="text-sm font-medium">
|
||||
Last Mile — Delivery
|
||||
</p>
|
||||
<p className="mt-0.5 text-xs text-gray-500">
|
||||
Truck delivery from the destination rail yard to the
|
||||
final address (Port to Door).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onChange={(e) => {
|
||||
const value = e.currentTarget.checked;
|
||||
field.onChange(value);
|
||||
if (!value) {
|
||||
form.setValue("lastMile.deliveryAddress", "", {
|
||||
shouldDirty: true,
|
||||
shouldValidate: true,
|
||||
});
|
||||
form.setValue("equipmentReturn", "with_return", {
|
||||
shouldDirty: true,
|
||||
});
|
||||
}
|
||||
}}
|
||||
color="edr-green"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{lastMileEnabled && (
|
||||
<Controller
|
||||
name="lastMile.deliveryAddress"
|
||||
control={form.control}
|
||||
render={({ field, fieldState }) => (
|
||||
<TextInput
|
||||
{...field}
|
||||
mt="sm"
|
||||
placeholder="Delivery address *"
|
||||
error={fieldState.error?.message}
|
||||
radius="md"
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Equipment Return */}
|
||||
{lastMileEnabled && (
|
||||
{includesLastMile && lastMileEnabled && (
|
||||
<div className="p-4">
|
||||
<Controller
|
||||
name="equipmentReturn"
|
||||
@@ -228,7 +232,9 @@ export function Step2ServiceType({ form }: { form: BookingForm }) {
|
||||
checked={field.value === "with_return"}
|
||||
onChange={(e) => {
|
||||
field.onChange(
|
||||
e.currentTarget.checked ? "with_return" : "without_return",
|
||||
e.currentTarget.checked
|
||||
? "with_return"
|
||||
: "without_return",
|
||||
);
|
||||
}}
|
||||
color="edr-green"
|
||||
@@ -240,31 +246,35 @@ export function Step2ServiceType({ form }: { form: BookingForm }) {
|
||||
)}
|
||||
|
||||
{/* Customs Clearing */}
|
||||
<div className="p-4">
|
||||
<Controller
|
||||
name="customsClearingEnabled"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<FileText className="mt-0.5 h-4 w-4 shrink-0 text-gray-400" />
|
||||
<div>
|
||||
<p className="text-sm font-medium">Customs Clearing Service</p>
|
||||
<p className="mt-0.5 text-xs text-gray-500">
|
||||
EDR handles customs documentation and clearance on your
|
||||
behalf.
|
||||
</p>
|
||||
{includesCustoms && (
|
||||
<div className="p-4">
|
||||
<Controller
|
||||
name="customsClearingEnabled"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="flex items-start gap-3">
|
||||
<FileText className="mt-0.5 h-4 w-4 shrink-0 text-gray-400" />
|
||||
<div>
|
||||
<p className="text-sm font-medium">
|
||||
Customs Clearing Service
|
||||
</p>
|
||||
<p className="mt-0.5 text-xs text-gray-500">
|
||||
EDR handles customs documentation and clearance on
|
||||
your behalf.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onChange={(e) => field.onChange(e.currentTarget.checked)}
|
||||
color="edr-green"
|
||||
/>
|
||||
</div>
|
||||
<Switch
|
||||
checked={field.value}
|
||||
onChange={(e) => field.onChange(e.currentTarget.checked)}
|
||||
color="edr-green"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -5,16 +5,16 @@ export * from "./dropdown_settings";
|
||||
export * from "./overview";
|
||||
|
||||
export enum TradeDirection {
|
||||
IMPORT = 'IMPORT',
|
||||
EXPORT = 'EXPORT',
|
||||
BOTH = 'BOTH',
|
||||
IMPORT = "IMPORT",
|
||||
EXPORT = "EXPORT",
|
||||
BOTH = "BOTH",
|
||||
}
|
||||
|
||||
export enum PriorityType {
|
||||
USD_PAYER = 'USD_PAYER',
|
||||
RAIL_AND_FORWARDING = 'RAIL_AND_FORWARDING',
|
||||
GOVERNMENT_ACCOUNT = 'GOVERNMENT_ACCOUNT',
|
||||
HIGH_VOLUME_SHIPMENT = 'HIGH_VOLUME_SHIPMENT',
|
||||
USD_PAYER = "USD_PAYER",
|
||||
RAIL_AND_FORWARDING = "RAIL_AND_FORWARDING",
|
||||
GOVERNMENT_ACCOUNT = "GOVERNMENT_ACCOUNT",
|
||||
HIGH_VOLUME_SHIPMENT = "HIGH_VOLUME_SHIPMENT",
|
||||
}
|
||||
|
||||
/** Bonus applied to government bookings so they outrank commercial priority. */
|
||||
@@ -26,19 +26,19 @@ export interface GovernmentBookingFields {
|
||||
}
|
||||
|
||||
export enum ExceededAction {
|
||||
WARNING_ONLY = 'WARNING_ONLY',
|
||||
HARD_BLOCK = 'HARD_BLOCK',
|
||||
WARNING_ONLY = "WARNING_ONLY",
|
||||
HARD_BLOCK = "HARD_BLOCK",
|
||||
}
|
||||
|
||||
export enum CalculationMethod {
|
||||
PER_TON = 'PER_TON',
|
||||
FLAT_FEE = 'FLAT_FEE',
|
||||
PERCENTAGE = 'PERCENTAGE',
|
||||
PER_TON = "PER_TON",
|
||||
FLAT_FEE = "FLAT_FEE",
|
||||
PERCENTAGE = "PERCENTAGE",
|
||||
}
|
||||
|
||||
export enum FreightType {
|
||||
Container = 'CONTAINER',
|
||||
Bulk = 'BULK',
|
||||
Container = "CONTAINER",
|
||||
Bulk = "BULK",
|
||||
}
|
||||
|
||||
export enum BookingStatus {
|
||||
@@ -390,6 +390,18 @@ export interface BookingReferenceService {
|
||||
id: string;
|
||||
name: string;
|
||||
code: string;
|
||||
serviceName: string;
|
||||
description?: string | null | undefined;
|
||||
canBeBookedAlone: boolean;
|
||||
includesFirstMile: boolean;
|
||||
includesLastMile: boolean;
|
||||
includesCustoms: boolean;
|
||||
priorityBonusPoints: number;
|
||||
isActive: boolean;
|
||||
displayOrder: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt?: string | null | undefined;
|
||||
}
|
||||
|
||||
export interface BookingReferenceShippingLine {
|
||||
@@ -462,31 +474,34 @@ export interface CreateBookingContainerDto {
|
||||
}
|
||||
|
||||
export interface CreateBookingDto {
|
||||
reference?: string;
|
||||
companyId?: string;
|
||||
trainId?: string;
|
||||
trainScheduleId?: string;
|
||||
freightShapeValidation?: boolean | undefined;
|
||||
reference?: string | undefined;
|
||||
isGovernment?: boolean | undefined;
|
||||
governmentInstitution?: string | undefined;
|
||||
companyId?: string | undefined;
|
||||
trainId?: string | undefined;
|
||||
trainScheduleId?: string | undefined;
|
||||
scheduledDate: string;
|
||||
contractType: "NEW" | "RENEWAL";
|
||||
previousContractId?: string;
|
||||
contractType: string;
|
||||
previousContractId?: string | undefined;
|
||||
serviceTypeId: string;
|
||||
firstMilePickupAddress?: string;
|
||||
lastMileDeliveryAddress?: string;
|
||||
equipmentReturn: "WITH_RETURN" | "WITHOUT_RETURN" | "NA";
|
||||
firstMilePickupAddress?: string | undefined;
|
||||
lastMileDeliveryAddress?: string | undefined;
|
||||
equipmentReturn: string;
|
||||
originYardId: string;
|
||||
destinationYardId: string;
|
||||
tradeDirection: "IMPORT" | "EXPORT" | "DOMESTIC";
|
||||
freightType: FreightType;
|
||||
cargoTypeId?: string;
|
||||
cargoFreeText?: string;
|
||||
shippingLineId?: string;
|
||||
tradeDirection: string;
|
||||
freightType: string;
|
||||
cargoTypeId?: string | undefined;
|
||||
cargoFreeText?: string | undefined;
|
||||
shippingLineId?: string | undefined;
|
||||
cargoTotalWeightVgm: number;
|
||||
isHazardous?: boolean;
|
||||
paymentCurrency: "ETB" | "USD";
|
||||
pnrCode?: string;
|
||||
startDate?: string;
|
||||
endDate?: string;
|
||||
financialTerms?: string;
|
||||
isHazardous?: boolean | undefined;
|
||||
paymentCurrency: string;
|
||||
pnrCode?: string | undefined;
|
||||
startDate?: string | undefined;
|
||||
endDate?: string | undefined;
|
||||
financialTerms?: string | undefined;
|
||||
containers?: CreateBookingContainerDto[];
|
||||
allowConsolidation?: boolean;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user