fix: complete overseas PDA inventory ledgers
This commit is contained in:
@@ -4,7 +4,7 @@ import path from 'node:path'
|
||||
import test from 'node:test'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
import { run } from './phase4-overseas-pda.mjs'
|
||||
import { expandOverseasCartonCandidates, run } from './phase4-overseas-pda.mjs'
|
||||
|
||||
const here = path.dirname(fileURLToPath(import.meta.url))
|
||||
const source = fs.readFileSync(path.join(here, 'phase4-overseas-pda.mjs'), 'utf8')
|
||||
@@ -61,7 +61,8 @@ test('PDA module covers the container-number receiving contract and excludes out
|
||||
assert.match(source, /const cartonCandidates =/)
|
||||
assert.doesNotMatch(source, /current\/skus\/resolve/)
|
||||
assert.doesNotMatch(source, /skuCode:/)
|
||||
assert.match(source, /FBA和OVERSEAS箱码resolve都必须HTTP 200\/code 200并返回当前柜唯一入仓码/)
|
||||
assert.match(source, /FBA箱码与OVERSEAS真实manifest箱码必须HTTP 200\/code 200并返回当前柜唯一入仓码/)
|
||||
assert.match(source, /排除未实装箱码候选/)
|
||||
assert.match(source, /const matches = inbounds\.filter/)
|
||||
assert.match(source, /!Array\.isArray\(resolved\?\.inboundCode\)/)
|
||||
assert.match(source, /matches\.length === 1/)
|
||||
@@ -102,6 +103,19 @@ test('PDA module covers the container-number receiving contract and excludes out
|
||||
assert.doesNotMatch(source, /awaitProducerCandidates/)
|
||||
})
|
||||
|
||||
test('OVERSEAS carton discovery probes the frozen sequence and lets the server exclude skipped cartons', () => {
|
||||
assert.deepEqual(expandOverseasCartonCandidates([
|
||||
{ inboundCode: 'NYEXX2609020042', destinationType: 'OVERSEAS' },
|
||||
{ inboundCode: 'FBA2609020001', destinationType: 'FBA' },
|
||||
], ['NYEXX2609020042#8-5', 'NYEXX2609020042#8-2', 'NYEXX2609020042#8-1']), [
|
||||
'NYEXX2609020042#8-1', 'NYEXX2609020042#8-2', 'NYEXX2609020042#8-3', 'NYEXX2609020042#8-4',
|
||||
'NYEXX2609020042#8-5', 'NYEXX2609020042#8-6', 'NYEXX2609020042#8-7', 'NYEXX2609020042#8-8',
|
||||
])
|
||||
assert.deepEqual(expandOverseasCartonCandidates([
|
||||
{ inboundCode: 'NYEXX2609020042', destinationType: 'OVERSEAS' },
|
||||
], ['NYEXX2609020042#2001-1']), [])
|
||||
})
|
||||
|
||||
test('real-device legacy FBA carton rejection is retained as regression evidence', () => {
|
||||
const evidence = {
|
||||
http: 200,
|
||||
|
||||
@@ -34,6 +34,19 @@ function receivingSnapshot(data) {
|
||||
})
|
||||
}
|
||||
|
||||
export function expandOverseasCartonCandidates(inbounds, producerCartonMarks = []) {
|
||||
const marks = (Array.isArray(producerCartonMarks) ? producerCartonMarks : [producerCartonMarks])
|
||||
.map(id).filter(nonBlank)
|
||||
return inbounds.filter((item) => item?.destinationType === 'OVERSEAS').flatMap((inbound) => {
|
||||
const patterns = marks.map((cartonMark) => ({ cartonMark, match: /^(.*)#(\d+)-(\d+)$/.exec(cartonMark) }))
|
||||
.filter(({ match }) => match && match[1] === inbound.inboundCode)
|
||||
const totals = [...new Set(patterns.map(({ match }) => Number(match[2]))
|
||||
.filter((total) => Number.isSafeInteger(total) && total > 0 && total <= 2000))]
|
||||
if (totals.length !== 1) return []
|
||||
return Array.from({ length: totals[0] }, (_, index) => `${inbound.inboundCode}#${totals[0]}-${index + 1}`)
|
||||
})
|
||||
}
|
||||
|
||||
function blockerGap(context, name, reason, category = 'fixture-unavailable', response = null) {
|
||||
context.addCoverageGap(MODULE, SCENARIO, name, reason, category, { deploymentBlocker: true })
|
||||
context.assert(MODULE, `${name}覆盖前置`, response, false, reason, OPTIONS)
|
||||
@@ -364,7 +377,7 @@ async function resolveCartonFixtures(context, token, inbounds, producerCartonMar
|
||||
.map(id).filter(nonBlank)
|
||||
const fbaCartons = inbounds.filter((item) => item.destinationType === 'FBA')
|
||||
.map((item, index) => `${item.inboundCode}#PDA-CONTRACT-${index + 1}`)
|
||||
const overseasCartons = inbounds.some((item) => item.destinationType === 'OVERSEAS') ? manifestCartons : []
|
||||
const overseasCartons = expandOverseasCartonCandidates(inbounds, manifestCartons)
|
||||
const cartonCandidates = [...new Set([...fbaCartons, ...overseasCartons])]
|
||||
if (!cartonCandidates.length) {
|
||||
blockerGap(context, '统一箱码解析链', 'FBA缺少当前柜入仓码或OVERSEAS缺少真实manifest箱码')
|
||||
@@ -374,6 +387,12 @@ async function resolveCartonFixtures(context, token, inbounds, producerCartonMar
|
||||
for (const [index, cartonMark] of cartonCandidates.entries()) {
|
||||
const response = await context.requestOverseas('POST',
|
||||
'/api/pda/v1/last-leg/receiving-containers/current/cartons/resolve', { cartonMark }, {}, token)
|
||||
if (overseasCartons.includes(cartonMark)
|
||||
&& a0404Message(response, /^Carton mark was not found$/)) {
|
||||
context.addStep(MODULE, `排除未实装箱码候选${index + 1}`, response, true,
|
||||
`cartonMark=${cartonMark}; ${trace(response)}`, OPTIONS)
|
||||
continue
|
||||
}
|
||||
const resolved = response.body?.data
|
||||
const matches = inbounds.filter((item) => item.inboundCode === resolved?.inboundCode)
|
||||
const destinations = new Set(matches.map((item) => item?.destinationType).filter(nonBlank))
|
||||
@@ -385,7 +404,7 @@ async function resolveCartonFixtures(context, token, inbounds, producerCartonMar
|
||||
unique, `cartonMark=${cartonMark}, inboundCode=${resolved?.inboundCode || 'missing'}, matches=${matches.length}; ${trace(response)}`, OPTIONS)
|
||||
if (!unique) {
|
||||
blockerGap(context, `箱码${cartonMark}唯一归属`,
|
||||
`FBA和OVERSEAS箱码resolve都必须HTTP 200/code 200并返回当前柜唯一入仓码;inboundCode=${resolved?.inboundCode || 'missing'}, matches=${matches.length}`,
|
||||
`FBA箱码与OVERSEAS真实manifest箱码必须HTTP 200/code 200并返回当前柜唯一入仓码;inboundCode=${resolved?.inboundCode || 'missing'}, matches=${matches.length}`,
|
||||
'fixture-mismatch', response)
|
||||
return null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user