update import gl flow

This commit is contained in:
Marshal
2026-07-02 13:24:39 +00:00
parent 03740ee719
commit fe40d9f4be
8 changed files with 280 additions and 29 deletions

View File

@@ -5,7 +5,9 @@ import {
isDeclarationFileCode,
isImportTransitPermitFileCode,
isExportTransportFileCode,
isT1TransportFileCode,
exportTransportFileLabel,
t1TransportFileLabel,
transitPermitFileLabel,
type ClearanceWorkflowFile,
} from '@edr/types';
@@ -160,6 +162,50 @@ export async function persistExportTransportUploads(
);
}
/** Require at least one T1 transport document in the upload batch. */
export function assertT1TransportFiles(files: Express.Multer.File[]): void {
if (files.length === 0) {
throw new BadRequestException('No T1 transport documents uploaded');
}
}
export function normalizeT1TransportFieldNames(
files: Express.Multer.File[],
): Express.Multer.File[] {
return files.map((file, index) => ({
...file,
fieldname: `t1_transport_document_${index}`,
}));
}
/** Replace all T1 transport documents on a booking with a new multi-file batch. */
export async function persistT1TransportUploads(
store: DeclarationFileStore,
bookingId: string,
files: Express.Multer.File[],
): Promise<void> {
const normalized = normalizeT1TransportFieldNames(files);
assertT1TransportFiles(normalized);
const existing = await store.findByResource(bookingId, 'bookings');
await Promise.all(
existing
.filter((f) => f.code && isT1TransportFileCode(f.code))
.map((f) => store.deleteByCode(bookingId, 'bookings', f.code!)),
);
await Promise.all(
normalized.map((file, index) =>
store.upload({
resourceId: bookingId,
resource: 'bookings',
code: `t1_transport_document_${index}`,
file,
}),
),
);
}
export function parseDutyRequiredForm(value: string | boolean | undefined): boolean {
if (typeof value === 'boolean') return value;
if (value === undefined || value === '') return false;
@@ -194,9 +240,9 @@ export function belongsOnDjClearanceQueue(
);
if (hasDjActivity) return true;
const preFinalized =
cycle?.preClearanceFinalizedAt ?? extras?.preClearanceFinalizedAt ?? null;
if (tradeDirection === 'IMPORT' && preFinalized) return true;
// Import DO upload is un-gated — Djibouti GL must see import customs items from
// the start, not only after Ethiopia finalizes pre-clearance.
if (tradeDirection === 'IMPORT') return true;
return false;
}
@@ -295,6 +341,22 @@ export function buildWorkflowFiles(
file: { id: file.id, name: file.name, url: file.url },
});
});
const extraT1 = files
.filter((f) => f.code && isT1TransportFileCode(f.code) && !included.has(f.code))
.sort((a, b) => (a.code ?? '').localeCompare(b.code ?? ''));
extraT1.forEach((file, index) => {
if (!file.code) return;
included.add(file.code);
out.push({
code: file.code,
label: t1TransportFileLabel(file.code, index),
uploadedBy: 'gl_dj',
category: 'djibouti',
file: { id: file.id, name: file.name, url: file.url },
});
});
}
if (tradeDirection === 'EXPORT') {