test: complete phase4 PDA shipping prerequisites
This commit is contained in:
@@ -987,11 +987,15 @@ export class AcceptanceRun {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async runPhase4ProducerVariant(label, destinationType, fulfillmentType = 'STANDARD') {
|
async runPhase4ProducerVariant(label, destinationType, fulfillmentType = 'STANDARD', pickupRequired = false) {
|
||||||
const matrixMarker = this.marker
|
const matrixMarker = this.marker
|
||||||
const variantMarker = `${matrixMarker}-P4-${label}`
|
const variantMarker = `${matrixMarker}-P4-${label}`
|
||||||
const contextKeys = ['orderDestinationType', 'orderFulfillmentType', 'phase4ProducerMatrixMarker']
|
const contextKeys = ['orderDestinationType', 'orderFulfillmentType', 'phase4ProducerMatrixMarker']
|
||||||
const createdKeys = ['phase3Loading', 'phase3LoadingCompletedProducer', 'orchestrationFixtures', 'oceanBooking']
|
const createdKeys = [
|
||||||
|
'phase3Loading', 'phase3LoadingCompletedProducer', 'orchestrationFixtures', 'oceanBooking',
|
||||||
|
'phase3CustomsSupplier', 'phase3Customs', 'serviceCenterFlow', 'portSchedule',
|
||||||
|
'phase3OutboundDispatch', 'phase3CarrierScheduleQuery', 'phase4CarrierPickupReady',
|
||||||
|
]
|
||||||
const contextSnapshot = new Map(contextKeys.map((key) => [key, {
|
const contextSnapshot = new Map(contextKeys.map((key) => [key, {
|
||||||
present: Object.hasOwn(this.context, key), value: this.context[key],
|
present: Object.hasOwn(this.context, key), value: this.context[key],
|
||||||
}]))
|
}]))
|
||||||
@@ -1009,6 +1013,45 @@ export class AcceptanceRun {
|
|||||||
await this.executeModule(`phase3-loading-phase4-${label}`, () => loading.run(this))
|
await this.executeModule(`phase3-loading-phase4-${label}`, () => loading.run(this))
|
||||||
const finalize = await import(new URL('./admin-test-env-modules/phase3-loading-finalize.mjs', import.meta.url))
|
const finalize = await import(new URL('./admin-test-env-modules/phase3-loading-finalize.mjs', import.meta.url))
|
||||||
await this.executeModule(`phase3-loading-finalize-phase4-${label}`, () => finalize.run(this))
|
await this.executeModule(`phase3-loading-finalize-phase4-${label}`, () => finalize.run(this))
|
||||||
|
const producerKey = this.createdResources.phase3LoadingCompletedProducer?.resourceKey
|
||||||
|
const writeShippingEvidence = (shippingReady, carrierScheduleQueryId = null) => {
|
||||||
|
const matrix = this.createdResources.phase4InboundProducerFixtures
|
||||||
|
const records = [matrix?.containers, matrix?.byDestinationType?.FBA,
|
||||||
|
matrix?.byDestinationType?.OVERSEAS].filter(Array.isArray)
|
||||||
|
for (const values of records) {
|
||||||
|
const target = values.find((item) => item?.resourceKey === producerKey)
|
||||||
|
if (target) Object.assign(target, { shippingReady, carrierScheduleQueryId })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (producerKey) writeShippingEvidence(false)
|
||||||
|
if (pickupRequired && !producerKey) {
|
||||||
|
this.assert('phase4-overseas-pda-fixture', `${label}产生者身份完整`, null, false,
|
||||||
|
'phase3LoadingCompletedProducer.resourceKey=missing',
|
||||||
|
{ scenario: 'phase3-phase4-producer-fixture', deploymentBlocker: true })
|
||||||
|
}
|
||||||
|
if (pickupRequired && producerKey) {
|
||||||
|
const customs = await import(new URL('./admin-test-env-modules/phase3-customs.mjs', import.meta.url))
|
||||||
|
await this.executeModule(`phase3-customs-phase4-${label}`, () => customs.run(this))
|
||||||
|
const serviceCenter = await import(new URL('./admin-test-env-modules/service-center-flow.mjs', import.meta.url))
|
||||||
|
await this.executeModule(`service-center-flow-phase4-${label}`, () => serviceCenter.run(this))
|
||||||
|
const portSchedules = await import(new URL('./admin-test-env-modules/phase3-port-schedules.mjs', import.meta.url))
|
||||||
|
await this.executeModule(`phase3-port-schedules-phase4-${label}`, () => portSchedules.run(this))
|
||||||
|
const outbound = await import(new URL('./admin-test-env-modules/phase3-outbound-dispatch.mjs', import.meta.url))
|
||||||
|
await this.executeModule(`phase3-outbound-dispatch-phase4-${label}`, () => outbound.run(this))
|
||||||
|
const carrierQueries = await import(new URL('./admin-test-env-modules/phase3-carrier-schedule-queries.mjs', import.meta.url))
|
||||||
|
await this.executeModule(`phase3-carrier-schedule-queries-phase4-${label}`, () => carrierQueries.run(this))
|
||||||
|
const carrierNodes = await import(new URL('./admin-test-env-modules/phase4-carrier-nodes.mjs', import.meta.url))
|
||||||
|
await this.executeModule(`phase4-carrier-pickup-ready-phase4-${label}`,
|
||||||
|
() => carrierNodes.runUntilPickupReady(this))
|
||||||
|
const pickup = this.createdResources.phase4CarrierPickupReady
|
||||||
|
const shippingReady = pickup?.marker === variantMarker && pickup?.ready === true
|
||||||
|
&& Boolean(pickup?.queryId)
|
||||||
|
writeShippingEvidence(shippingReady, shippingReady ? String(pickup.queryId) : null)
|
||||||
|
this.assert('phase4-overseas-pda-fixture', `${label}通过真实出仓与船节点进入PICKUP_READY`, null,
|
||||||
|
shippingReady,
|
||||||
|
`resourceKey=${producerKey}, queryId=${pickup?.queryId || 'missing'}, ready=${pickup?.ready === true}`,
|
||||||
|
{ scenario: 'phase3-phase4-producer-fixture', deploymentBlocker: true })
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (restoreFixture) restoreFixture()
|
if (restoreFixture) restoreFixture()
|
||||||
this.marker = matrixMarker
|
this.marker = matrixMarker
|
||||||
@@ -1026,21 +1069,32 @@ export class AcceptanceRun {
|
|||||||
async ensurePhase4PdaProducerMatrix() {
|
async ensurePhase4PdaProducerMatrix() {
|
||||||
const readiness = () => this.createdResources.phase4InboundProducerFixtures?.readiness || {}
|
const readiness = () => this.createdResources.phase4InboundProducerFixtures?.readiness || {}
|
||||||
if (Number(readiness().dropshipContainerCount || 0) < 1) {
|
if (Number(readiness().dropshipContainerCount || 0) < 1) {
|
||||||
await this.runPhase4ProducerVariant('DROPSHIP-PRIMARY', 'FBA', 'ONE_CLICK_DROPSHIP')
|
await this.runPhase4ProducerVariant('DROPSHIP-PRIMARY', 'FBA', 'ONE_CLICK_DROPSHIP', true)
|
||||||
}
|
}
|
||||||
if (Number(readiness().fbaContainerCount || 0) < 2) {
|
if (Number(readiness().fbaContainerCount || 0) < 2) {
|
||||||
await this.runPhase4ProducerVariant('FBA-STANDARD', 'FBA')
|
await this.runPhase4ProducerVariant('FBA-STANDARD', 'FBA', 'STANDARD', false)
|
||||||
}
|
}
|
||||||
if (Number(readiness().overseasContainerCount || 0) < 1) {
|
if (Number(readiness().overseasContainerCount || 0) < 1) {
|
||||||
await this.runPhase4ProducerVariant('OVERSEAS-PRIMARY', 'OVERSEAS')
|
await this.runPhase4ProducerVariant('OVERSEAS-PRIMARY', 'OVERSEAS', 'STANDARD', true)
|
||||||
}
|
}
|
||||||
if (Number(readiness().distinctContainerCount || 0) < 4) {
|
if (Number(readiness().distinctContainerCount || 0) < 4) {
|
||||||
await this.runPhase4ProducerVariant('SECONDARY', 'FBA')
|
await this.runPhase4ProducerVariant('SECONDARY', 'FBA', 'STANDARD', false)
|
||||||
}
|
}
|
||||||
const matrix = this.createdResources.phase4InboundProducerFixtures
|
const matrix = this.createdResources.phase4InboundProducerFixtures
|
||||||
|
const containers = Array.isArray(matrix?.containers) ? matrix.containers : []
|
||||||
|
const dropshipReady = containers.find((item) => item?.fulfillmentType === 'ONE_CLICK_DROPSHIP')
|
||||||
|
const overseasReady = containers.find((item) => item?.destinationType === 'OVERSEAS')
|
||||||
|
const awaitingVariants = containers.filter((item) => ['FBA-STANDARD', 'SECONDARY']
|
||||||
|
.some((label) => String(item?.resourceKey || '').includes(`-P4-${label}:`)))
|
||||||
|
const shippingMatrixReady = dropshipReady?.shippingReady === true
|
||||||
|
&& Boolean(dropshipReady?.carrierScheduleQueryId)
|
||||||
|
&& overseasReady?.shippingReady === true && Boolean(overseasReady?.carrierScheduleQueryId)
|
||||||
|
&& awaitingVariants.length >= 1
|
||||||
|
&& awaitingVariants.every((item) => item.shippingReady === false
|
||||||
|
&& item.carrierScheduleQueryId == null)
|
||||||
this.assert('phase4-overseas-pda-fixture', '本轮三期跨区生产矩阵已就绪', null,
|
this.assert('phase4-overseas-pda-fixture', '本轮三期跨区生产矩阵已就绪', null,
|
||||||
matrix?.marker === this.marker && matrix?.readiness?.readyForPhase4Pda === true,
|
matrix?.marker === this.marker && matrix?.readiness?.readyForPhase4Pda === true && shippingMatrixReady,
|
||||||
`marker=${matrix?.marker || 'missing'}, FBA=${matrix?.readiness?.fbaContainerCount ?? 0}, OVERSEAS=${matrix?.readiness?.overseasContainerCount ?? 0}, DROPSHIP=${matrix?.readiness?.dropshipContainerCount ?? 0}, containers=${matrix?.readiness?.distinctContainerCount ?? 0}`,
|
`marker=${matrix?.marker || 'missing'}, FBA=${matrix?.readiness?.fbaContainerCount ?? 0}, OVERSEAS=${matrix?.readiness?.overseasContainerCount ?? 0}, DROPSHIP=${matrix?.readiness?.dropshipContainerCount ?? 0}, containers=${matrix?.readiness?.distinctContainerCount ?? 0}, shippingReady=${containers.filter((item) => item?.shippingReady === true).length}, awaiting=${awaitingVariants.length}`,
|
||||||
{ scenario: 'phase3-phase4-producer-fixture', deploymentBlocker: true })
|
{ scenario: 'phase3-phase4-producer-fixture', deploymentBlocker: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ test('measurement and loading pass destination identity into the LOADED producer
|
|||||||
assert.match(finalize, /resourceKey: `\$\{context\.marker\}:\$\{fixture\.destinationType \|\| 'UNKNOWN'\}:\$\{fixture\.containerNo \|\| containerBookingId\}`/)
|
assert.match(finalize, /resourceKey: `\$\{context\.marker\}:\$\{fixture\.destinationType \|\| 'UNKNOWN'\}:\$\{fixture\.containerNo \|\| containerBookingId\}`/)
|
||||||
assert.match(finalize, /phase4InboundProducerFixtures = collectPhase4InboundProducerFixture/)
|
assert.match(finalize, /phase4InboundProducerFixtures = collectPhase4InboundProducerFixture/)
|
||||||
const entry = read('../admin-test-env-acceptance.mjs')
|
const entry = read('../admin-test-env-acceptance.mjs')
|
||||||
assert.match(entry, /runPhase4ProducerVariant\('DROPSHIP-PRIMARY', 'FBA', 'ONE_CLICK_DROPSHIP'\)/)
|
assert.match(entry, /runPhase4ProducerVariant\('DROPSHIP-PRIMARY', 'FBA', 'ONE_CLICK_DROPSHIP', true\)/)
|
||||||
assert.match(entry, /orderFulfillmentType/)
|
assert.match(entry, /orderFulfillmentType/)
|
||||||
assert.match(entry, /fulfillmentType: fixtureOrder\.fulfillmentType \|\| 'STANDARD'/)
|
assert.match(entry, /fulfillmentType: fixtureOrder\.fulfillmentType \|\| 'STANDARD'/)
|
||||||
assert.match(entry, /skuCodes: Array\.isArray\(fixtureOrder\.skuCodes\) \? fixtureOrder\.skuCodes : \[\]/)
|
assert.match(entry, /skuCodes: Array\.isArray\(fixtureOrder\.skuCodes\) \? fixtureOrder\.skuCodes : \[\]/)
|
||||||
@@ -90,3 +90,35 @@ test('measurement and loading pass destination identity into the LOADED producer
|
|||||||
assert.match(pda, /find\(\(item\) => item\?\.fulfillmentType === 'ONE_CLICK_DROPSHIP'\)/)
|
assert.match(pda, /find\(\(item\) => item\?\.fulfillmentType === 'ONE_CLICK_DROPSHIP'\)/)
|
||||||
assert.match(pda, /skuFixtures\(context, producer\)/)
|
assert.match(pda, /skuFixtures\(context, producer\)/)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('only PDA-operated variants traverse real outbound and carrier nodes before overseas receiving', () => {
|
||||||
|
const entry = read('../admin-test-env-acceptance.mjs')
|
||||||
|
assert.match(entry, /runPhase4ProducerVariant\('OVERSEAS-PRIMARY', 'OVERSEAS', 'STANDARD', true\)/)
|
||||||
|
assert.match(entry, /runPhase4ProducerVariant\('FBA-STANDARD', 'FBA', 'STANDARD', false\)/)
|
||||||
|
assert.match(entry, /runPhase4ProducerVariant\('SECONDARY', 'FBA', 'STANDARD', false\)/)
|
||||||
|
const start = entry.indexOf('if (pickupRequired && producerKey)')
|
||||||
|
const end = entry.indexOf('} finally {', start)
|
||||||
|
const pickupChain = entry.slice(start, end)
|
||||||
|
const ordered = [
|
||||||
|
'phase3-customs.mjs', 'service-center-flow.mjs', 'phase3-port-schedules.mjs',
|
||||||
|
'phase3-outbound-dispatch.mjs', 'phase3-carrier-schedule-queries.mjs',
|
||||||
|
'phase4-carrier-nodes.mjs', 'runUntilPickupReady(this)',
|
||||||
|
]
|
||||||
|
let cursor = -1
|
||||||
|
for (const token of ordered) {
|
||||||
|
const next = pickupChain.indexOf(token)
|
||||||
|
assert.ok(next > cursor, `${token} must follow the real prerequisite chain`)
|
||||||
|
cursor = next
|
||||||
|
}
|
||||||
|
for (const key of ['phase3Customs', 'serviceCenterFlow', 'portSchedule', 'phase3OutboundDispatch',
|
||||||
|
'phase3CarrierScheduleQuery', 'phase4CarrierPickupReady']) assert.match(entry, new RegExp(`'${key}'`))
|
||||||
|
assert.match(pickupChain, /shippingReady/)
|
||||||
|
assert.match(entry, /carrierScheduleQueryId/)
|
||||||
|
assert.match(pickupChain, /pickup\?\.marker === variantMarker/)
|
||||||
|
assert.doesNotMatch(pickupChain, /internal\/event-bridge|ll_container_shipping_gate|requestOverseas/)
|
||||||
|
assert.match(entry, /dropshipReady\?\.shippingReady === true/)
|
||||||
|
assert.match(entry, /overseasReady\?\.shippingReady === true/)
|
||||||
|
assert.match(entry, /awaitingVariants\.length >= 1/)
|
||||||
|
assert.doesNotMatch(entry, /awaitingVariants\.length === 2/)
|
||||||
|
assert.match(entry, /awaitingVariants\.every\(\(item\) => item\.shippingReady === false/)
|
||||||
|
})
|
||||||
|
|||||||
@@ -80,7 +80,14 @@ test('cross-region normalization keeps existing producers ahead of every phase-t
|
|||||||
test('phase-four producer variants restore the primary orchestration fixture after each matrix branch', async () => {
|
test('phase-four producer variants restore the primary orchestration fixture after each matrix branch', async () => {
|
||||||
const source = await import('node:fs/promises').then((fs) => fs.readFile(
|
const source = await import('node:fs/promises').then((fs) => fs.readFile(
|
||||||
new URL('../admin-test-env-acceptance.mjs', import.meta.url), 'utf8'))
|
new URL('../admin-test-env-acceptance.mjs', import.meta.url), 'utf8'))
|
||||||
assert.match(source, /const createdKeys = \['phase3Loading', 'phase3LoadingCompletedProducer', 'orchestrationFixtures', 'oceanBooking'\]/)
|
const start = source.indexOf('const createdKeys = [', source.indexOf('async runPhase4ProducerVariant'))
|
||||||
|
const end = source.indexOf(']', start)
|
||||||
|
const createdKeys = source.slice(start, end)
|
||||||
|
for (const key of [
|
||||||
|
'phase3Loading', 'phase3LoadingCompletedProducer', 'orchestrationFixtures', 'oceanBooking',
|
||||||
|
'phase3CustomsSupplier', 'phase3Customs', 'serviceCenterFlow', 'portSchedule',
|
||||||
|
'phase3OutboundDispatch', 'phase3CarrierScheduleQuery', 'phase4CarrierPickupReady',
|
||||||
|
]) assert.match(createdKeys, new RegExp(`'${key}'`))
|
||||||
})
|
})
|
||||||
|
|
||||||
test('contract covers dual audience, canonical 403, both event directions and diagnostics', () => {
|
test('contract covers dual audience, canonical 403, both event directions and diagnostics', () => {
|
||||||
|
|||||||
@@ -55,6 +55,18 @@ test('PDA module covers the container-number receiving contract and excludes out
|
|||||||
assert.match(source, /phase4OverseasPda\.customerId = id\(order\.customerId\)/)
|
assert.match(source, /phase4OverseasPda\.customerId = id\(order\.customerId\)/)
|
||||||
assert.match(source, /现场库存查询只返回Token绑定仓且包含库存位置/)
|
assert.match(source, /现场库存查询只返回Token绑定仓且包含库存位置/)
|
||||||
assert.match(source, /作业历史包含本轮柜号收货动作且分页稳定/)
|
assert.match(source, /作业历史包含本轮柜号收货动作且分页稳定/)
|
||||||
|
assert.match(source, /awaitProducerConsumption\(context, allProducers\)/)
|
||||||
|
assert.match(source, /last-leg\/orders\?page=1&size=200&containerNo=/)
|
||||||
|
assert.match(source, /跨区消费生成尾程订单/)
|
||||||
|
assert.match(source, /awaitPickupReadyCandidates\(context, primary\.token, producers, allProducers\)/)
|
||||||
|
assert.match(source, /missingPickupReady=/)
|
||||||
|
assert.match(source, /item\?\.shippingReady === false/)
|
||||||
|
assert.match(source, /!expectedSet\.has\(id\(item\?\.containerNo\)\)/)
|
||||||
|
assert.match(source, /unexpectedAwaiting=/)
|
||||||
|
assert.match(source, /missingPickupReady\.length === 0 && unexpectedAwaiting\.length === 0/)
|
||||||
|
assert.doesNotMatch(source, /shippingReady == null|shippingReady !== true/)
|
||||||
|
assert.match(source, /unexpectedHistorical=/)
|
||||||
|
assert.doesNotMatch(source, /awaitProducerCandidates/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('missing WAREHOUSE_PICKER overseas authority is a deployment blocker', async () => {
|
test('missing WAREHOUSE_PICKER overseas authority is a deployment blocker', async () => {
|
||||||
|
|||||||
@@ -205,22 +205,63 @@ async function uploadPhotos(context, token) {
|
|||||||
return photos
|
return photos
|
||||||
}
|
}
|
||||||
|
|
||||||
async function awaitProducerCandidates(context, token, producers) {
|
async function awaitProducerConsumption(context, producers) {
|
||||||
const expected = [...new Set(producers.map((item) => id(item?.containerNo)).filter(nonBlank))]
|
const expected = [...new Set(producers.map((item) => id(item?.containerNo)).filter(nonBlank))]
|
||||||
|
if (!expected.length) return true
|
||||||
|
const consumed = new Set()
|
||||||
|
const lastResponses = new Map()
|
||||||
|
for (let attempt = 1; attempt <= 30; attempt += 1) {
|
||||||
|
const missing = expected.filter((containerNo) => !consumed.has(containerNo))
|
||||||
|
const results = await Promise.all(missing.map(async (containerNo) => {
|
||||||
|
const response = await context.requestOverseas('GET',
|
||||||
|
`/api/platform/v1/last-leg/orders?page=1&size=200&containerNo=${encodeURIComponent(containerNo)}`)
|
||||||
|
return { containerNo, response }
|
||||||
|
}))
|
||||||
|
for (const { containerNo, response } of results) {
|
||||||
|
lastResponses.set(containerNo, response)
|
||||||
|
const rows = records(response?.body?.data)
|
||||||
|
if (success(response) && rows.some((item) => id(item?.containerNo) === containerNo)) {
|
||||||
|
consumed.add(containerNo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (expected.every((containerNo) => consumed.has(containerNo))) break
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||||
|
}
|
||||||
|
for (const containerNo of expected) {
|
||||||
|
const response = lastResponses.get(containerNo) || null
|
||||||
|
context.addStep(MODULE, `跨区消费生成尾程订单 ${containerNo}`, response,
|
||||||
|
consumed.has(containerNo),
|
||||||
|
`containerNo=${containerNo}, consumed=${consumed.has(containerNo)}; ${trace(response)}`, OPTIONS)
|
||||||
|
}
|
||||||
|
return expected.every((containerNo) => consumed.has(containerNo))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function awaitPickupReadyCandidates(context, token, producers, allProducers) {
|
||||||
|
const expected = [...new Set(producers.map((item) => id(item?.containerNo)).filter(nonBlank))]
|
||||||
|
const expectedSet = new Set(expected)
|
||||||
|
const awaiting = [...new Set(allProducers
|
||||||
|
.filter((item) => item?.shippingReady === false && !expectedSet.has(id(item?.containerNo)))
|
||||||
|
.map((item) => id(item?.containerNo)).filter(nonBlank))]
|
||||||
|
const known = new Set(allProducers.map((item) => id(item?.containerNo)).filter(nonBlank))
|
||||||
if (!expected.length) return false
|
if (!expected.length) return false
|
||||||
let response = null
|
let response = null
|
||||||
let seen = new Set()
|
let seen = new Set()
|
||||||
for (let attempt = 1; attempt <= 30; attempt += 1) {
|
for (let attempt = 1; attempt <= 30; attempt += 1) {
|
||||||
response = await context.requestOverseas('GET',
|
response = await context.requestOverseas('GET',
|
||||||
'/api/pda/v1/last-leg/receiving-containers/candidates', undefined, {}, token)
|
'/api/pda/v1/last-leg/receiving-containers/candidates', undefined, {}, token)
|
||||||
const records = success(response) && Array.isArray(response.body?.data) ? response.body.data : []
|
const candidateRows = success(response) && Array.isArray(response.body?.data) ? response.body.data : []
|
||||||
seen = new Set(records.map((item) => id(item?.containerNo)).filter(nonBlank))
|
seen = new Set(candidateRows.map((item) => id(item?.containerNo)).filter(nonBlank))
|
||||||
if (expected.every((containerNo) => seen.has(containerNo))) break
|
if (expected.every((containerNo) => seen.has(containerNo))
|
||||||
|
&& awaiting.every((containerNo) => !seen.has(containerNo))) break
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000))
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
||||||
}
|
}
|
||||||
const ready = expected.every((containerNo) => seen.has(containerNo))
|
const seenExpected = expected.filter((containerNo) => seen.has(containerNo))
|
||||||
context.addStep(MODULE, '三期生产矩阵全部进入海外待收候选后再开始PDA', response, ready,
|
const missingPickupReady = expected.filter((containerNo) => !seen.has(containerNo))
|
||||||
`expected=${expected.join('|')}, seen=${[...seen].join('|')}; ${trace(response)}`, OPTIONS)
|
const unexpectedAwaiting = awaiting.filter((containerNo) => seen.has(containerNo))
|
||||||
|
const unexpectedHistorical = [...seen].filter((containerNo) => !known.has(containerNo))
|
||||||
|
const ready = missingPickupReady.length === 0 && unexpectedAwaiting.length === 0
|
||||||
|
context.addStep(MODULE, '实际处理柜全部达到PICKUP_READY并进入PDA候选', response, ready,
|
||||||
|
`expected=${expected.join('|')}, awaiting=${awaiting.join('|') || 'none'}, seenExpected=${seenExpected.join('|') || 'none'}, missingPickupReady=${missingPickupReady.join('|') || 'none'}, unexpectedAwaiting=${unexpectedAwaiting.join('|') || 'none'}, unexpectedHistorical=${unexpectedHistorical.join('|') || 'none'}; ${trace(response)}`, OPTIONS)
|
||||||
return ready
|
return ready
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,9 +542,14 @@ export async function run(context) {
|
|||||||
const producers = [dropship || matrix?.byDestinationType?.FBA?.[0], matrix?.byDestinationType?.OVERSEAS?.[0]]
|
const producers = [dropship || matrix?.byDestinationType?.FBA?.[0], matrix?.byDestinationType?.OVERSEAS?.[0]]
|
||||||
.filter((item) => nonBlank(item?.containerNo))
|
.filter((item) => nonBlank(item?.containerNo))
|
||||||
const allProducers = Array.isArray(matrix?.containers) ? matrix.containers : producers
|
const allProducers = Array.isArray(matrix?.containers) ? matrix.containers : producers
|
||||||
if (allProducers.length && !(await awaitProducerCandidates(context, primary.token, allProducers))) {
|
if (allProducers.length && !(await awaitProducerConsumption(context, allProducers))) {
|
||||||
blockerGap(context, '海外待收柜生产矩阵',
|
blockerGap(context, '跨区消费生产矩阵',
|
||||||
'三期已发布的FBA、OVERSEAS和第二柜尚未全部被海外事件消费者提交,禁止与消费事务并发入库')
|
'三期已发布的四柜尚未全部由海外消费者生成尾程订单,禁止把PICKUP_READY缺口与事件消费混为一谈')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (producers.length && !(await awaitPickupReadyCandidates(context, primary.token, producers, allProducers))) {
|
||||||
|
blockerGap(context, '实际处理柜PICKUP_READY门禁',
|
||||||
|
'Dropship/FBA与OVERSEAS实际处理柜尚未全部达到PICKUP_READY;跨区消费已独立验证,不回退处理历史柜')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for (const [index, producer] of (producers.length ? producers : [null]).entries()) {
|
for (const [index, producer] of (producers.length ? producers : [null]).entries()) {
|
||||||
|
|||||||
@@ -80,8 +80,12 @@ test('PDA entry expands the real phase-three producer chain and builds an FBA/OV
|
|||||||
assert.ok(modules.indexOf(prerequisite) >= 0 && modules.indexOf(prerequisite) < modules.indexOf('phase4-overseas-pda'))
|
assert.ok(modules.indexOf(prerequisite) >= 0 && modules.indexOf(prerequisite) < modules.indexOf('phase4-overseas-pda'))
|
||||||
}
|
}
|
||||||
assert.match(source, /async ensurePhase4PdaProducerMatrix\(\)/)
|
assert.match(source, /async ensurePhase4PdaProducerMatrix\(\)/)
|
||||||
assert.match(source, /runPhase4ProducerVariant\('OVERSEAS-PRIMARY', 'OVERSEAS'\)/)
|
assert.match(source, /runPhase4ProducerVariant\('DROPSHIP-PRIMARY', 'FBA', 'ONE_CLICK_DROPSHIP', true\)/)
|
||||||
assert.match(source, /runPhase4ProducerVariant\('SECONDARY', 'FBA'\)/)
|
assert.match(source, /runPhase4ProducerVariant\('OVERSEAS-PRIMARY', 'OVERSEAS', 'STANDARD', true\)/)
|
||||||
|
assert.match(source, /runPhase4ProducerVariant\('FBA-STANDARD', 'FBA', 'STANDARD', false\)/)
|
||||||
|
assert.match(source, /runPhase4ProducerVariant\('SECONDARY', 'FBA', 'STANDARD', false\)/)
|
||||||
|
assert.match(source, /runUntilPickupReady\(this\)/)
|
||||||
|
assert.match(source, /carrierScheduleQueryId/)
|
||||||
assert.match(source, /readyForPhase4Pda === true/)
|
assert.match(source, /readyForPhase4Pda === true/)
|
||||||
assert.equal(modules.indexOf('phase4-overseas-pda-operations'), modules.indexOf('phase4-overseas-pda') + 1)
|
assert.equal(modules.indexOf('phase4-overseas-pda-operations'), modules.indexOf('phase4-overseas-pda') + 1)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user