feat(dispatch): unify whole vehicle scheduling, source ownership and staged execution

This commit is contained in:
2026-10-19 23:40:42 +08:00
parent e0677e7ae7
commit 9dd34791f7
346 changed files with 29245 additions and 12602 deletions
+47 -10
View File
@@ -1,5 +1,6 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import { parsePoolArguments, poolPlan, runPoolAcceptance, assertPoolRemaining, assertSingleCommercial,
shrinkingVehicleRequest, expiryWaitMs, poolLocalDateTime, poolPickScope, pickPoolDispatch, POOL_COVERAGE, POOL_REMAINING,
poolInquiryWrite, poolReadIsDenied, assertPoolBoundCapacity, verifyPoolConfirmedCancellation, verifyPoolBindingRevalidation,
@@ -122,7 +123,7 @@ test('PDA namespace belongs to the exact run, customer and dispatch while parent
assert.throws(() => poolPickScope(context, { dispatchNo: 'DS-A' }), /PICK_SCOPE_REQUIRED/)
})
test('real pickAll helper handles two same-customer dispatches with separate pick/complete keys and exact replays', async () => {
test('real native pickAll preserves separate command namespaces, version zero, exact replays and stale rejection', async () => {
const operations = new Map(), requests = [], steps = [], picked = new Map()
const dispatches = ['DS-A', 'DS-B']
const context = {
@@ -134,26 +135,34 @@ test('real pickAll helper handles two same-customer dispatches with separate pic
const dispatchNo = path.split('/dispatches/')[1].split('/')[0], index = dispatches.indexOf(dispatchNo)
assert.ok(index >= 0)
const response = data => ({ http: 200, body: { code: '200', data }, requestId: 'test', traceId: 'test' })
if (method === 'GET') return response({ items: [{ dispatchItemId: `${index + 1}`, scheduledPackages: 1,
pickedPackages: picked.get(dispatchNo) || 0, positions: [{ id: `${index + 100}`, availablePackages: 1 }] }] })
const version = picked.get(dispatchNo) || 0
if (method === 'GET') return response({ dispatchNo, status: 'ACTIVE', stage: 'LOADING', recordVersion: index === 0 ? version : String(version),
pickingReconciled: version === 1, counts: { packageCount: 1, pickedPackageCount: version },
items: [{ dispatchItemId: `${index + 1}`, scheduledPackages: 1, pickedPackages: version,
positions: [{ positionId: `${index + 100}`, availablePackages: 1 }] }] })
requests.push({ method, path, body: structuredClone(body) })
assert.ok(path.endsWith('/pick'))
assert.equal(body.recordVersion, index === 0 ? 0 : '0')
const prior = operations.get(body.idempotencyKey), payload = JSON.stringify([path, body])
if (prior) {
if (prior.payload !== payload) return { http: 200, body: { code: 'A0409', message: 'Idempotency key was reused with a different request' } }
assert.equal(prior.payload, payload)
return response({ ...prior.result, replayed: true })
}
let result
if (path.endsWith('/pick')) { picked.set(dispatchNo, 1); result = { pickedPackages: 1 } }
else result = { status: 'READY_TO_DEPART', plannedPackages: 1, pickedPackages: 1, remainingPackages: 0, replayed: false }
if (version !== Number(body.recordVersion)) return { http: 409, body: { code: 'A0409' } }
picked.set(dispatchNo, 1)
const result = { recordVersion: '1', result: { pickedPackages: 1 }, counts: { packageCount: 1, pickedPackageCount: 1 }, replayed: false }
operations.set(body.idempotencyKey, { payload, result })
return response(result)
},
}
for (const dispatchNo of dispatches) await pickPoolDispatch(context, 'test-pda', { customerId: '9', dispatchNo })
assert.equal(operations.size, 4)
assert.equal(requests.length, 8)
assert.equal(operations.size, 2)
assert.equal(requests.length, 6)
assert.ok(steps.every(Boolean))
for (let index = 0; index < requests.length; index += 2) assert.deepEqual(requests[index], requests[index + 1])
for (let index = 0; index < requests.length; index += 3) {
assert.deepEqual(requests[index], requests[index + 1])
assert.notEqual(requests[index].body.idempotencyKey, requests[index + 2].body.idempotencyKey)
}
})
test('failed helper result stops the pool stage immediately instead of appending a misleading generic failure', async () => {
@@ -277,3 +286,31 @@ test('confirmed cancellation verifies both commercial types and reuses exact suc
assert.equal(result.remainingPalletSpaces, 12)
}
})
test('pool orchestration keeps native one-main boundaries, explicit reviews and real loading before whole arrangement', () => {
const source = readFileSync(new URL('./fleet-capacity-pool-test-env.mjs', import.meta.url), 'utf8')
for (const old of ['controlledPalletMeasurements(', '/external-freight', '/loading-review`', "departed.status === 'IN_TRANSIT'", 'sourceStage:', "'/dispatches/pre-arrange'"]) assert.equal(source.includes(old), false, old)
assert.match(source, /testPlannedCapacity\(plan\.cargo, detail\.trip\.stops\)/)
assert.match(source, /actual: false/)
assert.match(source, /arranged\.booking\.dispatchNo === fixture\.dispatchNo/)
assert.match(source, /\['submit-review', 'dispatch-review', 'loading-review'\]/)
const pick = source.indexOf('const namespace = await pickPoolDispatch('), load = source.indexOf('await confirmFleetLoading('), arrange = source.indexOf('await arrangeDispatchDelivery('), depart = source.indexOf("const departed = await request('POST', departPath")
assert.ok(pick > 0 && pick < load && load < arrange && arrange < depart)
assert.match(source, /fixture\.loadingMeasurements/)
assert.match(source, /recordVersion: current\.recordVersion/)
assert.match(source, /readyTask\.actions\?\.DEPART\?\.allowed === true/)
assert.match(source, /JSON\.stringify\(actual\.fees\) === JSON\.stringify\(signed\.fees\)/)
assert.match(source, /sameCustomerOrders\.every\(source => actual\.operations\.filter/)
})
test('pool execution explicitly selects capacity verification before handing off the shared runner', async () => {
const config = parsePoolArguments(['--execute', '--environment', 'TEST', '--run-id', 'pool-scope', '--warehouse-id', '10', '--destination-warehouse-id', '11'])
let selected
await assert.rejects(runPoolAcceptance(config, { env: {}, runner: async (actual, options) => {
assert.equal(actual, config)
selected = options.verificationScope
throw Error('STOP_BEFORE_ENVIRONMENT_ACCESS')
} }), /STOP_BEFORE_ENVIRONMENT_ACCESS/)
assert.equal(selected, 'CAPACITY_POOL')
})