import type { Freight } from "@edr/types"; import { api as apiClient } from "../auth/http"; export interface Wagon { id: string; wagonNumber: string; wagonTypeId: string; trainId: string | null; sequenceNumber: number | null; currentLocationYardId: string | null; currentLocationYard?: { id: string; code: string; label: string; country?: string; } | null; /** Owns this wagon's spec — tare, capacity, length are read from here, never off the wagon. */ wagonType?: { id: string; code: string; name: string; supportedLoadTypes?: string[]; tareWeightTons?: number; capacityTons?: number; lengthMeters?: number; } | null; status: Freight.WagonStatus; currentYardId: string | null; currentYard?: { id: string; label?: string; code?: string } | null; notes?: string; } export interface WagonListFilters { search?: string; status?: Freight.WagonStatus; currentYardId?: string; wagonTypeId?: string; trainId?: string; } /** * One row of the wagon_movements ledger: every physical relocation between * yards — a booking's loaded leg, an empty reposition ride, or a manual staff * correction. Returned newest first by the API. */ export interface WagonMovementRecord { id: string; wagonId: string; fromYardId: string | null; toYardId: string; fromYard?: { id?: string; label?: string; code?: string } | null; toYard?: { id?: string; label?: string; code?: string } | null; trainScheduleId: string | null; bookingId: string | null; kind: Freight.WagonMovementKind; movedByUserId: string | null; /** The transfer request this move fulfilled, when one drove it. */ transferRequestId: string | null; occurredAt: string; note: string | null; createdAt: string; wagon?: { id: string; wagonNumber?: string } | null; } export const wagonService = { getAll: (filters: WagonListFilters = {}) => { const params = new URLSearchParams(); if (filters.search?.trim()) params.set('search', filters.search.trim()); if (filters.status) params.set('status', filters.status); if (filters.currentYardId) params.set('currentYardId', filters.currentYardId); if (filters.wagonTypeId) params.set('wagonTypeId', filters.wagonTypeId); if (filters.trainId) params.set('trainId', filters.trainId); const qs = params.toString(); return apiClient.get(`/wagons${qs ? `?${qs}` : ''}`); }, getById: (id: string) => apiClient.get(`/wagons/${id}`), getMovements: (id: string) => apiClient.get(`/wagons/${id}/movements`), getByTrain: (trainId: string) => apiClient.get(`/wagons?trainId=${trainId}`), assignToTrain: (wagonId: string, trainId: string, sequenceNumber?: number) => apiClient.post(`/wagons/${wagonId}/assign-train`, { trainId, sequenceNumber }), unassign: (wagonId: string) => apiClient.post(`/wagons/${wagonId}/unassign-train`), reorder: (trainId: string, wagonIds: string[]) => apiClient.post(`/trains/${trainId}/reorder-wagons`, { wagonIds }), create: (data: Partial) => apiClient.post('/wagons', data), update: (id: string, data: Partial) => apiClient.patch(`/wagons/${id}`, data), delete: (id: string) => apiClient.delete(`/wagons/${id}`), /** Relocate many wagons to one yard in a single call (writes movement ledger). */ bulkTransfer: (wagonIds: string[], toYardId: string) => apiClient.post<{ moved: number }>('/wagons/bulk-transfer', { wagonIds, toYardId }), /** Set the same status on many wagons in a single call. */ bulkSetStatus: (wagonIds: string[], status: Freight.WagonStatus) => apiClient.post<{ updated: number }>('/wagons/bulk-status', { wagonIds, status }), }; /** * A two-person wagon-transfer request: a requester asks for N wagons of a type * to move between yards (count only); OCC hand-picks the wagons and fulfils it. */ export interface WagonTransferRequest { id: string; fromYardId: string; toYardId: string; wagonTypeId: string; quantity: number; status: Freight.WagonTransferRequestStatus; requestedByUserId: string | null; fulfilledByUserId: string | null; fulfilledAt: string | null; note: string | null; fromYard?: { id: string; label?: string; code?: string } | null; toYard?: { id: string; label?: string; code?: string } | null; wagonType?: { id: string; code?: string; name?: string } | null; createdAt: string; } export interface CreateTransferRequestPayload { fromYardId: string; toYardId: string; wagonTypeId: string; quantity: number; note?: string; } /** Per-user activity: requests filed/fulfilled + the wagons physically moved. */ export interface TransferHistory { requests: WagonTransferRequest[]; movements: WagonMovementRecord[]; } export const wagonTransferRequestService = { list: (status?: Freight.WagonTransferRequestStatus) => apiClient.get( `/wagon-transfer-requests${status ? `?status=${status}` : ''}`, ), /** The caller's own history (both roles: requests they filed and fulfilled). */ myHistory: () => apiClient.get('/wagon-transfer-requests/history'), /** Admin: any/all staff's history (optional userId filter). */ allHistory: (userId?: string) => apiClient.get( `/wagon-transfer-requests/history/all${userId ? `?userId=${userId}` : ''}`, ), getById: (id: string) => apiClient.get(`/wagon-transfer-requests/${id}`), create: (data: CreateTransferRequestPayload) => apiClient.post('/wagon-transfer-requests', data), /** OCC: execute the transfer with the hand-picked wagons. */ fulfill: (id: string, wagonIds: string[]) => apiClient.post( `/wagon-transfer-requests/${id}/fulfill`, { wagonIds }, ), cancel: (id: string) => apiClient.post( `/wagon-transfer-requests/${id}/cancel`, ), };