75 lines
4.7 KiB
JavaScript
75 lines
4.7 KiB
JavaScript
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)
|
|
})
|