2026-10-05 00:37:18 +08:00
import { test } from 'node:test'
import assert from 'node:assert/strict'
import fs from 'node:fs'
import path from 'node:path'
import os from 'node:os'
import crypto from 'node:crypto'
import { validateSource , validateDestination , relabelPrerequisite , TRANSFER , CUSTOMER } from './fba-remaining-nodes-acceptance-transfer.mjs'
2026-10-05 02:50:29 +08:00
import { LA , NY , prepareOriginalTransferPlan , prepareTransferStage , runPreparedTransferStage , verifyTransferMilestone , redactTransferMessage } from './fba-remaining-nodes-acceptance-transfer.mjs'
2026-10-05 00:37:18 +08:00
const detail = { transferNo : TRANSFER , status : 'APPROVED' , packageCount : 1 , allocations : [], operatingWarehouseId : 'w' , sourceOrders : [{ inboundOrderId : 'o' }]}
const balance = { id : 'b' , customerId : CUSTOMER , inboundOrderId : 'o' , overseasWarehouseId : 'w' }
const position = { id : 'p' , balanceId : 'b' , customerId : CUSTOMER , palletId : 't' , availablePackages : 1 , frozenPackages : 0 , pickedPackages : 0 }
test ( 'original approved one-carton source passes exact ownership' ,()=> assert . deepEqual ( validateSource ( detail , balance , position ),{ inventoryPositionId : 'p' , palletId : 't' , packageCount : 1 }))
test ( 'other source, customer, warehouse and unavailable or occupied cartons stop before commands' ,()=>{
for ( const b of [{... balance , inboundOrderId : 'other' },{... balance , customerId : 'other' },{... balance , overseasWarehouseId : 'other' }]) assert . throws (()=> validateSource ( detail , b , position ))
for ( const p of [{... position , availablePackages : 0 },{... position , frozenPackages : 1 },{... position , holdPackages : 1 },{... position , allocatedPackages : 1 },{... position , pickedPackages : 1 },{... position , palletId : null }]) assert . throws (()=> validateSource ( detail , balance , p ))
assert . throws (()=> validateSource ({... detail , allocations : [{}]}, balance , position ))
})
test ( 'missing destination or FBA master cannot silently become a receiving overseas resource' ,()=>{
assert . throws (()=> validateDestination ( detail ))
assert . throws (()=> validateDestination ( detail ,{ warehouseType : 'FBA' , status : 'ACTIVE' },{},{}))
const d = { destinationWarehouseCode : 'ABE4' }, w = { id : 'ny' , warehouseType : 'OVERSEAS' , status : 'ACTIVE' }
const p = { warehouseId : 'ny' , locationId : 'loc' , status : 'IDLE' , customerId : '0' , fbaWarehouseCode : 'ABE4' }
const l = { id : 'loc' , warehouseId : 'ny' }
assert . equal ( validateDestination ( d , w , p , l ), true )
assert . throws (()=> validateDestination ( d , w ,{... p , warehouseId : 'la' }, l ))
assert . throws (()=> validateDestination ( d , w ,{... p , status : 'OCCUPIED' }, l ))
})
test ( 'available original-source cartons cannot waive original ticket relabel binding' ,()=>{
const d = { needRelabel : true , lastlegOrderId : '13' , relabelBindings : [{ quantity : 1 }]}
assert . equal ( relabelPrerequisite ( d ,{ relabelStatus : 'PENDING_BINDING' }). ready , false )
assert . equal ( relabelPrerequisite ({... d , relabelNo : 'original' },{ relabelApplications : [{ relabelNo : 'other' , lastlegOrderId : '13' }], relabelStatus : 'COMPLETED' }). ready , false )
assert . equal ( relabelPrerequisite ({... d , relabelNo : 'original' },{ relabelApplications : [{ relabelNo : 'original' , lastlegOrderId : '13' }], relabelStatus : 'PENDING_PROCESSING' }). ready , false )
assert . equal ( relabelPrerequisite ({... d , relabelNo : 'original' },{ relabelApplications : [{ relabelNo : 'original' , lastlegOrderId : 'other' }], relabelStatus : 'COMPLETED' }). ready , false )
assert . equal ( relabelPrerequisite ({... d , relabelNo : 'original' },{ relabelApplications : [{ relabelNo : 'original' , lastlegOrderId : '13' }], relabelStatus : 'COMPLETED' }). ready , true )
})
function linkedFixture ( status = 'WAIT_RELABEL' ){
const transfer = { transferNo : TRANSFER , needRelabel : true , packageCount : 1 , operatingWarehouseId : LA , destinationWarehouseCode : 'ABE4' ,
relabelNo : 'RL-SYNTHETIC-ONLY' , relabelApplicationId : 'app' , lastlegOrderId : 'tail' , status ,
relabelBindings : [{ newSku : 'NEW' }], allocations : [{ inventoryPositionId : 'selected-old' , palletId : 'source-pallet' , packageCount : 1 , status : 'RESERVED' , skuCode : 'OLD' }]}
const linked = { application : { id : 'app' , relabelNo : transfer . relabelNo , lastlegOrderId : 'tail' , customerOrderNo : TRANSFER , overseasWarehouseId : LA }, items : [{ cartonMark : 'BOX-1' }]}
const task = { relabelNo : transfer . relabelNo , customerOrderNo : TRANSFER , taskStatus : 'PROCESSING' , version : 2 ,
expectedPackages : 1 , relabelledPackages : 1 , skippedPackages : 0 , exceptionPackages : 0 ,
2026-10-05 02:50:29 +08:00
items : [{ itemId : 'item' , expectedPackages : 1 , cartonMark : 'BOX-1' , fbaCartonMark : 'FBA-BOX-1' , operationType : 'CARTON_AND_SKU' , skuItems : [{ skuCode : 'OLD' , newSkuCode : 'NEW' , quantity : 1 }]}],
unitFacts : [{ factId : 'fact' , itemId : 'item' , result : 'RELABELLED' , quantity : 1 }],
2026-10-05 00:37:18 +08:00
history : [{ action : 'PALLET_BIND' , detail : JSON . stringify ({ round : 'INITIAL' , cartonMarks : [ 'BOX-1' ], targetPallets : [ 'WORK-1' ]})}]}
return { transfer , linked , task , plan : prepareOriginalTransferPlan ( transfer , 'offline-contract' )}
}
const platform = { kind : 'platform' , appCode : 'PLATFORM' , tenantId : '0' , authorities : [ 'platform:overseas-warehouse:relabel-order:status' ]}
const release = stage =>({ execute : true , environment : 'TEST' , transferNo : TRANSFER , customerId : CUSTOMER , stage , runId : 'offline-contract' })
function temporaryJournal (){ const directory = fs . mkdtempSync ( path . join ( os . tmpdir (), 'f33-stage-' )); return { directory , cleanup (){ for ( const file of fs . readdirSync ( directory )) fs . unlinkSync ( path . join ( directory , file )); fs . rmdirSync ( directory )}}}
test ( 'unallocated original ticket remains a zero-network plan without inventing a relabel number' , async ()=>{
const f = linkedFixture (); delete f . transfer . relabelNo ; delete f . transfer . relabelApplicationId
const plan = prepareOriginalTransferPlan ( f . transfer , 'unallocated' )
assert . equal ( plan . linked , false ); assert . equal ( plan . networkIssued , false )
assert . throws (()=> prepareTransferStage ( plan , 'approve' ,{ linked : f . linked }), /WAIT_FOR_ORIGINAL_ALLOCATION/ )
assert . throws (()=> prepareTransferStage ( f . plan , 'review-approve' ,{ linked : f . linked }), /UNSUPPORTED_STAGE/ )
const command = prepareTransferStage ( f . plan , 'approve' ,{ linked : f . linked }); let calls = 0
assert . equal (( await runPreparedTransferStage ({ command , transport : async ()=>{ calls ++ }})). mode , 'PLAN' ); assert . equal ( calls , 0 )
})
test ( 'different relabel parent IDs or customer-order linkage cannot enter the original pipeline' ,()=>{
const f = linkedFixture ()
for ( const patch of [{ id : 'other' },{ lastlegOrderId : 'other' },{ customerOrderNo : 'OTHER-TICKET' },{ overseasWarehouseId : NY }]){
assert . throws (()=> prepareTransferStage ( f . plan , 'approve' ,{ linked : {... f . linked , application : {... f . linked . application ,... patch }}}), /EXACT_ORIGINAL_RELABEL/ )
}
})
test ( 'actual labels and approved SKU piece counts are required for one combined unit fact' ,()=>{
const f = linkedFixture (), context = { linked : f . linked , task : f . task , itemId : 'item' , observedOldLabel : 'BOX-1' , observedNewLabel : 'FBA-BOX-1' , observedSkus : [{ skuCode : 'OLD' , newSkuCode : 'NEW' , quantity : 1 }]}
const command = prepareTransferStage ( f . plan , 'unit' , context ); assert . equal ( command . body . expectedVersion , 2 ); assert . match ( command . path , /\/units$/ )
assert . throws (()=> prepareTransferStage ( f . plan , 'unit' ,{... context , observedOldLabel : 'OTHER' }))
assert . throws (()=> prepareTransferStage ( f . plan , 'unit' ,{... context , observedSkus : [{ skuCode : 'OLD' , newSkuCode : 'NEW' , quantity : 2 }]}))
})
test ( 'normal completion requires current-round physical binding photos and no skipped cartons' ,()=>{
const f = linkedFixture (), context = { linked : f . linked , task : f . task , photoFileIds : [ '77' ]}
assert . equal ( prepareTransferStage ( f . plan , 'complete' , context ). body . manualCompletion , false )
assert . throws (()=> prepareTransferStage ( f . plan , 'complete' ,{... context , task : {... f . task , reviewedAt : 'NEW-ROUND' }}))
assert . throws (()=> prepareTransferStage ( f . plan , 'complete' ,{... context , task : {... f . task , skippedPackages : 1 }}))
assert . throws (()=> prepareTransferStage ( f . plan , 'complete' ,{... context , photoFileIds : []}))
})
test ( 'receipt consumes the current shipped output position and keeps New York separate from ABE4' ,()=>{
const f = linkedFixture ( 'OUTBOUNDED' ); f . transfer . allocations = [{ inventoryPositionId : 'new-output' , palletId : 'work-pallet' , packageCount : 1 , status : 'SHIPPED' , skuCode : 'NEW' }]
const plan = prepareOriginalTransferPlan ( f . transfer , 'receipt' )
const receiptTarget = { warehouse : { id : NY , warehouseType : 'OVERSEAS' , status : 'ACTIVE' , warehouseCode : 'US-NYC-01' , warehouseName : '纽约仓' },
pallet : { id : 'ny-pallet' , warehouseId : NY , locationId : 'ny-location' , palletCode : 'F33-NY' , status : 'IDLE' , customerId : '0' , fbaWarehouseCode : 'ABE4' }, location : { id : 'ny-location' , warehouseId : NY , locationCode : 'F33-NY-LOC' }}
const command = prepareTransferStage ( plan , 'receipt' ,{ linked : f . linked , receiptTarget })
assert . equal ( command . body . sourceInventoryPositionId , 'new-output' ); assert . equal ( command . body . destinationOverseasWarehouseId , NY )
assert . equal ( command . body . destinationWarehouseCode , 'ABE4' ); assert . equal ( command . body . destinationWarehouseId , '193000000000000003' )
assert . throws (()=> prepareTransferStage ( plan , 'receipt' ,{ linked : f . linked , receiptTarget : {... receiptTarget , warehouse : {... receiptTarget . warehouse , id : LA }}}))
})
test ( 'write intent is durable before a single transport call; only known exact original replay is allowed' , async ()=>{
const f = linkedFixture (), command = prepareTransferStage ( f . plan , 'approve' ,{ linked : f . linked }), temp = temporaryJournal (); let count = 0
try {
const transport = async c =>{ count ++ ; const j = JSON . parse ( fs . readFileSync ( path . join ( temp . directory , ` ${ c . runId } - ${ c . stage } .json` ))); assert . equal ( count === 1 ? j . phase : j . replay . phase , 'INTENT' ); return { http : 200 , code : '200' , data : { approved : true }}}
const options = { command , release : release ( 'approve' ), actor : platform , transport , journalDirectory : temp . directory }
await runPreparedTransferStage ( options ); await assert . rejects ( runPreparedTransferStage ( options )); await runPreparedTransferStage ({... options , replay : true })
assert . equal ( count , 2 ); const journal = JSON . parse ( fs . readFileSync ( path . join ( temp . directory , ` ${ command . runId } - ${ command . stage } .json` ))); assert . equal ( journal . businessVerified , false )
await assert . rejects ( runPreparedTransferStage ({... options , replay : true })); assert . equal ( count , 2 )
} finally { temp . cleanup ()}
})
test ( 'unknown result or explicit rejection preserves evidence and blocks retry even with the original key' , async ()=>{
for ( const unknown of [ true , false ]){
const f = linkedFixture (), command = prepareTransferStage ( f . plan , 'approve' ,{ linked : f . linked }), temp = temporaryJournal (); let calls = 0
try {
const transport = async ()=>{ calls ++ ; if ( unknown ) throw Error ( 'secret diagnostics must not be recorded' ); return { http : 409 , code : 'A0409' , requestId : 'req' , traceId : 'trace' }}
const options = { command , release : release ( 'approve' ), actor : platform , transport , journalDirectory : temp . directory }
await assert . rejects ( runPreparedTransferStage ( options )); await assert . rejects ( runPreparedTransferStage ({... options , replay : true })); assert . equal ( calls , 1 )
const raw = fs . readFileSync ( path . join ( temp . directory , ` ${ command . runId } - ${ command . stage } .json` ), 'utf8' ); assert . doesNotMatch ( raw , /secret diagnostics/ )
const j = JSON . parse ( raw ); assert . equal ( j . phase , unknown ? 'OUTCOME_UNKNOWN' : 'ACKNOWLEDGED' ); if ( ! unknown ) assert . equal ( j . requestId , 'req' )
} finally { temp . cleanup ()}
}
})
test ( 'stage release actor or prepared-payload mismatch cannot send a request' , async ()=>{
const f = linkedFixture (), command = prepareTransferStage ( f . plan , 'approve' ,{ linked : f . linked }); let calls = 0
const options = { command , release : release ( 'approve' ), actor : platform , journalDirectory : 'not-created' , transport : async ()=>{ calls ++ }}
await assert . rejects ( runPreparedTransferStage ({... options , release : release ( 'receipt' )}))
await assert . rejects ( runPreparedTransferStage ({... options , actor : {... platform , tenantId : CUSTOMER }}))
await assert . rejects ( runPreparedTransferStage ({... options , command : {... command , body : { status : 'REJECTED' }}}))
assert . equal ( calls , 0 )
})
test ( 'photo upload bytes are frozen and an acknowledged no-key upload cannot be repeated' , async ()=>{
const f = linkedFixture (), binary = Buffer . from ( 'synthetic offline transport fixture' )
const command = prepareTransferStage ( f . plan , 'photo' ,{ linked : f . linked , photo : { fileName : 'fixture.png' , contentType : 'image/png' , sizeBytes : binary . length , sha256 : crypto . createHash ( 'sha256' ). update ( binary ). digest ( 'hex' )}})
const actor = { kind : 'pda' , appCode : 'PLATFORM' , tenantId : '0' , membershipId : '2106727769572478980' , warehouseId : LA , roles : [ 'OVERSEAS_WAREHOUSE_PDA_OPERATOR' ], authorities : [ 'lastleg:pda:operate' ]}
const temp = temporaryJournal (); let calls = 0
try {
const options = { command , release : release ( 'photo' ), actor , binary , journalDirectory : temp . directory , transport : async ()=>{ calls ++ ; return { http : 200 , code : '200' , data : { fileId : '77' }}}}
await assert . rejects ( runPreparedTransferStage ({... options , binary : Buffer . from ( 'changed' )})); assert . equal ( calls , 0 )
await runPreparedTransferStage ( options ); await assert . rejects ( runPreparedTransferStage ({... options , replay : true })); assert . equal ( calls , 1 )
} finally { temp . cleanup ()}
})
test ( 'physical binding uses selected source and current versions without client customer/warehouse scope in PDA body' ,()=>{
2026-10-05 02:50:29 +08:00
const f = linkedFixture (), context = { linked : f . linked , task : f . task , source : { warehouseId : LA , positionId : 'selected-old' , palletId : 'source-pallet' , palletCode : 'SOURCE' , palletVersion : 3 , positionVersion : 4 }, target : { warehouseId : LA , palletCode : 'WORK' , palletVersion : 0 , destinationWarehouseCode : 'ABE4' }, observedCartonMarks : [ 'BOX-1' ]}
2026-10-05 00:37:18 +08:00
const c = prepareTransferStage ( f . plan , 'bind' , context )
assert . equal ( c . body . actualSource . positionId , 'selected-old' ); assert . equal ( c . body . actualSource . packages , 1 ); assert . equal ( c . body . target . expectedVersion , 0 )
assert . equal ( c . body . customerId , undefined ); assert . equal ( c . body . warehouseId , undefined )
assert . throws (()=> prepareTransferStage ( f . plan , 'bind' ,{... context , target : {... context . target , warehouseId : NY }}))
})
test ( 'one original carton stays conserved and existing HOLD and append-only facts remain untouched' ,()=>{
const unchanged = { positionId : 'protected' , availablePackages : 0 , holdPackages : 1 }
const ship = { id : 'ship' , businessType : 'SHIP' , businessOrderNo : TRANSFER , deltaPackages :- 1 , skuCode : 'NEW' }
const receipt = { id : 'receipt' , businessType : 'STOCK_IN' , businessOrderNo : TRANSFER , overseasWarehouseId : NY , deltaPackages : 1 , skuCode : 'NEW' }
const base = { baselineSourceTotal : 4 , baselineTargetTotal : 0 , expectedNewSku : 'NEW' , protectedBefore : unchanged , protectedAfter : unchanged , ledgerBefore : [{ id : 'old' , packages : 1 }], ledgerAfter : [ ship , receipt ,{ id : 'old' , packages : 1 }]}
assert . equal ( verifyTransferMilestone ( 'customer-confirm' ,{... base , sourceTotal : 4 , targetTotal : 0 }). verified , true )
assert . equal ( verifyTransferMilestone ( 'outbound' ,{... base , sourceTotal : 3 , targetTotal : 0 }). inTransitCartons , 1 )
assert . equal ( verifyTransferMilestone ( 'receipt' ,{... base , sourceTotal : 3 , targetTotal : 1 }). inTransitCartons , 0 )
assert . throws (()=> verifyTransferMilestone ( 'receipt' ,{... base , sourceTotal : 2 , targetTotal : 1 }))
assert . throws (()=> verifyTransferMilestone ( 'receipt' ,{... base , sourceTotal : 3 , targetTotal : 1 , protectedAfter : {... unchanged , holdPackages : 0 }}))
assert . throws (()=> verifyTransferMilestone ( 'receipt' ,{... base , sourceTotal : 3 , targetTotal : 1 , ledgerAfter : [{ id : 'old' , packages : 2 }]}))
assert . throws (()=> verifyTransferMilestone ( 'receipt' ,{... base , sourceTotal : 3 , targetTotal : 1 , ledgerAfter : [ ship ,{... receipt , skuCode : 'OLD' },{ id : 'old' , packages : 1 }]}))
})
2026-10-05 02:50:29 +08:00
test ( 'actual PDA detail shape requires unit facts before bind and allows unit without PALLET_BIND history' ,()=>{
const f = linkedFixture (), context = { linked : f . linked , task : f . task ,
source : { warehouseId : LA , positionId : 'selected-old' , palletId : 'source-pallet' , palletCode : 'SOURCE' , palletVersion : 1 , positionVersion : 4 },
target : { warehouseId : LA , palletCode : 'WORK' , palletVersion : 0 , destinationWarehouseCode : 'ABE4' }, observedCartonMarks : [ 'BOX-1' ]}
assert . ok ( f . plan . phases . findIndex ( x => x . stage === 'unit' ) < f . plan . phases . findIndex ( x => x . stage === 'bind' ))
assert . throws (()=> prepareTransferStage ( f . plan , 'bind' ,{... context , task : {... f . task , relabelledPackages : 0 , unitFacts : []}}), /COMPLETE_UNIT_FACTS/ )
for ( const facts of [[],[{ itemId : 'other' , result : 'RELABELLED' , quantity : 1 }],[{ itemId : 'item' , result : 'SKIPPED' , quantity : 1 }],[{ itemId : 'item' , result : 'RELABELLED' , quantity : 2 }]])
assert . throws (()=> prepareTransferStage ( f . plan , 'bind' ,{... context , task : {... f . task , unitFacts : facts }}), /OWN_RELABELLED_UNIT_FACT/ )
for ( const expectedPackages of [ undefined , null , 0 , NaN , 2 , '1' ])
assert . throws (()=> prepareTransferStage ( f . plan , 'bind' ,{... context , task : {... f . task , items : f . task . items . map ( i =>({... i , expectedPackages }))}}), /OWN_RELABELLED_UNIT_FACT/ )
for ( const quantity of [ undefined , null , 0 , NaN , - 1 , '1' ])
assert . throws (()=> prepareTransferStage ( f . plan , 'bind' ,{... context , task : {... f . task , unitFacts : [{ itemId : 'item' , result : 'RELABELLED' , quantity }]}}), /OWN_RELABELLED_UNIT_FACT/ )
assert . throws (()=> prepareTransferStage ( f . plan , 'bind' ,{... context , task : {... f . task , unitFacts : [{ itemId : 'item' , result : 'RELABELLED' , quantity :- 1 },{ itemId : 'item' , result : 'RELABELLED' , quantity : 2 }]}}), /OWN_RELABELLED_UNIT_FACT/ )
const actual = {... f . task , history : [], unitFacts : [{ factId : '2106799999999999999' , itemId : 'item' , oldLabel : 'BOX-1' , newLabel : 'FBA-BOX-1' , result : 'RELABELLED' , quantity : 1 , operatorName : 'SYNTHETIC' , occurredAt : '2026-10-05T00:00:00' }]}
assert . ok ( prepareTransferStage ( f . plan , 'bind' ,{... context , task : actual }))
assert . ok ( prepareTransferStage ( f . plan , 'unit' ,{ linked : f . linked , task : {... actual , relabelledPackages : 0 , unitFacts : []}, itemId : 'item' , observedOldLabel : 'BOX-1' , observedNewLabel : 'FBA-BOX-1' , observedSkus : [{ skuCode : 'OLD' , newSkuCode : 'NEW' , quantity : 1 }]}))
})
function originalBindRecoveryFixture ( directory ){
const command = { stage : 'bind' , runId : 'f33-original-20261005-r1' , transferNo : TRANSFER , customerId : CUSTOMER , actor : 'pda' , permission : 'lastleg:pda:operate' , replay : 'KEYED' , method : 'POST' , path : '/pda/v1/last-leg/pallet-operations/relabel-disassemble' , body : { relabelNo : 'RL-WH-20261005-174913' , idempotencyKey : 'F33-WT-430594-f33-original-20261005-r1-bind' , source : { palletCode : 'DP-261002-0018' , expectedVersion : 1 }, target : { palletCode : 'PLT-USLAX01-261005-G08C1U1NQMMA' , expectedVersion : 0 }, cartonMarks : [ 'CM-ADMIN-API-20261002042009973' ], actualSource : { positionId : '2105878074206765058' , expectedPositionVersion : 4 , packages : 1 }, reason : 'F33-WT-430594-f33-original-20261005-r1-bind' }, preparedHash : 'bb1ccb10ebaef5f37d8f16782ae6f8f2051d31061142533a61e8ab020c1e2a0d' }
const journal = { command , phase : 'ACKNOWLEDGED' , http : 200 , code : 'A0409' , success : false , businessVerified : false }
const rollback = { verified : true , unchanged : [ 'transfer' , 'positions' , 'ledger' , 'linked' , 'order' , 'task' ]}
const fresh = { runId : command . runId , transferNo : TRANSFER , relabelNo : command . body . relabelNo , originalKeyNotExecuted : true , unitFactsVerified : true , unitFactCount : 1 , relabelledPackages : 1 , stockAndLedgerUnchangedByUnit : true , sourcePalletCode : command . body . source . palletCode , targetPalletCode : command . body . target . palletCode , sourcePalletVersion : 1 , targetPalletVersion : 0 , sourcePositionId : command . body . actualSource . positionId , sourcePositionVersion : 4 }
const journalFile = path . join ( directory , command . runId + '-bind.json' ), rollbackFile = path . join ( directory , 'rollback.json' ), freshFile = path . join ( directory , 'fresh.json' )
const store = ()=>{ fs . writeFileSync ( journalFile , JSON . stringify ( journal )); fs . writeFileSync ( rollbackFile , JSON . stringify ( rollback )); fs . writeFileSync ( freshFile , JSON . stringify ( fresh ))}
const sha = p => crypto . createHash ( 'sha256' ). update ( fs . readFileSync ( p )). digest ( 'hex' )
store ()
const recovery = ()=>({ authorization : 'F33_BIND_A0409_AFTER_UNIT' , originalJournalSha256 : sha ( journalFile ), rollbackProofFile : 'rollback.json' , rollbackProofSha256 : sha ( rollbackFile ), freshProofFile : 'fresh.json' , freshProofSha256 : sha ( freshFile )})
const actor = { kind : 'pda' , appCode : 'PLATFORM' , tenantId : '0' , membershipId : '2106727769572478980' , warehouseId : LA , roles : [ 'OVERSEAS_WAREHOUSE_PDA_OPERATOR' ], authorities : [ 'lastleg:pda:operate' ]}
return { command , journal , rollback , fresh , journalFile , store , recovery , options : { command , release : {... release ( 'bind' ), runId : command . runId }, actor , journalDirectory : directory }}
}
test ( 'released exact A0409 binding recovers once into durable side journal and preserves original failure bytes' , async ()=>{
const temp = temporaryJournal (); let calls = 0
try {
const f = originalBindRecoveryFixture ( temp . directory ), original = fs . readFileSync ( f . journalFile )
const side = path . join ( temp . directory , f . command . runId + '-bind-recovery.json' )
const transport = async ()=>{ calls ++ ; const j = JSON . parse ( fs . readFileSync ( side )); assert . equal ( calls === 1 ? j . phase : j . replay . phase , 'INTENT' ); return { http : 200 , code : '200' , data : { replayed : calls > 1 }, message : '完成' }}
const options = {... f . options , recovery : f . recovery (), transport }
await assert . rejects ( runPreparedTransferStage ({... options , recovery : undefined })); assert . equal ( calls , 0 )
await runPreparedTransferStage ( options ); assert . deepEqual ( fs . readFileSync ( f . journalFile ), original )
await assert . rejects ( runPreparedTransferStage ( options )); assert . equal ( calls , 1 )
await runPreparedTransferStage ({... options , replay : true }); assert . deepEqual ( fs . readFileSync ( f . journalFile ), original )
await assert . rejects ( runPreparedTransferStage ({... options , replay : true })); assert . equal ( calls , 2 )
} finally { temp . cleanup ()}
})
test ( 'recovery never releases unknown, other rejects, changed payload, incomplete proof or changed live versions' , async ()=>{
for ( const patch of [ f => f . journal . phase = 'OUTCOME_UNKNOWN' , f => f . journal . code = 'A0500' , f => f . journal . http = 409 ,
f => f . journal . success = true , f => f . rollback . unchanged = [ 'transfer' ], f => f . fresh . sourcePositionVersion = 5 ,
f => f . fresh . targetPalletVersion = 1 , f => f . fresh . unitFactCount = 0 , f => f . fresh . originalKeyNotExecuted = false ]){
const temp = temporaryJournal (); let calls = 0
try { const f = originalBindRecoveryFixture ( temp . directory ); patch ( f ); f . store (); await assert . rejects ( runPreparedTransferStage ({... f . options , recovery : f . recovery (), transport : async ()=>{ calls ++ }})); assert . equal ( calls , 0 )} finally { temp . cleanup ()}
}
const temp = temporaryJournal (); let calls = 0
try { const f = originalBindRecoveryFixture ( temp . directory ), options = {... f . options , transport : async ()=>{ calls ++ }}
await assert . rejects ( runPreparedTransferStage ({... options , recovery : {... f . recovery (), authorization : 'OTHER' }}))
await assert . rejects ( runPreparedTransferStage ({... options , recovery : {... f . recovery (), originalJournalSha256 : '0' . repeat ( 64 )}}))
await assert . rejects ( runPreparedTransferStage ({... options , recovery : f . recovery (), command : {... f . command , body : {... f . command . body , reason : 'NEW PAYLOAD' }}}))
assert . equal ( calls , 0 )
} finally { temp . cleanup ()}
})
test ( 'business rejection message is retained with tokens credentials and endpoint URLs redacted' , async ()=>{
assert . equal ( redactTransferMessage ( '请先完成本箱全部换标作业,再进行组托' ), '请先完成本箱全部换标作业,再进行组托' )
const temp = temporaryJournal ()
try { const f = linkedFixture (), command = prepareTransferStage ( f . plan , 'approve' ,{ linked : f . linked }); await assert . rejects ( runPreparedTransferStage ({ command , release : release ( 'approve' ), actor : platform , journalDirectory : temp . directory , transport : async ()=>({ http : 200 , code : 'A0409' , message : '业务拒绝 password=secret Bearer token123 https://private.example/path' })}));
const raw = fs . readFileSync ( path . join ( temp . directory , 'offline-contract-approve.json' ), 'utf8' ); assert . match ( raw , /业务拒绝/ ); assert . doesNotMatch ( raw , /secret|token123|private\.example/ )
} finally { temp . cleanup ()}
})
test ( 'combined /units SKU-only actual response needs carton scan before one final fact and physical bind' ,()=>{
const f = linkedFixture (); const task = {... f . task , version : 1 , relabelledPackages : 0 , unitFacts : [], history : [{ action : 'MIXED_SKU' , detail : JSON . stringify ({ itemId : 'item' , round : 'INITIAL' , stage : 'SKU' })}],
items : f . task . items . map ( i =>({... i , relabelledPackages : 0 , cartonProcessedPackages : 0 , skuProcessedPackages : 1 }))}
const context = { linked : f . linked , task , itemId : 'item' , observedOldLabel : 'BOX-1' , observedNewLabel : 'FBA-BOX-1' }
const command = prepareTransferStage ( f . plan , 'unit-carton' , context )
assert . match ( command . path , /\/cartons\/scan$/ ); assert . equal ( command . body . expectedVersion , 1 ); assert . equal ( command . body . cartonMark , 'BOX-1' )
assert . ok ( f . plan . phases . findIndex ( p => p . stage === 'unit' ) < f . plan . phases . findIndex ( p => p . stage === 'unit-carton' ))
assert . ok ( f . plan . phases . findIndex ( p => p . stage === 'unit-carton' ) < f . plan . phases . findIndex ( p => p . stage === 'bind' ))
for ( const patch of [{ skuProcessedPackages : 0 },{ cartonProcessedPackages : 1 },{ expectedPackages : undefined }])
assert . throws (()=> prepareTransferStage ( f . plan , 'unit-carton' ,{... context , task : {... task , items : task . items . map ( i =>({... i ,... patch }))}}), /OWN_SKU_ONLY_PARTIAL/ )
assert . throws (()=> prepareTransferStage ( f . plan , 'unit-carton' ,{... context , task : {... task , relabelledPackages : 1 }}))
assert . throws (()=> prepareTransferStage ( f . plan , 'unit-carton' ,{... context , observedNewLabel : 'OTHER' }))
})