2026-10-22 11:56:47 +08:00
import { LOADING_PHOTO_SLOTS } from './fleet-trip-fulfillment.mjs'
2026-10-03 16:11:52 +08:00
import test from 'node:test'
import assert from 'node:assert/strict'
2026-10-03 22:13:15 +08:00
import { mkdtempSync , mkdirSync , readFileSync , writeFileSync , rmSync } from 'node:fs'
import { join , resolve , dirname } from 'node:path'
import { tmpdir } from 'node:os'
import { createHash } from 'node:crypto'
import { selectReturnSources , verifyFleetReturnRedispatch , waitForRedispatchSignatureAudit } from './fleet-return-redispatch-acceptance.mjs'
2026-10-03 16:11:52 +08:00
2026-10-20 10:35:52 +08:00
const BASE = '/api/platform/v1/last-leg' , DISPATCH = ` ${ BASE } /dispatches` , PDA = '/api/pda/v1/last-leg/dispatches' , CUSTOMER = '900719925474099301' , WAREHOUSE = '92'
const copy = value => structuredClone ( value )
2026-10-03 16:11:52 +08:00
function fixture ( fault = '' ) {
2026-10-20 10:35:52 +08:00
const trip = { tripNo : 'TR-ORIGINAL' , dispatchNo : 'DP-ORIGINAL' }, requests = [], checkpoints = [], ledger = new Map (), controls = {}
2026-10-18 16:34:14 +08:00
const masterIds = { A : '9007199254740993' , B : '9007199254740995' }
2026-10-20 10:35:52 +08:00
const relations = [ 'A' , 'B' ]. map (( name , n ) => ({ lastMileOrderId : masterIds [ name ], lastMileOrderNo : `LM- ${ name } ` , customerId : CUSTOMER , overseasWarehouseId : WAREHOUSE ,
inboundOrderId : fault === 'no-inbound' ? null : ` ${ n + 10 } ` , inboundCode : `IN- ${ name } ` , deliveryNo : 'DL-ORIGINAL' , outboundNo : 'OUT-ORIGINAL' ,
returnSources : [{ outboundPalletItemId : ` ${ n + 20 } ` , inventoryPositionId : ` ${ n + 30 } ` , maxReturnPackages : n ? 3 : 4 , returnCartonId : null }] }))
let returned = false , originalSigned = false , newSigned = false , departed = false , picked = false , recordVersion = 0 , stage = 'BEFORE_LOADING' , review = false , arranged = false , created = false , nextCreated = false , nextCancelled = false
let vehiclePlate , vehicleOwner = 'TR-NEW' , driverOwner = 'TR-NEW' , closed = false , vehicleReleased = false , driverReleased = false , tripVersion = 0
const rootDone = name => name === 'A' ? newSigned || fault === 'root-premature-A' && originalSigned : originalSigned
const tail = name => ({ id : masterIds [ name ], orderNo : `LM- ${ name } ` , deliveryOrderNo : 'DL-ORIGINAL' , outboundOrderNo : 'OUT-ORIGINAL' , orderType : 'FIRST_LEG' ,
sourceInboundId : name === 'A' ? '801' : '802' , sourceOrderId : name === 'A' ? '701' : '702' , customerId : CUSTOMER , overseasWarehouseId : WAREHOUSE , inboundCode : `IN- ${ name } ` , packageCount : name === 'A' ? 4 : 3 ,
subOrderStatus : name === 'A' ? newSigned || fault === 'premature-A' && originalSigned ? 'DELIVERY:DELIVERED' : 'DELIVERY:WAIT_DELIVERY' : originalSigned && fault !== 'blocked-B' ? 'DELIVERY:DELIVERED' : 'DELIVERY:WAIT_DELIVERY' })
const signedQuantity = ( kind , fallback ) => controls [ kind ] ? . override ? controls [ kind ]. value : fallback
const order = name => name === 'DL-NEW' ? { deliveryNo : name , customerId : CUSTOMER , overseasWarehouseId : WAREHOUSE , dispatchNo : 'DP-NEW' , outboundNo : 'OUT-NEW' , status : newSigned ? 'DELIVERED' : departed ? 'DELIVERING' : 'WAIT_DELIVERY' , packageCount : 2 ,
signedPackages : newSigned ? signedQuantity ( 'newQuantity' , 2 ) : null , signedAt : newSigned ? '2026-10-19T04:00:00Z' : null , version : 0 }
: { deliveryNo : 'DL-ORIGINAL' , customerId : CUSTOMER , overseasWarehouseId : WAREHOUSE , dispatchNo : 'DP-ORIGINAL' , outboundNo : 'OUT-ORIGINAL' , status : originalSigned ? 'DELIVERED' : controls . waitDelivery ? 'WAIT_DELIVERY' : 'DELIVERING' , packageCount : 7 ,
signedPackages : originalSigned ? signedQuantity ( 'originalQuantity' , 5 ) : null , signedAt : originalSigned ? newSigned && fault === 'rewritten-original' ? 'changed' : '2026-10-19T02:00:00Z' : null , version : controls . deliveryVersion ?? 0 }
const counts = empty => ({ itemCount : empty ? 0 : 1 , palletCount : empty ? 0 : 1 , packageCount : empty ? 0 : 2 , pickedPackageCount : empty ? 0 : picked ? 2 : 0 , shippedPackageCount : empty ? 0 : departed ? 2 : 0 })
const destination = { key : 'FBA:ONT8' , type : 'FBA' , warehouseCode : 'ONT8' }
const stops = [{ index : 0 , name : 'Actual Origin' , destinationKey : 'ORIGIN:92' }, { index : 1 , name : 'ONT8' , destinationKey : 'FBA:ONT8' }]
const nativeItem = () => ({ dispatchItemId : '501' , customerId : CUSTOMER , sourceKey : 'RETURN:300' , sourceVersion : 'a' . repeat ( 64 ), sourceType : 'RETURN_RECEIPT' , planPalletId : null , returnReceiptId : '300' , warehousePalletId : '100' , palletNo : context . palletCode ,
inboundCode : 'IN-A' , destination , scheduledPackages : 2 , pickedPackages : picked ? 2 : 0 , positions : [{ positionId : '201' , availablePackages : picked ? 0 : 2 }] })
const detail = next => ({ dispatchNo : next ? 'DP-NEXT' : 'DP-NEW' , recordVersion : next ? 0 : recordVersion , status : next && nextCancelled ? 'CANCELLED' : 'ACTIVE' , stage : next ? 'BEFORE_LOADING' : newSigned ? 'DELIVERED' : stage ,
2026-10-21 14:30:41 +08:00
documents : { deliveries : departed && ! next ? [ ref ()] : [], outbounds : departed && ! next ? [ outbound ()] : [] },
2026-10-20 10:35:52 +08:00
reviewState : review ? 'APPROVED' : 'DRAFT' , reviews : { dispatchReview : { status : review ? 'APPROVED' : 'NOT_SUBMITTED' }, loadingReview : { status : review ? 'APPROVED' : 'NOT_SUBMITTED' } }, counts : counts ( next ), pickingReconciled : picked ,
2026-10-22 11:56:47 +08:00
vehicleInfo : { vehicle : { vehicleId : '601' , plate : vehiclePlate }, driver : { driverId : '701' } }, dispatchInfo : { route : next ? '' : 'ONT8' }, orderDetails : next ? [] : [{ customerId : CUSTOMER , sourceKey : 'RETURN:300' , inboundCode : 'IN-A' , destinationFbaWarehouse : 'ONT8' }] })
2026-10-20 10:35:52 +08:00
const ref = () => ({ groupKey : 'GROUP-A' , customerId : CUSTOMER , destination , outboundNo : 'OUT-NEW' , deliveryNo : 'DL-NEW' , status : departed ? 'DELIVERING' : 'WAIT_DELIVERY' , packageCount : 2 })
const outbound = () => ({ customerId : CUSTOMER , outboundNo : 'OUT-NEW' , status : departed ? 'OUTBOUNDED' : 'WAIT_OUTBOUND' , packageCount : 2 })
const command = ( action , result = {}, next = false ) => ({ ... detail ( next ), action , result , replayed : false })
const tripDetail = next => ({ trip : { tripNo : next ? 'TR-NEXT' : 'TR-NEW' , warehouseId : WAREHOUSE , vehicleId : '601' , driverId : '701' , vehiclePlate , tripPurpose : 'DELIVERY' , recordVersion : tripVersion , status : closed && ! next ? 'COMPLETED' : 'PLANNED' ,
completedAt : closed && ! next ? '2026-10-19T05:00:00Z' : null , vehicleRelease : vehicleReleased && ! next ? { endLocation : 'ONT8' } : null , driverRelease : driverReleased && ! next ? { endLocation : 'ONT8' } : null , stops }, dispatches : [{ dispatchNo : next ? 'DP-NEXT' : 'DP-NEW' }] })
const stockLedger = () => returned ? [{ id : '901' , customerId : CUSTOMER , overseasWarehouseId : WAREHOUSE , inboundCode : 'IN-A' , palletNo : context . palletCode , businessType : 'RETURN_STOCK_IN' , businessOrderNo : 'EX-NEW' , outboundOrderNo : 'OUT-ORIGINAL' , deltaPackages : 2 }] : []
const envelope = ( data , code = '200' , message = '' ) => ({ http : 200 , body : { code , message , data : copy ( data ) }, requestId : 'OFFLINE-REQ' , traceId : 'OFFLINE-TRACE' })
const context = { marker : 'FRESH' , createdResources : { fleetTrips : [ trip ], fleetAcceptance : { marker : 'FRESH' , customerId : CUSTOMER , warehouseId : WAREHOUSE , tripNo : trip . tripNo ,
2026-10-21 14:30:41 +08:00
departureDeliveries : [{ customerId : CUSTOMER , deliveryNo : 'DL-ORIGINAL' }],
departure : { dispatchNo : trip . dispatchNo , action : 'LOADING_COMPLETE' , status : 'ACTIVE' , stage : 'DELIVERING' , result : { confirmedLoad : { manifestHash : 'ORIGINAL' } } } } },
2026-10-20 10:35:52 +08:00
assert ( _m , label , _r , passed ) { if ( ! passed ) throw Error ( label ) }, addStep ( _m , label , _r , passed ) { if ( ! passed ) throw Error ( label ) }, addCoverageGap () {}, apiSuccess ( _m , _l , r ) { return r . body ? . data },
async checkpoint () { checkpoints . push ( copy ( trip . returnRedispatch )) },
async requestMultipart ( method , path , file ) {
requests . push ({ method , path , file : file . name })
if ( path . includes ( '/fleet/drivers/701/license' )) return envelope ({ licenseFileId : '801' , recordVersion : 1 })
return envelope ({ fileId : '99' })
2026-10-03 22:13:15 +08:00
},
2026-10-20 10:35:52 +08:00
async request ( method , raw , body , token ) {
requests . push ({ method , path : raw , body : copy ( body ), token })
const path = raw . split ( '?' )[ 0 ], params = new URLSearchParams ( raw . split ( '?' )[ 1 ]), normalized = path . replace ( PDA , DISPATCH ), ledgerKey = ` ${ method } : ${ normalized } : ${ body ? . idempotencyKey } `
2026-10-21 14:30:41 +08:00
if ( normalized . endsWith ( '/loading-complete' ) && ! token && ledger . has ( ledgerKey )) return envelope ( null , 'A0403' , '该请求标识不属于当前操作员' )
2026-10-20 10:35:52 +08:00
if ( body ? . idempotencyKey && ledger . has ( ledgerKey ) && ! path . endsWith ( '/resources/release' )) { const prior = ledger . get ( ledgerKey ); assert . deepEqual ( body , prior . body ); return envelope ({ ... copy ( prior . data ), replayed : true }) }
const remember = data => { if ( body ? . idempotencyKey ) ledger . set ( ledgerKey , { body : copy ( body ), data : copy ( data ) }); return envelope ( data ) }
if ( path === '/api/platform/inbounds' ) { const name = params . get ( 'inboundCode' ). slice ( - 1 ), delivered = name === 'A' ? newSigned || fault === 'domestic-premature-A' && originalSigned : originalSigned && fault !== 'domestic-blocked-B' ; return envelope ({ records : [{ inboundCode : `IN- ${ name } ` , processStatus : delivered ? 'DELIVERED' : 'LOADED' }] }) }
if ( path . startsWith ( '/api/platform/v1/orders/first-leg/' )) {
const orderId = path . split ( '/' ). at ( - 1 ), name = orderId === '701' ? 'A' : 'B' , done = rootDone ( name )
if ([ 'shared-root' , 'borrowed-child' , 'child-premature-A' , 'root-premature-with-pending' ]. includes ( fault )) {
const isRoot = orderId === '700' , complete = isRoot ? newSigned || fault === 'root-premature-with-pending' : done || name === 'A' && fault === 'child-premature-A'
return envelope ({ order : { id : orderId , orderNo : isRoot ? 'FIRST-ROOT' : `FIRST- ${ name } ` , customerId : CUSTOMER , tenantId : CUSTOMER , orderRole : isRoot ? 'MASTER' : 'CHILD' ,
rootOrderId : fault === 'borrowed-child' && name === 'B' && ! isRoot ? '999' : '700' , parentOrderId : '700' , status : complete ? 'COMPLETED' : 'PROCESSING' },
statusHistory : isRoot && complete ? [{ action : 'OVERSEAS_DELIVERED' }, { action : 'FULFILLMENT_COMPLETED' }] : [] })
}
return envelope ({ order : { id : orderId , orderNo : `FIRST- ${ name } ` , customerId : CUSTOMER , tenantId : CUSTOMER , orderRole : 'MASTER' , status : done ? 'COMPLETED' : 'PROCESSING' }, statusHistory : done ? [{ action : 'OVERSEAS_DELIVERED' }, { action : 'FULFILLMENT_COMPLETED' }] : [] })
}
if ( path . endsWith ( '/fulfillment-tree' )) { const orderId = path . split ( '/' ). at ( - 2 ); return envelope ({ parentOrderId : orderId , parentOrderNo : orderId === '700' ? 'FIRST-ROOT' : orderId === '701' ? 'FIRST-A' : 'FIRST-B' ,
children : orderId === '700' ? [{ orderId : '701' , orderNo : 'FIRST-A' }, { orderId : '702' , orderNo : 'FIRST-B' }] : [{ orderId , orderNo : orderId === '701' ? 'FIRST-A' : 'FIRST-B' }] }) }
if ( path . startsWith ( ` ${ BASE } /orders/` )) { const name = Object . keys ( masterIds ). find ( name => masterIds [ name ] === path . split ( '/' ). at ( - 1 )); assert . ok ( name ); return envelope ({ order : tail ( name ) }) }
if ( path . endsWith ( '/return-inbound-options' )) return envelope ( fault === 'missing-B' ? relations . slice ( 0 , 1 ) : relations )
if ( path . endsWith ( '/mark-return' )) { assert . equal ( body . lastMileOrderId , masterIds . A ); assert . equal ( Object . hasOwn ( body , 'inboundOrderId' ), false ); assert . deepEqual ( body . items , [{ outboundPalletItemId : '20' , inventoryPositionId : '30' , packageCount : 2 }]); return remember ({ exceptionNo : 'EX-NEW' , version : 0 , replayed : false }) }
if ( path . endsWith ( '/start-processing' )) return remember ({ status : 'PROCESSING' , version : 1 })
if ( path . includes ( '/exception-orders/' ) && path . endsWith ( '/complete' )) { returned = true ; if ( fault === 'unknown-return' ) throw Error ( 'connection lost after commit' ); return remember ({ status : 'COMPLETED' , restoredPackages : fault === 'wrong-return' ? 3 : 2 , inventoryAdjustmentId : '88' , version : 2 , replayed : false }) }
if ( path . endsWith ( '/exception-orders/EX-NEW' )) return envelope ({ order : { exceptionNo : 'EX-NEW' , customerId : CUSTOMER , outboundNo : 'OUT-ORIGINAL' }, returnReceipts : [{ receiptNo : 'RSR-300' , receivedPackages : 2 }] })
if ( path . endsWith ( '/pallets' ) && method === 'POST' ) { context . palletCode = body . palletCode ; return envelope ( '100' ) }
if ( path . endsWith ( '/pallets/100' )) return envelope ({ warehouseId : WAREHOUSE , locationId : '200' , palletCode : context . palletCode })
if ( path . endsWith ( '/locations' )) return envelope ({ records : [{ id : '200' , locationCode : 'L-1' }] })
if ( path . endsWith ( '/inventory/balances' )) return envelope ({ records : returned && ! departed ? [{ id : '401' , customerId : CUSTOMER , overseasWarehouseId : WAREHOUSE }] : [], total : returned && ! departed ? 1 : 0 })
if ( path . includes ( '/inventory/balances/' ) && path . endsWith ( '/positions' )) return envelope ([{ id : '201' , customerId : CUSTOMER , overseasWarehouseId : WAREHOUSE , inboundCode : 'IN-A' , palletId : '100' , palletNo : context . palletCode , availablePackages : picked ? 0 : 2 , pickedPackages : picked ? 2 : 0 }])
if ( path . endsWith ( '/inventory/ledger' )) { const rows = stockLedger (); if ( fault === 'duplicate-ledger' && returned ) rows . push ({ ... rows [ 0 ], id : '902' }); return envelope ({ records : rows , total : rows . length }) }
if ( path === ` ${ DISPATCH } /candidates` ) { assert . equal ( params . get ( 'warehouseId' ), WAREHOUSE ); return envelope ({ complete : true , snapshotAt : '2026-10-19' , candidates : [{ selection : { sourceType : 'RETURN_RECEIPT' , returnReceiptId : '300' , planPalletId : null , relabelNo : null , warehousePalletId : '100' , sourceVersion : 'a' . repeat ( 64 ) },
sourceKey : 'RETURN:300' , sourceVersion : 'a' . repeat ( 64 ), customerId : CUSTOMER , warehouseId : WAREHOUSE , orderNo : 'LM-A' , inboundCode : 'IN-A' , palletNo : context . palletCode , destination , availablePackages : fault === 'wrong-candidate' ? 4 : 2 , appointmentBatches : [], blockReasons : [] }] }) }
if ( path === DISPATCH && method === 'POST' ) { if ( ! body . cargo . length ) { nextCreated = true ; vehicleOwner = 'TR-NEXT' ; driverOwner = 'TR-NEXT' ; return remember ( command ( 'CREATE' , {}, true )) }; assert . equal ( body . cargo [ 0 ]. sourceType , 'RETURN_RECEIPT' ); assert . equal ( body . cargo [ 0 ]. planPalletId , null ); created = true ; return remember ( command ( 'CREATE' )) }
if ( path === DISPATCH ) return envelope ({ records : [{ ... detail ( params . get ( 'dispatchNo' ) === 'DP-NEXT' ), warehouseId : WAREHOUSE }] })
2026-10-21 14:30:41 +08:00
if ( path . endsWith ( '/master-data/vehicles' )) { vehiclePlate = body . plateNumber . toUpperCase (); return envelope ({ id : '601' }) }
2026-10-20 10:35:52 +08:00
if ( path . endsWith ( '/fleet/drivers' ) && method === 'POST' ) return envelope ({ id : '701' , recordVersion : 0 })
if ( path . endsWith ( '/fleet/drivers/701/review' )) return envelope ({ reviewStatus : 'APPROVED' })
if ( path === ` ${ BASE } /fleet/trips` ) { const trips = nextCreated ? [ tripDetail ( false ). trip , tripDetail ( true ). trip ] : [ tripDetail ( false ). trip ]; return envelope ({ records : trips , page : 1 , size : 200 , total : trips . length }) }
if ( path . endsWith ( '/fleet/trips/TR-NEW/completion' )) return envelope ({ canComplete : true , outcomes : [{}], recordVersion : tripVersion })
if ( path . endsWith ( '/fleet/trips/TR-NEW/complete' )) { closed = true ; tripVersion ++ ; return remember ( tripDetail ( false )) }
if ( path . endsWith ( '/resource-occupancy' )) return envelope ([{ resourceId : params . get ( 'resourceIds' ), occupiedTripNo : params . get ( 'kind' ) === 'VEHICLE' ? vehicleOwner : driverOwner }])
if ( path . endsWith ( '/resources/release' )) {
const prior = ledger . get ( ledgerKey )
if ( ! prior ) { if ( body . resourceKind === 'VEHICLE' ) { vehicleReleased = true ; vehicleOwner = null } else { driverReleased = true ; driverOwner = null }; tripVersion ++ ; ledger . set ( ledgerKey , { body : copy ( body ), data : null }) }
else assert . deepEqual ( prior . body , body )
return envelope ( tripDetail ( false ))
}
if ( path . endsWith ( '/fleet/trips/TR-NEW' )) return envelope ( tripDetail ( false ))
if ( path . endsWith ( '/fleet/trips/TR-NEXT' )) return envelope ( tripDetail ( true ))
if ( path . includes ( '/delivery-orders/' ) && path . endsWith ( '/documents' )) {
const number = path . split ( '/delivery-orders/' )[ 1 ]. split ( '/' )[ 0 ]
if ( method === 'GET' ) return envelope ({ version : 0 , categories : [] })
if ( number === 'DL-NEW' ) newSigned = true ; else originalSigned = true
return remember ({ version : 1 , categories : [{ category : 'RECEIPT' , status : 'UPLOADED' , fileCount : 1 }], replayed : false })
}
if ( path . endsWith ( '/status' ) && path . includes ( '/delivery-orders/' )) { assert . equal ( body . expectedVersion , controls . deliveryVersion ?? 0 ); controls . waitDelivery = false ; return envelope ({ deliveryStatus : 'DELIVERING' }) }
if ( path . includes ( '/delivery-orders/' )) return envelope ({ order : order ( path . split ( '/' ). at ( - 1 )), operations : [{ operationNode : 'RECEIPT_AUTO_COMPLETE' }] })
const next = normalized . startsWith ( ` ${ DISPATCH } /DP-NEXT` )
if ( method === 'GET' && normalized . endsWith ( '/items' )) return envelope ({ dispatchNo : next ? 'DP-NEXT' : 'DP-NEW' , recordVersion : next ? 0 : recordVersion , status : 'ACTIVE' , stage : next ? 'BEFORE_LOADING' : stage , items : next ? [] : [ nativeItem ()] })
if ( method === 'GET' && normalized . endsWith ( '/route' )) return envelope ({ dispatchNo : 'DP-NEW' , recordVersion , stops })
if ( method === 'GET' && path . startsWith ( PDA ) && normalized . endsWith ( '/DP-NEW' )) return envelope ({ ... detail ( false ), items : [ nativeItem ()] })
2026-10-26 19:21:11 +08:00
if ( method === 'GET' && path . endsWith ( '/loading-documents' )) return envelope ({ dispatchNo : 'DP-NEW' , stage : 'LOADING' , reviewRound : '1' , complete : true , photos : LOADING_PHOTO_SLOTS . map (( slot , index ) => ({ slot , fileId : String ( index + 1 ) })) })
2026-10-20 10:35:52 +08:00
if ( method === 'GET' && normalized . endsWith ( '/loading' )) return envelope ({ ... detail ( false ), manifestHash : 'b' . repeat ( 64 ), loadingComplete : { allowed : true }, pallets : [{ warehousePalletId : '100' , palletNo : context . palletCode , scheduledPackages : 2 , pickedPackages : 2 ,
2026-10-22 11:56:47 +08:00
deliveryIndex : 1 , ...( fault === 'missing-measurements' ? {} : { palletSpaces : 1 , weightKg : 37 , volumeCbm : 0.7 , evidence : [[ 'palletSpaces' , 2 ], [ 'weightKg' , 37 ], [ 'volumeCbm' , 0.7 ]]. map (([ field , value ]) => ({ field , value , actual : true , sourceType : 'MEASURED' , sourceBusinessNo : 'EX-NEW' , observedAt : '2026-10-19T02:00:00Z' })) }) }] })
2026-10-20 10:35:52 +08:00
if ( method === 'GET' && normalized . endsWith ( '/delivery-arrangement' )) return envelope ({ ... detail ( false ), cargoHash : 'a' . repeat ( 64 ), loadingCompletionHash : 'b' . repeat ( 64 ), arrange : { allowed : true }, groups : [{ groupKey : 'GROUP-A' , customerId : CUSTOMER , destination , groupCargoHash : 'c' . repeat ( 64 ), externalFreightHash : 'd' . repeat ( 64 ), feeCoverageCargoHash : 'c' . repeat ( 64 ), blockReasons : [], requiredServices : [ 'DELIVERY_FEE' ], cargo : [{ ... nativeItem (), packages : 2 }] }] })
if ( method === 'GET' && normalized === ` ${ DISPATCH } / ${ next ? 'DP-NEXT' : 'DP-NEW' } ` ) return envelope ( detail ( next ))
assert . ok ( created , ` ${ method } ${ raw } ` )
if ( normalized . endsWith ( '/cancel' )) { nextCancelled = true ; vehicleOwner = null ; driverOwner = null ; return remember ({ ... command ( 'CANCEL' , {}, true ), status : 'CANCELLED' }) }
if ( method === 'PUT' && normalized . endsWith ( '/DP-NEW' )) { if ( picked ) return envelope ( null , 'A0409' , '已扫码不能编辑' ); assert . equal ( body . recordVersion , recordVersion ); recordVersion ++ ; return remember ( command ( 'EDIT' )) }
if ( normalized . endsWith ( '/pick' ) && body . recordVersion !== recordVersion ) return envelope ( null , 'A0409' , '公共版本已变化' )
assert . equal ( body . recordVersion , recordVersion , raw )
if ( /\/(submit-review|dispatch-review|loading-review)$/ . test ( normalized )) { if ( normalized . endsWith ( '/loading-review' )) { review = true ; stage = 'LOADING' }; recordVersion ++ ; return remember ( command ( 'REVIEW' )) }
if ( normalized . endsWith ( '/pick' )) { assert . equal ( token , 'private-pda-token' ); picked = true ; recordVersion ++ ; return remember ( command ( 'PICK' , { packages : 2 })) }
2026-10-22 11:56:47 +08:00
if ( normalized . endsWith ( '/loading-complete' )) { assert . equal ( picked , true ); stage = 'DELIVERING' ; arranged = true ; departed = true ; recordVersion ++ ; return remember ( command ( 'LOADING_COMPLETE' , { confirmedLoad : { manifestHash : body . manifestHash , pallets : [{ warehousePalletId : '100' , palletSpaces : 1 , weightKg : fault === 'missing-measurements' ? null : 37 , volumeCbm : fault === 'missing-measurements' ? null : 0.7 , deliveryIndex : 1 }] } })) }
2026-10-20 10:35:52 +08:00
throw Error ( `Unexpected ${ method } ${ raw } ` )
} }
const dependencies = { wait : async () => {}, async onBeforeRedispatchSignature ( proof ) { assert . equal ( newSigned , false ); assert . equal ( originalSigned , true ); assert . equal ( proof . preSignatureGate . status , 'WAITING' ); if ( fault === 'audit-gate' ) throw Error ( 'Audit gate not approved' ); return { sourceAEventCount : 0 , sourceBEventCount : 1 , auditEvidenceSha256 : 'a' . repeat ( 64 ) } } }
const input = { customerId : CUSTOMER , warehouseId : WAREHOUSE , pickerToken : 'private-pda-token' , dispatchNos : [ 'DP-ORIGINAL' ], deliveryNos : [ 'DL-ORIGINAL' ] }
return { context , trip , input , dependencies , requests , checkpoints , relations , masterIds , controls }
2026-10-03 16:11:52 +08:00
}
const run = f => verifyFleetReturnRedispatch ( f . context , 'test' , f . trip , f . input , f . dependencies )
2026-10-22 11:56:47 +08:00
test ( 'server-owned loading permits absent optional weight and volume without inventing measurements' , async () => {
const f = fixture ( 'missing-measurements' )
await run ( f )
const request = f . requests . find ( item => item . path . endsWith ( '/loading-complete' ))
assert . ok ( request )
assert . equal ( request . body ? . measurements , undefined )
assert . equal ( f . trip . returnRedispatch . status , 'HTTP_CHAIN_VERIFIED_SOURCE_EVENT_EVIDENCE_REQUIRED' )
})
2026-10-20 10:35:52 +08:00
test ( 'native one-main multi-source return redispatch executes real APIs through new signature and resource closure' , async () => {
2026-10-03 16:11:52 +08:00
const f = fixture (), result = await run ( f )
2026-10-20 10:35:52 +08:00
assert . equal ( result . status , 'HTTP_CHAIN_VERIFIED_SOURCE_EVENT_EVIDENCE_REQUIRED' ); assert . equal ( result . sourceEventsVerified , false ); assert . equal ( result . readOnlyEvidenceRequired . length , 3 )
assert . equal ( result . beforeRedispatch . A . order . subOrderStatus , 'DELIVERY:WAIT_DELIVERY' ); assert . equal ( result . beforeRedispatch . B . order . subOrderStatus , 'DELIVERY:DELIVERED' )
2026-10-21 14:30:41 +08:00
assert . equal ( result . afterRedispatch . A . order . subOrderStatus , 'DELIVERY:DELIVERED' ); assert . equal ( result . afterRedispatch . departed . action , 'LOADING_COMPLETE' ); assert . equal ( result . afterRedispatch . departed . counts . shippedPackageCount , 2 )
2026-10-20 10:35:52 +08:00
assert . equal ( result . inventory . map ( s => s . ledger . length ). every (( n , i ) => n === ( i === 0 ? 0 : 1 )), true )
assert . ok ( ! JSON . stringify ( f . checkpoints ). includes ( 'private-pda-token' )); assert . ok ( f . checkpoints . some ( p => p . requests . at ( - 1 ) ? . status === 'SENDING' && p . requests . at ( - 1 ) ? . file ? . sha256 ))
2026-10-21 14:30:41 +08:00
assert . ok ( f . requests . some ( r => r . path . endsWith ( '/loading-complete' )))
assert . equal ( f . requests . some ( r => / \ / ( transfer - delivery | depart ) $ / . test ( r . path )), false )
2026-10-20 10:35:52 +08:00
assert . equal ( f . requests . some ( r => r . path . includes ( '/pre-arrange' )), false )
2026-10-03 16:11:52 +08:00
})
2026-10-03 22:13:15 +08:00
2026-10-20 10:35:52 +08:00
for ( const signedPackages of [ undefined , null , '5' , - 1 , 1.5 ]) test ( `invalid original signature quantity ${ signedPackages } stops before new Create` , async () => {
const f = fixture (); f . controls . originalQuantity = { override : true , value : signedPackages }; await assert . rejects ( run ( f ), /stored quantity/ )
assert . equal ( f . trip . returnRedispatch . originalSignatures . length , 0 ); assert . equal ( f . requests . some ( r => r . path === DISPATCH && r . method === 'POST' ), false )
})
for ( const signedPackages of [ undefined , null , '2' , 0 , 3 ]) test ( `new signature must contain numeric exactly two boxes: ${ signedPackages } ` , async () => {
const f = fixture (); f . controls . newQuantity = { override : true , value : signedPackages }; await assert . rejects ( run ( f ), /two boxes actually signed/ )
assert . equal ( f . requests . some ( r => r . path . endsWith ( '/TR-NEW/complete' )), false )
})
test ( 'actual selected master works without ordinary inbound relationship and uses immutable return receipt selector' , async () => {
const f = fixture ( 'no-inbound' ); assert . equal (( await run ( f )). returnReceiptId , '300' ); assert . ok ( f . relations . every ( r => r . inboundOrderId == null ))
assert . equal ( f . requests . filter ( r => r . path . includes ( '/mark-return' )). length , 2 )
const create = f . requests . find ( r => r . path === DISPATCH && r . body . cargo . length ); assert . equal ( create . body . cargo [ 0 ]. sourceType , 'RETURN_RECEIPT' ); assert . equal ( create . body . cargo [ 0 ]. planPalletId , null )
})
for ( const fault of [ 'missing-master' , 'wrong-delivery' , 'wrong-outbound' , 'foreign-customer' , 'foreign-warehouse' , 'borrowed-master' ]) test ( `reject return provenance ${ fault } before all writes` , async () => {
const f = fixture (), request = f . context . request
if ( fault === 'missing-master' ) delete f . relations [ 0 ]. lastMileOrderId
if ( fault === 'wrong-delivery' ) f . relations [ 0 ]. deliveryNo = 'DL-OTHER'
if ( fault === 'wrong-outbound' ) f . relations [ 0 ]. outboundNo = 'OUT-OTHER'
if ( fault === 'foreign-customer' ) f . relations [ 0 ]. customerId = '999'
if ( fault === 'foreign-warehouse' ) f . relations [ 0 ]. overseasWarehouseId = '999'
if ( fault === 'borrowed-master' ) f . context . request = async (... args ) => { const response = await request (... args ); if ( args [ 1 ]. includes ( `/orders/ ${ f . masterIds . A } ` )) response . body . data . order . id = f . masterIds . B ; return response }
await assert . rejects ( run ( f ), /real master ID|match this candidate/ ); assert . ok ( f . requests . every ( r => r . method === 'GET' ))
})
for ( const mutate of [ source => { source . inventoryPositionId = null }, source => { source . returnCartonId = '701' }]) test ( 'ordinary two-box return cannot borrow a source or native carton' , async () => {
const f = fixture (); mutate ( f . relations [ 0 ]. returnSources [ 0 ]); await assert . rejects ( run ( f ), /Selected master must contain/ ); assert . ok ( f . requests . every ( r => r . method === 'GET' ))
})
2026-10-22 11:56:47 +08:00
for ( const fault of [ 'missing-B' , 'wrong-return' , 'premature-A' , 'domestic-premature-A' , 'blocked-B' , 'domestic-blocked-B' , 'root-premature-A' , 'wrong-candidate' , 'rewritten-original' , 'duplicate-ledger' , 'borrowed-child' , 'child-premature-A' , 'root-premature-with-pending' ]) test ( `native chain rejects ${ fault } ` , async () => {
2026-10-20 10:35:52 +08:00
const f = fixture ( fault ); await assert . rejects ( run ( f )); assert . equal ( f . trip . returnRedispatch . status , 'FAILED' )
if ( fault === 'missing-B' ) assert . ok ( f . requests . every ( r => r . method === 'GET' ))
})
test ( 'a shared formal root stays pending for A while child B completes and finishes only after new A signature' , async () => {
const f = fixture ( 'shared-root' ), proof = await run ( f )
assert . equal ( proof . rootsBeforeRedispatch [ 0 ]. root . order . status , 'PROCESSING' )
assert . equal ( proof . rootsBeforeRedispatch [ 0 ]. children . find ( c => c . id === '701' ). status , 'PROCESSING' )
assert . equal ( proof . rootsBeforeRedispatch [ 0 ]. children . find ( c => c . id === '702' ). status , 'COMPLETED' )
assert . ok ( proof . rootsAfterRedispatch . every ( s => s . root . order . status === 'COMPLETED' && s . children . every ( c => c . status === 'COMPLETED' )))
})
for ( const missing of [ false , true ]) test ( `unapproved or missing readonly audit prevents new signature and closure; missing= ${ missing } ` , async () => {
const f = fixture ( 'audit-gate' ); if ( missing ) delete f . dependencies . onBeforeRedispatchSignature
await assert . rejects ( run ( f ), missing ? /audit gate is required/ : /Audit gate not approved/ ); assert . equal ( f . trip . returnRedispatch . preSignatureGate . status , 'WAITING' )
assert . equal ( f . requests . some ( r => r . method === 'PUT' && r . path . includes ( '/DL-NEW/documents' )), false ); assert . equal ( f . requests . some ( r => r . path . endsWith ( '/TR-NEW/complete' )), false )
})
test ( 'core producer, pick and successful signature cannot be externally substituted' , async () => {
for ( const name of [ 'prepareFleetTrip' , 'confirmFleetLoading' , 'pickAll' , 'saveReceiptAndComplete' , 'finishFleetTrip' ]) { const f = fixture (); f . dependencies [ name ] = async () => ({ success : true }); await assert . rejects ( run ( f ), /cannot be replaced/ ); assert . equal ( f . requests . length , 0 ) }
})
test ( 'native owned departure guard rejects old status and wrong original whole before HTTP' , async () => {
const f = fixture (); f . context . createdResources . fleetAcceptance . departure . status = 'IN_TRANSIT' ; await assert . rejects ( run ( f ), /owned departure/ ); assert . equal ( f . requests . length , 0 )
const other = fixture (); other . input . dispatchNos = [ 'BORROWED' ]; await assert . rejects ( run ( other ), /owned departure/ ); assert . equal ( other . requests . length , 0 )
})
test ( 'reviewed source selection retains started deliveries and refuses to repeat WAIT_DELIVERY start' , async () => {
const f = fixture (); f . input . sourceSelectionRecovery = true ; await run ( f ); assert . equal ( f . requests . some ( r => r . path . includes ( '/status' )), false )
const waiting = fixture (); waiting . input . sourceSelectionRecovery = true ; waiting . controls . waitDelivery = true ; await assert . rejects ( run ( waiting ), /never start it again/ ); assert . ok ( waiting . requests . every ( r => r . method === 'GET' ))
})
test ( 'fresh WAIT_DELIVERY start preserves exact server Long version including zero' , async () => {
for ( const version of [ 0 , '9223372036854775807' ]) { const f = fixture (); f . controls . waitDelivery = true ; f . controls . deliveryVersion = version ; await run ( f ); const started = f . requests . find ( r => r . path . includes ( '/status' )); assert . equal ( started . body . expectedVersion , version ) }
})
test ( 'fixture source A/B selection refuses borrowed or partial shipments' , () => {
const row = name => ({ tail : { orderType : 'FIRST_LEG' , sourceInboundId : name , inboundCode : name , packageCount : 4 }, relation : { inboundCode : name , returnSources : [{ maxReturnPackages : 3 }] } })
assert . throws (() => selectReturnSources ([ row ( 'A' ), row ( 'B' )]), /cover each selected source completely/ )
})
test ( 'write-ahead failure sends no HTTP and unknown return preserves original key without restart' , async () => {
const disk = fixture (); disk . context . checkpoint = async () => { throw Error ( 'disk full' ) }; await assert . rejects ( run ( disk ), /disk full/ ); assert . equal ( disk . requests . length , 0 )
const f = fixture ( 'unknown-return' ); await assert . rejects ( run ( f ), /connection lost/ ); const last = f . checkpoints . at ( - 1 ). requests . at ( - 1 ); assert . equal ( last . status , 'UNKNOWN_RESULT' ); assert . ok ( last . body . idempotencyKey )
const count = f . requests . length ; await assert . rejects ( run ( f ), /no automatic restart/ ); assert . equal ( f . requests . length , count )
})
for ( const [ name , response ] of Object . entries ({ http0 : { http : 0 , body : null }, server500 : { http : 500 , body : { code : 'B0001' }, requestId : 'r' , traceId : 't' }, proxy502 : { http : 502 , body : null }, malformed200 : { http : 200 , body : { unexpected : true }, requestId : 'r' , traceId : 't' }, htmlFailure : { http : 403 , body : '<html>blocked</html>' , requestId : 'r' , traceId : 't' }, uncorrelatedSuccess : { http : 200 , body : { code : '200' , data : {} } } })) test ( `ambiguous ${ name } stops without automatic replay` , async () => {
const f = fixture (), request = f . context . request ; f . context . request = async (... args ) => { if ( args [ 1 ]. includes ( '/mark-return' )) { f . requests . push ({ method : args [ 0 ], path : args [ 1 ], body : copy ( args [ 2 ]) }); return response }; return request (... args ) }
await assert . rejects ( run ( f ), /outcome unknown/ ); const last = f . checkpoints . at ( - 1 ). requests . at ( - 1 ); assert . equal ( last . status , 'UNKNOWN_RESULT' ); assert . ok ( last . body . idempotencyKey )
assert . equal ( f . requests . filter ( r => r . path . includes ( '/mark-return' )). length , 1 ); const count = f . requests . length ; await assert . rejects ( run ( f ), /no automatic restart/ ); assert . equal ( f . requests . length , count )
})
test ( 'unknown multipart writes retain file hash and stop before return stock receipt' , async () => {
const f = fixture (); f . context . requestMultipart = async ( method , path , file ) => { f . requests . push ({ method , path , file : file . name }); return { http : 0 , body : null } }
await assert . rejects ( run ( f ), /outcome unknown/ ); const entry = f . checkpoints . at ( - 1 ). requests . at ( - 1 ); assert . equal ( entry . status , 'UNKNOWN_RESULT' ); assert . match ( entry . file . sha256 , /^[a-f0-9]{64}$/ )
assert . equal ( f . requests . some ( r => r . path . includes ( '/exception-orders/' ) && r . path . includes ( '/complete' )), false )
})
test ( 'correlated business conflict is retained as a definite rejection without retry' , async () => {
const f = fixture (), request = f . context . request ; f . context . request = async (... args ) => { if ( args [ 1 ]. includes ( '/mark-return' )) { f . requests . push ({ method : args [ 0 ], path : args [ 1 ], body : copy ( args [ 2 ]) }); return { http : 409 , body : { code : 'A0409' }, requestId : 'r' , traceId : 't' } }; return request (... args ) }
await assert . rejects ( run ( f ), /HTTP failed/ ); assert . equal ( f . checkpoints . at ( - 1 ). requests . at ( - 1 ). status , 'RESPONDED' ); assert . equal ( f . requests . filter ( r => r . path . includes ( '/mark-return' )). length , 1 )
2026-10-03 22:13:15 +08:00
})
for ( const fault of [ 'none' , 'nonce' , 'counts' , 'hash' , 'trip' , 'timeout' ]) test ( `file gate requires exact checkpoint and hashed source audit: ${ fault } ` , async () => {
const root = mkdtempSync ( join ( tmpdir (), 'fleet-signature-gate-' )), output = join ( root , 'reports' , 'run' )
mkdirSync ( output , { recursive : true })
const context = { marker : 'CURRENT' , context : { fleetRunId : 'FRESH' }, createdResources : { fleetAcceptance : { tripNo : 'TR-ORIGINAL' , customerId : 'C' } } }
const proof = { newTripNo : 'TR-NEW' , sources : { A : { tail : { sourceInboundId : 'A' } }, B : { tail : { sourceInboundId : 'B' } } } }
try {
const wait = async () => {
const checkpoint = JSON . parse ( readFileSync ( join ( output , 'before-redispatch-signature.json' ), 'utf8' ))
assert . equal ( checkpoint . proof . newTripNo , 'TR-NEW' ); assert . equal ( checkpoint . sourceAInboundId , 'A' )
const evidence = Buffer . from ( '{"A":0,"B":1}' )
writeFileSync ( join ( root , 'reports' , 'audit.json' ), evidence )
writeFileSync ( join ( output , 'approve-before-redispatch-signature.json' ), JSON . stringify ({ gateNonce : fault === 'nonce' ? 'OTHER' : checkpoint . gateNonce ,
marker : checkpoint . marker , newTripNo : fault === 'trip' ? 'OTHER' : checkpoint . newTripNo ,
sourceAEventCount : fault === 'counts' ? 1 : 0 , sourceBEventCount : 1 , auditEvidencePath : 'reports/audit.json' ,
auditEvidenceSha256 : fault === 'hash' ? 'a' . repeat ( 64 ) : createHash ( 'sha256' ). update ( evidence ). digest ( 'hex' ) }))
}
const promise = waitForRedispatchSignatureAudit ( context , proof , { root , output , wait , timeoutMs : fault === 'timeout' ? 0 : 5000 })
if ( fault === 'none' ) { const result = await promise ; assert . equal ( result . sourceAEventCount , 0 ); assert . equal ( result . sourceBEventCount , 1 ) }
else await assert . rejects ( promise , /gate|approval|SHA256/ )
} finally {
assert . equal ( dirname ( resolve ( root )), resolve ( tmpdir ())); assert . ok ( resolve ( root ). startsWith ( join ( resolve ( tmpdir ()), 'fleet-signature-gate-' )))
rmSync ( root , { recursive : true , force : true })
}
})