41 lines
3.9 KiB
JavaScript
41 lines
3.9 KiB
JavaScript
import test from 'node:test'
|
|||
|
|
import assert from 'node:assert/strict'
|
||
|
|
import {assertSameRouteCost,assertSameRouteBasis,runSameRouteCost,verifySameRouteCost} from './fleet-same-route-cost-test-env.mjs'
|
||
|
|
function sample(){
|
||
|
|
const shares=[{businessNo:'DS-A',dispatchNo:'DS-A',sourceType:'OWN',customerId:'101',palletSpaces:1,warehousePalletIds:['1']},{businessNo:'DS-B',dispatchNo:'DS-B',sourceType:'OWN',customerId:'102',palletSpaces:1,warehousePalletIds:['2']},{businessNo:'BK-C',dispatchNo:'DS-C',sourceType:'EXTERNAL',customerId:'101',palletSpaces:1,warehousePalletIds:['3']}]
|
||
|
|
const departure={action:'DEPART',recordVersion:'7',snapshot:{trip:{stops:[{name:'Origin'},{destinationKey:'FBA:A'},{destinationKey:'FBA:B'}]},confirmedLoad:{manifestHash:'real-hash',pallets:shares.map(x=>({warehousePalletId:x.warehousePalletIds[0],palletSpaces:1,deliveryIndex:1})),cargo:shares.map(x=>({warehousePalletId:x.warehousePalletIds[0],dispatchNo:x.dispatchNo,customerId:x.customerId,packages:1,destinationKey:'FBA:A'}))},externalBookings:[{bookingNo:'BK-C',dispatchNo:'DS-C',customerId:'101',status:'BOUND',receipt:{source:{receivedPackages:1,pallets:[{warehousePalletId:'3',packages:1}]}}}]}}
|
||
|
|
// Three equal independent sources: the lexical first business number receives the residual cent.
|
||
|
|
const summary={departureVersion:'7',manifestHash:'real-hash',allocationMethod:'SAME_ROUTE_PALLET_SPACES',totals:[{currency:'USD',directCost:'1.00',ownCost:'0.66',externalCost:'0.34',allocations:shares.map(x=>({businessNo:x.businessNo,dispatchNo:x.dispatchNo,sourceType:x.sourceType,palletSpaces:1,amount:x.sourceType==='OWN'?'0.33':'0.34'}))}]}
|
||
|
|
return{shares,departure,summary}
|
||
|
|
}
|
||
|
|
test('offline entry does not call remote services and missing runtime scope is rejected',async()=>{
|
||
|
|
assert.equal((await runSameRouteCost({execute:false},{env:{}})).deploy,false)
|
||
|
|
assert.equal((await verifySameRouteCost()).businessSqlWrites,false)
|
||
|
|
await assert.rejects(verifySameRouteCost({},null,{execute:true}),/FIXTURE/)
|
||
|
|
})
|
||
|
|
test('exact three-source penny conservation follows real business-number tie break',()=>{
|
||
|
|
const s=sample();assert.equal(assertSameRouteBasis(s.departure,s.shares).pallets.length,3)
|
||
|
|
assert.deepEqual(assertSameRouteCost(s.summary,s.departure,s.shares).map(x=>[x.businessNo,x.cents]),[['BK-C','34'],['DS-A','33'],['DS-B','33']])
|
||
|
|
})
|
||
|
|
for(const fault of ['wrong action','missing pallet','overlapping source','different destination','wrong customer','wrong dispatch','wrong receipt','unbound booking','uncovered external','stale version','stale hash','invented method','mixed currency','lost penny','wrong source type','wrong aggregate','wrong residual winner'])test(`rejects invalid allocation evidence: ${fault}`,()=>{
|
||
|
|
const s=sample(),l=s.departure.snapshot.confirmedLoad,t=s.summary.totals[0],b=s.departure.snapshot.externalBookings[0]
|
||
|
|
if(fault==='wrong action')s.departure.action='PLAN'
|
||
|
|
if(fault==='missing pallet')l.pallets.pop()
|
||
|
|
if(fault==='overlapping source')s.shares[1].warehousePalletIds=['1']
|
||
|
|
if(fault==='different destination')l.pallets[2].deliveryIndex=2
|
||
|
|
if(fault==='wrong customer')l.cargo[0].customerId='FOREIGN'
|
||
|
|
if(fault==='wrong dispatch')l.cargo[0].dispatchNo='DS-FOREIGN'
|
||
|
|
if(fault==='wrong receipt')b.receipt.source.pallets[0].packages=2
|
||
|
|
if(fault==='unbound booking')b.status='CONFIRMED'
|
||
|
|
if(fault==='uncovered external')s.departure.snapshot.externalBookings.push({...b,bookingNo:'BK-OTHER'})
|
||
|
|
if(fault==='stale version')s.summary.departureVersion='8'
|
||
|
|
if(fault==='stale hash')s.summary.manifestHash='new-hash'
|
||
|
|
if(fault==='invented method')s.summary.allocationMethod='GUESS'
|
||
|
|
if(fault==='mixed currency')t.currency='CNY'
|
||
|
|
if(fault==='lost penny')t.allocations[0].amount='0.34'
|
||
|
|
if(fault==='wrong source type')t.allocations[2].sourceType='OWN'
|
||
|
|
if(fault==='wrong aggregate'){t.ownCost='0.67';t.externalCost='0.33'}
|
||
|
|
if(fault==='wrong residual winner'){t.allocations[0].amount='0.34';t.allocations[2].amount='0.33';t.ownCost='0.67';t.externalCost='0.33'}
|
||
|
|
assert.throws(()=>assertSameRouteCost(s.summary,s.departure,s.shares))
|
||
|
|
})
|