import { beforeEach, describe, expect, it, vi } from 'vitest' import { http } from '@/shared/api/http' import { getTerminalDrayageHistory, listTerminalDrayages, recordTerminalDrayageEmptyReturn, recordTerminalDrayagePickup, scheduleTerminalDrayagePickup, selectTerminalDrayageFleet, } from './terminalDrayages' vi.mock('@/shared/api/http', () => ({ http: { get: vi.fn(), post: vi.fn() }, unwrapApiResponse: (response: { data: T }) => response.data, })) const view = { containerBookingId: '9007199254740993', containerNo: 'MSCU1234567', oceanBookingId: '9007199254740994', status: 'UNLOADED', version: '3', fleetSupplierId: '9007199254740995', fleetSupplierName: '港运车队', pickupAppointmentAt: '2026-09-07T08:00:00', actualPickupAt: '2026-09-07T09:00:00', estimatedEmptyReturnAt: '2026-09-10T10:00:00', actualEmptyReturnAt: null, unloadingCompletedAt: '2026-09-07T10:00:00', emptyReturnWarning: { status: 'OVERDUE', deadlineAt: '2026-09-10T10:00:00', overdueHours: '26', overdueDays: '1' }, allowedActions: ['SELECT_FLEET', 'RECORD_EMPTY_RETURN'], updatedAt: '2026-09-11T12:00:00', } describe('terminal drayages API', () => { beforeEach(() => vi.clearAllMocks()) it('sends repeated container ids and preserves long identifiers as strings', async () => { vi.mocked(http.get).mockResolvedValueOnce({ data: [view] }) const result = await listTerminalDrayages(['9007199254740993', '9007199254740994']) const config = vi.mocked(http.get).mock.calls[0][1] as { params: URLSearchParams } expect(config.params.getAll('containerBookingIds')).toEqual(['9007199254740993', '9007199254740994']) expect(result[0]).toMatchObject({ containerBookingId: '9007199254740993', oceanBookingId: '9007199254740994', fleetSupplierId: '9007199254740995', version: 3 }) expect(result[0].emptyReturnWarning).toMatchObject({ overdueHours: 26, overdueDays: 1 }) }) it('uses frozen command paths, versions and idempotency keys', async () => { vi.mocked(http.post).mockResolvedValue({ data: view }) await selectTerminalDrayageFleet('101', { expectedVersion: 3, fleetSupplierId: '501', fleetSupplierName: '港运车队' }) await scheduleTerminalDrayagePickup('101', { expectedVersion: 4, pickupAppointmentAt: '2026-09-07T08:00:00' }) await recordTerminalDrayagePickup('101', { expectedVersion: 5, actualAt: '2026-09-07T09:00:00', remark: '实际提柜' }) await recordTerminalDrayageEmptyReturn('101', { expectedVersion: 6, actualAt: '2026-09-10T09:00:00', remark: '实际还柜' }) expect(http.post).toHaveBeenNthCalledWith(1, '/platform/v1/terminal-drayages/101/fleet', expect.objectContaining({ expectedVersion: 3, fleetSupplierId: '501' }), expect.objectContaining({ headers: { 'Idempotency-Key': expect.stringContaining('terminal-drayage-fleet-') } })) expect(http.post).toHaveBeenNthCalledWith(2, '/platform/v1/terminal-drayages/101/pickup-appointment', expect.objectContaining({ expectedVersion: 4 }), expect.any(Object)) expect(http.post).toHaveBeenNthCalledWith(3, '/platform/v1/terminal-drayages/101/pickup', expect.objectContaining({ expectedVersion: 5, remark: '实际提柜' }), expect.objectContaining({ headers: { 'Idempotency-Key': expect.stringContaining('terminal-drayage-pickup-') } })) expect(http.post).toHaveBeenNthCalledWith(4, '/platform/v1/terminal-drayages/101/empty-return', expect.objectContaining({ expectedVersion: 6, remark: '实际还柜' }), expect.objectContaining({ headers: { 'Idempotency-Key': expect.stringContaining('terminal-drayage-empty-return-') } })) }) it('loads operation history from the container business id', async () => { vi.mocked(http.get).mockResolvedValueOnce({ data: [{ action: 'SELECT_FLEET', fromStatus: 'ARRIVED', toStatus: 'ARRIVED', fromVersion: 0, toVersion: 1, reason: null, operatorId: '9007199254740993', operatorName: '平台管理员', createdAt: '2026-09-07T08:00:00' }] }) const result = await getTerminalDrayageHistory('101') expect(http.get).toHaveBeenCalledWith('/platform/v1/terminal-drayages/101/history') expect(result[0].operatorId).toBe('9007199254740993') }) })