优化
This commit is contained in:
@@ -2,16 +2,29 @@ import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { fulfillmentHistorySnapshot, validTwoFragmentTree, validSignatureGate,
|
||||
completionCounts, exactCompletionOutboxProof, resolveF40MerchantCredentials,
|
||||
completionCounts, exactCompletionOutboxProof, rootCompletionTimeMatches, resolveF40MerchantCredentials,
|
||||
f40TransferBody, f40LocalDateTime, validFragmentCabinetIdentity, validUnloadedRemainder,
|
||||
validRemainderCancellationGate, exactCancelledRemainderOutboxProof, cancelUnloadedRemainder,
|
||||
verifyRootProjections, verifyRemainderTaxIdentity, validFreshReceiptSave, preserveReceivingEvidence, run } from './phase5-root-fulfillment.mjs'
|
||||
verifyRootProjections, verifyRemainderTaxIdentity, validFreshReceiptSave, preserveReceivingEvidence,
|
||||
resolveF40ReceivingWarehouse, run } from './phase5-root-fulfillment.mjs'
|
||||
import { loadOneFragment } from './phase3-order-splitting.mjs'
|
||||
import { verifyPalletLabels } from './phase3-loading-finalize.mjs'
|
||||
import { awaitProducerConsumption, convertReceivingContainers, runReceiving,
|
||||
resolveSharedWarehouse } from './phase4-overseas-pda.mjs'
|
||||
|
||||
const source = readFileSync(new URL('./phase5-root-fulfillment.mjs', import.meta.url),'utf8')
|
||||
|
||||
test('根完成UTC时刻与上海本地签收最大值一致,拒绝时区偏移、较早来源和缺失证据', () => {
|
||||
const times = ['2026-10-05T21:55:00.000', '2026-10-05T21:56:07.922']
|
||||
assert.equal(rootCompletionTimeMatches('2026-10-05T13:56:07.922', times), true)
|
||||
assert.equal(rootCompletionTimeMatches('2026-10-05T13:56:07.922Z', [...times].reverse()), true)
|
||||
assert.equal(rootCompletionTimeMatches('2026-10-05T13:56:07.922Z', ['2026-10-05T21:56:07.922+08:00']), true)
|
||||
for (const value of ['2026-10-05T21:56:07.922', '2026-10-05T13:55:00', null]) {
|
||||
assert.equal(rootCompletionTimeMatches(value, times), false)
|
||||
}
|
||||
assert.equal(rootCompletionTimeMatches('2026-10-05T13:56:07.922', []), false)
|
||||
assert.equal(rootCompletionTimeMatches('2026-10-05T13:56:07.922', ['invalid']), false)
|
||||
})
|
||||
const history = (...actions) => actions.map((action,index) => ({id:String(index+1),action}))
|
||||
const tree = () => ({parentOrderId:'100',originalPackageCount:2,cumulativeLoadedPackageCount:2,
|
||||
currentRemainderPackageCount:0,children:[
|
||||
@@ -285,6 +298,85 @@ test('exported receiving warehouse resolver continues to choose only configured
|
||||
]}}})
|
||||
assert.deepEqual(await resolveSharedWarehouse(context),{id:'193000000000200003',name:'offline'})
|
||||
})
|
||||
|
||||
function warehouseSelectionFixture() {
|
||||
const producers = [1, 2].map(n => ({ tenantId: '90', containerNo: `CONTAINER-${n}`,
|
||||
containerBookingId: `BOOKING-${n}`, sourceInboundId: `INBOUND-${n}`, inboundCode: `CODE-${n}` }))
|
||||
const orders = producers.map((p, n) => ({ id: `LASTLEG-${n}`, customerId: p.tenantId,
|
||||
sourceContainerBookingId: p.containerBookingId, sourceInboundId: p.sourceInboundId,
|
||||
inboundCode: p.inboundCode, containerNo: p.containerNo, overseasWarehouseId: 'actual-warehouse',
|
||||
overseasWarehouseCode: 'ACTUAL' }))
|
||||
const warehouses = [{ id: 'other-warehouse', warehouseName: 'other', warehouseCode: 'OTHER',
|
||||
warehouseType: 'OVERSEAS', status: 'ACTIVE' },
|
||||
{ id: 'actual-warehouse', warehouseName: 'actual', warehouseCode: 'ACTUAL',
|
||||
warehouseType: 'OVERSEAS', status: 'ACTIVE' }]
|
||||
const calls = [], context = fixture()
|
||||
context.request = async (method, path) => {
|
||||
calls.push({ method, path })
|
||||
const rows = path.includes('/warehouse-admin?') ? warehouses
|
||||
: orders.filter(row => row.containerNo === new URL(path, 'https://offline.invalid').searchParams.get('containerNo'))
|
||||
return { http: 200, body: { code: 200, data: { records: rows, total: rows.length } } }
|
||||
}
|
||||
return { producers, orders, warehouses, calls, context }
|
||||
}
|
||||
|
||||
test('F40 selects actual source warehouse irrespective of authority list order and only performs GET', async () => {
|
||||
for (const reverse of [false, true]) {
|
||||
const f = warehouseSelectionFixture()
|
||||
if (reverse) { f.warehouses.reverse(); f.orders.reverse(); f.producers.reverse() }
|
||||
const warehouse = await resolveF40ReceivingWarehouse(f.context, f.producers)
|
||||
assert.equal(warehouse.id, 'actual-warehouse')
|
||||
assert.equal(warehouse.code, 'ACTUAL')
|
||||
assert.equal(warehouse.sourceOrders.length, 2)
|
||||
assert.ok(f.calls.every(row => row.method === 'GET'))
|
||||
}
|
||||
assert.ok(source.indexOf('await awaitProducerConsumption(scope,producers)')
|
||||
< source.indexOf('await resolveF40ReceivingWarehouse(scope,producers)'))
|
||||
assert.ok(source.indexOf('await resolveF40ReceivingWarehouse(scope,producers)')
|
||||
< source.indexOf('await createPicker(scope, 7'))
|
||||
assert.doesNotMatch(source, /resolveSharedWarehouse|19300000000020000[34]/)
|
||||
})
|
||||
|
||||
test('F40 warehouse resolution rejects wrong customer, booking, inbound identity, duplicates and missing assignment', async () => {
|
||||
for (const mutate of [
|
||||
f => { f.orders[0].customerId = 'foreign' },
|
||||
f => { f.orders[0].sourceContainerBookingId = 'foreign' },
|
||||
f => { f.orders[0].sourceInboundId = 'foreign' },
|
||||
f => { f.orders[0].inboundCode = 'foreign' },
|
||||
f => { f.orders[0].containerNo = 'foreign' },
|
||||
f => { f.orders[0].overseasWarehouseId = '' },
|
||||
f => { f.orders.push({ ...f.orders[0] }) },
|
||||
]) {
|
||||
const f = warehouseSelectionFixture(); mutate(f)
|
||||
await assert.rejects(resolveF40ReceivingWarehouse(f.context, f.producers), /来源柜客户入仓身份/)
|
||||
assert.ok(f.calls.every(row => !row.path.includes('/warehouse-admin?')))
|
||||
}
|
||||
})
|
||||
|
||||
test('F40 warehouse resolution blocks different receiving warehouses and invalid or ambiguous official master data', async () => {
|
||||
const mixed = warehouseSelectionFixture(); mixed.orders[1].overseasWarehouseId = 'other-warehouse'
|
||||
await assert.rejects(resolveF40ReceivingWarehouse(mixed.context, mixed.producers), /同一实际接柜仓/)
|
||||
for (const mutate of [
|
||||
f => { f.warehouses.pop() },
|
||||
f => { f.warehouses[1].status = 'DISABLED' },
|
||||
f => { f.warehouses[1].warehouseType = 'DOMESTIC' },
|
||||
f => { f.warehouses[1].warehouseCode = 'WRONG' },
|
||||
f => { f.warehouses.push({ ...f.warehouses[1] }) },
|
||||
]) {
|
||||
const f = warehouseSelectionFixture(); mutate(f)
|
||||
await assert.rejects(resolveF40ReceivingWarehouse(f.context, f.producers), /唯一启用海外收货仓/)
|
||||
assert.ok(f.calls.every(row => row.method === 'GET'))
|
||||
}
|
||||
})
|
||||
|
||||
test('F40 warehouse resolution rejects empty or duplicate producers before HTTP', async () => {
|
||||
for (const select of [() => [], f => [f.producers[0], f.producers[0]],
|
||||
f => [{ ...f.producers[0], sourceInboundId: '' }]]) {
|
||||
const f = warehouseSelectionFixture()
|
||||
await assert.rejects(resolveF40ReceivingWarehouse(f.context, select(f)), /唯.*本轮实装来源/)
|
||||
assert.equal(f.calls.length, 0)
|
||||
}
|
||||
})
|
||||
test('complete orchestrator calls actual source chain and blocks missing Outbox evidence; no fake callback or SQL',() => {
|
||||
assert.equal(typeof run,'function')
|
||||
for(const name of ['orders','inbound-measurement','phase3-customs','phase3-outbound-dispatch',
|
||||
|
||||
Reference in New Issue
Block a user