feat(admin): add simulated container booking links

This commit is contained in:
2026-08-14 20:59:19 +08:00
parent 1540b80c89
commit 086b4304c6
11 changed files with 235 additions and 48 deletions
@@ -6,6 +6,7 @@ import {
getContainerClearance, uploadContainerClearance, completeContainerClearance,
getContainerOverview, markContainerException, cancelContainerException, uploadContainerDocument, downloadContainerDocument, downloadContainerPdaPhoto,
getCustomerContainerTransitSummary,
createContainerSimulation, linkContainerOceanBooking, unlinkContainerOceanBooking,
updateContainer, updateContainerTransport,
} from './platformContainerLoading'
@@ -46,6 +47,17 @@ describe('platform container loading API', () => {
expect(http.patch).toHaveBeenCalledWith('/platform/v1/containers/7/transport', { version: 3, containerNo: 'MSCU1', voyageNo: 'V8' })
})
it('uses the frozen simulation create and ocean booking link contracts', async () => {
vi.mocked(http.post).mockResolvedValue({ code: '200', data: { ...container, oceanBookingId: 101, oceanBookingRequirementId: 202 } })
vi.mocked(http.delete).mockResolvedValue({ code: '200', data: { ...container, oceanBookingId: null, oceanBookingRequirementId: null } })
await createContainerSimulation({ channelCode: 'NY_EXX', warehouseId: '8', containerType: '40HQ', capacityCbm: 68, maxWeightKg: 28000 })
await linkContainerOceanBooking('7', { oceanBookingId: '101', requirementId: '202', expectedVersion: 3 })
await unlinkContainerOceanBooking('7', 4, '空柜改配')
expect(http.post).toHaveBeenNthCalledWith(1, '/platform/v1/containers', { channelCode: 'NY_EXX', warehouseId: '8', containerType: '40HQ', capacityCbm: 68, maxWeightKg: 28000 })
expect(http.post).toHaveBeenNthCalledWith(2, '/platform/v1/containers/7/ocean-booking-link', { oceanBookingId: '101', requirementId: '202', expectedVersion: 3 })
expect(http.delete).toHaveBeenCalledWith('/platform/v1/containers/7/ocean-booking-link', { data: { expectedVersion: 4, reason: '空柜改配' } })
})
it('normalizes every long id in candidates and plans', async () => {
vi.mocked(http.get)
.mockResolvedValueOnce({ code: '200', data: container })
@@ -13,6 +13,8 @@ import type {
ContainerPage,
ContainerQuery,
ContainerSaveRequest,
ContainerSimulationCreateRequest,
ContainerOceanBookingLinkRequest,
SmartLoadingCandidate,
SmartLoadingItem,
SmartLoadingPlan,
@@ -68,6 +70,9 @@ function container(raw: ContainerBookingResource): ContainerBookingResource {
id: id(raw.id),
planId: optionalId(raw.planId),
warehouseId: id(raw.warehouseId),
oceanBookingId: optionalId(raw.oceanBookingId),
oceanBookingRequirementId: optionalId(raw.oceanBookingRequirementId),
customerId: optionalId(raw.customerId),
shippingCompanyId: optionalId(raw.shippingCompanyId),
version: numberValue(raw.version),
capacityCbm: raw.capacityCbm == null ? null : numberValue(raw.capacityCbm),
@@ -149,11 +154,21 @@ export function downloadContainerPdaPhoto(downloadPath: string) {
return http.get<Blob, Blob>(downloadPath, { responseType: 'blob' })
}
export async function createContainer(payload: ContainerSaveRequest) {
export async function createContainerSimulation(payload: ContainerSimulationCreateRequest) {
const response = await http.post<ApiEnvelope<ContainerBookingResource>, ApiEnvelope<ContainerBookingResource>>(containerPath, payload)
return container(unwrapApiResponse(response))
}
export async function linkContainerOceanBooking(containerId: string, payload: ContainerOceanBookingLinkRequest) {
const response = await http.post<ApiEnvelope<ContainerBookingResource>, ApiEnvelope<ContainerBookingResource>>(`${containerPath}/${encodeURIComponent(containerId)}/ocean-booking-link`, payload)
return container(unwrapApiResponse(response))
}
export async function unlinkContainerOceanBooking(containerId: string, expectedVersion: number, reason: string) {
const response = await http.delete<ApiEnvelope<ContainerBookingResource>, ApiEnvelope<ContainerBookingResource>>(`${containerPath}/${encodeURIComponent(containerId)}/ocean-booking-link`, { data: { expectedVersion, reason } })
return container(unwrapApiResponse(response))
}
export async function updateContainer(containerId: string, version: number, data: ContainerSaveRequest) {
const response = await http.put<ApiEnvelope<ContainerBookingResource>, ApiEnvelope<ContainerBookingResource>>(`${containerPath}/${encodeURIComponent(containerId)}`, { version, data })
return container(unwrapApiResponse(response))