feat(admin): remove customer from truck appointments

This commit is contained in:
2026-08-31 21:05:03 +08:00
parent 49babd731a
commit 66c6dfdadc
14 changed files with 234 additions and 51 deletions
@@ -18,12 +18,21 @@ describe('truck appointment API', () => {
vi.mocked(http.post).mockResolvedValue({ data: '9001' })
vi.mocked(http.post).mockResolvedValue({ data: { id: '9001', status: 'DISPATCHED' } })
await expect(getTruckAppointment('9001')).resolves.toMatchObject({ id: '9001' })
await expect(createTruckAppointment({ customerId: '100', carrierId: '200', oceanBookingId: '300', containerBookingId: '400', loadingPlanId: null, plannedLoadingAt: '2026-08-10T10:00:00', expectedVersion: 0 })).resolves.toMatchObject({ id: '9001' })
expect(http.post).toHaveBeenNthCalledWith(1, '/platform/v1/truck-appointments', { customerId: '100', carrierId: '200', oceanBookingId: '300', containerBookingId: '400', loadingPlanId: null, plannedLoadingAt: '2026-08-10T10:00:00', expectedVersion: 0 })
await expect(createTruckAppointment({ carrierId: '200', oceanBookingId: '300', containerBookingId: '400', loadingPlanId: null, plannedLoadingAt: '2026-08-10T10:00:00', expectedVersion: 0 })).resolves.toMatchObject({ id: '9001' })
expect(http.post).toHaveBeenNthCalledWith(1, '/platform/v1/truck-appointments', { carrierId: '200', oceanBookingId: '300', containerBookingId: '400', loadingPlanId: null, plannedLoadingAt: '2026-08-10T10:00:00', expectedVersion: 0 })
await expect(performTruckAppointmentAction('9001', 'DISPATCH', 2)).resolves.toMatchObject({ status: 'DISPATCHED' })
expect(http.post).toHaveBeenCalledWith('/platform/v1/truck-appointments/9001/dispatch', { expectedVersion: 2, reason: null }, { headers: { 'Idempotency-Key': expect.stringContaining('truck-appointment-dispatch-9001-') } })
})
it('drops legacy customer fields instead of forwarding hidden compatibility data', async () => {
vi.mocked(http.post).mockResolvedValueOnce({ data: { id: '9001', status: 'DRAFT', attachmentCount: 0 } })
const payload = { carrierId: '200', oceanBookingId: '300', containerBookingId: '400', plannedLoadingAt: '2026-08-10T10:00:00', expectedVersion: 0, customerId: 'legacy-customer', customerName: '旧客户快照' }
await createTruckAppointment(payload as never)
expect(http.post).toHaveBeenCalledWith('/platform/v1/truck-appointments', {
carrierId: '200', oceanBookingId: '300', containerBookingId: '400', plannedLoadingAt: '2026-08-10T10:00:00', expectedVersion: 0,
})
})
it('sends the required idempotency header for rescheduling', async () => {
vi.mocked(http.post).mockResolvedValue({ data: { id: '9001', status: 'RESCHEDULED' } })
await expect(rescheduleTruckAppointment('9001', '2026-08-20T10:00:00', 2, '调整时间')).resolves.toMatchObject({ status: 'RESCHEDULED' })
+6 -2
View File
@@ -1,4 +1,5 @@
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
import { TRUCK_APPOINTMENT_SAVE_FIELDS } from '../types'
import type {
SaveTruckAppointmentRequest,
TruckAppointmentPage,
@@ -15,7 +16,10 @@ function operationId(action: string, id: string | number) {
}
function dtoPayload(payload: SaveTruckAppointmentRequest) {
return Object.fromEntries(Object.entries(payload).map(([key, value]) => [key, value === '' ? null : value])) as SaveTruckAppointmentRequest
return Object.fromEntries(TRUCK_APPOINTMENT_SAVE_FIELDS.flatMap((key) => {
const value = payload[key]
return value === undefined ? [] : [[key, value === '' ? null : value]]
})) as unknown as SaveTruckAppointmentRequest
}
type PagePayload = Omit<TruckAppointmentPage, 'page' | 'size' | 'total' | 'pages'> & {
@@ -33,7 +37,7 @@ function normalizePage(payload: PagePayload): TruckAppointmentPage {
}
function normalizeResource(resource: TruckAppointmentResource): TruckAppointmentResource {
const idKeys = ['id', 'outboundOrderId', 'oceanBookingId', 'containerBookingId', 'loadingPlanId', 'warehouseId', 'customerId', 'shippingCompanyId', 'bookingAgentId', 'carrierId']
const idKeys = ['id', 'outboundOrderId', 'oceanBookingId', 'containerBookingId', 'loadingPlanId', 'warehouseId', 'shippingCompanyId', 'bookingAgentId', '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])