2026-10-03 14:52:04 +08:00
import assert from 'node:assert/strict'
import test from 'node:test'
import { run } from './fleet-company-cost-acceptance.mjs'
import { requireReady , READY_COMMIT } from '../fleet-company-cost-test-env.mjs'
const copy = value => value == null ? value : structuredClone ( value )
const PNG = Buffer . from ( 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aH1kAAAAASUVORK5CYII=' , 'base64' )
function fixture ( fault ) {
const marker = 'CONTROLLED-COMPANY-COST' , calls = [], vehicles = new Map (), records = new Map (), costs = new Map (), submissions = new Map (), commands = new Map (), files = new Map ()
const response = ( data , code = '200' , http = 200 ) => ({ http , body : { code , data : copy ( data ) }, requestId : 'controlled-request' , traceId : 'controlled-trace' })
let sequence = 0
const history = row => ({ recordVersion : row . cost . recordVersion , action : row . action , snapshot : copy ( row . cost ) })
function save ( row , action ) { row . action = action ; row . history . unshift ( history ( row )) }
function current ( row ) { const { cost } = row ; return copy ( cost ) }
let supplier
const context = { marker , token : 'offline-test-only' , createdResources : {},
assert ( _module , label , _response , condition ) { assert . ok ( condition , label ) },
apiSuccess ( _module , label , result ) { assert . equal ( result ? . http , 200 , label ); assert . equal ( result ? . body ? . code , '200' , label ); return result . body . data },
async request ( method , raw , body , _token , headers ) {
calls . push ({ method , raw , body : copy ( body ), headers : copy ( headers ) }); const url = new URL ( raw , 'https://fixture.invalid' ), path = url . pathname
if ( method === 'POST' && path === '/api/platform/v1/suppliers' ) { supplier = { id : '8' , ... copy ( body ) }; return response ( '8' ) }
if ( method === 'GET' && path === '/api/platform/v1/suppliers/8' ) return response ( supplier )
if ( method === 'GET' && path . includes ( '/master-data/exchange-rates/' )) return response ({ month : path . split ( '/' ). at ( - 1 ), status : fault === 'inactive exchange' ? 'INACTIVE' : 'ACTIVE' , usdToCnyAverage : '7.123456' , recordVersion : 0 })
if ( path . endsWith ( '/fee-pool' )) return response ( fault === 'customer pollution' && costs . size ? [{ poolItemId : 'LEAK' , customerId : '9' , amount : 27.31 , feeItemName : marker }] : [])
if ( path . endsWith ( '/cost-entries' )) return response ([])
if ( path . endsWith ( '/customer-accounts/9/summary' )) return response ({ customerId : '9' , currency : 'CNY' , totalReceivable : 100 , receivedAmount : 30 , outstandingReceivable : 70 ,
pendingBilling : 0 , totalCost : 0 , paidCost : 0 , outstandingPayable : 0 , asOf : new Date (). toISOString () })
if ( path === '/api/platform/v1/last-leg/master-data/vehicles' && method === 'POST' ) {
const row = { id : '71' , ... copy ( body ), recordVersion : 0 }; vehicles . set ( row . id , row ); return response ( row )
}
if ( path . startsWith ( '/api/platform/v1/last-leg/master-data/vehicles/' )) {
const row = vehicles . get ( path . split ( '/vehicles/' )[ 1 ]. split ( '/' )[ 0 ]); assert . ok ( row )
if ( method === 'GET' ) return response ( row )
assert . equal ( method , 'PATCH' ); assert . equal ( body . status , 'INACTIVE' )
if ( fault === 'cleanup failure' ) return response ( null , 'S0503' , 503 )
row . status = 'INACTIVE' ; row . recordVersion ++ ; return response ( row )
}
const care = path . match ( /^\/api\/platform\/v1\/last-leg\/fleet\/vehicles\/71\/records(?:\/(.*))?$/ )
if ( care ) {
const suffix = care [ 1 ]
if ( ! suffix && method === 'POST' ) {
const recordNo = `VR- ${ records . size + 1 } ` , row = { recordNo , vehicleId : '71' , vehiclePlate : vehicles . get ( '71' ). plateNumber , recordVersion : 0 , details : copy ( body . details ) }
records . set ( recordNo , row ); return response ( row )
}
if ( suffix === 'finance-status' ) {
return response ( body . recordNos . map ( recordNo => {
const record = records . get ( recordNo ), row = costs . get ( recordNo ); assert . ok ( record && row )
if ( fault === 'delivery exhausted' ) return { recordNo , status : 'FINANCE_ATTENTION' , sourceVersion : row . cost . source . sourceVersion }
if ( fault === 'never delivered' ) return { recordNo , status : 'PENDING_FINANCE' , sourceVersion : row . cost . source . sourceVersion }
const cost = current ( row )
if ( fault === 'wrong source vehicle' ) cost . source . vehicleId = 'OTHER'
if ( fault === 'wrong source version' ) cost . source . sourceVersion = 999
if ( fault === 'wrong conversion' ) cost . source . amount = 999
if ( fault === 'premature paid' ) cost . status = 'PAID'
return { recordNo , status : cost . status , sourceVersion : cost . source . sourceVersion , submittedRecordVersion : record . recordVersion , finance : cost }
}))
}
const [ recordNo , action ] = suffix . split ( '/' ), record = records . get ( recordNo ); assert . ok ( record )
if ( method === 'GET' ) return response ( record )
if ( method === 'PUT' ) {
if ( fault === 'paid source mutable' ) { record . details = copy ( body . details ); record . recordVersion ++ ; return response ( record ) }
return response ( null , 'A0409' )
}
assert . equal ( action , 'finance' )
const key = ` ${ recordNo } : ${ body . idempotencyKey } `
if ( submissions . has ( key )) return response ({ ... submissions . get ( key ), replayed : true })
let row = costs . get ( recordNo ), sourceVersion = row ? row . cost . source . sourceVersion + 1 : 1
if ( row && row . cost . status !== 'VOIDED' ) return response ( null , 'A0409' )
const incident = record . details . incident , rate = incident . currency === 'CNY' ? 1 : 7.123456
const source = { sourceType : record . details . recordType , sourceNo : recordNo , sourceVersion , vehicleId : '71' , vehiclePlate : record . vehiclePlate ,
supplierId : body . supplierId , feeName : incident . item , businessDate : body . businessDate , originalCurrency : incident . currency ,
originalAmount : incident . reportedCost , exchangeRate : rate , exchangeRateMonth : body . businessDate . slice ( 0 , 7 ),
amount : Math . round ( incident . reportedCost * rate * 100 ) / 100 , remark : record . details . remark }
const cost = { costNo : row ? . cost . costNo ?? `VC- ${ ++ sequence } ` , subjectCode : 'PLATFORM_DEFAULT' , currency : 'CNY' , status : 'PENDING' , paidAmount : 0 , outstandingAmount : null ,
recordVersion : row ? row . cost . recordVersion + 1 : 0 , source }
if ( ! row ) row = { cost , payments : [], history : [] }
else row . cost = cost
save ( row , 'RECEIVE' ); costs . set ( recordNo , row )
const result = { recordNo , sourceVersion , submittedRecordVersion : record . recordVersion , replayed : false , status : 'PENDING_FINANCE' }
submissions . set ( key , copy ( result )); return response ( result )
}
const match = path . match ( /^\/api\/platform\/finance\/v1\/vehicle-costs\/([^/]+)(?:\/(.*))?$/ )
assert . ok ( match , `Unexpected ${ method } ${ raw } ` )
const [, no , action ] = match , row = [... costs . values ()]. find ( r => r . cost . costNo === no ); assert . ok ( row )
if ( method === 'GET' ) {
if ( ! action ) return response ( current ( row ))
const list = action === 'payments' ? row . payments : row . history
return response ({ records : list , page : 1 , size : 100 , total : list . length , pages : list . length ? 1 : 0 })
}
const key = ` ${ no } : ${ action } : ${ headers ? .[ 'Idempotency-Key' ] } `
assert . ok ( headers ? .[ 'Idempotency-Key' ], 'financial commands require their stable header key' )
if ( commands . has ( key ) && ! ( fault === 'duplicate payment replay' && action === 'payments' )) return response ( current ( row ))
if ( Number ( body . expectedVersion ) !== row . cost . recordVersion && ! ( fault === 'duplicate payment replay' && action === 'payments' )) return response ( null , 'FIN_409' )
if ( action === 'approve' ) { row . cost . status = 'APPROVED' ; row . cost . outstandingAmount = row . cost . source . amount ; row . cost . recordVersion ++ ; save ( row , 'APPROVE' ) }
else if ( action === 'void' ) {
if ( row . cost . paidAmount > 0 && fault !== 'paid void allowed' ) return response ( null , 'FIN_409' )
row . cost . status = 'VOIDED' ; row . cost . outstandingAmount = null ; row . cost . recordVersion ++ ; save ( row , 'VOID' )
} else if ( action === 'payments' ) {
if ( body . amount > row . cost . outstandingAmount && fault !== 'overpayment allowed' ) return response ( null , 'FIN_409' )
row . cost . paidAmount = Math . round (( row . cost . paidAmount + body . amount ) * 100 ) / 100
row . cost . outstandingAmount = Math . round (( row . cost . source . amount - row . cost . paidAmount ) * 100 ) / 100
row . cost . status = row . cost . outstandingAmount === 0 ? 'PAID' : 'PARTIALLY_PAID' ; row . cost . recordVersion ++
row . payments . push ({ paymentNo : `VP- ${ ++ sequence } ` , currency : 'CNY' , amount : body . amount , voucherFileIds : copy ( body . voucherFileIds ) }); save ( row , 'PAY' )
if ( fault === 'partial money drift' ) row . cost . outstandingAmount += 0.01
} else throw new Error ( `Unexpected action ${ action } ` )
commands . set ( key , true ); return response ( current ( row ))
},
async requestMultipart ( method , raw , file ) {
calls . push ({ method , raw , multipart : true }); assert . ok ( Buffer . from ( file . content ). equals ( PNG ))
if ( fault === 'file outage' ) return response ( null , 'FIN_503' , 503 )
const fileId = id ( files . size + 1 ); files . set ( fileId , raw )
return response ({ fileId , ownerScope : 'PLATFORM' , tenantId : '0' , businessType : 'FINANCE_VEHICLE_VOUCHER' , contentType : 'image/png' , sizeBytes : PNG . length })
},
async requestBinary ( method , raw ) { calls . push ({ method , raw , binary : true }); return { http : 200 , contentType : 'image/png' , bytes : fault === 'wrong file bytes' ? Buffer . from ( 'wrong' ) : PNG } },
}
return { context , calls , vehicles , records , costs }
}
const id = value => String ( value )
const options = { pollAttempts : 2 , pollDelayMs : 0 }
test ( 'independent runner requires explicit service readiness and only the specified TEST profile' , () => {
const env = 'C:/Users/BY-OY/.codex/env/chongchong-global/test-acceptance.env'
assert . throws (() => requireReady ([], [ `--env-file= ${ env } ` ]), /就绪/ )
assert . throws (() => requireReady ([ `--ready-commit= ${ READY_COMMIT } ` ], [ `--env-file= ${ env . replace ( 'test-acceptance' , 'dev-acceptance' ) } ` ]), /授权目录/ )
assert . ok ( requireReady ([ `--ready-commit= ${ READY_COMMIT } ` ], [ `--env-file= ${ env } ` ]). endsWith ( 'test-acceptance.env' ))
})
2026-10-03 16:38:37 +08:00
test ( 'readiness gate accepts only the full production anchor, not old anchors, shorthand or another commit' , () => {
const profile = [ '--env-file=C:/Users/BY-OY/.codex/env/chongchong-global/test-acceptance.env' ]
assert . equal ( READY_COMMIT , '8700fc34238bc33339351c73c15f3af8de8ce517' )
for ( const commit of [ 'a6fd0ba3' , 'cb6c54ff' , '8700fc34' , 'd05ff1cd' , ` ${ READY_COMMIT } 0` ]) {
assert . throws (() => requireReady ([ `--ready-commit= ${ commit } ` ], profile ), /就绪/ )
}
assert . ok ( requireReady ([ `--ready-commit= ${ READY_COMMIT } ` ], profile ). endsWith ( 'test-acceptance.env' ))
})
2026-10-03 14:52:04 +08:00
test ( 'company cost verifier exercises CNY/USD, void/rebuild, payment replay and customer isolation without direct transport' , async () => {
const { context , calls , vehicles , records , costs } = fixture ()
await run ( context , options )
const proof = context . createdResources . fleetCompanyCostAcceptance
assert . equal ( proof . status , 'VERIFIED' ); assert . equal ( proof . cleanup , 'INACTIVE' )
assert . equal ( proof . cases . length , 2 ); assert . equal ( records . size , 2 )
assert . ok ([... costs . values ()]. every ( row => row . cost . status === 'PAID' && row . payments . length === 2 ))
assert . ok ([... vehicles . values ()]. every ( row => row . status === 'INACTIVE' ))
assert . ok ( calls . every ( call => call . raw . startsWith ( '/api/platform/' )))
assert . equal ( calls . some ( call => / cost - entries | customer - accounts | customerId = /.test(call.raw)), false, 'must not borrow another task customer for evidence')
assert . equal ( calls . some ( call => call . method === 'DELETE' ), false )
await assert . rejects ( run ( context , options ), /本轮已存在/ )
})
test ( 'missing independent marker blocks before any write' , async () => {
const { context , calls } = fixture (); context . marker = ''
await assert . rejects ( run ( context , options ), /独立marker/ ); assert . equal ( calls . length , 0 )
})
for ( const fault of [ 'inactive exchange' , 'delivery exhausted' , 'never delivered' , 'wrong source vehicle' , 'wrong source version' , 'wrong conversion' , 'premature paid' ,
'duplicate payment replay' , 'overpayment allowed' , 'partial money drift' , 'paid void allowed' , 'paid source mutable' , 'customer pollution' , 'file outage' , 'wrong file bytes' , 'cleanup failure' ]) {
test ( `company cost verifier rejects ${ fault } and preserves failure evidence` , async () => {
const { context , vehicles } = fixture ( fault )
await assert . rejects ( run ( context , options ))
const proof = context . createdResources . fleetCompanyCostAcceptance
assert . equal ( proof . status , 'FAILED' )
assert . ok ( proof . error || proof . cleanupError )
if ( vehicles . size && fault !== 'cleanup failure' ) assert . ok ([... vehicles . values ()]. every ( row => row . status === 'INACTIVE' ))
if ( fault === 'cleanup failure' ) assert . equal ( proof . cleanup , 'FAILED' )
})
}