test(fleet): cover partial returns and redispatch through real API flow
This commit is contained in:
@@ -12,6 +12,7 @@ import { verifyFleetExternalReceipt } from './admin-test-env-modules/fleet-exter
|
||||
import { verifyFleetExternalDispatch } from './admin-test-env-modules/fleet-external-dispatch-acceptance.mjs'
|
||||
import { verifyFleetHandover, cleanupFleetHandoverResources } from './admin-test-env-modules/fleet-handover-acceptance.mjs'
|
||||
import { verifyFleetTripCosts } from './admin-test-env-modules/fleet-trip-cost-acceptance.mjs'
|
||||
import { verifyFleetReturnRedispatch } from './admin-test-env-modules/fleet-return-redispatch-acceptance.mjs'
|
||||
import { resolvePickerAccess, createPicker, disablePicker } from './admin-test-env-modules/phase4-overseas-pda.mjs'
|
||||
import { pickAll, saveReceiptAndComplete } from './admin-test-env-modules/phase5-overseas-fulfillment.mjs'
|
||||
|
||||
@@ -23,7 +24,7 @@ const success = response => response?.http === 200 && id(response?.body?.code) =
|
||||
const key = () => `fleet-${randomUUID()}`
|
||||
|
||||
export function parseFleetArguments(args) {
|
||||
const config = { execute: false, environment: 'TEST', runId: 'plan' }
|
||||
const config = { execute: false, environment: 'TEST', runId: 'plan', scenario: 'handover' }
|
||||
let action = null
|
||||
const seen = new Set()
|
||||
for (let index = 0; index < args.length; index++) {
|
||||
@@ -32,7 +33,7 @@ export function parseFleetArguments(args) {
|
||||
if (action) throw Error('Choose exactly one plan or execute action')
|
||||
action = name; config.execute = name === '--execute'; continue
|
||||
}
|
||||
if (!['--environment', '--run-id', '--output', '--resume-report', '--resume-stage'].includes(name) || !args[index + 1] || args[index + 1].startsWith('--')) throw Error('Unsupported or missing argument')
|
||||
if (!['--environment', '--run-id', '--output', '--resume-report', '--resume-stage', '--scenario'].includes(name) || !args[index + 1] || args[index + 1].startsWith('--')) throw Error('Unsupported or missing argument')
|
||||
if (seen.has(name)) throw Error('Duplicate argument')
|
||||
seen.add(name)
|
||||
const value = args[++index]
|
||||
@@ -40,16 +41,21 @@ export function parseFleetArguments(args) {
|
||||
else if (name === '--run-id') config.runId = value
|
||||
else if (name === '--output') config.outputDir = value
|
||||
else if (name === '--resume-report') config.resumeReport = value
|
||||
else if (name === '--scenario') config.scenario = value
|
||||
else config.resumeStage = value
|
||||
}
|
||||
if (config.environment !== 'TEST' || !/^[A-Za-z0-9][A-Za-z0-9_-]{0,47}$/.test(config.runId)
|
||||
|| (config.execute && (!args.includes('--environment') || config.runId === 'plan'))) throw Error('Explicit TEST and fresh run-id required')
|
||||
if (Boolean(config.resumeReport) !== Boolean(config.resumeStage) || (config.resumeStage && !['FULL_COVERAGE', 'FULL_COVERAGE_PERSISTED', 'EXTERNAL_RECEIPT_READY', 'EXTERNAL_PALLETIZED', 'EXTERNAL_RECEIPT_CONFIRMED', 'TERMINAL_READONLY'].includes(config.resumeStage))) throw Error('Explicit reviewed checkpoint required')
|
||||
if (config.outputDir && !/^reports\/[A-Za-z0-9][A-Za-z0-9_-]{0,95}$/.test(config.outputDir)) throw Error('Output must be a fresh named directory directly under reports')
|
||||
if (!['handover', 'return-redispatch'].includes(config.scenario) || (config.scenario === 'return-redispatch' && config.resumeReport))
|
||||
throw Error('Return redispatch only accepts a fresh run, never a reviewed old checkpoint')
|
||||
return config
|
||||
}
|
||||
export function fleetExecutionPlan(config) {
|
||||
return { environment: 'TEST', execution: config.execute ? 'EXECUTE' : 'PLAN', runId: config.runId,
|
||||
return { environment: 'TEST', execution: config.execute ? 'EXECUTE' : 'PLAN', runId: config.runId, scenario: config.scenario || 'handover',
|
||||
returnRedispatch: config.scenario === 'return-redispatch' ? { required: 'Two current-run domestic sources; A >=3 boxes; current departure covers A and B in full',
|
||||
stages: ['A actual return 2', 'original remaining signatures; A incomplete and B complete', 'RETURN_RECEIPT draft lock and pre-arrange', 'new PDA picks and DEPART 2', 'redispatch signature; A complete', 'source event/ACK read-only evidence remains required'] } : null,
|
||||
outputDir: config.outputDir || `reports/fleet-${config.runId}`, producer: config.resumeReport ? 'Reviewed read-only FULL_COVERAGE checkpoint in the same original fixture' : 'phase4-overseas-dispatch with its normal fresh prerequisites',
|
||||
resumeReport: config.resumeReport || null, resumeStage: config.resumeStage || null,
|
||||
stages: ['FULL original coverage', 'formal cancel/unbind/re-arrange', 'PARTIAL original coverage', 'reservation lifecycle',
|
||||
@@ -430,6 +436,13 @@ export async function runFleetScenario(context, { wait = ms => new Promise(resol
|
||||
})
|
||||
stage('RECEIPTS_AND_RESOURCE_RELEASE')
|
||||
proof.receipts = []
|
||||
if (context.context.fleetScenario === 'return-redispatch') {
|
||||
stage('RETURN_REDISPATCH')
|
||||
const returned = await verifyFleetReturnRedispatch(context, MODULE, trip, { customerId, warehouseId, pickerToken: picker.token,
|
||||
dispatchNos, deliveryNos: [...partial.proof.deliveryNos, external.deliveryNo] })
|
||||
proof.receipts = returned.originalSignatures.map(row => ({ deliveryNo: row.deliveryNo, signedAt: row.signedAt }))
|
||||
context.context.saveFleetReturnRedispatchFixture(returned)
|
||||
} else {
|
||||
for (const [index, deliveryNo] of [...partial.proof.deliveryNos, external.deliveryNo].entries()) {
|
||||
const delivery = await request('GET', `/api/platform/v1/last-leg/delivery-orders/${encodeURIComponent(deliveryNo)}?customerId=${encodeURIComponent(customerId)}`,
|
||||
undefined, '签收前读取本次实际派送')
|
||||
@@ -437,6 +450,7 @@ export async function runFleetScenario(context, { wait = ms => new Promise(resol
|
||||
check('每个目的地真实保存签收资料后完成', completed?.order?.status === 'DELIVERED' && completed.order.signedAt)
|
||||
proof.receipts.push({ deliveryNo, signedAt: completed.order.signedAt })
|
||||
}
|
||||
}
|
||||
proof.closure = await finishFleetTrip(context, MODULE, trip)
|
||||
check('本次车次货物结案及车辆司机释放完成', proof.closure?.status === 'CARGO_COMPLETED_AND_RESOURCES_RELEASED')
|
||||
stage('HANDOVER_RESOURCE_CLEANUP')
|
||||
@@ -485,7 +499,9 @@ export async function runFleetAcceptance(config, { env = process.env, readers, c
|
||||
markerNamespace: createHash('sha256').update(config.runId).digest('hex').slice(0, 12) })
|
||||
context = createContext ? createContext(options) : new AcceptanceRun(options)
|
||||
context.context.fleetRunId = config.runId
|
||||
context.context.fleetScenario = config.scenario || 'handover'
|
||||
context.context.saveFleetHandoverFixture = fixture => save('handover-fixture.json', fixture)
|
||||
context.context.saveFleetReturnRedispatchFixture = fixture => save('return-redispatch-fixture.json', fixture)
|
||||
let handoverCheckpoint = 0
|
||||
context.context.checkpointFleetHandover = proof => {
|
||||
const payload = JSON.stringify(redactEvidence({ marker: context.marker, runId: config.runId,
|
||||
|
||||
Reference in New Issue
Block a user