优化
This commit is contained in:
@@ -1,29 +1,29 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { overseasHttp } from '@/shared/api/overseasHttp'
|
||||
import { http } from '@/shared/api/http'
|
||||
import { changeContainerReceivingWarehouse, convertLastMileContainerToInboundPlans, createManualInboundPlan, downloadLastMileOrders, getContainerPlanProgress, getLastMileOrder, getLastMileOrderManualNodes, listContainerPlanProgress, listLastMileOrders, transferLastMileOrders, updateLastMileOrderHold, updateLastMileOrderManualNodes } from './lastMileOrders'
|
||||
|
||||
vi.mock('@/shared/api/overseasHttp', () => ({ overseasHttp: { get: vi.fn(), put: vi.fn(), post: vi.fn() } }))
|
||||
vi.mock('@/shared/api/http', async (importOriginal) => ({ ...(await importOriginal<typeof import('@/shared/api/http')>()), http: { get: vi.fn(), put: vi.fn(), post: vi.fn() } }))
|
||||
|
||||
describe('last-mile order overseas API', () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(overseasHttp.get).mockReset()
|
||||
vi.mocked(overseasHttp.put).mockReset()
|
||||
vi.mocked(overseasHttp.post).mockReset()
|
||||
vi.mocked(http.get).mockReset()
|
||||
vi.mocked(http.put).mockReset()
|
||||
vi.mocked(http.post).mockReset()
|
||||
})
|
||||
|
||||
it('loads all platform orders without a customer scope', async () => {
|
||||
const record = { id: '190000000000000099', customerId: '190000000000000001', sourceContainerBookingId: '190000000000000088', customerName: '华远贸易', orderNo: 'LMO-260827-0001' }
|
||||
vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', message: 'success', data: { records: [record], page: '2', size: '20', total: '1', pages: '1' } })
|
||||
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: { records: [record], page: '2', size: '20', total: '1', pages: '1' } })
|
||||
await expect(listLastMileOrders({ page: 2, size: 20, orderType: 'FIRST_LEG', currentStatus: 'PENDING_ASSIGNMENT', warehouse: 'LAX' })).resolves.toEqual({ records: [record], page: 2, size: 20, total: 1, pages: 1 })
|
||||
expect(overseasHttp.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders', {
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders', {
|
||||
params: { page: 2, size: 20, orderType: 'FIRST_LEG', currentStatus: 'PENDING_ASSIGNMENT', warehouse: 'LAX' },
|
||||
})
|
||||
})
|
||||
|
||||
it('preserves a long order id as a string in the detail path', async () => {
|
||||
vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', message: 'success', data: { order: { id: '190000000000000099' }, cargo: [], statusHistory: [] } })
|
||||
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: { order: { id: '190000000000000099' }, cargo: [], statusHistory: [] } })
|
||||
await getLastMileOrder('190000000000000099')
|
||||
expect(overseasHttp.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders/190000000000000099')
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders/190000000000000099')
|
||||
})
|
||||
|
||||
it('does not call outbound or delivery endpoints', () => {
|
||||
@@ -32,43 +32,43 @@ describe('last-mile order overseas API', () => {
|
||||
})
|
||||
|
||||
it('passes all supported list filters and pagination without customerId', async () => {
|
||||
vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', message: 'success', data: { records: [], page: 2, size: 50, total: 0, pages: 0 } })
|
||||
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: { records: [], page: 2, size: 50, total: 0, pages: 0 } })
|
||||
await listLastMileOrders({
|
||||
page: 2, size: 50, orderNo: 'LM-1', inboundCode: 'IN-1', sourceOrderNo: 'SRC-1',
|
||||
containerNo: 'CONT-1', status: 'PENDING_DELIVERY', transferWarehouseCode: 'ONT8',
|
||||
abnormal: true, detained: false, createdFrom: '2026-08-01T00:00:00', createdTo: '2026-08-31T23:59:59',
|
||||
})
|
||||
expect(overseasHttp.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders', {
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders', {
|
||||
params: expect.objectContaining({ page: 2, size: 50, sourceOrderNo: 'SRC-1', transferWarehouseCode: 'ONT8', abnormal: true, detained: false }),
|
||||
})
|
||||
expect(JSON.stringify(vi.mocked(overseasHttp.get).mock.calls[0]?.[1])).not.toContain('customerId')
|
||||
expect(JSON.stringify(vi.mocked(http.get).mock.calls[0]?.[1])).not.toContain('customerId')
|
||||
})
|
||||
|
||||
it('uses the real destination transfer endpoint and edit contract', async () => {
|
||||
vi.mocked(overseasHttp.put).mockResolvedValue({ code: '200', message: 'success', data: 1 })
|
||||
vi.mocked(http.put).mockResolvedValue({ code: '200', message: 'success', data: 1 })
|
||||
await transferLastMileOrders({
|
||||
orderIds: ['190000000000000099'], warehouseId: 'WH-1', warehouseCode: 'ONT8', warehouseName: 'Ontario',
|
||||
})
|
||||
expect(overseasHttp.put).toHaveBeenCalledWith('/platform/v1/last-leg/orders/destination', expect.objectContaining({ orderIds: ['190000000000000099'] }))
|
||||
expect(http.put).toHaveBeenCalledWith('/platform/v1/last-leg/orders/destination', expect.objectContaining({ orderIds: ['190000000000000099'] }))
|
||||
})
|
||||
|
||||
it('returns the exported CSV blob without reading data twice', async () => {
|
||||
const blob = new Blob(['orders'], { type: 'text/csv' })
|
||||
vi.mocked(overseasHttp.get).mockResolvedValue(blob)
|
||||
vi.mocked(http.get).mockResolvedValue(blob)
|
||||
|
||||
await expect(downloadLastMileOrders({ orderNo: 'LM-1' })).resolves.toBe(blob)
|
||||
expect(overseasHttp.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders/export', {
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders/export', {
|
||||
params: { orderNo: 'LM-1' }, responseType: 'blob',
|
||||
})
|
||||
})
|
||||
|
||||
it('exports all authorized orders without pagination or empty filters', async () => {
|
||||
const blob = new Blob(['orders'], { type: 'text/csv' })
|
||||
vi.mocked(overseasHttp.get).mockResolvedValue(blob)
|
||||
vi.mocked(http.get).mockResolvedValue(blob)
|
||||
|
||||
await downloadLastMileOrders({ page: 1, size: 10, orderNo: '', createdFrom: undefined })
|
||||
|
||||
expect(overseasHttp.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders/export', {
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders/export', {
|
||||
params: {}, responseType: 'blob',
|
||||
})
|
||||
})
|
||||
@@ -77,7 +77,7 @@ describe('last-mile order overseas API', () => {
|
||||
const blob = new Blob([JSON.stringify({
|
||||
code: 'S0500', message: '系统内部错误', data: null, requestId: 'req-1', traceId: 'trace-1',
|
||||
})], { type: 'application/json' })
|
||||
vi.mocked(overseasHttp.get).mockResolvedValue(blob)
|
||||
vi.mocked(http.get).mockResolvedValue(blob)
|
||||
|
||||
await expect(downloadLastMileOrders({})).rejects.toMatchObject({
|
||||
code: 'S0500', message: '系统内部错误', requestId: 'req-1', traceId: 'trace-1',
|
||||
@@ -85,12 +85,12 @@ describe('last-mile order overseas API', () => {
|
||||
})
|
||||
|
||||
it('uses the manual inbound-plan endpoint with the complete form and idempotency evidence', async () => {
|
||||
vi.mocked(overseasHttp.post).mockResolvedValue({ code: '200', message: 'success', data: {} })
|
||||
vi.mocked(http.post).mockResolvedValue({ code: '200', message: 'success', data: {} })
|
||||
const payload = { orderId: '190000000000000099', customerId: '190000000000000001', expectedOrderVersion: 4,
|
||||
palletCount: 8, palletType: 'STANDARD' as const,
|
||||
assigned: false, mergeRequired: false, urgent: true, remark: '加急' }
|
||||
await createManualInboundPlan(payload, 'plan-key-1')
|
||||
expect(overseasHttp.post).toHaveBeenCalledWith('/platform/v1/last-leg/inbound-plans/manual', payload,
|
||||
expect(http.post).toHaveBeenCalledWith('/platform/v1/last-leg/inbound-plans/manual', payload,
|
||||
{ headers: { 'Idempotency-Key': 'plan-key-1' } })
|
||||
expect(payload).not.toHaveProperty('inboundCode')
|
||||
expect(payload).not.toHaveProperty('plannedArrivalDate')
|
||||
@@ -100,28 +100,28 @@ describe('last-mile order overseas API', () => {
|
||||
})
|
||||
|
||||
it('uses versioned idempotent order hold and complete manual-node snapshot endpoints', async () => {
|
||||
vi.mocked(overseasHttp.put).mockResolvedValue({ code: '200', message: 'success', data: {} })
|
||||
vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', message: 'success', data: { nodes: [] } })
|
||||
vi.mocked(http.put).mockResolvedValue({ code: '200', message: 'success', data: {} })
|
||||
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: { nodes: [] } })
|
||||
await updateLastMileOrderHold('190000000000000099', { held: true, chargeable: true, reason: '海关查验', expectedVersion: 4 }, 'hold-key-1')
|
||||
expect(overseasHttp.put).toHaveBeenLastCalledWith('/platform/v1/last-leg/orders/190000000000000099/hold',
|
||||
expect(http.put).toHaveBeenLastCalledWith('/platform/v1/last-leg/orders/190000000000000099/hold',
|
||||
{ held: true, chargeable: true, reason: '海关查验', expectedVersion: 4 }, { headers: { 'Idempotency-Key': 'hold-key-1' } })
|
||||
await getLastMileOrderManualNodes('190000000000000099')
|
||||
expect(overseasHttp.get).toHaveBeenLastCalledWith('/platform/v1/last-leg/orders/190000000000000099/manual-nodes')
|
||||
expect(http.get).toHaveBeenLastCalledWith('/platform/v1/last-leg/orders/190000000000000099/manual-nodes')
|
||||
const nodes = [{ nodeCode: 'ESTIMATED_ARRIVAL' as const, nodeAt: '2026-09-10T10:00:00' }]
|
||||
await updateLastMileOrderManualNodes('190000000000000099', 5, nodes, 'node-key-1')
|
||||
expect(overseasHttp.put).toHaveBeenLastCalledWith('/platform/v1/last-leg/orders/190000000000000099/manual-nodes',
|
||||
expect(http.put).toHaveBeenLastCalledWith('/platform/v1/last-leg/orders/190000000000000099/manual-nodes',
|
||||
{ expectedVersion: 5, nodes }, { headers: { 'Idempotency-Key': 'node-key-1' } })
|
||||
})
|
||||
|
||||
it('uses one atomic container request without looping individual conversions', async () => {
|
||||
vi.mocked(overseasHttp.post).mockResolvedValue({ code: '200', message: 'success', data: [] })
|
||||
vi.mocked(http.post).mockResolvedValue({ code: '200', message: 'success', data: [] })
|
||||
await expect(convertLastMileContainerToInboundPlans({
|
||||
sourceContainerBookingId: '2092873463568597001',
|
||||
snapshotVersion: 9,
|
||||
snapshotHash: 'a'.repeat(64),
|
||||
}, 'container-plan-idempotency-key')).resolves.toEqual([])
|
||||
expect(overseasHttp.post).toHaveBeenCalledTimes(1)
|
||||
expect(overseasHttp.post).toHaveBeenCalledWith('/platform/v1/last-leg/inbound-plans/convert-container', {
|
||||
expect(http.post).toHaveBeenCalledTimes(1)
|
||||
expect(http.post).toHaveBeenCalledWith('/platform/v1/last-leg/inbound-plans/convert-container', {
|
||||
sourceContainerBookingId: '2092873463568597001',
|
||||
snapshotVersion: 9,
|
||||
snapshotHash: 'a'.repeat(64),
|
||||
@@ -134,14 +134,14 @@ describe('last-mile order overseas API', () => {
|
||||
inboundCodeCount: 13, missingInboundCodeCount: 2, planCount: 10, plannedInboundCodeCount: 10,
|
||||
pendingPlanCount: 5, resourcePendingPlanCount: 0, plannedArrivalAt: '2026-09-01T08:00:00', allPlansReady: false, blockingReason: '存在2票缺少入仓码',
|
||||
}
|
||||
vi.mocked(overseasHttp.get).mockResolvedValue({
|
||||
vi.mocked(http.get).mockResolvedValue({
|
||||
code: '200', message: 'success', data: { records: [record], page: '2', size: '10', total: '21', pages: '3' },
|
||||
})
|
||||
await expect(listContainerPlanProgress({
|
||||
page: 2, size: 10, containerNo: 'CONT-15',
|
||||
createdFrom: '2026-08-01T00:00:00', createdTo: '2026-08-31T23:59:59',
|
||||
})).resolves.toEqual({ records: [record], page: 2, size: 10, total: 21, pages: 3 })
|
||||
expect(overseasHttp.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders/container-summaries', {
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders/container-summaries', {
|
||||
params: {
|
||||
page: 2, size: 10, containerNo: 'CONT-15',
|
||||
createdFrom: '2026-08-01T00:00:00', createdTo: '2026-08-31T23:59:59',
|
||||
@@ -151,18 +151,18 @@ describe('last-mile order overseas API', () => {
|
||||
|
||||
it('loads one container detail with the encoded stable long id', async () => {
|
||||
const detail = { summary: { sourceContainerBookingId: '2092873463568597001' }, orders: [] }
|
||||
vi.mocked(overseasHttp.get).mockResolvedValue({ code: '200', message: 'success', data: detail })
|
||||
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: detail })
|
||||
await expect(getContainerPlanProgress('2092873463568597001/unsafe')).resolves.toEqual(detail)
|
||||
expect(overseasHttp.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders/container-summaries/2092873463568597001%2Funsafe')
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders/container-summaries/2092873463568597001%2Funsafe')
|
||||
})
|
||||
|
||||
it('changes one whole container receiving warehouse with version and idempotency evidence', async () => {
|
||||
const updated = { sourceContainerBookingId: '2092873463568597001', overseasWarehouseId: '9007199254740993' }
|
||||
vi.mocked(overseasHttp.put).mockResolvedValue({ code: '200', message: 'success', data: updated })
|
||||
vi.mocked(http.put).mockResolvedValue({ code: '200', message: 'success', data: updated })
|
||||
await expect(changeContainerReceivingWarehouse('2092873463568597001/unsafe', {
|
||||
overseasWarehouseId: '9007199254740993', expectedVersion: 7, remark: '改派洛杉矶接柜',
|
||||
}, 'receiving-key-1')).resolves.toEqual(updated)
|
||||
expect(overseasHttp.put).toHaveBeenCalledWith(
|
||||
expect(http.put).toHaveBeenCalledWith(
|
||||
'/platform/v1/last-leg/orders/container-summaries/2092873463568597001%2Funsafe/receiving-warehouse',
|
||||
{ overseasWarehouseId: '9007199254740993', expectedVersion: 7, remark: '改派洛杉矶接柜' },
|
||||
{ headers: { 'Idempotency-Key': 'receiving-key-1' } },
|
||||
|
||||
Reference in New Issue
Block a user