diff --git a/apps/edr-freight-api/src/modules/bookings/booking-lifecycle-notifier.service.ts b/apps/edr-freight-api/src/modules/bookings/booking-lifecycle-notifier.service.ts
index 1cef9528c..3809dc086 100644
--- a/apps/edr-freight-api/src/modules/bookings/booking-lifecycle-notifier.service.ts
+++ b/apps/edr-freight-api/src/modules/bookings/booking-lifecycle-notifier.service.ts
@@ -157,13 +157,13 @@ export class BookingLifecycleNotifierService {
});
}
- /** Clearance finalized → customer can proceed to request operation. */
+ /** Document approval finalized → customer can proceed to request operation. */
clearanceReady(b: Booking): void {
const msg =
- `Clearance for booking ${b.reference} is complete. ` +
+ `Document approval for booking ${b.reference} is finalized. ` +
`You can now proceed to request operation from the portal.`;
- void this.notifyContact(b, msg, 'CLEARANCE READY');
- this.inApp(b, 'Clearance complete', msg, {
+ void this.notifyContact(b, msg, 'DOCUMENT APPROVAL FINALIZED');
+ this.inApp(b, 'Document approval finalized', msg, {
type: NotificationType.CLEARANCE_DECISION,
});
}
diff --git a/apps/edr-freight-api/src/modules/contracts/contract-clearance.service.ts b/apps/edr-freight-api/src/modules/contracts/contract-clearance.service.ts
index d752d071a..029952f45 100644
--- a/apps/edr-freight-api/src/modules/contracts/contract-clearance.service.ts
+++ b/apps/edr-freight-api/src/modules/contracts/contract-clearance.service.ts
@@ -456,7 +456,7 @@ export class ContractClearanceService {
const allowed = ['CLEARANCE_UNDER_REVIEW', 'AWAITING_CLEARANCE_DOCUMENTS'];
if (!allowed.includes(contract.status)) {
throw new ConflictException(
- `Cannot finalize clearance on status "${contract.status}".`,
+ `Cannot finalize document approval on status "${contract.status}".`,
);
}
}
diff --git a/apps/edr-freight-web/backoffice/src/components/bookings/detail/ClearanceReviewSection.tsx b/apps/edr-freight-web/backoffice/src/components/bookings/detail/ClearanceReviewSection.tsx
index 3dcf1ea9e..501e074e2 100644
--- a/apps/edr-freight-web/backoffice/src/components/bookings/detail/ClearanceReviewSection.tsx
+++ b/apps/edr-freight-web/backoffice/src/components/bookings/detail/ClearanceReviewSection.tsx
@@ -135,12 +135,14 @@ export function ClearanceReviewSection({
const finalizeMutation = useMutation({
mutationFn: () => bookingsService.finalizeClearance(bookingId),
onSuccess: () => {
- toast.success("Clearance finalized");
+ toast.success("Document approval finalized");
refresh();
},
onError: (e) =>
toast.error(
- e instanceof Error ? e.message : "Could not finalize clearance",
+ e instanceof Error
+ ? e.message
+ : "Could not finalize document approval",
),
});
@@ -366,7 +368,7 @@ export function ClearanceReviewSection({
}>
{finalizeMutation.error instanceof Error
? finalizeMutation.error.message
- : "Could not finalize clearance."}
+ : "Could not finalize document approval."}
)}
@@ -445,7 +447,7 @@ export function ClearanceReviewSection({
loading={finalizeMutation.isPending}
onClick={() => finalizeMutation.mutate()}
>
- Finalize clearance
+ Finalize document approval
diff --git a/apps/edr-freight-web/backoffice/src/components/contracts/ContractClearanceReviewSection.tsx b/apps/edr-freight-web/backoffice/src/components/contracts/ContractClearanceReviewSection.tsx
index c85dc0b07..c7d668ade 100644
--- a/apps/edr-freight-web/backoffice/src/components/contracts/ContractClearanceReviewSection.tsx
+++ b/apps/edr-freight-web/backoffice/src/components/contracts/ContractClearanceReviewSection.tsx
@@ -68,7 +68,7 @@ export interface ContractClearanceReviewSectionProps {
queriesLocked?: boolean;
/**
* ONE_TIME customs contracts use the phased milestone workflow. Hides the
- * legacy "Finalize clearance" shortcut; booking readiness follows delivery
+ * legacy "Finalize document approval" shortcut; booking readiness follows delivery
* order (import) or export release.
*/
phasedCustoms?: boolean;
@@ -393,7 +393,7 @@ export function ContractClearanceReviewSection({
}>
{finalizeClearance.error instanceof Error
? finalizeClearance.error.message
- : "Could not finalize clearance."}
+ : "Could not finalize document approval."}
)}
@@ -482,7 +482,7 @@ export function ContractClearanceReviewSection({
})
}
>
- Finalize clearance
+ Finalize document approval
diff --git a/apps/edr-freight-web/backoffice/src/components/trainBuilder/BuildTrainModal.tsx b/apps/edr-freight-web/backoffice/src/components/trainBuilder/BuildTrainModal.tsx
index 05b4bd546..925ff528d 100644
--- a/apps/edr-freight-web/backoffice/src/components/trainBuilder/BuildTrainModal.tsx
+++ b/apps/edr-freight-web/backoffice/src/components/trainBuilder/BuildTrainModal.tsx
@@ -160,7 +160,8 @@ export default function BuildTrainModal({ opened, onClose, onBuilt }: BuildTrain
onChange={(value) => setImportTrainNumber(value ?? "")}
searchable
clearable
- nothingFoundMessage="No free run numbers — add more in Dropdown Settings"
+ nothingFoundMessage={importNumbers.emptyMessage}
+ error={importNumbers.settingMissing ? importNumbers.emptyMessage : undefined}
/>
{
toast.success(
selfClear
- ? "Clearance approved — customer can now book"
- : "Clearance finalized — ready for booking",
+ ? "Document approval finalized — customer can now book"
+ : "Document approval finalized — ready for booking",
);
refresh();
},
onError: (e) =>
toast.error(
- e instanceof Error ? e.message : "Could not finalize clearance",
+ e instanceof Error
+ ? e.message
+ : "Could not finalize document approval",
),
});
diff --git a/apps/edr-freight-web/backoffice/src/hooks/useImportTrainNumberOptions.ts b/apps/edr-freight-web/backoffice/src/hooks/useImportTrainNumberOptions.ts
index a26e127f3..d2cf2710d 100644
--- a/apps/edr-freight-web/backoffice/src/hooks/useImportTrainNumberOptions.ts
+++ b/apps/edr-freight-web/backoffice/src/hooks/useImportTrainNumberOptions.ts
@@ -1,7 +1,6 @@
import { useQuery } from "@tanstack/react-query";
import { useMemo } from "react";
-import { IMPORT_TRAIN_OPTIONS } from "@/constants/trainRuns";
import { api } from "@/services/api";
/** Dropdown-settings code holding the admin-managed IMPORT run numbers. */
@@ -14,10 +13,11 @@ export interface ImportTrainNumberOption {
}
/**
- * Selectable IMPORT run numbers for the Train Builder, sourced from the
- * admin-managed `import_train_numbers` dropdown setting (admins add new runs
- * from the Dropdown Settings editor). Falls back to the legacy hardcoded run
- * list while the setting is missing or has no options.
+ * Selectable IMPORT run numbers for the Train Builder, sourced solely from the
+ * admin-managed `import_train_numbers` dropdown setting — admins add and remove
+ * runs from /dashboard/dropdown-settings and the pickers follow. There is no
+ * hardcoded fallback on purpose: a missing setting must be visible (see
+ * `settingMissing`) rather than masked by stale defaults.
*
* Numbers already claimed by an existing train are kept in the list but
* disabled and tagged "in use". Pass `currentNumber` when editing a train so
@@ -37,14 +37,13 @@ export function useImportTrainNumberOptions(currentNumber?: string | null) {
);
const options = useMemo(() => {
- const configured = [...(settingQuery.data?.children ?? [])]
+ const base = [...(settingQuery.data?.children ?? [])]
.filter((option) => !option.disabled)
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
.map((option) => ({
value: option.value,
label: option.label || option.value,
}));
- const base = configured.length ? configured : IMPORT_TRAIN_OPTIONS;
const used = new Set(usedQuery.data?.importTrainNumbers ?? []);
if (currentNumber) used.delete(currentNumber);
@@ -60,8 +59,16 @@ export function useImportTrainNumberOptions(currentNumber?: string | null) {
return items;
}, [settingQuery.data, usedQuery.data, currentNumber]);
+ const settingMissing = settingQuery.isError;
+
return {
options,
isLoading: settingQuery.isLoading || usedQuery.isLoading,
+ /** True when the dropdown setting is absent — surfaced instead of silently
+ * falling back, so a broken config is visible rather than looking normal. */
+ settingMissing,
+ emptyMessage: settingMissing
+ ? `Dropdown setting "${IMPORT_TRAIN_NUMBERS_CODE}" is missing — create it in Dropdown Settings`
+ : "No free run numbers — add more in Dropdown Settings",
};
}
diff --git a/apps/edr-freight-web/backoffice/src/pages/bookings/DocumentClearanceListPage.tsx b/apps/edr-freight-web/backoffice/src/pages/bookings/DocumentClearanceListPage.tsx
index 542852a5f..34e659177 100644
--- a/apps/edr-freight-web/backoffice/src/pages/bookings/DocumentClearanceListPage.tsx
+++ b/apps/edr-freight-web/backoffice/src/pages/bookings/DocumentClearanceListPage.tsx
@@ -325,7 +325,7 @@ export default function DocumentClearanceListPage({
subtitle={
opsMode
? "Review the customer's own clearance documents per shipment booking, raise queries, and finalize."
- : "Review customer documents, raise queries, and finalize clearance for each booking."
+ : "Review customer documents, raise queries, and finalize document approval for each booking."
}
meta={statusBadge}
action={
diff --git a/apps/edr-freight-web/backoffice/src/pages/contracts/ContractClearanceListPage.tsx b/apps/edr-freight-web/backoffice/src/pages/contracts/ContractClearanceListPage.tsx
index 9cc9919e3..328736f3d 100644
--- a/apps/edr-freight-web/backoffice/src/pages/contracts/ContractClearanceListPage.tsx
+++ b/apps/edr-freight-web/backoffice/src/pages/contracts/ContractClearanceListPage.tsx
@@ -256,7 +256,7 @@ function StatusBadge({ row }: { row: ClearanceRow }) {
if (row.ready) {
return (
}
>
- Clearance finalized
+ Documents approved
);