import test from 'node:test' import assert from 'node:assert/strict' import { allocateWarehouseTransfer } from './warehouse-transfer-allocation.mjs' // 用独立来源快照验证隔离、幂等与未知结果停写,不访问测试环境。 function fixture(fault = '') { const proof = { marker: 'batch', customerId: '101', warehouseId: '201', transferNo: 'WT-1', inboundCode: 'IN-1', skuCode: 'SKU-1', status: 'APPROVED' } const calls = [], snapshots = [] const allocation = { inventoryPositionId: '301', inboundOrderId: '401', inboundCode: 'IN-1', palletId: '501', palletNo: 'P-1', packageCount: 1 } const allocated = { transferNo: 'WT-1', status: 'WAIT_RELABEL', relabelNo: 'RL-1', relabelApplicationId: '601', allocations: [allocation] } const context = { marker: 'batch', context: { merchantQualificationFixture: { tenantId: '101' } }, createdResources: { phase4OverseasClientServices: { transferFulfillment: proof } }, assert() {}, apiSuccess() {}, async request(method, path, body, token) { calls.push({ method, path, body: structuredClone(body), token }) let data if (method === 'POST') { if (fault === 'network') throw Error('connection closed') if (fault === 'server') return { http: 503, body: { code: '503' }, requestId: 'request-1' } data = structuredClone(allocated) if (fault === 'wrong allocation') data.allocations[0].inboundOrderId = '999' if (fault === 'replay' && calls.filter(c => c.method === 'POST').length === 2) data.relabelNo = 'RL-2' } else if (path.includes('inventory-candidates')) { data = [{ inventoryBalanceId: '701', inboundOrderId: '401', inboundCode: 'IN-1', overseasWarehouseId: '201', skuCode: 'SKU-1', positions: [{ positionId: '301', palletNo: 'P-1', availablePackages: 1 }] }] if (fault === 'old stock') data[0].inboundCode = 'IN-OLD' } else if (path.includes('/positions')) { data = [{ id: '301', balanceId: '701', customerId: '101', overseasWarehouseId: '201', inboundOrderId: '401', inboundCode: 'IN-1', palletId: '501', palletNo: 'P-1', availablePackages: 1 }] if (fault === 'foreign customer') data[0].customerId = '999' if (fault === 'foreign inbound') data[0].inboundOrderId = '999' if (fault === 'no stock') data[0].availablePackages = 0 } else if (path.startsWith('/api/merchant')) { data = structuredClone(allocated) if (fault === 'merchant drift') data.relabelApplicationId = '999' } else data = { transferNo: 'WT-1', status: 'APPROVED', operatingWarehouseId: '201', needRelabel: true, packageCount: 1, allocations: [], sourceOrders: [{ inboundOrderId: '401', inboundCode: 'IN-1' }] } return { http: 200, body: { code: '200', data } } } } const checkpoint = async () => { snapshots.push(structuredClone(proof)); if (fault === 'disk') throw Error('disk unavailable') } return { proof, context, calls, snapshots, options: { proof, merchantToken: 'secret-token', checkpoint } } } test('原转运分配同批库存、重放并由客户回查唯一换标申请', async () => { const f = fixture() await allocateWarehouseTransfer(f.context, f.options) assert.equal(f.proof.status, 'WAIT_RELABEL') assert.equal(f.proof.allocation.status, 'ALLOCATED_WAIT_RELABEL') assert.equal(f.proof.sourcePositionId, '301') const writes = f.calls.filter(c => c.method === 'POST') assert.equal(writes.length, 2) assert.deepEqual(writes[0].body, writes[1].body) assert.equal(writes[0].body.allocations[0].packageCount, 1) assert.equal(f.snapshots[0].allocation.requests[0].status, 'PREPARED') assert.equal(JSON.stringify(f.snapshots).includes('secret-token'), false) await assert.rejects(allocateWarehouseTransfer(f.context, f.options), /或已执行/) assert.equal(f.calls.length, 6) }) for (const fault of ['old stock', 'foreign customer', 'foreign inbound', 'no stock', 'network', 'server', 'wrong allocation', 'replay', 'merchant drift', 'disk']) { test(`转运分配遇到 ${fault} 停止且保留证据`, async () => { const f = fixture(fault) await assert.rejects(allocateWarehouseTransfer(f.context, f.options)) assert.equal(f.proof.allocation.status, 'FAILED') const writes = f.calls.filter(c => c.method === 'POST') assert.equal(writes.length, ['replay', 'merchant drift'].includes(fault) ? 2 : ['network', 'server', 'wrong allocation'].includes(fault) ? 1 : 0) if (['network', 'server'].includes(fault)) assert.equal(f.proof.allocation.requests.at(-1).status, 'UNKNOWN_RESULT') if (fault === 'disk') assert.equal(f.calls.length, 0) }) } test('未登记的同形证明不得触发请求', async () => { const f = fixture() f.options.proof = structuredClone(f.proof) await assert.rejects(allocateWarehouseTransfer(f.context, f.options)) assert.equal(f.calls.length, 0) })