216 lines
11 KiB
TypeScript
216 lines
11 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { http } from '@/shared/api/http'
|
|
import { downloadAllDropshipPalletLabels, downloadDropshipPalletLabel, downloadInboundCartonLabels, downloadInboundCartonLabelsBatch, downloadPlatformInboundHoldEvidence, getPlatformInbound, getPlatformInboundHold, holdPlatformInbound, listPlatformInboundDropshipPallets, listPlatformInbounds, releasePlatformInbound, uploadPlatformInboundHoldEvidence } from './api'
|
|
|
|
vi.mock('@/shared/api/http', () => ({
|
|
ApiResponseError: class ApiResponseError extends Error {
|
|
code: string
|
|
constructor(message: string, code: string) { super(message); this.code = code }
|
|
},
|
|
http: { get: vi.fn(), post: vi.fn() },
|
|
unwrapApiResponse: <T>(response: { data: T }) => response.data,
|
|
}))
|
|
|
|
describe('platform inbound query API', () => {
|
|
beforeEach(() => {
|
|
vi.mocked(http.get).mockReset()
|
|
vi.mocked(http.post).mockReset()
|
|
})
|
|
|
|
it('omits the backend tenant filter for an all-customer list query', async () => {
|
|
vi.mocked(http.get).mockResolvedValue({
|
|
code: '200', message: 'success', data: { records: [], page: 1, size: 20, total: 0, pages: 0 },
|
|
})
|
|
|
|
await listPlatformInbounds(undefined, { page: 1, size: 20 })
|
|
|
|
expect(http.get).toHaveBeenCalledWith('/platform/inbounds', { params: { page: 1, size: 20 } })
|
|
})
|
|
|
|
it('uses the implemented non-v1 list path and normalizes page values and IDs', async () => {
|
|
vi.mocked(http.get).mockResolvedValue({
|
|
code: '200', message: 'success', data: {
|
|
records: [{
|
|
id: 19001, tenantId: 10002, orderId: 18001, customerId: 10001,
|
|
totalPackageCount: '6', palletCount: '2', actualGrossWeightKg: '21.5',
|
|
actualNetWeightKg: '18.25', actualVolumeCbm: '0.456', holdFlag: 'false',
|
|
}],
|
|
page: '1', size: '20', total: '1', pages: '1',
|
|
},
|
|
})
|
|
|
|
await expect(listPlatformInbounds('10001', {
|
|
page: 1, size: 20, tab: 'WAIT_MEASURE', inboundCode: 'RK', holdFlag: false,
|
|
})).resolves.toMatchObject({
|
|
records: [{
|
|
id: '19001', tenantId: '10002', orderId: '18001', customerId: '10001',
|
|
totalPackageCount: 6, palletCount: 2, actualGrossWeightKg: 21.5,
|
|
actualNetWeightKg: 18.25, actualVolumeCbm: 0.456, holdFlag: false,
|
|
}],
|
|
total: 1, pages: 1,
|
|
})
|
|
expect(http.get).toHaveBeenCalledWith('/platform/inbounds', {
|
|
params: { tenantId: '10001', page: 1, size: 20, tab: 'WAIT_MEASURE', inboundCode: 'RK', holdFlag: false },
|
|
})
|
|
})
|
|
|
|
it('loads a tenant-scoped aggregate detail and keeps nested IDs as strings', async () => {
|
|
vi.mocked(http.get).mockResolvedValue({
|
|
code: '200', message: 'success', data: {
|
|
summary: { id: 19001, tenantId: 10002, orderId: 18001 }, publicRemark: null,
|
|
palletLocations: [{ palletId: 21001, locationId: 22001 }], files: [{ fileId: 23001, uploadedBy: 2 }],
|
|
internalNotes: [{ id: 24001, createdBy: 2 }], statusHistory: [{ operatorId: 2 }],
|
|
},
|
|
})
|
|
|
|
await expect(getPlatformInbound('10001', '19001')).resolves.toMatchObject({
|
|
summary: { id: '19001', tenantId: '10002', orderId: '18001' },
|
|
palletLocations: [{ palletId: '21001', locationId: '22001' }],
|
|
files: [{ fileId: '23001', uploadedBy: '2' }],
|
|
internalNotes: [{ id: '24001', createdBy: '2' }],
|
|
statusHistory: [{ operatorId: '2' }],
|
|
})
|
|
expect(http.get).toHaveBeenCalledWith('/platform/inbounds/19001', { params: { tenantId: '10001' } })
|
|
})
|
|
|
|
it('loads and normalizes the inbound-scoped dropship pallet result', async () => {
|
|
vi.mocked(http.get).mockResolvedValue({ code: '200', data: [{
|
|
palletId: 9007199254740993n, palletNo: 'PLT-001', status: 'SEALED', cartonCount: '2', skuCount: '1', version: '3',
|
|
weightKg: '20.5', volumeCbm: '0.88', discrepancyCartons: '1', sealedAt: '2026-09-08T10:00:00',
|
|
items: [{ inboundId: 19001, inboundCode: 'RK001', inboundDetailId: 9007199254740994n, skuCode: 'SKU001', cargoName: '服装', cartonCount: '2', skuQuantity: '19', cartonMarks: ['BOX-001', 'BOX-002'] }],
|
|
}] })
|
|
|
|
await expect(listPlatformInboundDropshipPallets('10001', '19001')).resolves.toMatchObject([{
|
|
palletId: '9007199254740993', weightKg: 20.5, volumeCbm: 0.88, discrepancyCartons: 1,
|
|
items: [{ inboundId: '19001', inboundDetailId: '9007199254740994', cartonCount: 2, skuQuantity: 19, cartonMarks: ['BOX-001', 'BOX-002'] }],
|
|
}])
|
|
expect(http.get).toHaveBeenCalledWith('/platform/v1/first-leg/pda-dropship/inbound-orders/19001/pallets', { params: { accountId: '10001' } })
|
|
})
|
|
|
|
it('downloads one or all inbound-scoped dropship pallet documents for desktop printing', async () => {
|
|
const pdf = new Blob(['pdf'], { type: 'application/pdf' })
|
|
vi.mocked(http.get).mockResolvedValue(pdf)
|
|
|
|
await expect(downloadDropshipPalletLabel('10001', '19001', '21001')).resolves.toBe(pdf)
|
|
await expect(downloadAllDropshipPalletLabels('10001', '19001')).resolves.toBe(pdf)
|
|
|
|
expect(http.get).toHaveBeenNthCalledWith(1,
|
|
'/platform/v1/first-leg/pda-dropship/inbound-orders/19001/pallets/21001/print',
|
|
{ params: { accountId: '10001' }, responseType: 'blob', timeout: 60_000 })
|
|
expect(http.get).toHaveBeenNthCalledWith(2,
|
|
'/platform/v1/first-leg/pda-dropship/inbound-orders/19001/pallets/print',
|
|
{ params: { accountId: '10001' }, responseType: 'blob', timeout: 60_000 })
|
|
})
|
|
|
|
it('passes the implemented order, process, measurement and fee review filters without renaming them', async () => {
|
|
vi.mocked(http.get).mockResolvedValue({
|
|
code: '200', message: 'success', data: { records: [], page: 1, size: 20, total: 0, pages: 0 },
|
|
})
|
|
|
|
await listPlatformInbounds('10001', {
|
|
page: 1,
|
|
size: 20,
|
|
processStatus: 'MEASURE_PENDING',
|
|
orderStatus: 'APPROVED',
|
|
measureReviewStatus: 'PENDING',
|
|
feeStatus: 'UNPRICED',
|
|
feeReviewStatus: 'PENDING',
|
|
warehouseId: '9007199254740993',
|
|
deliveryWarehouseId: '9007199254740995',
|
|
})
|
|
|
|
expect(http.get).toHaveBeenCalledWith('/platform/inbounds', {
|
|
params: {
|
|
tenantId: '10001', page: 1, size: 20, processStatus: 'MEASURE_PENDING',
|
|
orderStatus: 'APPROVED', measureReviewStatus: 'PENDING', feeStatus: 'UNPRICED', feeReviewStatus: 'PENDING',
|
|
warehouseId: '9007199254740993', deliveryWarehouseId: '9007199254740995',
|
|
},
|
|
})
|
|
})
|
|
|
|
it('downloads stable carton labels and rejects JSON business errors', async () => {
|
|
const pdf = new Blob(['pdf'], { type: 'application/pdf' })
|
|
vi.mocked(http.post).mockResolvedValueOnce(pdf)
|
|
|
|
await expect(downloadInboundCartonLabels('10001', '19001', [1, 3])).resolves.toBe(pdf)
|
|
expect(http.post).toHaveBeenCalledWith('/platform/inbounds/19001/carton-label-pdf', null, {
|
|
params: { tenantId: '10001', cartonIndex: [1, 3] }, responseType: 'blob', timeout: 60_000,
|
|
})
|
|
|
|
vi.mocked(http.post).mockResolvedValueOnce({
|
|
type: 'application/json',
|
|
text: async () => JSON.stringify({ code: 'A0422', message: '箱号映射不完整' }),
|
|
} as Blob)
|
|
await expect(downloadInboundCartonLabels('10001', '19001')).rejects.toMatchObject({
|
|
message: '箱号映射不完整', code: 'A0422',
|
|
})
|
|
})
|
|
|
|
it('downloads one PDF for a cross-customer batch of inbound orders', async () => {
|
|
const pdf = new Blob(['pdf'], { type: 'application/pdf' })
|
|
vi.mocked(http.post).mockResolvedValueOnce(pdf)
|
|
const items = [
|
|
{ tenantId: '10001', inboundId: '19001' },
|
|
{ tenantId: '10002', inboundId: '19002' },
|
|
]
|
|
|
|
await expect(downloadInboundCartonLabelsBatch(items)).resolves.toBe(pdf)
|
|
expect(http.post).toHaveBeenCalledWith('/platform/inbounds/carton-label-pdf', items, {
|
|
responseType: 'blob', timeout: 120_000,
|
|
})
|
|
})
|
|
|
|
it('loads and normalizes the tenant-scoped hold state and immutable history', async () => {
|
|
vi.mocked(http.get).mockResolvedValue({ data: {
|
|
inboundId: 19001, tenantId: 10002, holdFlag: true, currentHoldReason: ' 待核对货款 ', version: '4',
|
|
canHold: false, canRelease: true, actionBlockReason: null,
|
|
history: [{ id: 88001, action: 'HOLD', reason: ' 待核对货款 ', evidenceFileId: 99001, operatorName: ' 财务A ', operatedAt: '2026-09-07T10:00:00' }],
|
|
} })
|
|
|
|
await expect(getPlatformInboundHold('10002', '19001')).resolves.toEqual({
|
|
inboundId: '19001', tenantId: '10002', holdFlag: true, currentHoldReason: '待核对货款', version: 4,
|
|
canHold: false, canRelease: true, actionBlockReason: null,
|
|
history: [{ id: '88001', action: 'HOLD', reason: '待核对货款', evidenceFileId: '99001', operatorName: '财务A', operatedAt: '2026-09-07T10:00:00' }],
|
|
})
|
|
expect(http.get).toHaveBeenCalledWith('/platform/inbounds/19001/hold', { params: { tenantId: '10002' } })
|
|
})
|
|
|
|
it('posts hold and release commands with versions, reasons and independent idempotency keys', async () => {
|
|
const result = { data: { inboundId: '19001', tenantId: '10002', holdFlag: true, currentHoldReason: '待核对货款', version: 4, canHold: false, canRelease: true, actionBlockReason: null, history: [] } }
|
|
vi.mocked(http.post).mockResolvedValue(result)
|
|
|
|
await holdPlatformInbound('10002', '19001', { expectedVersion: 3, reason: '待核对货款' }, 'hold-key')
|
|
expect(http.post).toHaveBeenNthCalledWith(1, '/platform/inbounds/19001/hold', { expectedVersion: 3, reason: '待核对货款' }, {
|
|
params: { tenantId: '10002' }, headers: { 'Idempotency-Key': 'hold-key' },
|
|
})
|
|
|
|
await releasePlatformInbound('10002', '19001', { expectedVersion: 4, reason: '货款已核对' }, 'release-key')
|
|
expect(http.post).toHaveBeenNthCalledWith(2, '/platform/inbounds/19001/hold/release', { expectedVersion: 4, reason: '货款已核对' }, {
|
|
params: { tenantId: '10002' }, headers: { 'Idempotency-Key': 'release-key' },
|
|
})
|
|
})
|
|
|
|
it('uploads and downloads tenant-scoped hold evidence without narrowing long IDs', async () => {
|
|
const file = new File(['evidence'], '扣货说明.pdf', { type: 'application/pdf' })
|
|
vi.mocked(http.post).mockResolvedValueOnce({ data: {
|
|
fileId: '9007199254740999', fileName: '扣货说明.pdf', contentType: 'application/pdf', sizeBytes: '8',
|
|
} })
|
|
await expect(uploadPlatformInboundHoldEvidence('10002', '19001', file)).resolves.toEqual({
|
|
fileId: '9007199254740999', fileName: '扣货说明.pdf', contentType: 'application/pdf', sizeBytes: 8,
|
|
})
|
|
const [path, body, options] = vi.mocked(http.post).mock.calls[0]!
|
|
expect(path).toBe('/platform/inbounds/19001/hold/evidence')
|
|
expect(body).toBeInstanceOf(FormData)
|
|
expect((body as FormData).get('file')).toBe(file)
|
|
expect(options).toEqual({ params: { tenantId: '10002' }, headers: { 'Content-Type': 'multipart/form-data' } })
|
|
|
|
const blob = new Blob(['evidence'], { type: 'application/pdf' })
|
|
vi.mocked(http.get).mockResolvedValueOnce(blob)
|
|
await expect(downloadPlatformInboundHoldEvidence('10002', '19001', '9007199254740999')).resolves.toBe(blob)
|
|
expect(http.get).toHaveBeenLastCalledWith(
|
|
'/platform/inbounds/19001/hold/evidence/9007199254740999/download',
|
|
{ params: { tenantId: '10002' }, responseType: 'blob' },
|
|
)
|
|
})
|
|
})
|