test(fba): preserve verified fleet and fulfillment acceptance workflows
This commit is contained in:
@@ -5,7 +5,7 @@ import { fulfillmentHistorySnapshot, validTwoFragmentTree, validSignatureGate,
|
||||
completionCounts, exactCompletionOutboxProof, resolveF40MerchantCredentials,
|
||||
f40TransferBody, f40LocalDateTime, validFragmentCabinetIdentity, validUnloadedRemainder,
|
||||
validRemainderCancellationGate, exactCancelledRemainderOutboxProof, cancelUnloadedRemainder,
|
||||
verifyRootProjections, validFreshReceiptSave, preserveReceivingEvidence, run } from './phase5-root-fulfillment.mjs'
|
||||
verifyRootProjections, verifyRemainderTaxIdentity, validFreshReceiptSave, preserveReceivingEvidence, run } from './phase5-root-fulfillment.mjs'
|
||||
import { loadOneFragment } from './phase3-order-splitting.mjs'
|
||||
import { verifyPalletLabels } from './phase3-loading-finalize.mjs'
|
||||
import { awaitProducerConsumption, convertReceivingContainers, runReceiving,
|
||||
@@ -32,6 +32,50 @@ const fixture = () => ({steps:[],token:'offline',marker:'offline-only',createdRe
|
||||
addCoverageGap(){},apiSuccess(_module,_label,response){return response?.body?.data},
|
||||
})
|
||||
|
||||
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/)
|
||||
})
|
||||
|
||||
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')}}
|
||||
@@ -232,7 +276,7 @@ test('exported consumer polling and conversion fail closed when real producer co
|
||||
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}})
|
||||
await runReceiving(context,'offline-pda',null,null,{containerNo:'EXPECTED',containerBookingId:'100'},false)
|
||||
await runReceiving(context,'offline-pda',null,null,{containerNo:'EXPECTED',containerBookingId:'100'},false,{attempts:1})
|
||||
assert.equal(context.steps.some(step => step.passed === false),true)
|
||||
})
|
||||
test('exported receiving warehouse resolver continues to choose only configured active official warehouse',async() => {
|
||||
|
||||
Reference in New Issue
Block a user