优化
This commit is contained in:
@@ -13,12 +13,26 @@ function code(response) { return String(response?.body?.code ?? '') }
|
||||
function traced(response) { return nonBlank(response?.requestId) && nonBlank(response?.traceId) }
|
||||
function conflict(response) { return (response?.http === 409 || (response?.http === 200 && ['409', 'A0409'].includes(code(response)))) && traced(response) }
|
||||
function a0409Message(response, pattern) { return response?.http === 200 && code(response) === 'A0409' && traced(response) && pattern.test(String(response?.body?.message || '')) }
|
||||
function a0404Message(response, pattern) { return response?.http === 200 && code(response) === 'A0404' && traced(response) && pattern.test(String(response?.body?.message || '')) }
|
||||
function cartonResolveRejected(response) { return response?.http === 200 && ['A0400', 'A0404', 'A0409'].includes(code(response)) && traced(response) }
|
||||
function notFound(response) { return (response?.http === 404 || (response?.http === 200 && ['404', 'A0404'].includes(code(response)))) && traced(response) }
|
||||
function forbidden(response) { return [401, 403].includes(response?.http) || (response?.http === 200 && ['A0401', 'A0403'].includes(code(response))) }
|
||||
function trace(response) { return `HTTP=${response?.http ?? 'missing'}, code=${response?.body?.code ?? 'missing'}, requestId=${response?.requestId || 'missing'}, traceId=${response?.traceId || 'missing'}` }
|
||||
function key(context, action, suffix = '') { return `${context.marker}-${context.pdaContainerSuffix || ''}-${action}-${suffix}`.replace(/[^A-Za-z0-9:_-]/g, '').slice(0, 120) }
|
||||
function markerSuffix(context) { return `${context.marker}${context.pdaContainerSuffix || ''}`.replace(/[^A-Za-z0-9]/g, '').slice(-16).toUpperCase() }
|
||||
function records(data) { return Array.isArray(data?.records) ? data.records : Array.isArray(data) ? data : [] }
|
||||
function receivingSnapshot(data) {
|
||||
return JSON.stringify({
|
||||
containerNo: data?.containerNo, status: data?.status, version: data?.version,
|
||||
totalPackages: data?.totalPackages, receivedPackages: data?.receivedPackages,
|
||||
pendingPackages: data?.pendingPackages,
|
||||
inbounds: (Array.isArray(data?.inbounds) ? data.inbounds : []).map((item) => ({
|
||||
inboundCode: item?.inboundCode, destinationType: item?.destinationType,
|
||||
totalPackages: item?.totalPackages, receivedPackages: item?.receivedPackages,
|
||||
pendingPackages: item?.pendingPackages,
|
||||
})).sort((left, right) => `${left.inboundCode}:${left.destinationType}`.localeCompare(`${right.inboundCode}:${right.destinationType}`)),
|
||||
})
|
||||
}
|
||||
|
||||
function blockerGap(context, name, reason, category = 'fixture-unavailable', response = null) {
|
||||
context.addCoverageGap(MODULE, SCENARIO, name, reason, category, { deploymentBlocker: true })
|
||||
@@ -293,10 +307,14 @@ async function awaitPickupReadyCandidates(context, token, producers, allProducer
|
||||
}
|
||||
|
||||
async function resolveCartonFixtures(context, token, inbounds, producerCartonMarks = []) {
|
||||
const cartonCandidates = [...new Set((Array.isArray(producerCartonMarks) ? producerCartonMarks : [producerCartonMarks])
|
||||
.map(id).filter(nonBlank))]
|
||||
const manifestCartons = (Array.isArray(producerCartonMarks) ? producerCartonMarks : [producerCartonMarks])
|
||||
.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 cartonCandidates = [...new Set([...fbaCartons, ...overseasCartons])]
|
||||
if (!cartonCandidates.length) {
|
||||
blockerGap(context, '统一箱码解析链', '缺少本轮PDA任务冻结箱码,FBA和OVERSEAS均不能使用伪造箱号')
|
||||
blockerGap(context, '统一箱码解析链', 'FBA缺少当前柜入仓码或OVERSEAS缺少真实manifest箱码')
|
||||
return null
|
||||
}
|
||||
const cartonFixtures = []
|
||||
@@ -307,7 +325,7 @@ async function resolveCartonFixtures(context, token, inbounds, producerCartonMar
|
||||
const matches = inbounds.filter((item) => item.inboundCode === resolved?.inboundCode)
|
||||
const destinations = new Set(matches.map((item) => item?.destinationType).filter(nonBlank))
|
||||
const unique = success(response) && nonBlank(resolved?.inboundCode) && !Array.isArray(resolved?.inboundCode)
|
||||
&& matches.length > 0 && destinations.size === 1
|
||||
&& matches.length === 1 && destinations.size === 1
|
||||
&& ['FBA', 'OVERSEAS'].includes(resolved?.destinationType)
|
||||
&& destinations.has(resolved?.destinationType)
|
||||
context.addStep(MODULE, `统一解析${resolved?.destinationType || 'UNKNOWN'}箱码${index + 1}并返回唯一入仓码`, response,
|
||||
@@ -323,6 +341,41 @@ async function resolveCartonFixtures(context, token, inbounds, producerCartonMar
|
||||
return cartonFixtures
|
||||
}
|
||||
|
||||
async function probeCartonResolveNegatives(context, token, current) {
|
||||
const fba = current.inbounds.find((item) => item.destinationType === 'FBA')
|
||||
await expected(context, token, 'POST', '无#箱码被服务端拒绝',
|
||||
'/api/pda/v1/last-leg/receiving-containers/current/cartons/resolve',
|
||||
{ cartonMark: fba?.inboundCode || `NO-HASH-${markerSuffix(context)}` }, cartonResolveRejected)
|
||||
await expected(context, token, 'POST', '空#前缀箱码被服务端拒绝',
|
||||
'/api/pda/v1/last-leg/receiving-containers/current/cartons/resolve',
|
||||
{ cartonMark: `#${markerSuffix(context)}` }, cartonResolveRejected)
|
||||
await expected(context, token, 'POST', '未命中入仓码前缀被服务端拒绝',
|
||||
'/api/pda/v1/last-leg/receiving-containers/current/cartons/resolve',
|
||||
{ cartonMark: `UNMATCHED-${markerSuffix(context)}#ANY-SUFFIX` }, cartonResolveRejected)
|
||||
|
||||
const allProducers = context.createdResources?.phase4InboundProducerFixtures?.containers || []
|
||||
const crossContainerMark = allProducers
|
||||
.filter((item) => id(item?.containerNo) !== id(current.containerNo))
|
||||
.flatMap((item) => Array.isArray(item?.cartonMarks) ? item.cartonMarks : [item?.cartonMark])
|
||||
.map(id).find(nonBlank)
|
||||
if (crossContainerMark) {
|
||||
await expected(context, token, 'POST', '其他柜箱码前缀被当前锁定柜拒绝',
|
||||
'/api/pda/v1/last-leg/receiving-containers/current/cartons/resolve',
|
||||
{ cartonMark: crossContainerMark }, cartonResolveRejected)
|
||||
} else {
|
||||
blockerGap(context, '箱码跨柜负向', '缺少另一真实柜的冻结箱码,不能伪造跨柜归属反证')
|
||||
}
|
||||
|
||||
const overseas = current.inbounds.find((item) => item.destinationType === 'OVERSEAS')
|
||||
if (overseas) {
|
||||
const total = Math.max(1, Number(overseas.totalPackages || 1))
|
||||
await expected(context, token, 'POST', 'OVERSEAS缺少真实manifest行时不得按标准箱码推导',
|
||||
'/api/pda/v1/last-leg/receiving-containers/current/cartons/resolve',
|
||||
{ cartonMark: `${overseas.inboundCode}#${total + 1}-1` },
|
||||
(response) => a0404Message(response, /^Carton mark was not found$/))
|
||||
}
|
||||
}
|
||||
|
||||
async function receiveFba(context, token, inbound, pallet, cartonFixtures, index) {
|
||||
const resolvedCartons = cartonFixtures.filter((item) => item.inbound.inboundCode === inbound.inboundCode
|
||||
&& item.resolved.destinationType === 'FBA')
|
||||
@@ -454,10 +507,18 @@ async function runReceiving(context, token, secondaryToken, merchantToken, prefe
|
||||
{ ...signBody, photos: [...photos].reverse() }, conflict)
|
||||
const current = await pda(context, token, 'GET', '签收后按账号恢复当前柜', '/api/pda/v1/last-leg/receiving-containers/current')
|
||||
if (!success(current.response)) return
|
||||
const beforeResolve = receivingSnapshot(current.data)
|
||||
await probeCartonResolveNegatives(context, token, current.data)
|
||||
const producerCartonMarks = preferredProducer?.cartonMarks?.length
|
||||
? preferredProducer.cartonMarks : [preferredProducer?.cartonMark]
|
||||
const cartonFixtures = await resolveCartonFixtures(context, token, current.data.inbounds, producerCartonMarks)
|
||||
if (!cartonFixtures) return
|
||||
const afterResolve = await pda(context, token, 'GET', '箱码解析正负向后回查当前柜零写入',
|
||||
'/api/pda/v1/last-leg/receiving-containers/current')
|
||||
context.assert(MODULE, 'FBA与OVERSEAS箱码resolve均为纯查询且零状态写入', afterResolve.response,
|
||||
success(afterResolve.response) && receivingSnapshot(afterResolve.data) === beforeResolve,
|
||||
`before=${beforeResolve}, after=${receivingSnapshot(afterResolve.data)}; ${trace(afterResolve.response)}`, OPTIONS)
|
||||
if (!success(afterResolve.response) || receivingSnapshot(afterResolve.data) !== beforeResolve) return
|
||||
const pallets = new Map()
|
||||
for (const [index, inbound] of current.data.inbounds.entries()) {
|
||||
const pallet = await createPallet(context, inbound, index)
|
||||
|
||||
Reference in New Issue
Block a user