feat(pda): receive dropship cartons by sealed pallet

This commit is contained in:
2026-09-09 18:33:17 +08:00
parent f6ee80d677
commit 1c01352a39
6 changed files with 36 additions and 13 deletions
+6 -3
View File
@@ -53,8 +53,8 @@ test('login has no committed demo credentials and inbound operation implements t
assert.match(runtime, /#ifdef H5[\s\S]*?VITE_H5_AUTH_API_BASE_URL/)
assert.match(runtime, /#ifdef H5[\s\S]*?VITE_H5_OVERSEAS_API_BASE_URL/)
assert.match(operation, /startScanBroadcast/)
for (const action of ['prepareReceivingContainer', 'getCurrentReceiving', 'resolveCurrentCarton', 'resolveCurrentPallet', 'receiveCurrentBulk', 'receiveCurrentCarton', 'completeCurrentReceiving']) assert.match(operation, new RegExp(action))
for (const path of ['/candidates', '/prepare', '/unload-photos/files', '/sign', '/cartons/resolve', '/pallets/resolve', '/receipts/bulk', '/receipts/carton', '/complete']) assert.match(inbound, new RegExp(path.replaceAll('/', '\\/')))
for (const action of ['prepareReceivingContainer', 'getCurrentReceiving', 'resolveCurrentCarton', 'resolveCurrentPallet', 'receiveCurrentBulk', 'receiveCurrentCarton', 'receiveCurrentWholePallet', 'completeCurrentReceiving']) assert.match(operation, new RegExp(action))
for (const path of ['/candidates', '/prepare', '/unload-photos/files', '/sign', '/cartons/resolve', '/pallets/resolve', '/receipts/bulk', '/receipts/carton', '/receipts/pallet', '/complete']) assert.match(inbound, new RegExp(path.replaceAll('/', '\\/')))
assert.match(inbound, /current\('\/pallets\/resolve'\)/)
assert.doesNotMatch(inbound, /platform\/v1\/warehouse-admin/, 'PDA只能调用current/pallets/resolve,不能访问Admin仓储资源接口')
assert.doesNotMatch(operation, /resolveCurrentSku|resolvedSku|skuInput|selectedInboundCode|chooseInbound|class="inbound-tabs"/)
@@ -63,7 +63,10 @@ test('login has no committed demo credentials and inbound operation implements t
assert.doesNotMatch(operation, /\.split\([^\n]*['"]#['"]/, '前端必须原样提交完整箱码,禁止按 # 猜测入仓码或箱序号')
assert.match(operation, /const payload = isFba \? \{ inboundCode: this\.activeInbound\.inboundCode, palletCode: this\.resolvedPallet\.palletCode, packageCount: Number\(this\.packageCount\) \}/)
assert.doesNotMatch(operation, /skuCode/)
assert.match(operation, /clearReceiptContext\(\)[\s\S]*activeScanTarget = 'carton'/)
assert.match(operation, /currentDropshipInbound[\s\S]*wholePalletInbound/)
assert.match(operation, /name="source-pallet"[\s\S]*@submit="submitWholePallet"/)
assert.match(operation, /submitWholePallet[\s\S]*sourcePalletNo[\s\S]*receiveCurrentWholePallet/)
assert.match(operation, /clearReceiptContext\(\)[\s\S]*activeScanTarget = this\.currentDropshipInbound \? 'source-pallet' : 'carton'/)
assert.match(operation, /name="pallet"[\s\S]*@activate="activeTarget = 'pallet'"/)
assert.doesNotMatch(operation, /receiving\.activeScanTarget = 'pallet'/, '箱码解析成功后必须由作业员手动选择托盘扫码,不得自动跳转')
assert.match(operation, /\[Overseas PDA scan\] dispatch/)
+11 -2
View File
@@ -25,7 +25,7 @@ test('reservation mismatch asks for the reserved pallet and retains diagnostics'
test('first scan and receipt requests confirm server reservations without resource assignment commands', async () => {
const source = await readFile(new URL('../src/api/inbound.js', import.meta.url), 'utf8')
const calls = []
const api = new Function('overseasRequest', 'normalizeReceivingAssignment', 'normalizeReceivingInbound', source.replace(/^import .*$/gm, '').replace(/^export /gm, '') + '; return {resolveCurrentCarton,resolveCurrentPallet,receiveCurrentBulk,receiveCurrentCarton};')(async (...args) => {
const api = new Function('overseasRequest', 'normalizeReceivingAssignment', 'normalizeReceivingInbound', source.replace(/^import .*$/gm, '').replace(/^export /gm, '') + '; return {resolveCurrentCarton,resolveCurrentPallet,receiveCurrentBulk,receiveCurrentCarton,receiveCurrentWholePallet};')(async (...args) => {
calls.push(args)
return { compatible: true, assigned: true, mergeAllowed: 'true', urgent: true, mergeHint: 'unsafe hint' }
}, normalizeReceivingAssignment, normalizeReceivingInbound)
@@ -33,11 +33,13 @@ test('first scan and receipt requests confirm server reservations without resour
assert.equal((await api.resolveCurrentPallet('P-1', 'IN-1')).compatible, true)
assert.equal((await api.receiveCurrentBulk({ inboundCode: 'IN-1', palletCode: 'P-1', packageCount: 2 })).urgent, true)
assert.equal((await api.receiveCurrentCarton({ cartonMark: 'BOX-1', palletCode: 'P-1' })).mergeHint, '')
assert.equal((await api.receiveCurrentWholePallet({ sourcePalletNo: 'DP-1' })).urgent, true)
assert.deepEqual(calls, [
['POST', '/pda/v1/last-leg/receiving-containers/current/cartons/resolve', { cartonMark: 'BOX-1' }],
['POST', '/pda/v1/last-leg/receiving-containers/current/pallets/resolve', { palletCode: 'P-1', inboundCode: 'IN-1' }],
['POST', '/pda/v1/last-leg/receiving-containers/current/receipts/bulk', { inboundCode: 'IN-1', palletCode: 'P-1', packageCount: 2 }],
['POST', '/pda/v1/last-leg/receiving-containers/current/receipts/carton', { cartonMark: 'BOX-1', palletCode: 'P-1' }]
['POST', '/pda/v1/last-leg/receiving-containers/current/receipts/carton', { cartonMark: 'BOX-1', palletCode: 'P-1' }],
['POST', '/pda/v1/last-leg/receiving-containers/current/receipts/pallet', { sourcePalletNo: 'DP-1' }]
])
const page = await readFile(new URL('../src/pages/operation/operation.vue', import.meta.url), 'utf8')
assert.match(page, /activeInbound\.assigned/)
@@ -49,6 +51,13 @@ test('first scan and receipt requests confirm server reservations without resour
assert.match(gate, /resolvedPallet\?\.compatible/)
})
test('one-click dropship inbound is marked only by an explicit server boolean', () => {
for (const value of [undefined, null, false, 1, 'true', 'false']) {
assert.equal(normalizeReceivingInbound({ wholePalletInbound: value }).wholePalletInbound, false)
}
assert.equal(normalizeReceivingInbound({ wholePalletInbound: true }).wholePalletInbound, true)
})
test('receiving adapter preserves the three signed photo roles in workflow order', () => {
const snowflakeFileId = '2092476334483931138'
const session = normalizeReceivingSession({