fix: complete October 22 workflow feedback and request failure recovery
This commit is contained in:
@@ -11,12 +11,15 @@ test('box merge component compiles both its script and template', () => {
|
||||
compileScript(descriptor, { id: 'box-merge' })
|
||||
assert.deepEqual(compileTemplate({ source: descriptor.template.content, filename, id: 'box-merge' }).errors, [])
|
||||
})
|
||||
function instance() {
|
||||
function instance(runtime = {}) {
|
||||
const boxes = [{cartonMark:'A',customerId:'C1',items:[{skuCode:'SKU1',quantity:2},{skuCode:'SKU2',quantity:3}]},{cartonMark:'B',customerId:'C1',items:[{skuCode:'SKU1',quantity:2}]}]
|
||||
const component = vm.runInNewContext(descriptor.script.content.replace(/^import .*$/gm, '').replace('export default', 'component ='), { ScanTargetInput: {}, ReturnLabelConfirmation: {}, component: null, scanReturnCarton: async mark => boxes.find(box => box.cartonMark === mark) })
|
||||
const context = vm.createContext({ reactive: value => value, ScanTargetInput: {}, ReturnLabelConfirmation: {}, component: null, scanReturnCarton: async mark => boxes.find(box => box.cartonMark === mark), ...runtime })
|
||||
vm.runInContext(readFileSync(new URL('../src/stores/warehouse-work.js', import.meta.url), 'utf8').replace(/^import .*$/gm, '').replace(/export /g, ''), context)
|
||||
const component = vm.runInContext(descriptor.script.content.replace(/^import .*$/gm, '').replace('export default', 'component ='), context)
|
||||
const work = { ...component.data(), plan: {customerId:'C1',sources:[{cartonMark:'A',items:[{skuCode:'SKU1',quantity:2},{skuCode:'SKU2',quantity:3}]},{cartonMark:'B',items:[{skuCode:'SKU1',quantity:2}]}]}, $emit(){} }
|
||||
for (const [name, method] of Object.entries(component.methods)) work[name] = method.bind(work)
|
||||
work.save = () => {}
|
||||
Object.defineProperty(work, 'canComplete', { get: () => component.computed.canComplete.call(work) })
|
||||
return {work,component}
|
||||
}
|
||||
test('new plan requires scanning each source and preserves locked SKU quantities', async () => {
|
||||
@@ -31,6 +34,34 @@ test('new plan requires scanning each source and preserves locked SKU quantities
|
||||
assert.equal(component.computed.canComplete.call(work),true)
|
||||
})
|
||||
|
||||
test('partial merge preserves the scanned snapshot after failure and accepts a fresh scan without locking', async () => {
|
||||
let available = 10
|
||||
const calls = [], errors = []
|
||||
const { work } = instance({
|
||||
scanReturnCarton: async () => ({ cartonMark: 'A', customerId: 'C1', items: [{ skuCode: 'SKU1', quantity: available }] }),
|
||||
mergeReturnBoxes: async request => {
|
||||
calls.push(JSON.parse(JSON.stringify(request)))
|
||||
if (request.expectedSourceQuantities[0].quantity !== available) throw new Error('来源箱库存已变化')
|
||||
available -= request.sourceDeductions[0].quantity
|
||||
if (calls.length === 1) throw new Error('response lost after commit')
|
||||
return { label: { cartonMark: 'NEW' } }
|
||||
}
|
||||
})
|
||||
work.plan = null; work.choose('NEW'); work.$emit = (name, value) => { if (name === 'error') errors.push(value) }
|
||||
await work.scanSource('A'); work.setDeduction('A', 'SKU1', 3)
|
||||
work.dimensions = { length: 10, width: 10, height: 10, weight: 1 }
|
||||
await work.complete(); await work.complete()
|
||||
assert.equal(available, 7)
|
||||
assert.equal(work.busy, false)
|
||||
assert.equal(errors.at(-1).message, '来源箱库存已变化')
|
||||
assert.notEqual(calls[0].idempotencyKey, calls[1].idempotencyKey)
|
||||
work.remove('A'); await work.scanSource('A'); work.setDeduction('A', 'SKU1', 2)
|
||||
await work.complete()
|
||||
assert.equal(available, 5)
|
||||
assert.deepEqual(calls.map(call => call.expectedSourceQuantities[0].quantity), [10, 10, 7])
|
||||
assert.equal(work.busy, false)
|
||||
})
|
||||
|
||||
test('planned source carton marks are visible before scanning', () => {
|
||||
const {work, component} = instance()
|
||||
work.plan = { sourceCartonMarks: ['A', 'B'], sources: [] }
|
||||
|
||||
Reference in New Issue
Block a user