feat(warehouse): batch 3 — loading, dispatch & train-departure visibility

- WarehouseLoading entity + Batch3 migration (wagon loading records)
- wagon-aware load() with validation; dispatch moved to PATCH
- read-only SchedulingReadFacade (schedule/wagon/departure) — never writes scheduling
- new endpoints: GET /warehouse-loadings, loadable-wagons, booking schedule
- Loading Queue / Loaded Inventory / Dispatch Queue pages + routes + sidebar
- FreightVisual illustrations (page heroes + empty states)
- booking detail: loaded/dispatched/wagon + read-only train schedule

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hagernesh
2026-06-12 12:44:40 +00:00
parent 72e2e3c985
commit 95c6a71438
27 changed files with 1193 additions and 30 deletions

View File

@@ -2,10 +2,13 @@ import { api as apiClient } from '../auth/http';
import { URL_CONSTANTS } from '@/constants/URLS';
import type {
BookingScheduleView,
InventoryFilter,
InventoryInquiryFilter,
InventoryInquiryResult,
InventoryMovement,
LoadableWagon,
LoadInventoryPayload,
MoveInventoryPayload,
ReceiveInventoryPayload,
ReserveInventoryPayload,
@@ -17,6 +20,7 @@ import type {
WarehouseDashboard,
WarehouseFilter,
WarehouseInventoryItem,
WarehouseLoading,
WarehouseYard,
WarehouseZone,
} from '@/types/warehouse';
@@ -80,14 +84,26 @@ export const warehouseService = {
apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.RESERVE, payload),
markReadyForLoading: (id: string) =>
apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.MARK_READY(id)),
load: (id: string) =>
apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.LOAD(id)),
load: (id: string, payload: LoadInventoryPayload) =>
apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.LOAD(id), payload),
dispatch: (id: string) =>
apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.DISPATCH(id)),
apiClient.patch<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.DISPATCH(id)),
move: (id: string, payload: MoveInventoryPayload) =>
apiClient.post<WarehouseInventoryItem>(URL_CONSTANTS.WAREHOUSE_INVENTORY.MOVE(id), payload),
movements: (id: string) =>
apiClient.get<InventoryMovement[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.MOVEMENTS(id)),
activity: (id: string) =>
apiClient.get<WarehouseActivityLog[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.ACTIVITY(id)),
// ── Loading (Batch 3) ─────────────────────────────────────────────────────
loadableWagons: () =>
apiClient.get<LoadableWagon[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.LOADABLE_WAGONS),
bookingSchedule: (bookingId: string) =>
apiClient.get<BookingScheduleView>(URL_CONSTANTS.WAREHOUSE_INVENTORY.BOOKING_SCHEDULE(bookingId)),
inventoryLoadings: (id: string) =>
apiClient.get<WarehouseLoading[]>(URL_CONSTANTS.WAREHOUSE_INVENTORY.LOADINGS(id)),
loadings: (params?: { bookingId?: string; wagonId?: string }) =>
apiClient.get<WarehouseLoading[]>(URL_CONSTANTS.WAREHOUSE_LOADINGS.BASE, {
params: cleanParams(params ?? {}),
}),
};