diff --git a/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts b/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts
index 8e9e0bc76..e42cbdcea 100644
--- a/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts
+++ b/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts
@@ -4087,10 +4087,11 @@ export class WarehouseInventoryService {
await this.invoices.assertClearanceAllowed(item.id);
const approvedAt = new Date();
+ const signatureImageUrl = signature?.signatureImageUrl ?? null;
const approval = {
approvedAt: approvedAt.toISOString(),
signerDisplayName: name,
- signatureImageUrl: signature?.signatureImageUrl ?? null,
+ signatureImageUrl,
userId,
};
const existingNotes = this.stripCustomerDeliveryApproval(item.notes);
@@ -4114,7 +4115,7 @@ export class WarehouseInventoryService {
// Sign the structured handover record(s) for this booking (self-haul: before
// the truck leaves). Kept alongside the legacy approval note.
- await this.handover.signForBooking(bookingId, userId, name);
+ await this.handover.signForBooking(bookingId, userId, name, signatureImageUrl);
return {
bookingId,
@@ -4149,6 +4150,8 @@ export class WarehouseInventoryService {
throw new BadRequestException('Please enter your full name to sign the handover');
}
+ const signature = await this.signatures.getForUser(userId).catch(() => null);
+
const [h]: Array<{
bookingId: string;
reference: string;
@@ -4181,7 +4184,7 @@ export class WarehouseInventoryService {
);
if (inv) await this.invoices.assertClearanceAllowed(inv.id);
- const signed = await this.handover.sign(handoverId, userId, name);
+ const signed = await this.handover.sign(handoverId, userId, name, signature?.signatureImageUrl ?? null);
const allSigned = await this.handover.isFullySigned(h.bookingId);
if (inv) {
diff --git a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/DocumentsTab.tsx b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/DocumentsTab.tsx
index 8934a0a60..e43bb43b9 100644
--- a/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/DocumentsTab.tsx
+++ b/apps/edr-freight-web/portal/src/pages/bookings/BookingDetailPage/components/DocumentsTab.tsx
@@ -15,6 +15,7 @@ import { isViewable } from "@edr/ui-common";
import { api } from "@/services/api";
import { fetchViewableFile, downloadStoredFile } from "@/services/files.service";
+import { warehouseService } from "@/services/warehouse.service";
import { useFileViewer } from "@/hooks/useFileViewer";
import { BookingActionModal } from "@/pages/bookings/clearance/BookingActionModal";
import { getBookingNextAction } from "@/pages/bookings/clearance/bookingNextAction";
@@ -241,6 +242,11 @@ export function DocumentsTab({ booking }: { booking: Freight.IBooking }) {
}),
);
+ const { data: handovers = [] } = useQuery({
+ queryKey: ["bookingHandovers", booking.id],
+ queryFn: () => warehouseService.bookingHandovers(booking.id),
+ });
+
const customerDocs = useMemo(
() => (clearance?.documents ?? []).filter((d) => d.uploadedBy === "customer"),
[clearance],
@@ -486,6 +492,69 @@ export function DocumentsTab({ booking }: { booking: Freight.IBooking }) {
)}
+ {/* ── 4. Handover signatures ──────────────────────────────────────── */}
+ {handovers.length > 0 && (
+
+ Handover signatures
+
+ Records of goods handover and customer signatures.
+
+
+ {handovers.map((h, i) => (
+
+
+
+
+ {h.reference}
+
+
+ {h.mileType === "SELF_HAUL"
+ ? "Customer truck delivery"
+ : `EDR delivery${h.truckPlate ? ` (${h.truckPlate})` : ""}`}
+
+ {h.signedAt && (
+
+ Signed by {h.signerName || "Unknown"} on{" "}
+ {new Date(h.signedAt).toLocaleDateString()}
+
+ )}
+
+
+
+ {h.signedAt && h.signatureImageUrl && (
+
+
+
+ )}
+
+ ))}
+
+
+ )}
+
{/* ── Warehouse documents (one-click bundle) ──────────────────────── */}
Warehouse documents
diff --git a/apps/edr-freight-web/portal/src/services/warehouse.service.ts b/apps/edr-freight-web/portal/src/services/warehouse.service.ts
index b641a8809..990077147 100644
--- a/apps/edr-freight-web/portal/src/services/warehouse.service.ts
+++ b/apps/edr-freight-web/portal/src/services/warehouse.service.ts
@@ -41,6 +41,22 @@ export interface BookingScheduleView {
} | null;
}
+export interface BookingHandover {
+ id: string;
+ bookingId: string;
+ truckAssignmentId?: string | null;
+ edrAssignmentId?: string | null;
+ truckPlate?: string | null;
+ mileType: 'SELF_HAUL' | 'EDR_LAST_MILE';
+ reference: string;
+ generatedAt: string;
+ signedAt?: string | null;
+ signerName?: string | null;
+ signedByUserId?: string | null;
+ signatureImageUrl?: string | null;
+ deliveredAt?: string | null;
+}
+
export const warehouseService = {
listInventory: async (filter?: InventoryFilter): Promise => {
const { data } = await client.get("/warehouse-inventory", {
@@ -59,4 +75,9 @@ export const warehouseService = {
const { data } = await client.get(`/warehouse-inventory/booking-schedule/${bookingId}`);
return data?.data ?? data ?? { schedule: null, wagon: null };
},
+
+ bookingHandovers: async (bookingId: string): Promise => {
+ const { data } = await client.get(`/warehouse-inventory/bookings/${bookingId}/handovers`);
+ return data?.data ?? data ?? [];
+ },
};