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 7cd47f203..1355b7218 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 @@ -1682,6 +1682,7 @@ export class WarehouseInventoryService { for (const pending of pendingNotifications) { void this.notifyOwnerInventoryReceived(pending.owner); void this.notifyTruckAssignmentNeeded(pending.booking, pending.bookingId); + if (dto.direction === 'EXPORT') void this.notifyCarriageAcceptanceReady(pending.bookingId); } return result; @@ -2809,6 +2810,10 @@ export class WarehouseInventoryService { return saved.id; }); + if (dto.bookingId && bookingDirection === 'EXPORT') { + void this.notifyCarriageAcceptanceReady(dto.bookingId); + } + return this.findById(id); } @@ -5978,6 +5983,36 @@ export class WarehouseInventoryService { return booking ?? {}; } + /** + * Tell the customer their export carriage acceptance sheet is ready to + * download from the portal. Export acceptance happens at the warehouse gate + * (see BookingsService.carriageAcceptanceSheet) — the sheet is generatable + * as soon as the cargo is received, no wagon allocation required, so this + * fires right after receive, not at marshalling. + */ + private async notifyCarriageAcceptanceReady(bookingId: string): Promise { + try { + const [b]: Array<{ companyId: string | null; reference: string }> = await this.dataSource.query( + `SELECT company_id AS "companyId", reference FROM freight.bookings WHERE id = $1 AND deleted_at IS NULL`, + [bookingId], + ); + if (!b?.companyId) return; + const body = `Your carriage acceptance sheet for booking ${b.reference} is ready to download from the portal.`; + await this.inbox.notify({ + recipients: { companyId: b.companyId }, + audience: NotificationAudience.PORTAL, + type: NotificationType.DOCUMENT_ACTION, + title: 'Carriage acceptance sheet ready', + body, + link: `/bookings/${bookingId}`, + data: { bookingId, reference: b.reference }, + }); + await sendCompanyChannels(this.dataSource, this.notifications, b.companyId, body); + } catch (err) { + this.logger.warn(`Carriage acceptance ready notify failed for ${bookingId}: ${(err as Error).message}`); + } + } + private async notifyOwnerInventoryReceived(params: { phone?: string | null; ownerName?: string | null;