优化
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { http } from '@/shared/api/http'
|
||||
import { changeTruckAppointmentStatus, createTruckAppointment, getTruckAppointment, listTruckAppointments } from './platformTrucking'
|
||||
|
||||
vi.mock('@/shared/api/http', () => ({ http: { get: vi.fn(), post: vi.fn(), put: vi.fn(), patch: vi.fn() }, unwrapApiResponse: (response: { data: unknown }) => response.data }))
|
||||
|
||||
describe('truck appointment API', () => {
|
||||
beforeEach(() => { vi.clearAllMocks() })
|
||||
|
||||
it('normalizes page values and maps filters', async () => {
|
||||
vi.mocked(http.get).mockResolvedValue({ data: { records: [], page: '2', size: '20', total: '21', pages: '2' } })
|
||||
await expect(listTruckAppointments({ page: 2, size: 20, keyword: ' BY ', status: 'DISPATCHED', containerType: '40HC' })).resolves.toMatchObject({ page: 2, total: 21, pages: 2 })
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/truck-appointments', { params: { page: 2, size: 20, keyword: 'BY', status: 'DISPATCHED', containerType: '40HC' } })
|
||||
})
|
||||
|
||||
it('uses detail, create, and status contracts', async () => {
|
||||
vi.mocked(http.get).mockResolvedValue({ data: { id: '9001', status: 'DRAFT' } })
|
||||
vi.mocked(http.post).mockResolvedValue({ data: '9001' })
|
||||
vi.mocked(http.patch).mockResolvedValue({ data: null })
|
||||
await expect(getTruckAppointment('9001')).resolves.toMatchObject({ id: '9001' })
|
||||
await expect(createTruckAppointment({ expectedLoadingDate: '2026-08-10' })).resolves.toBe('9001')
|
||||
await expect(changeTruckAppointmentStatus('9001', 'DISPATCHED')).resolves.toBeNull()
|
||||
expect(http.patch).toHaveBeenCalledWith('/platform/v1/truck-appointments/9001/status', { status: 'DISPATCHED' })
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,84 @@
|
||||
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
|
||||
import type {
|
||||
SaveTruckAppointmentRequest,
|
||||
TruckAppointmentPage,
|
||||
TruckAppointmentQuery,
|
||||
TruckAppointmentResource,
|
||||
} from '../types'
|
||||
|
||||
const basePath = '/platform/v1/truck-appointments'
|
||||
function dtoPayload(payload: SaveTruckAppointmentRequest) {
|
||||
const { attachmentRefs: _attachmentRefs, ...dto } = payload
|
||||
return dto
|
||||
}
|
||||
|
||||
type PagePayload = Omit<TruckAppointmentPage, 'page' | 'size' | 'total' | 'pages'> & {
|
||||
page: number | string
|
||||
size: number | string
|
||||
total: number | string
|
||||
pages?: number | string
|
||||
}
|
||||
|
||||
function normalizePage(payload: PagePayload): TruckAppointmentPage {
|
||||
const page = Number(payload.page || 1)
|
||||
const size = Number(payload.size || 20)
|
||||
const total = Number(payload.total || 0)
|
||||
return { records: (payload.records || []).map(normalizeResource), page, size, total, pages: Number(payload.pages || Math.max(Math.ceil(total / size), 1)) }
|
||||
}
|
||||
|
||||
function normalizeResource(resource: TruckAppointmentResource): TruckAppointmentResource {
|
||||
const idKeys = ['id', 'outboundOrderId', 'oceanBookingId', 'containerBookingId', 'loadingPlanId', 'warehouseId', 'customerId', 'carrierId']
|
||||
const normalized = { ...resource } as Record<string, unknown>
|
||||
for (const key of idKeys) {
|
||||
if (normalized[key] !== null && normalized[key] !== undefined) normalized[key] = String(normalized[key])
|
||||
}
|
||||
return normalized as unknown as TruckAppointmentResource
|
||||
}
|
||||
|
||||
export async function listTruckAppointments(query: TruckAppointmentQuery = {}) {
|
||||
const response = await http.get<ApiEnvelope<PagePayload>, ApiEnvelope<PagePayload>>(basePath, {
|
||||
params: {
|
||||
...query,
|
||||
keyword: query.keyword?.trim() || undefined,
|
||||
status: query.status || undefined,
|
||||
containerBookingId: query.containerBookingId || undefined,
|
||||
},
|
||||
})
|
||||
return normalizePage(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export async function getTruckAppointment(id: string | number) {
|
||||
const response = await http.get<ApiEnvelope<TruckAppointmentResource>, ApiEnvelope<TruckAppointmentResource>>(`${basePath}/${id}`)
|
||||
return normalizeResource(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export async function createTruckAppointment(payload: SaveTruckAppointmentRequest) {
|
||||
const response = await http.post<ApiEnvelope<TruckAppointmentResource>, ApiEnvelope<TruckAppointmentResource>>(basePath, dtoPayload(payload))
|
||||
return normalizeResource(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export async function updateTruckAppointment(id: string | number, payload: SaveTruckAppointmentRequest) {
|
||||
const response = await http.put<ApiEnvelope<TruckAppointmentResource>, ApiEnvelope<TruckAppointmentResource>>(`${basePath}/${id}`, dtoPayload(payload))
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export type TruckAppointmentAction = 'SUBMIT' | 'DISPATCH' | 'PICKUP' | 'ARRIVE' | 'LOAD' | 'DEPART' | 'COMPLETE' | 'EXCEPTION' | 'CANCEL'
|
||||
|
||||
export async function performTruckAppointmentAction(
|
||||
id: string | number,
|
||||
action: TruckAppointmentAction,
|
||||
expectedVersion: number,
|
||||
reason?: string,
|
||||
idempotencyKey?: string,
|
||||
requestHash?: string,
|
||||
) {
|
||||
const response = await http.post<ApiEnvelope<TruckAppointmentResource>, ApiEnvelope<TruckAppointmentResource>>(`${basePath}/${id}/${action.toLowerCase()}`, { expectedVersion, reason: reason || null }, {
|
||||
headers: { ...(idempotencyKey ? { 'Idempotency-Key': idempotencyKey } : {}), ...(requestHash ? { 'X-Request-Hash': requestHash } : {}) },
|
||||
})
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function rescheduleTruckAppointment(id: string | number, plannedLoadingAt: string, expectedVersion: number, reason?: string) {
|
||||
const response = await http.post<ApiEnvelope<TruckAppointmentResource>, ApiEnvelope<TruckAppointmentResource>>(`${basePath}/${id}/reschedule`, { expectedVersion, reason: reason || null }, { params: { plannedLoadingAt } })
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
Reference in New Issue
Block a user