优化
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import test from 'node:test'
|
||||
import { relabelOutboundMarksMatch, inventoryQuantitySnapshot, inventorySnapshot, dispatchInventorySources, inventorySourcesPresent, dispatchStockConservation, verifyDepartureReadiness, verifyPartialOrderCompletion,
|
||||
import { relabelOutboundMarksMatch, inventoryQuantitySnapshot, inventorySnapshot, dispatchInventorySources, inventorySourcesPresent, dispatchStockConservation, verifyDepartureReadiness, verifyPartialOrderCompletion, verifyFulfillmentRootStatus,
|
||||
completeReturnedException, verifyCustomerSignedDocuments, createSignedDocumentIsolationCustomer } from './phase5-overseas-fulfillment.mjs'
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
@@ -74,7 +74,9 @@ test('phase-five module proves receipt-save completion, cross-region convergence
|
||||
assert.match(source, /query\('\/api\/platform\/inbounds'/)
|
||||
assert.match(source, /inboundCode: inbound\.inboundCode/)
|
||||
assert.match(source, /inboundSummary\?\.processStatus === 'DELIVERED'/)
|
||||
assert.match(source, /\/api\/platform\/v1\/orders\/\$\{encodeURIComponent\(sourceOrderId\)\}/)
|
||||
assert.match(source, /verifyFulfillmentRootStatus\(context, \{ sourceOrderId, customerId, merchantToken \}\)/)
|
||||
assert.match(source, /\/api\/platform\/v1\/orders\/\$\{encodeURIComponent\(rootOrderId\)\}/)
|
||||
assert.match(source, /\/fulfillment-tree/)
|
||||
assert.match(source, /mainStatus === 'COMPLETED'/)
|
||||
assert.doesNotMatch(source, /platform\(context, 'POST', '确认派送完成/)
|
||||
assert.match(source, /manualExceptionNo/)
|
||||
@@ -550,3 +552,108 @@ test('G05 failures still independently review and preserve raw, group, each SHIP
|
||||
assert.deepEqual(context.createdResources.phase5OverseasFulfillment.inventoryProof.ledgers.afterPick, fixture.ledgerAfter)
|
||||
}
|
||||
})
|
||||
|
||||
function rootCompletionFixture({ childStatus = 'PROCESSING', rootStatus = 'PROCESSING', rootDelivered = true,
|
||||
fullyLoaded = false, mainStatus = rootStatus === 'COMPLETED' ? 'COMPLETED' : 'DELIVERED', sourceOrderId = '1001' } = {}) {
|
||||
const root = { order: { id: '1001', tenantId: '100', customerId: '100', orderRole: 'MASTER', rootOrderId: '1001',
|
||||
orderNo: 'FL1001', status: rootStatus }, statusHistory: [
|
||||
...(rootDelivered ? [{ action: 'OVERSEAS_DELIVERED' }] : []),
|
||||
...(rootStatus === 'COMPLETED' ? [{ action: 'FULFILLMENT_COMPLETED' }] : [])] }
|
||||
const child = { order: { id: '1002', tenantId: '100', customerId: '100', orderRole: 'CHILD',
|
||||
rootOrderId: '1001', parentOrderId: '1001', orderNo: 'FL1001-1', status: childStatus } }
|
||||
const tree = { parentOrderId: '1001', parentOrderNo: 'FL1001', originalPackageCount: 4,
|
||||
cumulativeLoadedPackageCount: fullyLoaded ? 4 : 1, currentRemainderPackageCount: fullyLoaded ? 0 : 3,
|
||||
children: [{ orderId: '1001', orderNo: 'FL1001', splitRole: 'LOADED', sourceOrderId: '1001', packageCount: 1 },
|
||||
{ orderId: '1002', orderNo: 'FL1001-1', splitRole: 'REMAINDER', sourceOrderId: '1001', packageCount: 3 },
|
||||
...(fullyLoaded ? [{ orderId: '1002', orderNo: 'FL1001-1', splitRole: 'LOADED', sourceOrderId: '1002', packageCount: 3 }] : [])] }
|
||||
const context = contextFor((method, path) => {
|
||||
if (path.includes('/fulfillment-tree')) return ok(tree)
|
||||
if (path.includes('/first-leg/1002')) return ok(child)
|
||||
if (path.includes('/first-leg/1001')) return ok(root)
|
||||
return ok({ summary: { orderId: '1001', mainStatus } })
|
||||
})
|
||||
context.createdResources.phase5OverseasFulfillment = {}
|
||||
return { root, child, tree, context,
|
||||
args: { sourceOrderId, customerId: '100', merchantToken: 'ONLY-IN-MEMORY', pollAttempts: 1, pollIntervalMs: 0 } }
|
||||
}
|
||||
|
||||
test('real root1 signed plus effective remainder3 keeps raw PROCESSING and both platform/client DELIVERED', async () => {
|
||||
const fixture = rootCompletionFixture()
|
||||
const result = await verifyFulfillmentRootStatus(fixture.context, fixture.args)
|
||||
assert.equal(result.passed, true)
|
||||
assert.equal(result.expectedCompleted, false)
|
||||
assert.deepEqual(result.pendingChildren.map(row => row.orderId), ['1002'])
|
||||
assert.deepEqual(fixture.context.assertions.filter(row => !row.passed), [])
|
||||
const proof = fixture.context.createdResources.phase5OverseasFulfillment.orderCompletionProof
|
||||
assert.equal(proof.tree.originalPackageCount, 4)
|
||||
assert.equal(proof.tree.currentRemainderPackageCount, 3)
|
||||
assert.deepEqual(proof.pendingChildOrderIds, ['1002'])
|
||||
assert.doesNotMatch(JSON.stringify(proof), /ONLY-IN-MEMORY|password|accessToken|Bearer/)
|
||||
})
|
||||
|
||||
test('missing, foreign, unknown or omitted real child cannot be treated as all fulfillment completed', async () => {
|
||||
for (const mutate of [
|
||||
fixture => { fixture.child.order = null },
|
||||
fixture => { fixture.child.order.customerId = 'FOREIGN' },
|
||||
fixture => { fixture.child.order.rootOrderId = 'OTHER' },
|
||||
fixture => { fixture.child.order.parentOrderId = 'OTHER' },
|
||||
fixture => { fixture.child.order.orderNo = 'WRONG' },
|
||||
fixture => { fixture.child.order.status = undefined },
|
||||
fixture => { fixture.child.order.status = 'UNKNOWN' },
|
||||
fixture => { fixture.tree.children.pop() },
|
||||
fixture => { fixture.tree.children = undefined },
|
||||
]) {
|
||||
const fixture = rootCompletionFixture(); mutate(fixture)
|
||||
assert.equal(await verifyFulfillmentRootStatus(fixture.context, fixture.args), null)
|
||||
assert.ok(fixture.context.assertions.some(row => !row.passed))
|
||||
assert.equal(fixture.context.calls.some(call => call.path.startsWith('/api/merchant/')), false)
|
||||
}
|
||||
})
|
||||
|
||||
test('draft, rejected and pending child stay effective, and a premature root COMPLETED still fails', async () => {
|
||||
for (const childStatus of ['DRAFT', 'SUBMITTED', 'APPROVED', 'ACCEPTED', 'REJECTED', 'PROCESSING']) {
|
||||
const fixture = rootCompletionFixture({ childStatus, rootStatus: 'COMPLETED' })
|
||||
const result = await verifyFulfillmentRootStatus(fixture.context, fixture.args)
|
||||
assert.equal(result.expectedCompleted, false)
|
||||
assert.equal(result.passed, false)
|
||||
assert.equal(result.pendingChildren.length, 1)
|
||||
assert.ok(fixture.context.assertions.some(row => !row.passed))
|
||||
}
|
||||
})
|
||||
|
||||
test('actual completed child or explicit CANCELLED permits completion only with root own receipt and raw completion fact', async () => {
|
||||
for (const childStatus of ['COMPLETED', 'CANCELLED']) {
|
||||
const fixture = rootCompletionFixture({ childStatus, rootStatus: 'COMPLETED', fullyLoaded: childStatus === 'COMPLETED' })
|
||||
const result = await verifyFulfillmentRootStatus(fixture.context, fixture.args)
|
||||
assert.equal(result.expectedCompleted, true)
|
||||
assert.equal(result.passed, true)
|
||||
assert.deepEqual(result.pendingChildren, [])
|
||||
assert.deepEqual(fixture.context.assertions.filter(row => !row.passed), [])
|
||||
}
|
||||
const fixture = rootCompletionFixture({ childStatus: 'COMPLETED', fullyLoaded: true, rootDelivered: false })
|
||||
const result = await verifyFulfillmentRootStatus(fixture.context, fixture.args)
|
||||
assert.equal(result.expectedCompleted, false)
|
||||
assert.equal(result.passed, true)
|
||||
})
|
||||
|
||||
test('receipt of a real child resolves and checks its owning root instead of completing the child as the aggregate', async () => {
|
||||
const fixture = rootCompletionFixture({ childStatus: 'COMPLETED', rootStatus: 'COMPLETED', fullyLoaded: true, sourceOrderId: '1002' })
|
||||
const result = await verifyFulfillmentRootStatus(fixture.context, fixture.args)
|
||||
assert.equal(result.rootOrderId, '1001')
|
||||
assert.equal(result.passed, true)
|
||||
assert.ok(fixture.context.calls.some(call => call.path === '/api/merchant/v1/orders/1001'))
|
||||
assert.equal(fixture.context.calls.some(call => call.path === '/api/merchant/v1/orders/1002'), false)
|
||||
})
|
||||
|
||||
test('all fragments completed still requires raw aggregate history and matching platform/customer completion', async () => {
|
||||
const missingHistory = rootCompletionFixture({ childStatus: 'COMPLETED', rootStatus: 'COMPLETED', fullyLoaded: true })
|
||||
missingHistory.root.statusHistory = [{ action: 'OVERSEAS_DELIVERED' }]
|
||||
assert.equal((await verifyFulfillmentRootStatus(missingHistory.context, missingHistory.args)).passed, false)
|
||||
const notProjected = rootCompletionFixture({ childStatus: 'COMPLETED', rootStatus: 'COMPLETED', fullyLoaded: true, mainStatus: 'DELIVERED' })
|
||||
assert.equal((await verifyFulfillmentRootStatus(notProjected.context, notProjected.args)).passed, false)
|
||||
const foreignProjection = rootCompletionFixture({ childStatus: 'COMPLETED', rootStatus: 'COMPLETED', fullyLoaded: true })
|
||||
const originalRequest = foreignProjection.context.request
|
||||
foreignProjection.context.request = async (...args) => args[1].startsWith('/api/merchant/')
|
||||
? ok({ summary: { orderId: '1002', mainStatus: 'COMPLETED' } }) : originalRequest(...args)
|
||||
assert.equal((await verifyFulfillmentRootStatus(foreignProjection.context, foreignProjection.args)).passed, false)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user