优化
This commit is contained in:
@@ -1,27 +1,12 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { http } from '@/shared/api/http'
|
||||
import { downloadInventoryBalances, downloadInventoryLedger, getInventorySummary, listInventoryBalances, listInventoryLedger, listInventoryPositions } from './inventory'
|
||||
import { getInventorySummary, listInventoryBalances, listInventoryLedger, listInventoryPositions } from './inventory'
|
||||
|
||||
vi.mock('@/shared/api/http', async (importOriginal) => ({ ...(await importOriginal<typeof import('@/shared/api/http')>()), http: { get: vi.fn() } }))
|
||||
|
||||
describe('overseas inventory API', () => {
|
||||
beforeEach(() => { vi.clearAllMocks() })
|
||||
|
||||
it('returns the binary response directly for inventory exports', async () => {
|
||||
const balances = new Blob(['customerId\\r\\n10001\\r\\n'], { type: 'text/csv' })
|
||||
const ledger = new Blob(['occurredAt\\r\\n'], { type: 'text/csv' })
|
||||
vi.mocked(http.get).mockResolvedValueOnce(balances).mockResolvedValueOnce(ledger)
|
||||
|
||||
await expect(downloadInventoryBalances({ skuCode: 'SKU-1' })).resolves.toBe(balances)
|
||||
await expect(downloadInventoryLedger({ inboundCode: 'IN-1' })).resolves.toBe(ledger)
|
||||
|
||||
expect(http.get).toHaveBeenNthCalledWith(1, '/platform/v1/last-leg/inventory/balances/export', {
|
||||
params: { skuCode: 'SKU-1' }, responseType: 'blob',
|
||||
})
|
||||
expect(http.get).toHaveBeenNthCalledWith(2, '/platform/v1/last-leg/inventory/ledger/export', {
|
||||
params: { inboundCode: 'IN-1' }, responseType: 'blob',
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps skuCode and nullable location filters on real balance queries', async () => {
|
||||
vi.mocked(http.get).mockResolvedValueOnce({ code: '200', data: { records: [], page: 1, size: 20, total: 0, pages: 0 } }).mockResolvedValueOnce({ code: '200', data: { totalPackages: 0 } })
|
||||
|
||||
@@ -117,9 +117,6 @@ export async function listInventoryBalances(query: InventoryBalanceQuery) {
|
||||
return normalizeOverseasPage(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export async function downloadInventoryBalances(query: Partial<InventoryBalanceQuery>) {
|
||||
return http.get<Blob, Blob>('/platform/v1/last-leg/inventory/balances/export', { params: query, responseType: 'blob' })
|
||||
}
|
||||
|
||||
export async function getInventorySummary(query: InventoryBalanceQuery) {
|
||||
const response = await http.get<ApiEnvelope<InventoryDashboardDto>, ApiEnvelope<InventoryDashboardDto>>(
|
||||
@@ -165,7 +162,3 @@ export async function listInventoryLedger(query: InventoryLedgerQuery) {
|
||||
)
|
||||
return normalizeOverseasPage(unwrapApiResponse(response))
|
||||
}
|
||||
|
||||
export async function downloadInventoryLedger(query: Partial<InventoryLedgerQuery>) {
|
||||
return http.get<Blob, Blob>('/platform/v1/last-leg/inventory/ledger/export', { params: query, responseType: 'blob' })
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { http } from '@/shared/api/http'
|
||||
import { reviewCargoDiscard } from './lastMileOrders'
|
||||
import { changeContainerReceivingWarehouse, convertLastMileContainerToInboundPlans, createManualInboundPlan, downloadLastMileOrders, getContainerPlanProgress, getLastMileOrder, getLastMileOrderManualNodes, listContainerPlanProgress, listLastMileOrders, transferLastMileOrders, updateLastMileOrderHold, updateLastMileOrderManualNodes } from './lastMileOrders'
|
||||
import { changeContainerReceivingWarehouse, convertLastMileContainerToInboundPlans, createManualInboundPlan, getContainerPlanProgress, getLastMileOrder, getLastMileOrderManualNodes, listContainerPlanProgress, listLastMileOrders, transferLastMileOrders, updateLastMileOrderHold, updateLastMileOrderManualNodes } from './lastMileOrders'
|
||||
|
||||
vi.mock('@/shared/api/http', async (importOriginal) => ({ ...(await importOriginal<typeof import('@/shared/api/http')>()), http: { get: vi.fn(), put: vi.fn(), post: vi.fn() } }))
|
||||
|
||||
@@ -60,37 +60,8 @@ describe('last-mile order overseas API', () => {
|
||||
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(http.get).mockResolvedValue(blob)
|
||||
|
||||
await expect(downloadLastMileOrders({ orderNo: 'LM-1' })).resolves.toBe(blob)
|
||||
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(http.get).mockResolvedValue(blob)
|
||||
|
||||
await downloadLastMileOrders({ page: 1, size: 10, orderNo: '', createdFrom: undefined })
|
||||
|
||||
expect(http.get).toHaveBeenCalledWith('/platform/v1/last-leg/orders/export', {
|
||||
params: {}, responseType: 'blob',
|
||||
})
|
||||
})
|
||||
|
||||
it('rejects a JSON business error instead of saving it as CSV', async () => {
|
||||
const blob = new Blob([JSON.stringify({
|
||||
code: 'S0500', message: '系统内部错误', data: null, requestId: 'req-1', traceId: 'trace-1',
|
||||
})], { type: 'application/json' })
|
||||
vi.mocked(http.get).mockResolvedValue(blob)
|
||||
|
||||
await expect(downloadLastMileOrders({})).rejects.toMatchObject({
|
||||
code: 'S0500', message: '系统内部错误', requestId: 'req-1', traceId: 'trace-1',
|
||||
})
|
||||
})
|
||||
|
||||
it('uses the manual inbound-plan endpoint with the complete form and idempotency evidence', async () => {
|
||||
vi.mocked(http.post).mockResolvedValue({ code: '200', message: 'success', data: {} })
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { http, ApiResponseError, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
|
||||
import { http, unwrapApiResponse, type ApiEnvelope } from '@/shared/api/http'
|
||||
|
||||
import type { InboundPlanDetailDto } from './inboundPlans'
|
||||
|
||||
@@ -394,28 +394,6 @@ export async function reviewDirectRelabelOrder(orderId: string, customerId: stri
|
||||
return unwrapApiResponse(response)
|
||||
}
|
||||
|
||||
export async function downloadLastMileOrders(query: Partial<LastMileOrderQuery>) {
|
||||
const { page: _page, size: _size, ...filters } = query
|
||||
const params = Object.fromEntries(
|
||||
Object.entries(filters).filter(([, value]) => value !== undefined && value !== null && value !== ''),
|
||||
)
|
||||
const blob = await http.get<Blob, Blob>('/platform/v1/last-leg/orders/export', { params, responseType: 'blob' })
|
||||
if (!blob.type.toLowerCase().includes('json')) return blob
|
||||
let error: Partial<ApiEnvelope<unknown>>
|
||||
try {
|
||||
error = JSON.parse(await blob.text()) as Partial<ApiEnvelope<unknown>>
|
||||
} catch {
|
||||
throw new ApiResponseError('导出接口返回了非 CSV 内容', 'INVALID_EXPORT_RESPONSE')
|
||||
}
|
||||
throw new ApiResponseError(
|
||||
error.message || '尾程订单导出失败',
|
||||
error.code || 'INVALID_EXPORT_RESPONSE',
|
||||
undefined,
|
||||
error.data,
|
||||
error.requestId,
|
||||
error.traceId,
|
||||
)
|
||||
}
|
||||
|
||||
export async function createLastMileOrderFee(orderId: string, payload: CreateLastMileFeePayload) {
|
||||
const response = await http.post<ApiEnvelope<LastMileFeeDto>, ApiEnvelope<LastMileFeeDto>>(
|
||||
|
||||
Reference in New Issue
Block a user