test: align overseas PDA group receipt semantics
This commit is contained in:
@@ -107,10 +107,12 @@ test('PDA module covers the container-number receiving contract and excludes out
|
|||||||
assert.match(source, /安全投影已收敛/)
|
assert.match(source, /安全投影已收敛/)
|
||||||
assert.match(source, /projectionReady = success\(projectionResponse\) \|\| notFound\(projectionResponse\)/)
|
assert.match(source, /projectionReady = success\(projectionResponse\) \|\| notFound\(projectionResponse\)/)
|
||||||
assert.match(source, /setTimeout\(resolve, 500\)/)
|
assert.match(source, /setTimeout\(resolve, 500\)/)
|
||||||
assert.match(source, /超收被拒绝/)
|
assert.match(source, /重复累计不产生超收/)
|
||||||
assert.match(source, /重复箱新键被拒绝/)
|
assert.match(source, /重复箱新键被拒绝/)
|
||||||
assert.match(source, /key\(context, `fba-bulk-\$\{index\}`\)/)
|
assert.match(source, /key\(context, `fba-bulk-\$\{index\}`\)/)
|
||||||
assert.match(source, /packageCount = Number\(inbound\.pendingPackages \|\| 0\)/)
|
assert.match(source, /inbounds\.reduce\(\(total, inbound\) => total \+ Number\(inbound\.totalPackages \|\| 0\), 0\)/)
|
||||||
|
assert.match(source, /resolvedInboundCodes\.includes\(scannedInboundCode\)/)
|
||||||
|
assert.match(source, /duplicate\.data\?\.result === 'ALREADY_RECEIVED'/)
|
||||||
assert.match(source, /if \(packageCount <= 0\) return true/)
|
assert.match(source, /if \(packageCount <= 0\) return true/)
|
||||||
assert.match(source, /key\(context, `overseas-carton-\$\{index\}`\)/)
|
assert.match(source, /key\(context, `overseas-carton-\$\{index\}`\)/)
|
||||||
assert.match(source, /模式硬拒绝/)
|
assert.match(source, /模式硬拒绝/)
|
||||||
|
|||||||
@@ -465,12 +465,17 @@ export async function resolveCartonFixtures(context, token, inbounds, producerCa
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const resolved = response.body?.data
|
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 destinations = new Set(matches.map((item) => item?.destinationType).filter(nonBlank))
|
||||||
const unique = success(response) && nonBlank(resolved?.inboundCode) && !Array.isArray(resolved?.inboundCode)
|
const unique = success(response) && nonBlank(resolved?.inboundCode) && !Array.isArray(resolved?.inboundCode)
|
||||||
&& matches.length === 1 && destinations.size === 1
|
&& matches.length === 1 && destinations.size === 1
|
||||||
&& ['FBA', 'OVERSEAS'].includes(resolved?.destinationType)
|
&& ['FBA', 'OVERSEAS'].includes(resolved?.destinationType)
|
||||||
&& destinations.has(resolved?.destinationType)
|
&& destinations.has(resolved?.destinationType)
|
||||||
|
&& resolvedInboundCodes.includes(scannedInboundCode)
|
||||||
&& (!strictDropship || (resolved?.cartonMark === cartonMark
|
&& (!strictDropship || (resolved?.cartonMark === cartonMark
|
||||||
&& resolved?.inboundCode === dropshipProducer.inboundCode && resolved?.destinationType === dropshipProducer.destinationType))
|
&& resolved?.inboundCode === dropshipProducer.inboundCode && resolved?.destinationType === dropshipProducer.destinationType))
|
||||||
context.addStep(MODULE, `统一解析${resolved?.destinationType || 'UNKNOWN'}箱码${index + 1}并返回唯一入仓码`, response,
|
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) {
|
async function receiveFba(context, token, inbounds, pallet, cartonFixtures, index) {
|
||||||
const resolvedCartons = cartonFixtures.filter((item) => item.inbound.inboundCode === inbound.inboundCode
|
const inboundCodes = new Set(inbounds.map((item) => item.inboundCode))
|
||||||
|
const resolvedCartons = cartonFixtures.filter((item) => inboundCodes.has(item.inbound.inboundCode)
|
||||||
&& item.resolved.destinationType === 'FBA')
|
&& item.resolved.destinationType === 'FBA')
|
||||||
if (!resolvedCartons.length) {
|
if (resolvedCartons.length !== inbounds.length) {
|
||||||
blockerGap(context, `FBA入仓码${inbound.inboundCode}箱码解析`, '没有冻结箱码以200/code 200唯一解析到当前FBA入仓码')
|
blockerGap(context, `FBA组${[...inboundCodes].join('|')}箱码解析`, '没有为FBA组内每个入仓码完成唯一解析')
|
||||||
return false
|
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
|
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}`) }
|
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)
|
'/api/pda/v1/last-leg/receiving-containers/current/receipts/bulk', body)
|
||||||
if (!success(first.response)) return false
|
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)
|
'/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)
|
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)
|
'/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',
|
'/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
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,9 +613,12 @@ async function receiveDropship(context, token, producer, inbounds) {
|
|||||||
await expected(context, token, 'POST', `一件代发整托${index + 1}同键异载荷冲突`,
|
await expected(context, token, 'POST', `一件代发整托${index + 1}同键异载荷冲突`,
|
||||||
'/api/pda/v1/last-leg/receiving-containers/current/receipts/pallet',
|
'/api/pda/v1/last-leg/receiving-containers/current/receipts/pallet',
|
||||||
{ ...body, sourcePalletNo: `${sourcePalletNo}-MUTATED` }, conflict)
|
{ ...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',
|
'/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,
|
context.assert(MODULE, '一件代发整托实收箱数与待收箱数守恒', null,
|
||||||
accepted === expectedPending, `accepted=${accepted}, expected=${expectedPending}`, OPTIONS)
|
accepted === expectedPending, `accepted=${accepted}, expected=${expectedPending}`, OPTIONS)
|
||||||
@@ -728,8 +740,15 @@ async function runReceiving(context, token, secondaryToken, merchantToken, prefe
|
|||||||
cartonMark: fbaCarton?.cartonMark,
|
cartonMark: fbaCarton?.cartonMark,
|
||||||
palletCode: pallets.get(firstFba.inboundCode).palletCode, idempotencyKey: key(context, 'fba-carton-forbidden'),
|
palletCode: pallets.get(firstFba.inboundCode).palletCode, idempotencyKey: key(context, 'fba-carton-forbidden'),
|
||||||
}, (response) => a0409Message(response, /^FBA destination must use bulk count$/))
|
}, (response) => a0409Message(response, /^FBA destination must use bulk count$/))
|
||||||
for (const [index, inbound] of fbaInbounds.entries()) {
|
const groups = new Map()
|
||||||
await receiveFba(context, token, inbound, pallets.get(inbound.inboundCode), cartonFixtures, index)
|
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') {
|
} else if (!strictDropship && preferredProducer?.destinationType !== 'OVERSEAS') {
|
||||||
blockerGap(context, 'FBA按箱数链', '当前FBA柜没有带真实托盘的 FBA 入仓码')
|
blockerGap(context, 'FBA按箱数链', '当前FBA柜没有带真实托盘的 FBA 入仓码')
|
||||||
|
|||||||
+1
@@ -18,6 +18,7 @@ test('采购单号按北京时间日期执行精确合同', () => {
|
|||||||
test('钱包闭环覆盖充值、授信、采购冻结结算和换标结算释放', () => {
|
test('钱包闭环覆盖充值、授信、采购冻结结算和换标结算释放', () => {
|
||||||
for (const token of [
|
for (const token of [
|
||||||
'/accounts/${encodeURIComponent(customerId)}/credit-limit',
|
'/accounts/${encodeURIComponent(customerId)}/credit-limit',
|
||||||
|
'creditExpiresOn',
|
||||||
'/accounts/${encodeURIComponent(customerId)}/adjustments',
|
'/accounts/${encodeURIComponent(customerId)}/adjustments',
|
||||||
"const CLIENT_FINANCE = '/api/client/finance/v1'",
|
"const CLIENT_FINANCE = '/api/client/finance/v1'",
|
||||||
"['VOUCHER', 'RECEIPT']",
|
"['VOUCHER', 'RECEIPT']",
|
||||||
|
|||||||
@@ -67,8 +67,10 @@ async function prepareWallet(context, customerId) {
|
|||||||
if (!before.account) return null
|
if (!before.account) return null
|
||||||
|
|
||||||
const creditLimit = 2.00
|
const creditLimit = 2.00
|
||||||
|
const creditExpiresOn = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10)
|
||||||
const credit = await context.request('PUT', `${FINANCE}/accounts/${encodeURIComponent(customerId)}/credit-limit`,
|
const credit = await context.request('PUT', `${FINANCE}/accounts/${encodeURIComponent(customerId)}/credit-limit`,
|
||||||
{ creditLimit, remark: context.marker, expectedAccountVersion: Number(before.account.accountVersion) }, context.token,
|
{ creditLimit, creditExpiresOn, remark: context.marker,
|
||||||
|
expectedAccountVersion: Number(before.account.accountVersion) }, context.token,
|
||||||
{ 'Idempotency-Key': `${context.marker}-wallet-credit-limit`.slice(0, 128) })
|
{ 'Idempotency-Key': `${context.marker}-wallet-credit-limit`.slice(0, 128) })
|
||||||
assert(context, '授信额度可通过正式接口初始化', credit,
|
assert(context, '授信额度可通过正式接口初始化', credit,
|
||||||
success(credit) && money(credit.body.data?.creditLimitAfter) === creditLimit,
|
success(credit) && money(credit.body.data?.creditLimitAfter) === creditLimit,
|
||||||
|
|||||||
Reference in New Issue
Block a user