121 lines
5.0 KiB
TypeScript
121 lines
5.0 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||
import { http } from '@/shared/api/http'
|
||
import { createManualCartonScan, downloadInboundMeasurementImage, getInboundMeasurement, saveInboundMeasurementDraft, submitInboundMeasurement, updateConfirmedPackageCount } from './api'
|
||
import type { SaveInboundMeasurementDraftRequest } from './types'
|
||
|
||
vi.mock('@/shared/api/http', () => ({
|
||
http: { get: vi.fn(), put: vi.fn(), post: vi.fn() },
|
||
unwrapApiResponse: <T>(response: { data: T }) => response.data,
|
||
}))
|
||
|
||
const draft: SaveInboundMeasurementDraftRequest = {
|
||
measurementId: '9001',
|
||
version: 2,
|
||
originalDocumentNo: 'DOC-01',
|
||
originalGrossWeightKg: 120,
|
||
originalVolumeCbm: 1.2,
|
||
actualGoodsName: '蓝牙音箱',
|
||
items: [{
|
||
boxCode: 'RK202608040001#10-1',
|
||
itemNo: '001',
|
||
boxSpecification: '50×40×30cm',
|
||
packageCount: 10,
|
||
lengthCm: 50,
|
||
widthCm: 40,
|
||
heightCm: 30,
|
||
unitWeightKg: 12,
|
||
intelligentImageFileId: '88001',
|
||
machineNo: 'MJ20210327',
|
||
measuredAt: '2026-08-04T10:30:00+08:00',
|
||
overLimitWarning: null,
|
||
outerLengthCm: null,
|
||
outerWidthCm: null,
|
||
outerHeightCm: null,
|
||
remark: null,
|
||
}],
|
||
}
|
||
|
||
describe('inbound measurement API', () => {
|
||
beforeEach(() => {
|
||
vi.mocked(http.get).mockReset()
|
||
vi.mocked(http.put).mockReset()
|
||
vi.mocked(http.post).mockReset()
|
||
})
|
||
|
||
it('maps the selected customer to the backend tenant compatibility parameter', async () => {
|
||
const detail = { inboundId: '7001', items: [], weightResults: [] }
|
||
vi.mocked(http.get).mockResolvedValue({ code: '200', message: 'success', data: detail })
|
||
|
||
await expect(getInboundMeasurement('10001', '7001')).resolves.toEqual(detail)
|
||
expect(http.get).toHaveBeenCalledWith('/platform/v1/first-leg/inbounds/7001/measurement', {
|
||
params: { tenantId: '10001' },
|
||
})
|
||
})
|
||
|
||
it('saves a versioned draft without inventing an idempotency header', async () => {
|
||
const saved = { measurementId: '9001', version: 3, status: 'DRAFT' }
|
||
vi.mocked(http.put).mockResolvedValue({ code: '200', message: 'success', data: saved })
|
||
|
||
await expect(saveInboundMeasurementDraft('10001', '7001', draft)).resolves.toEqual(saved)
|
||
expect(http.put).toHaveBeenCalledWith(
|
||
'/platform/v1/first-leg/inbounds/7001/measurement/draft',
|
||
draft,
|
||
{ params: { tenantId: '10001' } },
|
||
)
|
||
})
|
||
|
||
it('submits the server measurement id and optimistic-lock version', async () => {
|
||
const submitted = { measurementId: '9001', version: 3, processStatus: 'MEASURE_PENDING' }
|
||
vi.mocked(http.post).mockResolvedValue({ code: '200', message: 'success', data: submitted })
|
||
|
||
await expect(submitInboundMeasurement('10001', '7001', { measurementId: '9001', version: 3 })).resolves.toEqual(submitted)
|
||
expect(http.post).toHaveBeenCalledWith(
|
||
'/platform/v1/first-leg/inbounds/7001/measurement/submit',
|
||
{ measurementId: '9001', version: 3 },
|
||
{ params: { tenantId: '10001' } },
|
||
)
|
||
})
|
||
|
||
it('downloads the current measurement image using the scoped file route', async () => {
|
||
const image = new Blob(['image-data'], { type: 'image/jpeg' })
|
||
vi.mocked(http.get).mockResolvedValue(image)
|
||
|
||
await expect(downloadInboundMeasurementImage('100/01', '7001#1', '88001')).resolves.toBe(image)
|
||
expect(http.get).toHaveBeenCalledWith(
|
||
'/platform/v1/files/measurements/100%2F01/7001%231/88001',
|
||
{ responseType: 'blob' },
|
||
)
|
||
})
|
||
|
||
it('updates one scanned carton confirmed package count', async () => {
|
||
const saved = { measurementId: '9001', measurementVersion: 3, itemId: '1', boxCode: 'RK#10-1', confirmedPackageCount: 9 }
|
||
vi.mocked(http.put).mockResolvedValue({ code: '200', message: 'success', data: saved })
|
||
|
||
await expect(updateConfirmedPackageCount('10001', '7001', '1', {
|
||
measurementVersion: 2,
|
||
confirmedPackageCount: 9,
|
||
})).resolves.toEqual(saved)
|
||
expect(http.put).toHaveBeenCalledWith(
|
||
'/platform/v1/first-leg/inbounds/7001/measurement/items/1/confirmed-package-count',
|
||
{ measurementVersion: 2, confirmedPackageCount: 9 },
|
||
{ params: { tenantId: '10001' } },
|
||
)
|
||
})
|
||
|
||
it('posts manual carton scan data and image to the scoped multipart route', async () => {
|
||
const result = { measurementId: '9001', measurementVersion: 3, itemId: '2', boxCode: 'RK#10-2', confirmedPackageCount: 1 }
|
||
vi.mocked(http.post).mockResolvedValue({ code: '200', message: 'success', data: result })
|
||
const image = new File(['image'], 'carton.jpg', { type: 'image/jpeg' })
|
||
|
||
await expect(createManualCartonScan('10001', '7001', {
|
||
boxCode: 'RK#10-2', length: 40, width: 30, height: 20, weight: 5,
|
||
machineNo: 'MANUAL-ADMIN', measuredAt: '2026-08-12T14:00:00', scannedShipmentId: null,
|
||
}, image)).resolves.toEqual(result)
|
||
const [path, body, config] = vi.mocked(http.post).mock.calls[0]!
|
||
expect(path).toBe('/platform/v1/first-leg/inbounds/7001/measurement/manual-cartons')
|
||
expect(body).toBeInstanceOf(FormData)
|
||
expect((body as FormData).get('image')).toBe(image)
|
||
expect(config).toEqual({ params: { tenantId: '10001' }, headers: { 'Content-Type': 'multipart/form-data' } })
|
||
})
|
||
})
|