fix(overseas): normalize transfer inventory quantities at API boundary

This commit is contained in:
2026-10-04 22:26:36 +08:00
parent 939cc11d7b
commit ea24496b11
7 changed files with 90 additions and 14 deletions
@@ -7,8 +7,21 @@ vi.mock('@/shared/api/http', async (importOriginal) => ({ ...(await importOrigin
describe('warehouseTransfers API', () => {
beforeEach(() => vi.clearAllMocks())
it('normalizes detail, review and allocation box counts at the API boundary', async () => {
vi.mocked(http.get).mockResolvedValue({ code: '200', data: { transferNo: 'WT-1', packageCount: '1' } })
vi.mocked(http.post).mockResolvedValue({ code: '200', data: { transferNo: 'WT-1', packageCount: '1' } })
expect((await getWarehouseTransfer('customer-1', 'WT-1')).packageCount).toBe(1)
expect((await reviewWarehouseTransfer('customer-1', 'WT-1', 'APPROVE')).packageCount).toBe(1)
expect((await allocateWarehouseTransfer('customer-1', 'WT-1', { idempotencyKey: 'fixed', allocations: [{ inventoryPositionId: 'position', palletId: 'pallet', packageCount: 1 }] })).packageCount).toBe(1)
})
it('rejects an ambiguous transfer total instead of passing it into strict selected-package comparison', async () => {
vi.mocked(http.get).mockResolvedValue({ code: '200', data: { transferNo: 'WT-1', packageCount: true } })
await expect(getWarehouseTransfer('customer-1', 'WT-1')).rejects.toThrow('本票转运箱数返回格式无效')
})
it('preserves the body idempotency key, exact source positions and selected customer on replay', async () => {
const value = { transferNo: 'WT-1', status: 'WAIT_RELABEL', relabelNo: 'RL-1', items: [], cartons: [], relabelBindings: [] }
const value = { transferNo: 'WT-1', packageCount: 2, status: 'WAIT_RELABEL', relabelNo: 'RL-1', items: [], cartons: [], relabelBindings: [] }
vi.mocked(http.post).mockResolvedValue({ code: '200', data: value })
const payload = { idempotencyKey: 'allocation-fixed', allocations: [{ inventoryPositionId: '2100000000000000001', palletId: '2100000000000000002', packageCount: 2 }] }
expect(await allocateWarehouseTransfer('20001', 'WT-1', payload)).toEqual(value)
@@ -25,7 +38,7 @@ describe('warehouseTransfers API', () => {
it('reuses the original command after an unknown transport result without dropping source rows', async () => {
const payload = { idempotencyKey: 'same-key-after-response-loss', allocations: [{ inventoryPositionId: '2100000000000000001', palletId: '2100000000000000002', packageCount: 1 }, { inventoryPositionId: '2100000000000000003', palletId: '2100000000000000004', packageCount: 2 }] }
const before = structuredClone(payload)
vi.mocked(http.post).mockRejectedValueOnce(new Error('response lost')).mockResolvedValueOnce({ code: '200', data: { transferNo: 'WT-1', status: 'WAIT_RELABEL', relabelNo: 'RL-SAME' } })
vi.mocked(http.post).mockRejectedValueOnce(new Error('response lost')).mockResolvedValueOnce({ code: '200', data: { transferNo: 'WT-1', packageCount: 3, status: 'WAIT_RELABEL', relabelNo: 'RL-SAME' } })
await expect(allocateWarehouseTransfer('customer-1', 'WT-1', payload)).rejects.toThrow('response lost')
expect(payload).toEqual(before)
expect(await allocateWarehouseTransfer('customer-1', 'WT-1', payload)).toMatchObject({ status: 'WAIT_RELABEL', relabelNo: 'RL-SAME' })
@@ -35,7 +48,7 @@ describe('warehouseTransfers API', () => {
it('always scopes platform list and detail requests to the selected customer', async () => {
vi.mocked(http.get).mockResolvedValueOnce({ code: '200', data: { records: [], page: 1, size: 10, total: 0, pages: 0 } })
vi.mocked(http.get).mockResolvedValueOnce({ code: '200', data: { transferNo: 'WT-1', items: [], cartons: [], relabelBindings: [] } })
vi.mocked(http.get).mockResolvedValueOnce({ code: '200', data: { transferNo: 'WT-1', packageCount: 2, items: [], cartons: [], relabelBindings: [] } })
await listWarehouseTransfers('20001', { page: 1, size: 10, status: 'PENDING_REVIEW' })
await getWarehouseTransfer('20001', 'WT-1')
expect(vi.mocked(http.get).mock.calls[0]).toEqual(['/platform/v1/last-leg/warehouse-transfers', { params: { page: 1, size: 10, status: 'PENDING_REVIEW', customerId: '20001' } }])
@@ -43,7 +56,7 @@ describe('warehouseTransfers API', () => {
})
it('posts the real review decision with customer scope', async () => {
vi.mocked(http.post).mockResolvedValue({ code: '200', data: { transferNo: 'WT-1', items: [], cartons: [], relabelBindings: [] } })
vi.mocked(http.post).mockResolvedValue({ code: '200', data: { transferNo: 'WT-1', packageCount: 2, items: [], cartons: [], relabelBindings: [] } })
await reviewWarehouseTransfer('20001', 'WT-1', 'APPROVE', '资料无误')
expect(http.post).toHaveBeenCalledWith(
'/platform/v1/last-leg/warehouse-transfers/WT-1/review',