This commit is contained in:
2026-09-15 10:37:34 +08:00
parent 4f13ee2ec3
commit 88e2fb0eb1
49 changed files with 465 additions and 236 deletions
@@ -3,6 +3,26 @@ import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import { normalizeModuleOrder } from '../admin-test-env-acceptance.mjs'
import { sameOutboundTask } from './dropship-pallet-matrix.mjs'
import { probePartialPick } from './dropship-outbound-edge-cases.mjs'
test('partial-pick rejection stays failed; a changed snapshot aborts further picking', async () => {
const failures = []
const snapshot = { pallets: [{ pickedPackageCount: 0 }] }
const edge = {
label: 'SINGLE-SINGLE', task: { outboundNo: 'OD', taskNo: 'PDA' },
pick: { packages: 4, cartonMarks: ['A', 'B', 'C', 'D'], idempotencyKey: 'pick' },
context: { assert: (_module, name, _response, passed) => { if (!passed) failures.push(name) },
requestOverseas: async () => ({ body: { code: 'A0409' } }) },
check: (_name, _response, passed) => assert.ok(passed),
call: async () => structuredClone(snapshot),
}
assert.equal(await probePartialPick(edge), 0)
assert.equal(failures.length, 1)
assert.match(failures[0], /四箱任务先拣一箱成功/)
let calls = 0
edge.call = async () => ({ pallets: [{ pickedPackageCount: calls++ }] })
await assert.rejects(probePartialPick(edge))
})
test('outbound replay preserves business identity and database millisecond timestamps', () => {
const task = { id: '1', taskNo: 'PDA1', outboundNo: 'OD1', status: 'PENDING', pushedAt: '2026-09-14T20:24:45.920278604' }
@@ -15,6 +35,34 @@ test('outbound replay preserves business identity and database millisecond times
})
const source = readFileSync(new URL('./dropship-pallet-matrix.mjs', import.meta.url), 'utf8')
const edges = readFileSync(new URL('./dropship-outbound-edge-cases.mjs', import.meta.url), 'utf8')
test('outbound edge probes preserve failures and require zero drift before continuing', () => {
assert.match(edges, /deploymentBlocker: true/)
assert.match(edges, /四箱任务先拣一箱成功/)
assert.match(edges, /分批拣货失败后无库存明细变化/)
assert.match(edges, /JSON.stringify\(before\) === JSON.stringify\(after\)/)
assert.match(source, /await probePartialPick/)
assert.match(source, /pick.packages -= count/)
assert.match(source, /pick.cartonMarks = pick.cartonMarks.slice\(count\)/)
})
test('outbound creation probes cover concurrent idempotency, invalid cartons and cancellation', () => {
assert.match(edges, /Promise.all\(\[create\(\), create\(\)\]\)/)
for (const scenario of ['超量创建', '错误SKU创建', '不存在箱唛创建', '重复箱唛创建',
'箱数与箱唛不符创建', '出库创建同键异载荷返回A0409', '未拣齐禁止完成出库', '部分已拣禁止取消']) {
assert.ok(edges.includes(scenario))
}
assert.match(edges, /取消后逐票SKU可用箱数恢复/)
assert.match(source, /await outboundCreationGuards\(edge\)/)
assert.match(source, /await outboundTaskGuards\(\{ ...edge, task \}\)/)
})
test('two inbound orders explicitly share a SKU without losing their separate identities', () => {
assert.match(source, /label.startsWith\('MULTI-MERGE-'\)/)
assert.match(source, /skuCodes = \[`SKU-SHARED-\$\{marker\}`/)
assert.match(source, /row.inboundCode === candidate.inboundCode/)
})
test('dedicated outbound uses exact source cartons and verifies completion and stock deduction', () => {
assert.match(source, /await outboundOverseas\(group, picker.token\)/)