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 && ( + + Signature + + )} + + ))} + + + )} + {/* ── 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 ?? []; + }, };