优化
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { http } from '@/shared/api/http'
|
||||
import { getCarrierScheduleQuery, listCarrierScheduleQueries } from './platformCarrierScheduleQueries'
|
||||
|
||||
vi.mock('@/shared/api/http', async () => {
|
||||
const actual = await vi.importActual<typeof import('@/shared/api/http')>('@/shared/api/http')
|
||||
return { ...actual, http: { get: vi.fn() } }
|
||||
})
|
||||
|
||||
const query = {
|
||||
id: 9007199254740993n,
|
||||
queryNo: 'CSQ-1',
|
||||
customerId: 101,
|
||||
oceanBookingId: 202,
|
||||
containerBookingId: 303,
|
||||
carrierCode: 'COSCO',
|
||||
trackingType: 'CONTAINER_NO',
|
||||
trackingNo: 'CSNU1234567',
|
||||
status: 'MANUAL_REQUIRED',
|
||||
attemptCount: '2',
|
||||
resultPortScheduleId: 404,
|
||||
version: '3',
|
||||
}
|
||||
|
||||
describe('platformCarrierScheduleQueries', () => {
|
||||
beforeEach(() => vi.clearAllMocks())
|
||||
|
||||
it('filters by real booking/container relations and preserves long ids as strings', async () => {
|
||||
vi.mocked(http.get).mockResolvedValue({ code: '200', data: { records: [{ query, expired: true, maxAttempts: '3', nextAllowedAt: null }], page: '1', size: '200', total: '1', pages: '1' } })
|
||||
const result = await listCarrierScheduleQueries({ page: 1, size: 200, oceanBookingId: '202', containerBookingId: '303' })
|
||||
expect(vi.mocked(http.get)).toHaveBeenCalledWith('/platform/v1/carrier-schedule-queries', { params: { page: 1, size: 200, oceanBookingId: '202', containerBookingId: '303' } })
|
||||
expect(result.records[0]).toMatchObject({ query: { id: '9007199254740993', customerId: '101', oceanBookingId: '202', containerBookingId: '303', resultPortScheduleId: '404', attemptCount: 2, version: 3 }, expired: true, maxAttempts: 3 })
|
||||
})
|
||||
|
||||
it('normalizes attempts and immutable history without creating query operations', async () => {
|
||||
vi.mocked(http.get).mockResolvedValue({ code: '200', data: { query: { query, expired: false, maxAttempts: 3 }, attempts: [{ id: 1, queryId: query.id, windowAttemptNo: '2', carrierCode: 'COSCO', attemptStatus: 'FAILED', coverageGap: true }], histories: [{ id: 2, queryId: query.id, action: 'ATTEMPT', fromVersion: '1', toVersion: '2' }] } })
|
||||
const result = await getCarrierScheduleQuery('9007199254740993')
|
||||
expect(vi.mocked(http.get)).toHaveBeenCalledWith('/platform/v1/carrier-schedule-queries/9007199254740993')
|
||||
expect(result.attempts[0]).toMatchObject({ id: '1', queryId: '9007199254740993', windowAttemptNo: 2, attemptStatus: 'FAILED' })
|
||||
expect(result.histories[0]).toMatchObject({ id: '2', fromVersion: 1, toVersion: 2 })
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,52 @@
|
||||
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
|
||||
import type {
|
||||
CarrierScheduleQueryAttempt,
|
||||
CarrierScheduleQueryDetail,
|
||||
CarrierScheduleQueryFilter,
|
||||
CarrierScheduleQueryHistory,
|
||||
CarrierScheduleQueryPage,
|
||||
CarrierScheduleQueryResource,
|
||||
CarrierScheduleQueryView,
|
||||
} from '../types'
|
||||
|
||||
const basePath = '/platform/v1/carrier-schedule-queries'
|
||||
|
||||
function optionalId(value: unknown): string | null { return value == null ? null : String(value) }
|
||||
function numberValue(value: unknown, fallback = 0): number { const parsed = Number(value); return Number.isFinite(parsed) ? parsed : fallback }
|
||||
|
||||
function resource(raw: CarrierScheduleQueryResource): CarrierScheduleQueryResource {
|
||||
return {
|
||||
...raw,
|
||||
id: String(raw.id),
|
||||
customerId: String(raw.customerId),
|
||||
oceanBookingId: String(raw.oceanBookingId),
|
||||
containerBookingId: optionalId(raw.containerBookingId),
|
||||
resultPortScheduleId: optionalId(raw.resultPortScheduleId),
|
||||
attemptCount: numberValue(raw.attemptCount),
|
||||
version: numberValue(raw.version),
|
||||
}
|
||||
}
|
||||
|
||||
function view(raw: CarrierScheduleQueryView): CarrierScheduleQueryView {
|
||||
return { ...raw, query: resource(raw.query), maxAttempts: numberValue(raw.maxAttempts), nextAllowedAt: raw.nextAllowedAt ?? raw.query.nextAllowedAt ?? null }
|
||||
}
|
||||
|
||||
function attempt(raw: CarrierScheduleQueryAttempt): CarrierScheduleQueryAttempt {
|
||||
return { ...raw, id: String(raw.id), queryId: String(raw.queryId), windowAttemptNo: numberValue(raw.windowAttemptNo), coverageGap: Boolean(raw.coverageGap) }
|
||||
}
|
||||
|
||||
function history(raw: CarrierScheduleQueryHistory): CarrierScheduleQueryHistory {
|
||||
return { ...raw, id: String(raw.id), queryId: String(raw.queryId), fromVersion: raw.fromVersion == null ? null : numberValue(raw.fromVersion), toVersion: raw.toVersion == null ? null : numberValue(raw.toVersion) }
|
||||
}
|
||||
|
||||
export async function listCarrierScheduleQueries(filter: CarrierScheduleQueryFilter): Promise<CarrierScheduleQueryPage> {
|
||||
const response = await http.get<ApiEnvelope<CarrierScheduleQueryPage>, ApiEnvelope<CarrierScheduleQueryPage>>(basePath, { params: filter })
|
||||
const result = unwrapApiResponse(response)
|
||||
return { ...result, records: (result.records || []).map(view), page: numberValue(result.page, filter.page), size: numberValue(result.size, filter.size), total: numberValue(result.total), pages: numberValue(result.pages) }
|
||||
}
|
||||
|
||||
export async function getCarrierScheduleQuery(queryId: string): Promise<CarrierScheduleQueryDetail> {
|
||||
const response = await http.get<ApiEnvelope<CarrierScheduleQueryDetail>, ApiEnvelope<CarrierScheduleQueryDetail>>(`${basePath}/${encodeURIComponent(queryId)}`)
|
||||
const result = unwrapApiResponse(response)
|
||||
return { ...result, query: view(result.query), attempts: (result.attempts || []).map(attempt), histories: (result.histories || []).map(history) }
|
||||
}
|
||||
Reference in New Issue
Block a user