test: align overseas PDA group receipt semantics

This commit is contained in:
2026-09-11 00:24:35 +08:00
parent 2bd12f8a5f
commit 9abb0004dd
4 changed files with 44 additions and 20 deletions
@@ -465,12 +465,17 @@ export async function resolveCartonFixtures(context, token, inbounds, producerCa
continue
}
const resolved = response.body?.data
const matches = inbounds.filter((item) => item.inboundCode === resolved?.inboundCode)
const delimiter = cartonMark.indexOf('#')
const scannedInboundCode = delimiter > 0 ? cartonMark.slice(0, delimiter).trim() : ''
const resolvedInboundCodes = Array.isArray(resolved?.inboundCodes)
? resolved.inboundCodes.map(id) : [id(resolved?.inboundCode)].filter(nonBlank)
const matches = inbounds.filter((item) => item.inboundCode === scannedInboundCode)
const destinations = new Set(matches.map((item) => item?.destinationType).filter(nonBlank))
const unique = success(response) && nonBlank(resolved?.inboundCode) && !Array.isArray(resolved?.inboundCode)
&& matches.length === 1 && destinations.size === 1
&& ['FBA', 'OVERSEAS'].includes(resolved?.destinationType)
&& destinations.has(resolved?.destinationType)
&& resolvedInboundCodes.includes(scannedInboundCode)
&& (!strictDropship || (resolved?.cartonMark === cartonMark
&& resolved?.inboundCode === dropshipProducer.inboundCode && resolved?.destinationType === dropshipProducer.destinationType))
context.addStep(MODULE, `统一解析${resolved?.destinationType || 'UNKNOWN'}箱码${index + 1}并返回唯一入仓码`, response,
@@ -521,29 +526,33 @@ async function probeCartonResolveNegatives(context, token, current) {
}
}
async function receiveFba(context, token, inbound, pallet, cartonFixtures, index) {
const resolvedCartons = cartonFixtures.filter((item) => item.inbound.inboundCode === inbound.inboundCode
async function receiveFba(context, token, inbounds, pallet, cartonFixtures, index) {
const inboundCodes = new Set(inbounds.map((item) => item.inboundCode))
const resolvedCartons = cartonFixtures.filter((item) => inboundCodes.has(item.inbound.inboundCode)
&& item.resolved.destinationType === 'FBA')
if (!resolvedCartons.length) {
blockerGap(context, `FBA入仓码${inbound.inboundCode}箱码解析`, '没有冻结箱码以200/code 200唯一解析到当前FBA入仓码')
if (resolvedCartons.length !== inbounds.length) {
blockerGap(context, `FBA组${[...inboundCodes].join('|')}箱码解析`, '没有为FBA组内每个入仓码完成唯一解析')
return false
}
const packageCount = Number(inbound.pendingPackages || 0)
const packageCount = inbounds.reduce((total, inbound) => total + Number(inbound.totalPackages || 0), 0)
if (packageCount <= 0) return true
const body = { inboundCode: inbound.inboundCode, palletCode: pallet.palletCode,
const body = { inboundCode: inbounds[0].inboundCode, palletCode: pallet.palletCode,
packageCount, idempotencyKey: key(context, `fba-bulk-${index}`) }
const first = await pda(context, token, 'POST', `FBA入仓码${inbound.inboundCode}按箱数实收`,
const first = await pda(context, token, 'POST', `FBA组${[...inboundCodes].join('|')}按累计箱数实收`,
'/api/pda/v1/last-leg/receiving-containers/current/receipts/bulk', body)
if (!success(first.response)) return false
const replay = await pda(context, token, 'POST', `FBA入仓码${inbound.inboundCode}同键同载荷重放`,
const replay = await pda(context, token, 'POST', `FBA组${[...inboundCodes].join('|')}同键同载荷重放`,
'/api/pda/v1/last-leg/receiving-containers/current/receipts/bulk', body)
context.assert(MODULE, `FBA入仓码${inbound.inboundCode}幂等结果一致`, replay.response,
context.assert(MODULE, `FBA组${[...inboundCodes].join('|')}幂等结果一致`, replay.response,
success(replay.response) && JSON.stringify(replay.data) === JSON.stringify(first.data), trace(replay.response), OPTIONS)
await expected(context, token, 'POST', `FBA入仓码${inbound.inboundCode}同键异载荷冲突`,
await expected(context, token, 'POST', `FBA组${[...inboundCodes].join('|')}同键异载荷冲突`,
'/api/pda/v1/last-leg/receiving-containers/current/receipts/bulk', { ...body, packageCount: packageCount + 1 }, conflict)
await expected(context, token, 'POST', `FBA入仓码${inbound.inboundCode}超收被拒绝`,
const already = await pda(context, token, 'POST', `FBA组${[...inboundCodes].join('|')}新键重复累计为零增量`,
'/api/pda/v1/last-leg/receiving-containers/current/receipts/bulk',
{ ...body, packageCount: Number(inbound.totalPackages) + 1, idempotencyKey: key(context, `fba-over-${index}`) }, conflict)
{ ...body, idempotencyKey: key(context, `fba-already-${index}`) })
context.assert(MODULE, `FBA组${[...inboundCodes].join('|')}重复累计不产生超收`, already.response,
success(already.response) && already.data?.result === 'ALREADY_RECEIVED'
&& Number(already.data?.acceptedPackages) === 0, trace(already.response), OPTIONS)
return true
}
@@ -604,9 +613,12 @@ async function receiveDropship(context, token, producer, inbounds) {
await expected(context, token, 'POST', `一件代发整托${index + 1}同键异载荷冲突`,
'/api/pda/v1/last-leg/receiving-containers/current/receipts/pallet',
{ ...body, sourcePalletNo: `${sourcePalletNo}-MUTATED` }, conflict)
await expected(context, token, 'POST', `一件代发来源托盘重复收货被拒绝${index + 1}`,
const duplicate = await pda(context, token, 'POST', `一件代发来源托盘新键重复收货${index + 1}`,
'/api/pda/v1/last-leg/receiving-containers/current/receipts/pallet',
{ ...body, idempotencyKey: key(context, `dropship-pallet-duplicate-${index}`) }, conflict)
{ ...body, idempotencyKey: key(context, `dropship-pallet-duplicate-${index}`) })
context.assert(MODULE, `一件代发来源托盘重复收货不重复入账${index + 1}`, duplicate.response,
success(duplicate.response) && duplicate.data?.result === 'ALREADY_RECEIVED'
&& Number(duplicate.data?.acceptedPackages) === 0, trace(duplicate.response), OPTIONS)
}
context.assert(MODULE, '一件代发整托实收箱数与待收箱数守恒', null,
accepted === expectedPending, `accepted=${accepted}, expected=${expectedPending}`, OPTIONS)
@@ -728,8 +740,15 @@ async function runReceiving(context, token, secondaryToken, merchantToken, prefe
cartonMark: fbaCarton?.cartonMark,
palletCode: pallets.get(firstFba.inboundCode).palletCode, idempotencyKey: key(context, 'fba-carton-forbidden'),
}, (response) => a0409Message(response, /^FBA destination must use bulk count$/))
for (const [index, inbound] of fbaInbounds.entries()) {
await receiveFba(context, token, inbound, pallets.get(inbound.inboundCode), cartonFixtures, index)
const groups = new Map()
for (const inbound of fbaInbounds) {
const fixture = cartonFixtures.find((item) => item.inbound.inboundCode === inbound.inboundCode)
const groupKey = fixture?.resolved?.groupKey || `INBOUND:${inbound.inboundCode}`
if (!groups.has(groupKey)) groups.set(groupKey, [])
groups.get(groupKey).push(inbound)
}
for (const [index, group] of [...groups.values()].entries()) {
await receiveFba(context, token, group, pallets.get(group[0].inboundCode), cartonFixtures, index)
}
} else if (!strictDropship && preferredProducer?.destinationType !== 'OVERSEAS') {
blockerGap(context, 'FBA按箱数链', '当前FBA柜没有带真实托盘的 FBA 入仓码')