From a8bc5b19de5a40ee7539cb5abb7ef6148da2eeee Mon Sep 17 00:00:00 2001 From: Hagernesh Date: Sat, 20 Jun 2026 20:15:26 +0000 Subject: [PATCH] feat(warehouse): fetch all PAID bookings in one call, classified IMPORT/EXPORT by route - eligibleBookings(direction?) now returns all import+export bookings when direction omitted (DOMESTIC excluded); per-direction filter preserved for backward compatibility - GET /warehouse-inventory/eligible-bookings (no query) returns the combined set - Frontend: single shared useEligibleBookings() query; both Receive tabs filter client-side by route-derived direction, so only one HTTP request fires Co-Authored-By: Claude Sonnet 4.6 --- .../warehouses/warehouse-inventory.controller.ts | 7 ++++--- .../warehouses/warehouse-inventory.service.ts | 12 +++++++++--- .../components/warehouses/ReceiveInventoryModal.tsx | 3 ++- .../edr-freight-web/backoffice/src/constants/URLS.ts | 5 ++++- .../backoffice/src/hooks/useWarehouses.ts | 11 ++++++++--- .../backoffice/src/services/warehouse.service.ts | 2 +- 6 files changed, 28 insertions(+), 12 deletions(-) diff --git a/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.controller.ts b/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.controller.ts index 9fb31f11a..2e282d770 100644 --- a/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.controller.ts +++ b/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.controller.ts @@ -61,9 +61,10 @@ export class WarehouseInventoryController { } @Get('eligible-bookings') - @ApiOperation({ summary: 'Eligible PAID bookings for a direction (IMPORT/EXPORT) not yet received' }) - eligibleBookings(@Query('direction') direction: 'IMPORT' | 'EXPORT') { - return this.inventoryService.eligibleBookings(direction === 'EXPORT' ? 'EXPORT' : 'IMPORT'); + @ApiOperation({ summary: 'PAID bookings not yet received, classified IMPORT/EXPORT by route; omit direction for all' }) + eligibleBookings(@Query('direction') direction?: string) { + const dir = direction === 'IMPORT' || direction === 'EXPORT' ? direction : undefined; + return this.inventoryService.eligibleBookings(dir); } @Post('receive-bulk') 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 79cb9dde2..00127c1b9 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 @@ -468,8 +468,12 @@ export class WarehouseInventoryService { // ── Receive (Import/Export bulk) ─────────────────────────────────────────── - /** Eligible PAID bookings for a direction (DERIVED FROM ROUTE) that have NOT been received yet. */ - async eligibleBookings(direction: 'IMPORT' | 'EXPORT'): Promise { + /** + * Eligible PAID bookings that have NOT been received yet, classified IMPORT/EXPORT by route + * (origin/destination yard countries). Pass a direction to filter to one; omit it to return + * all import + export bookings in a single call (DOMESTIC routes are excluded either way). + */ + async eligibleBookings(direction?: 'IMPORT' | 'EXPORT'): Promise { const rows: Array< EligibleBookingRow & { originCountry: string | null; destinationCountry: string | null } > = await this.dataSource.query( @@ -504,7 +508,9 @@ export class WarehouseInventoryService { ...r, direction: deriveTradeDirection({ country: r.originCountry }, { country: r.destinationCountry }), })) - .filter((r) => r.direction === direction); + .filter((r) => + direction ? r.direction === direction : r.direction === 'IMPORT' || r.direction === 'EXPORT', + ); } /** Bulk-receive eligible PAID bookings into a location. Skips duplicates / wrong direction. */ diff --git a/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx b/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx index 9a14cdfb3..52b18d4be 100644 --- a/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx +++ b/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx @@ -135,7 +135,8 @@ function EligibleTab({ onChanged?: () => void; }) { const { toast } = useToast(); - const { data: rows = [], isLoading } = useEligibleBookings(direction, enabled); + const { data: allRows = [], isLoading } = useEligibleBookings(enabled); + const rows = useMemo(() => allRows.filter((r) => r.direction === direction), [allRows, direction]); const bulkReceive = useBulkReceive(); const loadPassed = useLoadPassedExport(); const [selected, setSelected] = useState>(new Set()); diff --git a/apps/edr-freight-web/backoffice/src/constants/URLS.ts b/apps/edr-freight-web/backoffice/src/constants/URLS.ts index c9254c447..3ee96d9c3 100644 --- a/apps/edr-freight-web/backoffice/src/constants/URLS.ts +++ b/apps/edr-freight-web/backoffice/src/constants/URLS.ts @@ -307,7 +307,10 @@ export const URL_CONSTANTS = { RELEASE: (id: string) => `/warehouse-inventory/${id}/release`, DELIVER: (id: string) => `/warehouse-inventory/${id}/deliver`, // Receive (Import/Export bulk) - ELIGIBLE_BOOKINGS: (direction: string) => `/warehouse-inventory/eligible-bookings?direction=${direction}`, + ELIGIBLE_BOOKINGS: (direction?: string) => + direction + ? `/warehouse-inventory/eligible-bookings?direction=${direction}` + : `/warehouse-inventory/eligible-bookings`, RECEIVE_BULK: '/warehouse-inventory/receive-bulk', LOAD_PASSED_EXPORT: '/warehouse-inventory/load-passed-export', BULK_MARK_INSPECTED: '/warehouse-inventory/bulk-mark-inspected', diff --git a/apps/edr-freight-web/backoffice/src/hooks/useWarehouses.ts b/apps/edr-freight-web/backoffice/src/hooks/useWarehouses.ts index 84af0e714..6b625fc33 100644 --- a/apps/edr-freight-web/backoffice/src/hooks/useWarehouses.ts +++ b/apps/edr-freight-web/backoffice/src/hooks/useWarehouses.ts @@ -189,10 +189,15 @@ export const useDeliverInventory = () => ); // ── Receive (Import/Export bulk) ─────────────────────────────────────────── -export function useEligibleBookings(direction: 'IMPORT' | 'EXPORT', enabled = true) { +/** + * All not-yet-received PAID bookings, classified IMPORT/EXPORT by route, in one call. + * Both Receive tabs share this single query (same key) — only one HTTP request fires — + * then filter client-side by direction. + */ +export function useEligibleBookings(enabled = true) { return useQuery({ - queryKey: ['warehouse-inventory', 'eligible-bookings', direction], - queryFn: () => warehouseService.eligibleBookings(direction).then((r) => r.data), + queryKey: ['warehouse-inventory', 'eligible-bookings'], + queryFn: () => warehouseService.eligibleBookings().then((r) => r.data), enabled, }); } diff --git a/apps/edr-freight-web/backoffice/src/services/warehouse.service.ts b/apps/edr-freight-web/backoffice/src/services/warehouse.service.ts index 2a1ccf29f..7769c0969 100644 --- a/apps/edr-freight-web/backoffice/src/services/warehouse.service.ts +++ b/apps/edr-freight-web/backoffice/src/services/warehouse.service.ts @@ -124,7 +124,7 @@ export const warehouseService = { apiClient.post(URL_CONSTANTS.WAREHOUSE_INVENTORY.DELIVER(id), payload), // ── Receive (Import/Export bulk) ───────────────────────────────────────── - eligibleBookings: (direction: 'IMPORT' | 'EXPORT') => + eligibleBookings: (direction?: 'IMPORT' | 'EXPORT') => apiClient.get(URL_CONSTANTS.WAREHOUSE_INVENTORY.ELIGIBLE_BOOKINGS(direction)), receiveBulk: (payload: BulkReceivePayload) => apiClient.post(URL_CONSTANTS.WAREHOUSE_INVENTORY.RECEIVE_BULK, payload),