185 lines
12 KiB
JavaScript
185 lines
12 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import { dirname, resolve } from 'node:path'
|
|
import test from 'node:test'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
import { requestedOrderDestinationType } from './orders.mjs'
|
|
import { collectPhase4InboundProducerFixture } from './phase3-loading-finalize.mjs'
|
|
|
|
const here = dirname(fileURLToPath(import.meta.url))
|
|
const read = (name) => readFileSync(resolve(here, name), 'utf8')
|
|
|
|
test('order fixture defaults to FBA and preserves explicit OVERSEAS or PRIVATE routes', () => {
|
|
assert.equal(requestedOrderDestinationType({ context: {} }), 'FBA')
|
|
assert.equal(requestedOrderDestinationType({ context: { orderDestinationType: 'overseas' } }), 'OVERSEAS')
|
|
assert.equal(requestedOrderDestinationType({ context: { orderDestinationType: 'PRIVATE' } }), 'PRIVATE')
|
|
assert.equal(requestedOrderDestinationType({ context: { orderDestinationType: 'invalid' } }), 'FBA')
|
|
const orders = read('orders.mjs')
|
|
assert.match(orders, /warehouseType=\$\{encodeURIComponent\(destinationType\)\}/)
|
|
assert.match(orders, /destinationType: master\.destinationType/)
|
|
assert.match(orders, /fulfillmentType: dropship \? 'ONE_CLICK_DROPSHIP' : 'STANDARD'/)
|
|
assert.match(orders, /skuCodes: payload\.cargoes\.map\(\(cargo\) => cargo\.skuNo\)/)
|
|
assert.match(orders, /skuLines: payload\.cargoes\.map\(\(cargo\) => \(\{/)
|
|
assert.match(orders, /destinationType,\s*\n\s*\}\)/)
|
|
assert.doesNotMatch(orders, /const fbaResponse =/)
|
|
})
|
|
|
|
test('loading pick operation schemas accept whole-pallet dropship audits', () => {
|
|
const moduleSql = read('../../firstleg/src/main/resources/db/phase3-pda-convergence-schema.sql')
|
|
const unifiedSql = read('../../deploy/sql/头程数据库统一增量-MySQL8.sql')
|
|
for (const sql of [moduleSql, unifiedSql]) {
|
|
assert.match(sql, /chk_loading_pick_operation_action[\s\S]*?(?:_utf8mb4)?'PICK_PALLET'/)
|
|
}
|
|
assert.equal((unifiedSql.match(/CHECK \(\(?action_type in \([^)]*(?:_utf8mb4)?'PICK_PALLET'[^)]*\)\)?\)/gi) || []).length, 1)
|
|
})
|
|
|
|
test('producer collector requires dropship FBA, standard FBA, OVERSEAS and a fourth distinct container', () => {
|
|
const common = { marker: 'RUN-1', eventType: 'FIRST_LEG_LOADING_PLAN_COMPLETED', sourceStatus: 'LOADED' }
|
|
const dropship = { ...common, eventKey: 'DROP-EVENT', destinationType: 'FBA',
|
|
fulfillmentType: 'ONE_CLICK_DROPSHIP', containerNo: 'DROP-001' }
|
|
const fba = { ...common, eventKey: 'FBA-EVENT', destinationType: 'FBA',
|
|
fulfillmentType: 'STANDARD', containerNo: 'FBA-001' }
|
|
const overseasPrimary = { ...common, eventKey: 'OS-EVENT-1', destinationType: 'OVERSEAS', containerNo: 'OS-001' }
|
|
const secondary = { ...common, eventKey: 'FBA-EVENT-2', destinationType: 'FBA', containerNo: 'FBA-002' }
|
|
const one = collectPhase4InboundProducerFixture(null, dropship)
|
|
const two = collectPhase4InboundProducerFixture(one, fba)
|
|
const three = collectPhase4InboundProducerFixture(two, overseasPrimary)
|
|
const ready = collectPhase4InboundProducerFixture(three, secondary)
|
|
assert.equal(one.readiness.readyForPhase4Pda, false)
|
|
assert.equal(two.readiness.readyForPhase4Pda, false)
|
|
assert.equal(three.readiness.readyForPhase4Pda, false)
|
|
assert.equal(ready.readiness.readyForPhase4Pda, true)
|
|
assert.equal(ready.readiness.fbaContainerCount, 3)
|
|
assert.equal(ready.readiness.overseasContainerCount, 1)
|
|
assert.equal(ready.readiness.dropshipContainerCount, 1)
|
|
assert.equal(ready.readiness.distinctContainerCount, 4)
|
|
assert.equal(ready.byDestinationType.FBA[2].eventKey, 'FBA-EVENT-2')
|
|
})
|
|
|
|
test('same event key is idempotently replaced and another marker starts a new matrix', () => {
|
|
const first = collectPhase4InboundProducerFixture(null,
|
|
{ marker: 'RUN-1', eventKey: 'EVENT-1', destinationType: 'FBA', containerNo: 'FBA-001' })
|
|
const replay = collectPhase4InboundProducerFixture(first,
|
|
{ marker: 'RUN-1', eventKey: 'EVENT-1', destinationType: 'FBA', containerNo: 'FBA-001' })
|
|
assert.equal(replay.containers.length, 1)
|
|
const nextRun = collectPhase4InboundProducerFixture(replay,
|
|
{ marker: 'RUN-2', eventKey: 'EVENT-2', destinationType: 'OVERSEAS', containerNo: 'OS-002' })
|
|
assert.equal(nextRun.containers.length, 1)
|
|
assert.equal(nextRun.marker, 'RUN-2')
|
|
assert.deepEqual(nextRun.requiredEntryOrchestration, [
|
|
'DROPSHIP-FBA: public order fulfillmentType -> inbound-measurement -> phase3-loading -> phase3-loading-finalize -> overseas PDA',
|
|
'FBA: orders -> inbound-measurement -> phase3-loading -> phase3-customs -> phase3-loading-finalize',
|
|
'OVERSEAS-PRIMARY: orders -> inbound-measurement -> phase3-loading -> phase3-customs -> phase3-loading-finalize',
|
|
'SECONDARY(FBA|OVERSEAS): orders -> inbound-measurement -> phase3-loading -> phase3-customs -> phase3-loading-finalize',
|
|
])
|
|
})
|
|
|
|
test('measurement and loading pass destination identity into the LOADED producer key', () => {
|
|
const measurement = read('inbound-measurement.mjs')
|
|
const loading = read('phase3-loading.mjs')
|
|
const finalize = read('phase3-loading-finalize.mjs')
|
|
assert.match(measurement, /destinationType: context\.createdResources\?\.orders\?\.destinationType/)
|
|
assert.match(loading, /destinationType: initial\?\.summary\?\.destinationType \|\| source\?\.destinationType/)
|
|
assert.match(loading, /cabinetNo: simulation\.cabinetNo, containerNo/)
|
|
assert.match(loading, /fulfillmentType: source\?\.fulfillmentType \|\| 'STANDARD'/)
|
|
assert.match(loading, /Array\.isArray\(incrementalFixture\?\.skuCodes\)/)
|
|
assert.match(loading, /Array\.isArray\(incrementalFixture\?\.skuLines\)/)
|
|
assert.match(finalize, /destinationType: fixture\.destinationType \|\| null/)
|
|
assert.match(finalize, /cabinetNo: fixture\.cabinetNo \|\| null/)
|
|
assert.match(finalize, /`\$\{fixture\.cabinetNo\}-\$\{label\.destinationWarehouseInternalCode\}-/)
|
|
assert.match(finalize, /fulfillmentType: fixture\.fulfillmentType \|\| 'STANDARD'/)
|
|
assert.match(finalize, /skuCodes: Array\.isArray\(fixture\.skuCodes\) \? fixture\.skuCodes : \[\]/)
|
|
assert.match(finalize, /skuLines: Array\.isArray\(fixture\.skuLines\) \? fixture\.skuLines : \[\]/)
|
|
assert.match(finalize, /resourceKey: `\$\{context\.marker\}:\$\{fixture\.destinationType \|\| 'UNKNOWN'\}:\$\{fixture\.containerNo \|\| containerBookingId\}`/)
|
|
assert.match(finalize, /phase4InboundProducerFixtures = collectPhase4InboundProducerFixture/)
|
|
const entry = read('../admin-test-env-acceptance.mjs')
|
|
assert.match(entry, /runPhase4ProducerVariant\('DROPSHIP-PRIMARY', 'FBA', 'ONE_CLICK_DROPSHIP', true\)/)
|
|
assert.match(entry, /packageCounts: \[4\], palletCount: 2/)
|
|
assert.match(entry, /sealedSourcePalletNos: Array\.isArray\(fixture\.sealedSourcePalletNos\)/)
|
|
assert.match(entry, /orderFulfillmentType/)
|
|
assert.match(entry, /fulfillmentType: fixtureOrder\.fulfillmentType \|\| 'STANDARD'/)
|
|
assert.match(entry, /inboundFees\.ensureInitialCalculated\(this,/)
|
|
assert.match(entry, /this\.createdResources\.orchestrationFixtures\?\.phase3Loading/)
|
|
assert.doesNotMatch(entry, /inbound-fees-phase4-|createdResources\.inboundMeasurement = this\.createdResources\.orchestrationFixtures/)
|
|
assert.match(entry, /skuCodes: Array\.isArray\(fixtureOrder\.skuCodes\) \? fixtureOrder\.skuCodes : \[\]/)
|
|
assert.match(entry, /skuLines: Array\.isArray\(fixtureOrder\.skuLines\) \? fixtureOrder\.skuLines : \[\]/)
|
|
const pda = read('phase4-overseas-pda.mjs')
|
|
assert.match(loading, /pallet-assignments/)
|
|
assert.match(loading, /一件代发分配首托后其余托盘仍可独立分配/)
|
|
assert.match(loading, /已封托托盘拒绝按单条装柜明细删除/)
|
|
assert.match(loading, /智能推荐按整托重新加入一件代发多托/)
|
|
assert.match(loading, /智能推荐保留同票全部封托托盘且不按箱拆分/)
|
|
assert.match(loading, /customerId:\s*tenantId/)
|
|
assert.match(loading, /inboundCode:\s*initial\?\.summary\?\.inboundCode\s*\|\|\s*source\?\.inboundCode/)
|
|
assert.match(loading, /canonicalPickItems\.map/)
|
|
assert.match(loading, /pickedPackageCount: Number\(item\.plannedPackageCount\)/)
|
|
assert.match(loading, /const dropshipWholePallet = source\?\.fulfillmentType === 'ONE_CLICK_DROPSHIP'/)
|
|
assert.match(loading, /const canonicalPickPath = batchPath/)
|
|
assert.match(loading, /action: 'PICK_PALLET', palletNo: item\.palletNo/)
|
|
assert.match(loading, /const canonicalPickAction = 'BATCH'/)
|
|
assert.match(loading, /一件代发整托生产者不执行可拆分动态增量场景/)
|
|
assert.match(loading, /!dropshipWholePallet && Array\.isArray\(incrementalFixture\?\.skuCodes\)/)
|
|
assert.match(pda, /find\(\(item\) => item\?\.fulfillmentType === 'ONE_CLICK_DROPSHIP'\)/)
|
|
assert.match(pda, /resolveCartonFixtures\(context, token, current\.data\.inbounds, producerCartonMarks, preferredProducer\)/)
|
|
assert.match(pda, /FBA与OVERSEAS箱码resolve均为纯查询且零状态写入/)
|
|
})
|
|
|
|
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', 'ONE_CLICK_DROPSHIP', true\)/)
|
|
assert.match(entry, /runPhase4ProducerVariant\('FBA-STANDARD', 'FBA', 'STANDARD', true\)/)
|
|
assert.match(entry, /runPhase4ProducerVariant\('SECONDARY', 'FBA', 'STANDARD', false\)/)
|
|
assert.match(entry, /const hasSecondaryProducer =/)
|
|
assert.match(entry, /if \(!hasSecondaryProducer\(\)\)/)
|
|
assert.doesNotMatch(entry, /if \(Number\(readiness\(\)\.distinctContainerCount \|\| 0\) < 4\)/)
|
|
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(entry, /for \(const key of createdKeys\) delete this\.createdResources\[key\]/)
|
|
assert.match(pickupChain, /shippingReady/)
|
|
assert.match(entry, /carrierScheduleQueryId/)
|
|
assert.match(entry, /carrierLatestActualAt/)
|
|
assert.match(pickupChain, /pickup\.latestActualAt/)
|
|
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, /standardFbaReady\?\.shippingReady === true/)
|
|
assert.match(entry, /awaitingVariants\.every\(\(item\) => item\.shippingReady === false/)
|
|
})
|
|
|
|
|
|
test('full phase3 chain validates sealed pallet query metadata and atomic batch protection', () => {
|
|
const loading = read('phase3-loading.mjs')
|
|
assert.match(loading, /canonicalPickItems\.every\(\(item\) => item\.unitType === 'SEALED_PALLET'/)
|
|
assert.match(loading, /unit\.unitType === 'SEALED_PALLET'/)
|
|
for (const field of ['pickItemId', 'loadingPlanItemId', 'inboundId', 'palletId', 'palletNo', 'indivisible']) {
|
|
assert.ok(loading.includes(`unit.${field}`), `inventory units must verify ${field}`)
|
|
}
|
|
assert.match(loading, /if \(!taskUnitsValid \|\| !inventoryUnitsValid\) return/)
|
|
assert.match(loading, /items: \[\.\.\.batchPayload\.items, \{/)
|
|
assert.match(loading, /taskItemsSignature\(unchangedAfterInvalid\) === taskItemsSignature\(beforeInvalidTask\)/)
|
|
assert.match(loading, /operationsSignature\(afterInvalidOperations\) === operationsSignature\(beforeInvalidOperations\)/)
|
|
assert.match(loading, /for \(const action of \['PICK', 'PARTIAL', 'SKIP'\]\)/)
|
|
assert.match(loading, /operationsSignature\(afterBypassOperations\) === operationsSignature\(beforeInvalidOperations\)/)
|
|
assert.match(loading, /整托batch同键改托盘码必须冲突/)
|
|
assert.match(loading, /item\.operationId === batchKey[\s\S]*?\.length === 1/)
|
|
assert.doesNotMatch(loading, /tasks\/\$\{canonicalTaskId\}\/pallets\/pick/)
|
|
})
|