Files
baiyue-firstleg/scripts/admin-test-env-modules/phase5-root-fulfillment-contract.test.mjs
T
2026-09-30 15:16:39 +08:00

203 lines
15 KiB
JavaScript

import assert from 'node:assert/strict'
import test from 'node:test'
import { readFileSync } from 'node:fs'
import { fulfillmentHistorySnapshot, validTwoFragmentTree, validSignatureGate,
completionCounts, exactCompletionOutboxProof, resolveF40MerchantCredentials,
f40TransferBody, f40LocalDateTime, validFragmentCabinetIdentity, run } from './phase5-root-fulfillment.mjs'
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},
})
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}})
await runReceiving(context,'offline-pda',null,null,{containerNo:'EXPECTED',containerBookingId:'100'},false)
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'})
})
test('complete orchestrator calls actual source chain and blocks missing Outbox evidence; no fake callback, SQL or cancellation substitute',() => {
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',
'convertReceivingContainers','prepareTerminalDrayage','runReceiving','pickAll','saveReceiptAndComplete'])
assert.match(source,new RegExp(`await ${name}\\(`))
assert.match(source,/rootOrderId, sourceOrderIds:\[rootOrderId,childOrderId\]/)
assert.match(source,/HTTP_VERIFIED_OUTBOX_PENDING/)
assert.match(source,/finally \{ proof.currentStage = 'PDA_IDENTITY_CLEANUP'; await disablePicker/)
assert.doesNotMatch(source,/['"`]\/internal\/|UPDATE\s+ord_|INSERT\s+INTO|\/cancel|\/complete-delivery/)
})
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)
})