2026-09-30 15:16:39 +08:00
import assert from 'node:assert/strict'
import test from 'node:test'
import { readFileSync } from 'node:fs'
import { fulfillmentHistorySnapshot , validTwoFragmentTree , validSignatureGate ,
completionCounts , exactCompletionOutboxProof , resolveF40MerchantCredentials ,
2026-09-30 17:13:11 +08:00
f40TransferBody , f40LocalDateTime , validFragmentCabinetIdentity , validUnloadedRemainder ,
validRemainderCancellationGate , exactCancelledRemainderOutboxProof , cancelUnloadedRemainder ,
2026-10-03 06:26:33 +08:00
verifyRootProjections , verifyRemainderTaxIdentity , validFreshReceiptSave , preserveReceivingEvidence , run } from './phase5-root-fulfillment.mjs'
2026-09-30 15:16:39 +08:00
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' )
const history = (... actions ) => actions . map (( action , index ) => ({ id : String ( index + 1 ), action }))
const tree = () => ({ parentOrderId : '100' , originalPackageCount : 2 , cumulativeLoadedPackageCount : 2 ,
currentRemainderPackageCount : 0 , children : [
{ orderId : '100' , sourceOrderId : '100' , splitRole : 'LOADED' , packageCount : 1 },
{ orderId : '101' , sourceOrderId : '100' , splitRole : 'REMAINDER' , packageCount : 1 },
{ orderId : '101' , sourceOrderId : '101' , splitRole : 'LOADED' , packageCount : 1 },
]})
const signed = () => ({ root : { status : 'COMPLETED' , histories : history ( 'OVERSEAS_DELIVERED' , 'FULFILLMENT_COMPLETED' )},
child : { status : 'COMPLETED' , histories : history ( 'OVERSEAS_DELIVERED' )},
rootInbound : { processStatus : 'DELIVERED' , orderStatusSnapshot : 'COMPLETED' }})
const outbox = () => ({ readOnly : true , customerId : '90' , rootOrderId : '100' , orders : [ '100' , '101' ]. map ( orderId => ({
orderId , customerId : '90' , rootOrderId : '100' , eventType : 'FIRST_LEG_ORDER_FULFILLMENT_COMPLETED' ,
count : 1 , publishedCount : 1 , pendingCount : 0 , failedCount : 0 ,
}))})
const fixture = () => ({ steps : [], token : 'offline' , marker : 'offline-only' , createdResources : {},
addStep ( _module , _label , _response , passed ){ this . steps . push ({ passed })},
assert ( _module , _label , _response , passed ){ this . steps . push ({ passed })},
addCoverageGap (){}, apiSuccess ( _module , _label , response ){ return response ? . body ? . data },
})
2026-10-03 06:26:33 +08:00
function remainderTaxFixture ( taxMode ) {
const context = fixture (), calls = []
const evidence = { taxMode , customerId : '90' , rootOrderId : '100' , childOrderId : '101' , rootOrderNo : 'ORDER-ROOT' ,
rawChild : { id : '101' , tenantId : '90' , taxMode }, rootInbound : { orderId : '100' , taxMode },
childInbound : { orderId : '101' , tenantId : '90' , taxMode }}
const rows = [{ orderId : '100' , tenantId : '90' , taxMode , relation : { role : 'PARENT' , rootOrderId : '100' }},
{ orderId : '101' , tenantId : '90' , taxMode , relation : { role : 'CHILD' , rootOrderId : '100' , parentOrderId : '100' }}]
context . request = async ( method , path , body , token )=>{
calls . push ({ method , path , body , token })
const filter = new URL ( path , 'https://offline.invalid' ). searchParams . get ( 'taxMode' )
const records = filter && filter !== taxMode ? [] : structuredClone ( rows )
return { http : 200 , body : { code : '200' , data : { records , total : records . length }}}
}
return { context , evidence , calls , rows }
}
test ( 'raw remainder and actual inbound summary taxMode agree for BUY and TAX and customer filters retain exact parent/child' , async ()=>{
for ( const mode of [ 'BUY_DECLARATION' , 'TAX_REFUND' ]){
const f = remainderTaxFixture ( mode )
await verifyRemainderTaxIdentity ( f . context , f . evidence , 'own-customer' )
assert . equal ( f . calls . length , 3 )
assert . ok ( f . calls . every ( c => c . method === 'GET' && c . token === 'own-customer' &&! c . path . includes ( '/customs' )))
assert . deepEqual ( f . evidence . matchingTax . records . map ( r => r . orderId ),[ '100' , '101' ])
assert . equal ( f . evidence . otherTax . total , 0 )
assert . match ( f . calls [ 1 ]. path , new RegExp ( 'taxMode=' + mode ))
}
})
test ( 'missing or wrong raw remainder taxMode is rejected before customer/customs calls despite valid inbound projection' , async ()=>{
for ( const mode of [ 'BUY_DECLARATION' , 'TAX_REFUND' ]) for ( const actual of [ null , undefined , mode === 'BUY_DECLARATION' ? 'TAX_REFUND' : 'BUY_DECLARATION' ]){
const f = remainderTaxFixture ( mode ); f . evidence . rawChild . taxMode = actual
await assert . rejects ( verifyRemainderTaxIdentity ( f . context , f . evidence , 'own-customer' ), /原始余量子订单继承/ )
assert . equal ( f . calls . length , 0 )
}
})
test ( 'wrong inbound tax, missing filtered child, foreign customer or wrong parent identity cannot pass' , async ()=>{
for ( const mutate of [ f => f . evidence . childInbound . taxMode = null , f => f . rows . pop (), f => f . rows [ 1 ]. tenantId = '91' ,
f => f . rows [ 1 ]. relation . parentOrderId = '999' , f => f . rows [ 1 ]. taxMode = 'BUY_DECLARATION' ]) {
const f = remainderTaxFixture ( 'TAX_REFUND' ); mutate ( f )
await assert . rejects ( verifyRemainderTaxIdentity ( f . context , f . evidence , 'own-customer' ))
}
const f = remainderTaxFixture ( 'TAX_REFUND' ), original = f . context . request
f . context . request = async (... args )=>{ const r = await original (... args ); if ( args [ 1 ]. includes ( 'taxMode=BUY_DECLARATION' )) r . body . data = { records : [ f . rows [ 1 ]], total : 1 }; return r }
await assert . rejects ( verifyRemainderTaxIdentity ( f . context , f . evidence , 'own-customer' ), /otherTax/ )
})
2026-09-30 17:13:11 +08:00
test ( 'F40 unified projections require exact root and customer session with final COMPLETED or unfinished DELIVERED' , async ()=>{
for ( const completed of [ true , false ]) {
const context = fixture (), calls = [], snapshot = { root : { status : completed ? 'COMPLETED' : 'TRANSPORTING' , histories : history ( 'OVERSEAS_DELIVERED' )}}
context . request = async ( method , path , body , token )=>{
calls . push ({ method , path , token })
return { http : 200 , body : { code : '200' , data : { summary : { orderId : '100' , mainStatus : completed ? 'COMPLETED' : 'DELIVERED' }}}}
}
const result = await verifyRootProjections ( context , '90' , '100' , 'customer-session' , snapshot )
assert . deepEqual ( result . platform , result . customer )
assert . equal ( calls [ 0 ]. path , '/api/platform/v1/orders/100?tenantId=90' )
assert . equal ( calls [ 1 ]. path , '/api/merchant/v1/orders/100' )
assert . equal ( calls [ 1 ]. token , 'customer-session' )
assert . equal ( context . steps . every ( step => step . passed ), true )
}
})
test ( 'F40 customer mismatched root or prematurely completed projection fails closed' , async ()=>{
for ( const summary of [{ orderId : '101' , mainStatus : 'COMPLETED' },{ orderId : '100' , mainStatus : 'DELIVERED' }]) {
const context = fixture ()
context . request = async ( _method , path )=>({ http : 200 , body : { code : '200' , data : { summary :
path . startsWith ( '/api/platform' ) ? { orderId : '100' , mainStatus : 'COMPLETED' } : summary }}})
await assert . rejects ( verifyRootProjections ( context , '90' , '100' , 'customer-session' ,{ root : { status : 'COMPLETED' , histories : []}}),
/平台客户统一状态/ )
}
})
test ( 'F40 README documents all three independent modes and fail-closed receiving/zero child event evidence' ,()=>{
const readme = readFileSync ( new URL ( './README.md' , import . meta . url ), 'utf8' )
for ( const value of [ 'CHILD_FIRST' , 'ROOT_SIGNED_REMAINDER_CANCELLED' , 'orderStopAtApproved=true' ,
'PROCESSING' , 'WAIT_SPLIT' , 'A0409' , 'phase4ReceivingEvidenceReader' , '零事件子行' ]) assert . ok ( readme . includes ( value ), value )
assert . match ( source , /proof\.beforeReceiptReplayOutbox = await waitState/ )
assert . match ( source , /outboxCounts\(proof.beforeReceiptReplayOutbox\) === outboxCounts\(proof.outboxProof\)/ )
assert . match ( source , /validFreshReceiptSave\(beforeFresh,afterFresh\)/ )
assert . match ( source , /JSON.stringify\(afterFresh\) === JSON.stringify\(receiptProof.afterSameKey\)/ )
})
test ( 'fresh receipt save allows exactly one document version/revision/audit while business completion stays unchanged' ,()=>{
const documents = { version : '2' , uploadedCategoryCount : 1 , categories : [{ category : 'RECEIPT' , files : [{ fileId : '1' }]}], replayed : false }
const before = { documents , delivery : { order : { version : '2' , status : 'DELIVERED' , signedAt : '2026-09-30T16:00:00' },
operations : [{ id : '1' , operationNode : 'RECEIPT_AUTO_COMPLETE' }], skus : [{ packageCount : 1 }], fees : []}, revisions : [{ version : '2' }]}
const after = structuredClone ( before ); after . documents . version = '3' ; after . delivery . order . version = '3'
after . delivery . operations . push ({ id : '2' , operationNode : 'SAVE_DOCUMENTS' , result : '保存派送资料:1/3类' ,
operatedAt : '2026-09-30T16:01:00' , operatorName : 'platform' })
after . revisions . push ({ version : '3' , savedAt : '2026-09-30T16:01:00' , operatorId : 'platform' , snapshot : after . documents })
assert . equal ( validFreshReceiptSave ( before , after ), true )
for ( const mutate of [
value => value . documents . version = '4' , value => value . delivery . order . version = '2' ,
value => value . delivery . order . signedAt = '2026-09-30T16:01:00' , value => value . delivery . order . status = 'RETURNED' ,
value => value . documents . categories [ 0 ]. files [ 0 ]. fileId = '2' , value => value . delivery . skus [ 0 ]. packageCount = 2 ,
value => value . delivery . fees . push ({ amount : 1 }), value => value . delivery . operations [ 0 ]. id = '999' ,
value => value . delivery . operations [ 1 ]. operationNode = 'RECEIPT_AUTO_COMPLETE' ,
value => value . delivery . operations . push ({... value . delivery . operations [ 1 ], id : '3' }),
value => value . revisions . pop (), value => value . revisions [ 0 ]. version = '1' ,
]){ const bad = structuredClone ( after ); mutate ( bad ); assert . equal ( validFreshReceiptSave ( before , bad ), false )}
})
test ( 'F40 retains partial and failed receiving raw snapshots without exporting identity credentials' ,()=>{
const proof = {}, scope = { createdResources : { phase4OverseasPda : { receivingCompletionEvidence : {}}}, token : 'secret' }
preserveReceivingEvidence ( proof , scope )
scope . createdResources . phase4OverseasPda . receivingCompletionEvidence [ '20' ] = { status : 'UNPROVEN' , stages : {
BEFORE_COMPLETE : { captured : true , evidence : { balances : []}}, AFTER_COMPLETE : { captured : false , evidence : { balances : [{ id : '1' }]}}}}
assert . deepEqual ( proof . receivingCompletionEvidence , scope . createdResources . phase4OverseasPda . receivingCompletionEvidence )
assert . equal ( JSON . stringify ( proof ). includes ( 'secret' ), false )
assert . match ( source , /finally \{ preserveReceivingEvidence\(proof,scope\);/ )
assert . match ( source , /proof.receiptReplayProofs \|\|= \[\]/ )
})
2026-09-30 15:16:39 +08:00
test ( 'F40 transfer uses the current formal Transfer DTO including required positive fee and same LocalDateTime tool' ,() => {
const dto = readFileSync ( new URL ( '../../lastleg-service/src/main/java/com/baiyue/lastleg/delivery/dto/DeliveryRequests.java' , import . meta . url ), 'utf8' )
const vehicle = { carrierName : 'offline-fleet' , vehiclePlate : 'offline-plate' , driverName : 'offline-driver' , driverPhone : '19900000000' }
const now = new Date ( '2026-09-30T01:02:03.456Z' ), body = f40TransferBody ( 'offline' , 1 , vehicle , now )
for ( const field of [ 'idempotencyKey' , 'plannedDeliveryAt' , 'deliveryMethod' , 'pickupMethod' , 'loadingType' , 'fees' ]) {
assert . match ( dto , new RegExp ( `\\b ${ field } \\b` )); assert . ok ( body [ field ])
}
assert . equal ( body . plannedDeliveryAt , '2026-10-02T01:02:03' )
assert . equal ( f40LocalDateTime ( now ), '2026-09-30T01:02:03' )
assert . equal ( body . deliveryMethod , 'TRUCK_PALLET' ); assert . equal ( body . pickupMethod , 'WAREHOUSE_PICKUP' )
assert . equal ( body . loadingType , 'PALLET' ); assert . equal ( body . vehicleSize , '15托' )
for ( const field of Object . keys ( vehicle )) assert . equal ( body [ field ], vehicle [ field ])
assert . equal ( body . fees . length , 1 )
assert . deepEqual ( Object . fromEntries ([ 'feeType' , 'feeName' , 'direction' , 'currency' , 'amount' ]. map ( field =>[ field , body . fees [ 0 ][ field ]])),
{ feeType : 'DELIVERY_FEE' , feeName : '派送费' , direction : 'RECEIVABLE' , currency : 'USD' , amount : 10 })
assert . match ( source , /f40TransferBody\(context.marker,index,vehicle\)/ )
assert . match ( source , /estimatedArrivalAt: f40LocalDateTime\(/ )
})
test ( 'F40 credentials prefer a complete current fixture pair and never combine fixture with configured customer' ,() => {
const options = { username : 'offline-admin' , password : 'offline-admin-secret' , merchantUsername : 'configured-customer' , merchantPassword : 'configured-secret' }
const current = { username : 'fixture-customer' , password : 'fixture-secret' , tenantId : '90' }
assert . deepEqual ( resolveF40MerchantCredentials ({ options , context : { merchantQualificationFixture : current }}),
{ username : 'fixture-customer' , password : 'fixture-secret' , customerId : '90' })
assert . deepEqual ( resolveF40MerchantCredentials ({ options , context : {}}),
{ username : 'configured-customer' , password : 'configured-secret' , customerId : null })
for ( const incomplete of [{ username : 'fixture-only' , tenantId : '90' },{ password : 'fixture-only' , tenantId : '90' },
{ username : 'fixture-customer' , password : 'fixture-secret' }])
assert . equal ( resolveF40MerchantCredentials ({ options , context : { merchantQualificationFixture : incomplete }}), null )
assert . equal ( resolveF40MerchantCredentials ({ options : { merchantUsername : 'incomplete' }, context : {}}), null )
assert . ok ( source . indexOf ( "'F40 正式订单创建客户与本轮登录客户一致'" ) < source . indexOf ( "await stage(scope, 'inbound-measurement')" ))
})
test ( 'F40 reads formal nested domestic cabinet workbench and compares booking/plan/task identity instead of inventing GET containers/id' ,() => {
const controller = readFileSync ( new URL ( '../../firstleg/src/main/java/com/baiyue/firstleg/controller/PlatformContainerController.java' , import . meta . url ), 'utf8' )
const dto = readFileSync ( new URL ( '../../firstleg/src/main/java/com/baiyue/firstleg/terminaldrayage/dto/ContainerWorkbenchDtos.java' , import . meta . url ), 'utf8' )
assert . match ( controller , /@GetMapping\("\/domestic\/\{id\}"\)/ )
assert . doesNotMatch ( controller , /@GetMapping\("\/\{id\}"\)/ )
assert . match ( dto , /record WorkbenchItem\(ContainerBookingEntity container, String workbenchStage/ )
assert . match ( source , /`\/api\/platform\/v1\/containers\/domestic\/\$\{result.containerId\}`/ )
assert . doesNotMatch ( source , /`\/api\/platform\/v1\/containers\/\$\{result.containerId\}`/ )
const fragment = { containerId : '20' , planId : '30' , taskId : '40' , oceanBookingId : '50' }, task = { id : '40' , containerBookingId : '20' , loadingPlanId : '30' }
const workbench = { container : { id : '20' , cabinetNo : 'D0001' , containerNo : 'OFFLINE' , oceanBookingId : '50' }}
assert . equal ( validFragmentCabinetIdentity ( workbench , fragment , task ), true )
assert . equal ( validFragmentCabinetIdentity ( workbench ,{... fragment , containerId : '21' }, task ), false )
assert . equal ( validFragmentCabinetIdentity ( workbench , fragment ,{... task , containerBookingId : '21' }), false )
assert . equal ( validFragmentCabinetIdentity ( workbench , fragment ,{... task , loadingPlanId : '31' }), false )
assert . equal ( validFragmentCabinetIdentity ( workbench , fragment ,{... task , id : '41' }), false )
assert . equal ( validFragmentCabinetIdentity ( workbench ,{... fragment , oceanBookingId : '51' }, task ), false )
assert . equal ( validFragmentCabinetIdentity ( workbench . container , fragment , task ), false )
})
test ( 'formal tree requires one root physical source plus its exact real remainder child and conserves two boxes' ,() => {
assert . equal ( validTwoFragmentTree ( tree (), '100' , '101' ), true )
for ( const change of [
value => value . parentOrderId = '999' , value => value . currentRemainderPackageCount = 1 ,
value => value . children [ 2 ]. sourceOrderId = '999' , value => value . children [ 1 ]. sourceOrderId = '999' ,
value => value . children [ 2 ]. packageCount = 2 ,
value => value . children . push ({ splitRole : 'UNKNOWN' , orderId : '999' }),
]) { const value = tree (); change ( value ); assert . equal ( validTwoFragmentTree ( value , '100' , '101' ), false )}
})
test ( 'F40 separates immutable physical task cartons from current actual FBA receiving prefix scans' ,() => {
assert . match ( source , /cartonMarks: stableLoadedCartonMarks\(task.items\)/ )
assert . match ( source , /receivingCartonMarks:\[`\$\{current.summary.inboundCode\}#PDA-CONTRACT-1`\]/ )
assert . doesNotMatch ( source , /cartonMarks:\s*\[`\$\{current.summary.inboundCode\}#PDA-CONTRACT/ )
})
test ( 'raw Order and original status history remain in evidence including operator, reason and timestamp' ,() => {
const detail = { order : { id : '100' , orderRole : 'MASTER' , version : 3 , status : 'TRANSPORTING' }, statusHistory : [
{ id : '11' , orderId : '100' , action : 'OVERSEAS_DELIVERED' , operatorName : 'OVERSEAS_DELIVERY_EVENT' ,
reason : 'signed actual delivery' , occurredAt : '2026-09-30T01:00:00' , fromStatus : 'TRANSPORTING' , toStatus : 'TRANSPORTING' },
]}
const snapshot = fulfillmentHistorySnapshot ( detail )
assert . deepEqual ( snapshot . rawOrder , detail . order )
assert . deepEqual ( snapshot . histories , detail . statusHistory )
assert . deepEqual ( completionCounts ( snapshot ),{ own : 1 , final : 0 })
})
test ( 'root shipment signed first preserves unfinished root while effective child remains pending' ,() => {
const snapshot = signed (); snapshot . root . status = 'TRANSPORTING'
snapshot . root . histories = history ( 'OVERSEAS_DELIVERED' ); snapshot . child = { status : 'TRANSPORTING' , histories : []}
snapshot . rootInbound . orderStatusSnapshot = 'TRANSPORTING'
assert . equal ( validSignatureGate ( snapshot , 'MASTER' ), true )
snapshot . root . status = 'COMPLETED'
assert . equal ( validSignatureGate ( snapshot , 'MASTER' ), false )
})
test ( 'child signed before root remains an independent completed child and cannot finish unsigned root' ,() => {
const snapshot = signed (); snapshot . root = { status : 'TRANSPORTING' , histories : []}
snapshot . rootInbound = { processStatus : 'IN_TRANSIT' , orderStatusSnapshot : 'TRANSPORTING' }
assert . equal ( validSignatureGate ( snapshot , 'CHILD' ), true )
assert . equal ( validSignatureGate ( snapshot , 'MASTER' ), false )
snapshot . root . histories = history ( 'OVERSEAS_DELIVERED' )
assert . equal ( validSignatureGate ( snapshot , 'CHILD' ), false )
})
test ( 'all signed requires root own fact, exactly one aggregate final history and real Firstleg delivered completion' ,() => {
assert . equal ( validSignatureGate ( signed (), 'MASTER' , true ), true )
for ( const change of [
value => value . root . histories = history ( 'FULFILLMENT_COMPLETED' ),
value => value . root . histories . push ({ action : 'FULFILLMENT_COMPLETED' }),
value => value . child . histories . push ({ action : 'OVERSEAS_DELIVERED' }),
value => value . child . status = 'CANCELLED' ,
value => value . rootInbound . orderStatusSnapshot = 'TRANSPORTING' ,
value => value . rootInbound . processStatus = 'RECEIVED' ,
]) { const value = signed (); change ( value ); assert . equal ( validSignatureGate ( value , 'MASTER' , true ), false )}
})
test ( 'Outbox requires exact customer/root/source aggregate membership, unique completion and PUBLISHED' ,() => {
assert . equal ( exactCompletionOutboxProof ( outbox (), '90' , '100' ,[ '101' , '100' ]), true )
for ( const change of [
value => value . readOnly = false , value => value . customerId = '91' , value => value . rootOrderId = '999' ,
value => value . orders [ 0 ]. rootOrderId = '999' , value => value . orders [ 0 ]. customerId = '91' ,
value => value . orders [ 1 ]. orderId = '100' , value => value . orders [ 0 ]. count = 2 ,
value => value . orders [ 1 ]. publishedCount = 0 , value => value . orders [ 1 ]. pendingCount = 1 ,
value => value . orders [ 0 ]. failedCount = 1 , value => value . orders [ 0 ]. eventType = 'OVERSEAS_DELIVERED' ,
value => value . orders . pop (),
]) { const value = outbox (); change ( value ); assert . equal ( exactCompletionOutboxProof ( value , '90' , '100' ,[ '100' , '101' ]), false )}
})
test ( 'exported fragment producer preserves fail closed supplier precondition and never writes without actual source master' , async () => {
const context = fixture (), calls = []
context . request = async ( method , path ) => { calls . push ([ method , path ]); return { http : 200 , body : { code : 200 , data : { records : []}}}}
assert . equal ( await loadOneFragment ( context ,{ sourceOrderNo : 'offline-only' }), null )
assert . equal ( calls . length , 1 )
assert . equal ( calls [ 0 ][ 0 ], 'GET' )
assert . match ( calls [ 0 ][ 1 ], /category=BOOKING&status=ACTIVE/ )
})
test ( 'exported pallet label helper preserves FBA eligibility without introducing writes for other destinations' , async () => {
const context = fixture (); context . request = async () => { throw new Error ( 'unexpected HTTP' )}
assert . equal ( await verifyPalletLabels ( context ,{ destinationType : 'OVERSEAS' }, '1' ), null )
assert . equal ( await verifyPalletLabels ( context ,{ destinationType : 'FBA' , fulfillmentType : 'ONE_CLICK_DROPSHIP' }, '1' ), null )
})
test ( 'exported consumer polling and conversion fail closed when real producer consumption is absent' , async () => {
const context = fixture (), calls = []
context . request = async ( method , path ) => { calls . push ([ method , path ]); return { http : 200 , body : { code : 200 , data : { records : []}}}}
assert . equal ( await awaitProducerConsumption ( context ,[]), true )
assert . equal ( await convertReceivingContainers ( context ,[{ containerNo : 'OFFLINE' }]), false )
assert . equal ( calls . every (([ method ]) => method === 'GET' ), true )
assert . equal ( context . steps . at ( - 1 ). passed , false )
})
test ( 'exported receiving rejects unmatched current producer instead of borrowing any history container' , async () => {
const context = fixture (); context . request = async ( _method , path ) => ({ http : 200 , body : { code : 200 , data :
path . endsWith ( '/candidates' ) ? [{ containerNo : 'ANOTHER' , sourceContainerBookingId : '999' , totalPackages : 1 }] : null }})
2026-10-03 06:26:33 +08:00
await runReceiving ( context , 'offline-pda' , null , null ,{ containerNo : 'EXPECTED' , containerBookingId : '100' }, false ,{ attempts : 1 })
2026-09-30 15:16:39 +08:00
assert . equal ( context . steps . some ( step => step . passed === false ), true )
})
test ( 'exported receiving warehouse resolver continues to choose only configured active official warehouse' , async () => {
const context = fixture (); context . request = async () => ({ http : 200 , body : { code : 200 , data : { records : [
{ id : '193000000000200003' , warehouseType : 'OVERSEAS' , status : 'ACTIVE' , warehouseName : 'offline' },
]}}})
assert . deepEqual ( await resolveSharedWarehouse ( context ),{ id : '193000000000200003' , name : 'offline' })
})
2026-09-30 17:13:11 +08:00
test ( 'complete orchestrator calls actual source chain and blocks missing Outbox evidence; no fake callback or SQL' ,() => {
2026-09-30 15:16:39 +08:00
assert . equal ( typeof run , 'function' )
for ( const name of [ 'orders' , 'inbound-measurement' , 'phase3-customs' , 'phase3-outbound-dispatch' ,
'phase3-carrier-schedule-queries' ]) assert . ok ( source . includes ( `' ${ name } '` ))
for ( const name of [ 'loadOneFragment' , 'verifyPalletLabels' , 'awaitProducerConsumption' ,
2026-10-03 08:13:04 +08:00
'convertReceivingContainers' , 'prepareTerminalDrayage' , 'runReceiving' , 'pickAll' , 'withDeliveryEventRecovery' ])
2026-09-30 15:16:39 +08:00
assert . match ( source , new RegExp ( `await ${ name } \\(` ))
2026-10-03 08:13:04 +08:00
assert . match ( source , /\(\) => saveReceiptAndComplete\(context, deliveries\[0\], customerId, index\)/ )
2026-09-30 17:13:11 +08:00
assert . match ( source , /rootOrderId,\s*sourceOrderIds:\[rootOrderId,childOrderId\]/ )
2026-09-30 15:16:39 +08:00
assert . match ( source , /HTTP_VERIFIED_OUTBOX_PENDING/ )
2026-09-30 17:13:11 +08:00
assert . match ( source , /finally \{ preserveReceivingEvidence\(proof,scope\); proof.currentStage = 'PDA_IDENTITY_CLEANUP'; await disablePicker/ )
assert . doesNotMatch ( source , /['"`]\/internal\/|UPDATE\s+ord_|INSERT\s+INTO|\/complete-delivery/ )
})
const oneLoadedTree = () => ({... tree (), cumulativeLoadedPackageCount : 1 , currentRemainderPackageCount : 1 ,
children : tree (). children . slice ( 0 , 2 ). map ( row =>({... row , loadingPlanId : '30' , containerBookingId : '20' }))})
const approvedChild = () => fulfillmentHistorySnapshot ({ order : { id : '101' , tenantId : '90' , orderRole : 'CHILD' ,
rootOrderId : '100' , parentOrderId : '100' , status : 'APPROVED' , version : 1 , orderNo : 'R-1' , inboundCode : 'I-1' , completedAt : null }, statusHistory : []})
const unshippedInbound = () => ({ id : '301' , tenantId : '90' , orderId : '101' , orderNo : 'R-1' , inboundCode : 'I-1' ,
processStatus : 'WAIT_SPLIT' , orderStatusSnapshot : 'APPROVED' , totalPackageCount : 1 , containerNo : null , cabinetNo : null })
const cancelled = () => ({ root : { status : 'COMPLETED' , histories : history ( 'OVERSEAS_DELIVERED' , 'FULFILLMENT_COMPLETED' )},
child : { status : 'CANCELLED' , rawOrder : { completedAt : null }, histories : history ( 'CANCELLED' )},
rootInbound : { processStatus : 'DELIVERED' , orderStatusSnapshot : 'COMPLETED' }})
const cancellationOutbox = () => { const value = outbox (); value . orders [ 1 ]. count = 0 ; value . orders [ 1 ]. publishedCount = 0 ; return value }
test ( 'unloaded remainder requires real raw APPROVED child, exact customer/root/source and one remaining physical box' ,() => {
const child = approvedChild (), inbound = unshippedInbound (), tree = oneLoadedTree ()
assert . equal ( validUnloadedRemainder ( tree , child , inbound , '90' , '100' , '101' ), true )
for ( const mutate of [
value => value . child . status = 'PROCESSING' , value => value . child . status = 'ACCEPTED' ,
value => value . child . rootOrderId = '999' , value => value . child . parentOrderId = '999' ,
value => value . child . rawOrder . tenantId = '91' , value => value . child . orderId = '102' ,
value => value . child . histories = history ( 'OVERSEAS_DELIVERED' ),
value => value . inbound . orderId = '102' , value => value . inbound . tenantId = '91' ,
value => value . inbound . inboundCode = 'ANOTHER' , value => value . inbound . orderNo = 'ANOTHER' ,
value => value . inbound . processStatus = 'LOADED' , value => value . inbound . totalPackageCount = 2 ,
value => value . inbound . orderStatusSnapshot = 'PROCESSING' , value => value . inbound . containerNo = 'ACTUAL-CABINET' ,
value => value . inbound . cabinetNo = 'ACTUAL-CABINET' , value => value . tree . children . push ( tree . children [ 0 ]),
value => value . tree . children [ 0 ]. sourceOrderId = '101' , value => value . tree . children [ 1 ]. loadingPlanId = '31' ,
value => value . tree . children [ 1 ]. containerBookingId = '21' , value => value . tree . currentRemainderPackageCount = 0 ,
]) {
const value = { tree : oneLoadedTree (), child : approvedChild (), inbound : unshippedInbound ()}; mutate ( value )
assert . equal ( validUnloadedRemainder ( value . tree , value . child , value . inbound , '90' , '100' , '101' ), false )
}
})
test ( 'cancelled remainder cannot substitute for child signature in either full-signature mode' ,() => {
assert . equal ( validRemainderCancellationGate ( cancelled ()), true )
assert . equal ( validSignatureGate ( cancelled (), 'MASTER' , true ), false )
assert . equal ( validSignatureGate ( cancelled (), 'CHILD' , true ), false )
for ( const mutate of [
value => value . root . histories = history ( 'FULFILLMENT_COMPLETED' ),
value => value . root . histories . push ({ action : 'FULFILLMENT_COMPLETED' }),
value => value . child . status = 'COMPLETED' , value => value . child . histories . push ({ action : 'OVERSEAS_DELIVERED' }),
value => value . child . histories . push ({ action : 'CANCELLED' }), value => value . child . rawOrder . completedAt = '2026-09-30T01:00:00' ,
value => value . rootInbound . orderStatusSnapshot = 'APPROVED' , value => value . rootInbound . processStatus = 'RECEIVED' ,
]){ const value = cancelled (); mutate ( value ); assert . equal ( validRemainderCancellationGate ( value ), false )}
})
test ( 'cancellation Outbox requires exactly one published root completion and explicit zero child completion counts' ,() => {
assert . equal ( exactCancelledRemainderOutboxProof ( cancellationOutbox (), '90' , '100' , '101' ), true )
assert . equal ( exactCompletionOutboxProof ( cancellationOutbox (), '90' , '100' ,[ '100' , '101' ]), false )
for ( const mutate of [
value => value . orders . pop (), value => value . orders [ 1 ]. count = 1 , value => value . orders [ 1 ]. publishedCount = 1 ,
value => value . orders [ 1 ]. pendingCount = 1 , value => value . orders [ 1 ]. failedCount = 1 ,
value => value . orders [ 1 ]. count = null , value => delete value . orders [ 1 ]. failedCount ,
value => value . orders [ 1 ]. rootOrderId = '999' , value => value . orders [ 1 ]. customerId = '91' ,
value => value . orders [ 1 ]. orderId = '100' , value => value . orders [ 1 ]. eventType = 'ORDER_CANCELLED' ,
value => value . orders [ 0 ]. count = 2 , value => value . orders [ 0 ]. publishedCount = 0 , value => value . readOnly = false ,
]){ const value = cancellationOutbox (); mutate ( value ); assert . equal ( exactCancelledRemainderOutboxProof ( value , '90' , '100' , '101' ), false )}
})
function cancellationFixture ( change = null ) {
const context = fixture (), calls = [], proof = { snapshots : []}
const rootDetail = { order : { id : '100' , tenantId : '90' , orderRole : 'MASTER' , rootOrderId : '100' , status : 'APPROVED' ,
version : 1 , orderNo : 'R' , inboundCode : 'I' , completedAt : null }, statusHistory : history ( 'OVERSEAS_DELIVERED' )}
const childDetail = { order : approvedChild (). rawOrder , statusHistory : []}
const rootInbound = { summary : { processStatus : 'DELIVERED' , orderStatusSnapshot : 'APPROVED' }}
const childInbound = { summary : unshippedInbound ()}, tree = oneLoadedTree ()
let count = 0
context . context = { f40BaseMarker : 'offline-only' , f40ReadOnlyOutboxEvidence : async args =>{
assert . deepEqual ( args ,{ customerId : '90' , rootOrderId : '100' , sourceOrderIds : [ '100' , '101' ],
eventType : 'FIRST_LEG_ORDER_FULFILLMENT_COMPLETED' })
return cancellationOutbox ()
}}
if ( change ) change ({ rootDetail , childDetail , childInbound , tree })
2026-10-02 23:14:24 +08:00
let frozenCancel
context . request = async ( method , path , body , token , headers )=>{
calls . push ({ method , path , body , headers })
2026-09-30 17:13:11 +08:00
if ( method === 'POST' ){
assert . equal ( path , '/api/platform/v1/orders/first-leg/101/cancel?tenantId=90' )
assert . ok ( body . reason . includes ( 'offline-only' ))
2026-10-02 23:14:24 +08:00
assert . ok ( headers ? .[ 'Idempotency-Key' ])
if ( count ++ ) return { http : 200 , body : { code : headers [ 'Idempotency-Key' ] === frozenCancel . key && JSON . stringify ( body ) === frozenCancel . payload ? '200' : 'A0409' }}
assert . equal ( body . expectedVersion , childDetail . order . version )
frozenCancel = { key : headers [ 'Idempotency-Key' ], payload : JSON . stringify ( body )}
2026-09-30 17:13:11 +08:00
childDetail . order . status = 'CANCELLED' ; childDetail . order . version ++
childDetail . statusHistory = history ( 'CANCELLED' )
rootDetail . order . status = 'COMPLETED' ; rootDetail . order . version ++
rootDetail . order . completedAt = '2026-09-30T01:00:00'
rootDetail . statusHistory = history ( 'OVERSEAS_DELIVERED' , 'FULFILLMENT_COMPLETED' )
rootInbound . summary . orderStatusSnapshot = 'COMPLETED'
return { http : 200 , body : { code : '200' , data : null }}
}
let data
if ( path . includes ( '/fulfillment-tree?' )) data = tree
else if ( path . includes ( '/orders/first-leg/100?' )) data = rootDetail
else if ( path . includes ( '/orders/first-leg/101?' )) data = childDetail
else if ( path . includes ( '/inbounds/300?' )) data = rootInbound
else if ( path . includes ( '/inbounds/301?' )) data = childInbound
else throw new Error ( `unexpected offline request ${ path } ` )
return { http : 200 , body : { code : '200' , data : structuredClone ( data )}}
}
return { context , proof , calls }
}
test ( 'formal cancellation helper rereads physical eligibility, uses public cancel and accepts replay rejection only with unchanged facts and Outbox' , async ()=>{
const { context , proof , calls } = cancellationFixture ()
const result = await cancelUnloadedRemainder ( context , proof , '90' , '100' , '101' , '300' , '301' )
assert . equal ( validRemainderCancellationGate ( result ), true )
2026-10-02 23:14:24 +08:00
const writes = calls . filter ( row => row . method === 'POST' )
assert . equal ( writes . length , 4 )
assert . deepEqual ( writes [ 1 ]. body , writes [ 0 ]. body )
assert . deepEqual ( writes [ 1 ]. headers , writes [ 0 ]. headers )
assert . equal ( writes [ 2 ]. headers [ 'Idempotency-Key' ], writes [ 0 ]. headers [ 'Idempotency-Key' ])
assert . notEqual ( writes [ 3 ]. headers [ 'Idempotency-Key' ], writes [ 0 ]. headers [ 'Idempotency-Key' ])
assert . ok ( writes [ 3 ]. body . expectedVersion > writes [ 0 ]. body . expectedVersion )
2026-09-30 17:13:11 +08:00
assert . equal ( proof . snapshots . length , 3 )
assert . deepEqual ( proof . cancelReplayOutbox . before , proof . cancelReplayOutbox . after )
assert . equal ( context . steps . every ( step => step . passed ), true )
})
test ( 'formal cancellation helper stops before any mutation for PROCESSING, unsigned root or already loaded child' , async ()=>{
for ( const change of [ value => value . childDetail . order . status = 'PROCESSING' ,
value => value . rootDetail . order . status = 'PROCESSING' , value => value . rootDetail . statusHistory = [],
value => value . childInbound . summary . processStatus = 'LOADED' , value => value . tree . children . push ( tree (). children [ 2 ])]) {
const { context , proof , calls } = cancellationFixture ( change )
await assert . rejects ( cancelUnloadedRemainder ( context , proof , '90' , '100' , '101' , '300' , '301' ), /仅取消真实签收根下未装 APPROVED/ )
assert . equal ( calls . some ( row => row . method !== 'GET' ), false )
}
})
test ( 'cancel scenario uses new approved-only order and exactly root shipment; both existing full-signature modes remain independent' ,()=>{
assert . match ( source , /const cancelRemainder = signatureOrder === 'ROOT_SIGNED_REMAINDER_CANCELLED'/ )
assert . match ( source , /orderStopAtApproved:cancelRemainder/ )
assert . match ( source , /approvedRoot.status === 'APPROVED'/ )
assert . match ( source , /if \(cancelRemainder\) \{[\s\S]*?proof.unloadedRemainder[\s\S]*?\} else \{[\s\S]*?second = await fragment/ )
assert . match ( source , /const producers = cancelRemainder \? \[first\] : \[first,second\]/ )
assert . match ( source , /signatureOrder === 'CHILD_FIRST' \? \[second,first\] : producers/ )
assert . match ( source , /if \(cancelRemainder\) await cancelUnloadedRemainder/ )
const orderSource = readFileSync ( new URL ( './orders.mjs' , import . meta . url ), 'utf8' )
assert . match ( orderSource , /context.context\?\.orderStopAtApproved === true/ )
2026-09-30 15:16:39 +08:00
})
test ( 'early F40 failures become FAILED with only a safe stage and preserve the original exception' , async () => {
const context = fixture (); context . context = {}; context . options = {}
await assert . rejects ( run ( context ), /F40 本轮客户完整凭据有效/ )
assert . equal ( context . createdResources . phase5RootFulfillment . finalStatus , 'FAILED' )
assert . equal ( context . createdResources . phase5RootFulfillment . failedStage , 'CUSTOMER_IDENTITY' )
assert . equal ( 'error' in context . createdResources . phase5RootFulfillment , false )
const secretError = new Error ( 'offline-secret-body-not-recorded' )
const withLogin = fixture (); withLogin . context = {}; withLogin . options = { merchantUsername : 'offline' , merchantPassword : 'offline' }
withLogin . request = async ()=>{ throw secretError }
await assert . rejects ( run ( withLogin ), error => error === secretError )
assert . equal ( withLogin . createdResources . phase5RootFulfillment . finalStatus , 'FAILED' )
assert . equal ( JSON . stringify ( withLogin . createdResources . phase5RootFulfillment ). includes ( secretError . message ), false )
})