fix(admin): allow manual container nodes without tracking

This commit is contained in:
2026-09-10 12:17:54 +08:00
parent e3b2552d8d
commit 20e4da5bb5
7 changed files with 75 additions and 85 deletions
@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { http } from '@/shared/api/http'
import { appendCarrierScheduleManualNode, ensureCarrierScheduleQueryForContainer, getCarrierScheduleQuery, listCarrierScheduleQueries } from './platformCarrierScheduleQueries'
import { appendCarrierScheduleManualNode, getCarrierScheduleQuery, listCarrierScheduleQueries } from './platformCarrierScheduleQueries'
vi.mock('@/shared/api/http', async () => {
const actual = await vi.importActual<typeof import('@/shared/api/http')>('@/shared/api/http')
@@ -62,10 +62,4 @@ describe('platformCarrierScheduleQueries', () => {
expect(vi.mocked(http.post)).toHaveBeenCalledWith('/platform/v1/carrier-schedule-queries/9007199254740993/manual-nodes', request, { headers: { 'Idempotency-Key': 'manual-session-key' } })
})
it('ensures a missing departed-container task before manual entry', async () => {
const detail = { query: { query: { ...query, customerId: 0 }, expired: false }, nodes: [], exceptions: [], histories: [] }
vi.mocked(http.post).mockResolvedValue({ code: '200', data: detail })
await expect(ensureCarrierScheduleQueryForContainer('303', 'ensure-key')).resolves.toMatchObject({ query: { query: { customerId: '0', containerBookingId: '303' } } })
expect(vi.mocked(http.post)).toHaveBeenCalledWith('/platform/v1/carrier-schedule-queries/containers/303/ensure', null, { headers: { 'Idempotency-Key': 'ensure-key' } })
})
})
@@ -56,16 +56,6 @@ export async function getCarrierScheduleQuery(queryId: string): Promise<CarrierS
return { ...result, query: view(result.query), nodes: (result.nodes || []).map(node), exceptions: (result.exceptions || []).map(exception), histories: (result.histories || []).map(history) }
}
export async function ensureCarrierScheduleQueryForContainer(containerBookingId: string, idempotencyKey: string): Promise<CarrierScheduleQueryDetail> {
const response = await http.post<ApiEnvelope<CarrierScheduleQueryDetail>, ApiEnvelope<CarrierScheduleQueryDetail>>(
`${basePath}/containers/${encodeURIComponent(containerBookingId)}/ensure`,
null,
{ headers: { 'Idempotency-Key': idempotencyKey } },
)
const result = unwrapApiResponse(response)
return { ...result, query: view(result.query), nodes: (result.nodes || []).map(node), exceptions: (result.exceptions || []).map(exception), histories: (result.histories || []).map(history) }
}
export async function appendCarrierScheduleManualNode(queryId: string, idempotencyKey: string, request: CarrierScheduleManualNodeRequest): Promise<CarrierScheduleQueryDetail> {
const response = await http.post<ApiEnvelope<CarrierScheduleQueryDetail>, ApiEnvelope<CarrierScheduleQueryDetail>>(
`${basePath}/${encodeURIComponent(queryId)}/manual-nodes`,
@@ -0,0 +1,18 @@
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
import type { ContainerManualNodeRequest, ContainerShippingNodeDetail } from '../types'
const basePath = '/platform/v1/container-shipping-nodes'
function normalize(raw: ContainerShippingNodeDetail): ContainerShippingNodeDetail {
return { ...raw, containerBookingId: String(raw.containerBookingId), nodes: (raw.nodes || []).map((item) => ({ ...item, id: String(item.id), nodeSequence: Number(item.nodeSequence) })) }
}
export async function getContainerShippingNodes(containerBookingId: string): Promise<ContainerShippingNodeDetail> {
const response = await http.get<ApiEnvelope<ContainerShippingNodeDetail>, ApiEnvelope<ContainerShippingNodeDetail>>(`${basePath}/${encodeURIComponent(containerBookingId)}`)
return normalize(unwrapApiResponse(response))
}
export async function appendContainerShippingNode(containerBookingId: string, idempotencyKey: string, request: ContainerManualNodeRequest): Promise<ContainerShippingNodeDetail> {
const response = await http.post<ApiEnvelope<ContainerShippingNodeDetail>, ApiEnvelope<ContainerShippingNodeDetail>>(`${basePath}/${encodeURIComponent(containerBookingId)}`, request, { headers: { 'Idempotency-Key': idempotencyKey } })
return normalize(unwrapApiResponse(response))
}