import test from 'node:test' import assert from 'node:assert/strict' import { readFile } from 'node:fs/promises' import vm from 'node:vm' import { createHash } from 'node:crypto' import { inflateRawSync, deflateRawSync } from 'node:zlib' const source = await readFile(new URL('./client-test-env-acceptance.mjs', import.meta.url), 'utf8') test('client registration distinguishes incomplete-registration replay from credential conflicts', () => { assert.match(source, /same credentials replay the incomplete registration/) assert.match(source, /\['accountId', 'tenantId', 'membershipId'\]/) assert.match(source, /String\(json\.data\[field\]\), String\(registration\.json\.data\[field\]\)/) assert.match(source, /duplicate username with different credentials is rejected/) assert.match(source, /body: \{ \.\.\.registrationBody, password: `Different/) }) const helperSource = source.slice(source.indexOf('// BEGIN ORDER ACCEPTANCE HELPERS'), source.indexOf('// END ORDER ACCEPTANCE HELPERS')) const workflowSource = source.slice(source.indexOf('async function ownedOrderSnapshot('), source.indexOf('async function apiStep(')) function runtime(extra = {}) { const context = vm.createContext({ Buffer, createHash, inflateRawSync, deflateRawSync, structuredClone, Blob, FormData, assertEqual: (actual, expected, label) => assert.equal(actual, expected, label), assertTrue: (value, label) => assert.ok(value, label), assertPresent: (value, label) => assert.ok(value !== null && value !== undefined && value !== '', label), requireSuccess: json => assert.equal(String(json?.code), '200'), ...extra }) vm.runInContext(`${helperSource}\n${workflowSource}`, context) return context } const plain = value => JSON.parse(JSON.stringify(value)) function priceBookSource(r) { const channels=[{channelCode:'MATSON_CLX_TRUCK',sourceSheetName:'美森正班海卡'}, {channelCode:'HEDE_TRUCK',sourceSheetName:'合德海卡'}] const rates=channels.map(channel=>({channelCode:channel.channelCode,originWarehouseCode:'YIWU',originWarehouseId:'2', destinationType:'FBA',destinationCode:'ONT8',unitPrice:10})) const entries=new Map([ ['xl/workbook.xml',''], ['xl/_rels/workbook.xml.rels',''], ['xl/worksheets/sheet1.xml',''], ['xl/worksheets/sheet2.xml',''], ['xl/media/image1.png',Buffer.from([0x89,0x50,0x4e,0x47,0xff,0x00,0x80])], ]) const bytes=r.orderZipWrite(entries,true) const version={id:'100',customerId:'0',status:'ACTIVE',sourceSha256:createHash('sha256').update(bytes).digest('hex')} return {bytes,entries,reference:{version,channels,rates}} } test('private B removes target sheet only, preserves binary source parts and uses published mapping IDs',()=>{ const r=runtime(),source=priceBookSource(r) const b=r.channelGateWorkbook(source.bytes,source.reference,'MATSON_CLX_TRUCK'),entries=r.orderZipRead(b.bytes) assert.deepEqual(plain(b.removedCodes),['MATSON_CLX_TRUCK']) assert.doesNotMatch(entries.get('xl/workbook.xml'),/美森正班海卡/) assert.match(entries.get('xl/workbook.xml'),/合德海卡/) for(const [name,original] of source.entries)if(name!=='xl/workbook.xml')assert.deepEqual(entries.get(name),original) assert.deepEqual(plain(r.channelGateMappings({rates:[source.reference.rates[1]]},source.reference)),{ originMappings:[{originWarehouseCode:'YIWU',warehouseId:'2'}],overseasMappings:[], }) assert.throws(()=>r.channelGateWorkbook(source.bytes,{...source.reference,channels:[source.reference.channels[0]]},'MATSON_CLX_TRUCK'),/retain another/) assert.throws(()=>r.channelGateMappings({rates:[source.reference.rates[1]]},{rates:[{...source.reference.rates[1],originWarehouseId:null}]}),/unique published/) assert.throws(()=>r.channelGateMappings({rates:[source.reference.rates[1]]},{rates:[source.reference.rates[1],{...source.reference.rates[1],originWarehouseId:'9'}]}),/unique published/) }) test('shared parcel source sheet removes all its channel codes and cannot leave an empty price book',()=>{ const r=runtime(),source=priceBookSource(r) source.reference.channels.push({channelCode:'SAME_SHEET_SECOND_CODE',sourceSheetName:'美森正班海卡'}) assert.deepEqual(plain(r.channelGateWorkbook(source.bytes,source.reference,'MATSON_CLX_TRUCK').removedCodes),['MATSON_CLX_TRUCK','SAME_SHEET_SECOND_CODE']) }) function channelGateHarness(fault='') { const r=runtime(),source=priceBookSource(r),calls=[],books=new Map(),publicVersions=[structuredClone(source.reference.version)] const report={resources:{tenantId:'20',orderIds:[]},steps:[{module:'registration',name:'enterprise self-registration',passed:true,evidence:{tenantId:'20'}}], orderSubmissionGates:{balance:{restoration:'RESTORED_WITH_AUDIT'},remaining:['Channel-offline requires fixture','Other pending scope']}} const order={order:{id:'42',tenantId:'20',orderNo:'FL42',status:'DRAFT',version:7,channelCode:'MATSON_CLX_TRUCK'}, cargoes:[{skuNo:'SKU'}],parties:[],internalNotes:[],statusHistory:[]} let nextId=201,nextKey=0,task=null if(fault==='unowned-customer')report.steps[0].evidence.tenantId='21' const base='/api/platform/v1/fba-pricing/carrier-rates/price-books' Object.assign(r,{report,marker:'channel-fixture',merchantToken:'owner',platformToken:'platform',newIdempotencyKey:()=>`key-${++nextKey}`, orderAcceptanceFixture:{masterData:{receiving:{id:'2'},channel:{priceBookVersionId:'100'}},payload:{channelCode:'MATSON_CLX_TRUCK',cargoes:[{skuNo:'SKU'}]}}, apiStep:async(_module,name,request,validate)=>{ calls.push({name,path:request.path,method:request.method,body:request.body,token:request.token,headers:request.headers}) const url=new URL(request.path,'https://offline.invalid') let data=null,bytes=null,code='200',message='success' if(url.pathname.endsWith('/tenant/profile'))data={id:'20',status:'ACTIVE'} else if(url.pathname===base && request.method!=='POST')data=url.searchParams.get('customerId')==='0'?structuredClone(publicVersions):[...books.values()].map(book=>structuredClone(book.version)) else if(request.path===`${base}/100`)data=structuredClone(source.reference) else if(request.path===`${base}/100/source`)bytes=source.bytes else if(url.pathname===base && request.method==='POST') { assert.equal(url.searchParams.get('customerId'),'20') assert.equal(request.token,'platform') const file=request.body.get('file'),raw=Buffer.from(await file.arrayBuffer()),entries=r.orderZipRead(raw) const containsTarget=entries.get('xl/workbook.xml').includes('美森正班海卡') const id=String(nextId++),channels=source.reference.channels.filter(channel=>containsTarget||channel.channelCode!=='MATSON_CLX_TRUCK') data={version:{id,customerId:fault==='wrong-version-owner'?'0':'20',status:'PENDING_CONFIRMATION',sourceSha256:createHash('sha256').update(raw).digest('hex')}, channels:structuredClone(channels),rates:structuredClone(source.reference.rates.filter(rate=>channels.some(channel=>channel.channelCode===rate.channelCode)))} books.set(id,data) } else if(url.pathname.startsWith(`${base}/`)) { const id=url.pathname.slice(base.length+1).split('/')[0],book=books.get(id) assert.ok(book,'only this run uploaded version may be read/published') if(request.method==='POST') { assert.ok(request.path.endsWith('/publish'));assert.equal(book.version.customerId,'20') assert.deepEqual(plain(request.body),{originMappings:[{originWarehouseCode:'YIWU',warehouseId:'2'}],overseasMappings:[]}) for(const previous of books.values())if(previous.version.status==='ACTIVE')previous.version.status='SUPERSEDED' book.version.status='ACTIVE';book.version.blockingErrorCount=0 if(fault==='public-drift')publicVersions[0].status='SUPERSEDED' } data=structuredClone(book) } else if(url.pathname.endsWith('/pricing/channels')) { const active=[...books.values()].find(book=>book.version.status==='ACTIVE') let channels=active.channels if(fault==='channel-retained'&&active.version.id==='202')channels=source.reference.channels data=channels.map(channel=>({...channel,priceBookVersionId:active.version.id})) } else if(url.pathname==='/api/merchant/v1/orders/first-leg'&&request.method==='POST')data='42' else if(url.pathname==='/api/merchant/v1/orders/first-leg/42')data=structuredClone(order) else if(url.pathname.includes('/tasks/by-order/'))data=structuredClone(task) else if(url.pathname==='/api/platform/inbounds')data={page:1,total:0,records:[]} else if(url.pathname.endsWith('/submit')) { assert.equal(request.body.expectedVersion,7) code='A0409';message=fault==='wrong-conflict'?'订单版本已变化,请刷新后重试':'所选渠道已下线,请重新选择' if(fault==='order-drift')order.order.version++ if(fault==='task-drift')task={id:'task',orderId:'42',tenantId:'20'} } else throw new Error(`unhandled offline request ${request.path}`) const response={status:200,json:{code,message,data},bytes};validate(response);return response }, }) return {r,report,calls,books} } test('channel gate publishes private A then B, proves client removal and rejects both original-version submits',async()=>{ const {r,report,calls,books}=channelGateHarness() await r.orderSubmissionChannelGateModule() assert.equal(report.orderSubmissionGates.channel.status,'REJECTIONS_VERIFIED') assert.equal(report.orderSubmissionGates.channel.publicVersionsUnchanged,true) assert.deepEqual(report.orderSubmissionGates.remaining,['Other pending scope']) assert.equal(books.get('201').version.status,'SUPERSEDED');assert.equal(books.get('202').version.status,'ACTIVE') assert.equal(calls.filter(call=>call.path.endsWith('/publish')).length,2) assert.equal(calls.filter(call=>call.path.includes('/submit')).length,2) assert.ok(calls.filter(call=>call.method==='POST').every(call=>!call.path.includes('customerId=0')&&!call.path.includes('/100/'))) }) for(const fault of ['unowned-customer','wrong-version-owner','channel-retained','wrong-conflict','order-drift','task-drift','public-drift'])test(`channel gate fails closed: ${fault}`,async()=>{ const {r,calls}=channelGateHarness(fault) await assert.rejects(r.orderSubmissionChannelGateModule()) if(['unowned-customer','wrong-version-owner'].includes(fault))assert.equal(calls.some(call=>call.path.endsWith('/publish')),false) }) function balanceGateHarness(fault='') { const calls=[],ledger=[],report={resources:{tenantId:'20',orderIds:[]},steps:[{module:'registration',name:'enterprise self-registration',passed:true,evidence:{tenantId:'20'}}]} const wallet={currencyCode:'CNY',version:0,creditActive:false,actualBalance:0,availableBalance:0,frozenBalance:0, creditLimit:0,creditUsed:0,creditFrozen:0,availableCredit:0} const detail={order:{id:'42',tenantId:'20',customerId:'20',orderNo:'FL42',status:'DRAFT',version:3},cargoes:[{skuNo:'SKU'}],parties:[],internalNotes:[],statusHistory:[]} let sequence=0,task=null if(fault==='other-customer')report.steps[0].evidence.tenantId='21' if(fault==='funded-account')wallet.actualBalance=1 const r=runtime({report,marker:'isolated-fixture',merchantToken:'owner',platformToken:'platform',newIdempotencyKey:()=>`key-${++sequence}`, orderAcceptanceFixture:{payload:{cargoes:[{skuNo:'SKU'}]}}, apiStep:async(_module,name,request,validate)=>{ calls.push({name,request:structuredClone(request)}) let data=null,code='200',message='success' if(request.path.endsWith('/tenant/profile'))data={id:'20',status:'ACTIVE'} else if(request.path==='/api/client/finance/v1/account')data=structuredClone(wallet) else if(request.path.includes('/account/ledger'))data={total:ledger.length,records:structuredClone(ledger)} else if(request.path.endsWith('/adjustments')) { assert.equal(request.path,'/api/platform/finance/v1/accounts/20/adjustments') assert.equal(request.token,'platform');assert.ok(request.headers['Idempotency-Key']) assert.equal(request.body.amount,0.01);assert.equal(request.body.expectedAccountVersion,wallet.version) const deduct=request.body.type==='DEDUCTION' if(deduct&&fault==='deduction-not-applied')throw new Error('not applied') wallet.actualBalance+=deduct?-0.01:0.01;wallet.availableBalance=wallet.actualBalance;wallet.version++ ledger.push({sourceType:deduct?'MANUAL_DEDUCTION':'MANUAL_RECHARGE',referenceNo:request.body.referenceNo,amount:deduct?-0.01:0.01}) if(deduct&&fault==='lost-deduction-response')throw new Error('response lost') data=ledger.at(-1) } else if(request.method==='POST'&&request.path==='/api/merchant/v1/orders/first-leg')data='42' else if(request.path.includes('/submit')) { assert.equal(wallet.actualBalance,-0.01) assert.equal(request.body.expectedVersion,3) assert.ok(request.headers['Idempotency-Key']) code='A0403';message=fault==='wrong-gate'?'企业未审核':'账户实际余额为负,请充值后再下单' if(fault==='order-drift')detail.order.version++ if(fault==='task-drift')task={orderId:'42',tenantId:'20',id:'unexpected'} } else if(request.path.includes('/tasks/by-order/'))data=structuredClone(task) else if(request.path.includes('/inbounds?'))data={page:1,total:0,records:[]} else if(request.path==='/api/merchant/v1/orders/first-leg/42')data=structuredClone(detail) else throw new Error(`unhandled offline request ${request.path}`) const response={status:200,json:{code,message,data}};validate(response);return response }, }) return {r,calls,report,wallet,ledger} } test('negative actual funds fixture touches only the new registered customer and restores an audited cent',async()=>{ const {r,calls,report,wallet,ledger}=balanceGateHarness() await r.orderSubmissionBalanceGateModule() assert.equal(wallet.actualBalance,0);assert.equal(wallet.version,2);assert.equal(ledger.length,2) assert.equal(report.orderSubmissionGates.balance.status,'REJECTIONS_VERIFIED') assert.equal(report.orderSubmissionGates.balance.restoration,'RESTORED_WITH_AUDIT') assert.equal(calls.filter(call=>call.request.path.includes('/submit')).length,2) assert.equal(calls.filter(call=>call.request.path.endsWith('/adjustments')).length,2) assert.ok(calls.every(call=>!call.request.path.includes('channels')&&!call.request.path.includes('price-books'))) }) for(const fault of ['other-customer','funded-account'])test(`financial fixture refuses unsafe scope: ${fault}`,async()=>{ const {r,calls}=balanceGateHarness(fault) await assert.rejects(r.orderSubmissionBalanceGateModule()) assert.equal(calls.some(call=>call.request.method==='POST'),false) }) for(const fault of ['wrong-gate','order-drift','task-drift','lost-deduction-response'])test(`gate evidence fails and restores its proven deduction after ${fault}`,async()=>{ const {r,wallet,ledger}=balanceGateHarness(fault) await assert.rejects(r.orderSubmissionBalanceGateModule()) assert.equal(wallet.actualBalance,0);assert.equal(ledger.length,2) }) test('unapplied deduction does not trigger a blind restoring credit',async()=>{ const {r,wallet,ledger,calls}=balanceGateHarness('deduction-not-applied') await assert.rejects(r.orderSubmissionBalanceGateModule(),/not applied/) assert.equal(wallet.actualBalance,0);assert.equal(ledger.length,0) assert.equal(calls.filter(call=>call.request.path.endsWith('/adjustments')).length,1) }) test('frozen edit command preserves original version, key and nested payload through retries', () => { const r = runtime(), snapshot = { order: { version: 7 } }, payload = { draft: { cargoes: [{ skuNo: 'ORIGINAL' }] } } const command = r.orderMutationCommand(snapshot, payload, 'original-key') snapshot.order.version = 99; payload.draft.cargoes[0].skuNo = 'CHANGED' assert.deepEqual(plain(command), { headers: { 'Idempotency-Key': 'original-key' }, body: { expectedVersion: 7, draft: { cargoes: [{ skuNo: 'ORIGINAL' }] } } }) assert.ok(Object.isFrozen(command.body.draft.cargoes[0])) assert.throws(() => r.orderMutationCommand({ order: {} }, payload, 'key'), /version/) assert.throws(() => r.orderMutationCommand(snapshot, payload, ''), /key/) }) test('submit command carries only frozen expectedVersion with the same original replay key',()=>{ const r=runtime(),detail={order:{version:4}} const command=r.orderMutationCommand(detail,{},'submit-original') detail.order.version=9 assert.deepEqual(plain(command),{headers:{'Idempotency-Key':'submit-original'},body:{expectedVersion:4}}) assert.match(source,/const submitCommand = orderMutationCommand\(submitBefore, \{\}, submitKey\)/) assert.match(source,/submit replay keeps version and history unchanged/) assert.match(source,/submit same key different version conflicts/) assert.match(source,/submit new key cannot submit already submitted order/) for(const name of ['pre-approval-submit','incomplete-submit','cancelled-submit','cancelled-submit-proof']) { assert.match(source,new RegExp(`orderMutationCommand\\([^\\n]+(?:\\n[^\\n]+)?newIdempotencyKey\\('${name}'\\)`)) } }) test('zero-drift validator detects changes in every aggregate and preserves array ordering', () => { const r = runtime(), before = { order: { version: 2 }, cargoes: [{ id: '1', amount: 2 }], parties: [], internalNotes: [], statusHistory: [{ id: 'h1' }, { id: 'h2' }] } r.assertOrderUnchanged(before, structuredClone(before)) for (const field of Object.keys(before)) { const changed = structuredClone(before) if (field === 'order') changed.order.version++ else changed[field].push({ id: 'new' }) assert.throws(() => r.assertOrderUnchanged(before, changed), /unchanged/) } assert.throws(() => r.assertOrderUnchanged(before, { ...before, statusHistory: [...before.statusHistory].reverse() }), /unchanged/) r.assertOrderUnchanged({ b: 2, a: 1 }, { a: 1, b: 2 }) }) test('partial import validates physical row, exact counts, failure details and identities', () => { const r = runtime(), data = { mode: 'PARTIAL', batchNo: 'batch', sourceFileId: 'f', errorReportFileId: 'e', result: { total: 2, succeeded: 1, failed: 1, items: [ { index: 0, clientRowId: 'excel-row-3', success: false, orderId: null, errorCode: 'A0422', errorMessage: 'cargo required' }, { index: 1, clientRowId: 'excel-row-4', success: true, orderId: '99', orderNo: 'FL99' }, ], } } r.assertImportResult(data, 'PARTIAL', [false, true]) for (const mutate of [ value => value.result.succeeded++, value => value.result.items[0].clientRowId = 'excel-row-2', value => value.result.items[0].orderId = 'unexpected', value => value.result.items[0].errorCode = 'S0500', value => value.result.items[1].orderNo = '', value => value.errorReportFileId = null, ]) { const changed = structuredClone(data); mutate(changed) assert.throws(() => r.assertImportResult(changed, 'PARTIAL', [false, true])) } }) test('PARTIAL wire response accepts only null or omitted failed-row identifiers', () => { const r = runtime() // Shape captured from r1: Jackson omits all null fields on both failed and successful rows. const wire = JSON.parse('{"mode":"PARTIAL","batchNo":"OBI-contract","sourceFileId":"101","errorReportFileId":"102","result":{"total":2,"succeeded":1,"failed":1,"items":[{"index":0,"clientRowId":"excel-row-3","success":false,"errorCode":"A0422","errorMessage":"货物名称不能为空"},{"index":1,"clientRowId":"excel-row-4","success":true,"orderId":"2106016937331458049","orderNo":"FL2106016937331458049"}]}}') r.assertImportResult(wire, 'PARTIAL', [false, true]) for (const field of ['orderId', 'orderNo', 'inboundCode']) { const explicitNull = structuredClone(wire); explicitNull.result.items[0][field] = null r.assertImportResult(explicitNull, 'PARTIAL', [false, true]) for (const value of ['2106016937331458049', 'FL-example', 'NYEXX-example', '', 0, false, NaN, [], {}]) { const invalid = structuredClone(wire); invalid.result.items[0][field] = value assert.throws(() => r.assertImportResult(invalid, 'PARTIAL', [false, true]), new RegExp(`no ${field}`)) } } for (const field of ['orderId', 'orderNo']) { const missingSuccess = structuredClone(wire); delete missingSuccess.result.items[1][field] assert.throws(() => r.assertImportResult(missingSuccess, 'PARTIAL', [false, true]), /created order/) } }) function templateFixture(r) { return new Map([ ['xl/workbook.xml', ''], ['xl/sharedStrings.xml', '运输方式 *客户备注仓库|CODE'], ['xl/worksheets/sheet1.xml', '订单基础01old data'], ['xl/worksheets/sheet2.xml', '2'], ]) } test('XLSX mutation preserves downloaded headers/options and writes 31 columns past Z', () => { const r = runtime(), template = templateFixture(r), row = Array.from({ length: 31 }, (_, i) => `column-${i}`) row[30] = '备注<&"\'中文' const bytes = r.orderWorkbookRows(template, [row]), parsed = r.orderZipRead(bytes), rows = r.orderSheetRows(parsed) assert.equal(parsed.get('xl/worksheets/sheet2.xml'), template.get('xl/worksheets/sheet2.xml')) assert.match(parsed.get('xl/worksheets/sheet1.xml'), /dataValidations/) assert.deepEqual(plain(rows.find(item => item.number === 2).cells.map(cell => cell.text)), ['运输方式 *', '', '客户备注']) assert.equal(rows[2].cells[30].ref, 'AE'); assert.equal(rows[2].cells[30].text, row[30]) assert.doesNotMatch(parsed.get('xl/worksheets/sheet1.xml'), /old data/) assert.deepEqual(plain(r.orderSheetRows(parsed, 'xl/worksheets/sheet2.xml')[0].cells), [{ ref: 'A', text: '仓库|CODE' }]) const corrupted = Buffer.from(bytes); corrupted[80] ^= 1 assert.throws(() => r.orderZipRead(corrupted)) assert.throws(() => r.orderZipRead(Buffer.from('not zip'))) }) test('ZIP reader accepts independently compressed entries and rejects damaged checksums', () => { const r = runtime(), data = Buffer.from('中文'), name = Buffer.from('xl/worksheets/sheet1.xml') const compressed = deflateRawSync(data) let checksum = 0xffffffff for (const byte of data) { checksum ^= byte; for (let i = 0; i < 8; i++) checksum = checksum & 1 ? 0xedb88320 ^ (checksum >>> 1) : checksum >>> 1 } checksum = (checksum ^ 0xffffffff) >>> 0 const local = Buffer.alloc(30); local.writeUInt32LE(0x04034b50); local.writeUInt16LE(8, 8); local.writeUInt16LE(name.length, 26) const central = Buffer.alloc(46); central.writeUInt32LE(0x02014b50); central.writeUInt16LE(8, 10) central.writeUInt32LE(checksum, 16); central.writeUInt32LE(compressed.length, 20); central.writeUInt32LE(data.length, 24); central.writeUInt16LE(name.length, 28) const end = Buffer.alloc(22); end.writeUInt32LE(0x06054b50); end.writeUInt16LE(1, 10); end.writeUInt32LE(local.length + name.length + compressed.length, 16) const archive = Buffer.concat([local, name, compressed, central, name, end]) assert.equal(r.orderZipRead(archive).get(name.toString()), data.toString()) central.writeUInt32LE((checksum ^ 1) >>> 0, 16) assert.throws(() => r.orderZipRead(Buffer.concat([local, name, compressed, central, name, end])), /checksum/) }) test('rollback plan changes only row 3 validity and row 4 hash without moving physical rows', () => { const r = runtime(), first = Array.from({ length: 31 }, (_, index) => `first-${index}`), second = Array.from({ length: 31 }, (_, index) => `second-${index}`) const plan = r.importRollbackRows(first, second) assert.equal(plan.seed[0][10], ''); assert.deepEqual(plain(plan.seed[1]), second) assert.deepEqual(plain(plan.conflict[0]), first) assert.deepEqual(plain(plan.conflict[1].slice(0, 30)), second.slice(0, 30)) assert.notEqual(plan.conflict[1][30], second[30]); assert.deepEqual(plain(plan.retry), [first, second]) const rows = r.orderSheetRows(r.orderZipRead(r.orderWorkbookRows(templateFixture(r), plan.conflict))) assert.deepEqual(plain(rows.slice(2).map(row => row.number)), [3, 4]) }) test('actual Java path derives row keys without mode and joins both writes to the atomic transaction', async () => { const service = await readFile(new URL('../order/src/main/java/com/baiyue/order/service/MerchantBatchDraftService.java', import.meta.url), 'utf8') const item = await readFile(new URL('../order/src/main/java/com/baiyue/order/service/MerchantBatchDraftItemService.java', import.meta.url), 'utf8') const orders = await readFile(new URL('../order/src/main/java/com/baiyue/order/service/OrderApplicationService.java', import.meta.url), 'utf8') assert.match(service, /batchKey\.trim\(\) \+ "\\n" \+ rowId/) assert.match(service, /@Transactional\s+public MerchantBatchDraftDtos.Response createAtomic/) assert.match(service, /itemService.createJoined\(tenantId, userId, username, item.draft\(\),\s*derivedKey\(batchKey, item.clientRowId\(\)\)\)/) assert.match(item, /@Transactional\(propagation = Propagation.MANDATORY\)/) assert.match(orders, /requestHash\("CREATE_DRAFT", request\)/) }) function mutationHarness(fault = '') { let nextId = 100, nextKey = 0, nextHistory = 0 const draft = { customerRemark: 'original', cargoes: [{ skuNo: 'SKU', packageCount: 2, model: 'M', productImageFileId: 'img' }] } const make = (id, status, body) => ({ order: { id, orderNo: `FL${id}`, inboundCode: null, tenantId: 'tenant', customerId: 'customer', version: 0, status, customerRemark: body.customerRemark }, cargoes: structuredClone(body.cargoes), parties: [], internalNotes: [], statusHistory: [] }) const orders = new Map([['submitted', make('submitted', 'SUBMITTED', draft)]]), commands = new Map(), requests = [], report = { resources: { orderIds: [] } } const r = runtime({ merchantToken: 'owner', existingClientToken: 'other', marker: 'local-contract', report, orderAcceptanceFixture: { payload: draft, orderId: 'submitted' }, newIdempotencyKey: () => `key-${++nextKey}`, apiStep: async (module, name, request, validate) => { requests.push({ name, request: structuredClone(request) }) const id = request.path.split('/')[6], current = orders.get(id) let code = '200', data = null if (!request.method || request.method === 'GET') data = structuredClone(current) else if (request.path.endsWith('/first-leg')) { data = String(nextId++); orders.set(data, make(data, 'DRAFT', request.body)) } else if (request.token === 'other') code = 'A0404' else if (request.path.endsWith('/submit')) code = 'A0409' else { const key = request.headers?.['Idempotency-Key'], payload = request.body const signature = JSON.stringify(payload), stored = commands.get(key) if (!key) code = 'A0400' else if (payload.expectedVersion == null || (request.method === 'POST' && !payload.reason?.trim()) || payload.draft?.cargoes[0].productImageFileId === -1) code = 'A0422' else if (stored) { code = stored === signature ? '200' : 'A0409' if (fault === 'replay-write' && code === '200') current.order.version++ } else if (payload.expectedVersion !== current.order.version || current.order.status !== 'DRAFT') code = 'A0409' else { commands.set(key, signature); current.order.version++ const cancelled = request.method === 'POST' if (cancelled) current.order.status = 'CANCELLED' else { current.order.customerRemark = payload.draft.customerRemark; current.cargoes = structuredClone(payload.draft.cargoes) } current.statusHistory.push({ id: `h${++nextHistory}`, action: cancelled ? 'CANCELLED' : 'UPDATE', fromStatus: 'DRAFT', toStatus: current.order.status, reason: payload.reason ?? null, operatorId: 'owner', occurredAt: '2026-10-02T12:00:00' }) } } if (fault === 'rejection-drift' && code !== '200' && current) current.parties.push({ id: 'unexpected' }) const response = { status: 200, json: { code, data } }; validate(response); return response }, }) return { r, requests, report, orders } } test('F06 actual orchestration covers frozen success replay, stale versions, missing protocol and isolation', async () => { const { r, requests, report } = mutationHarness() await r.orderMutationEvidenceModule() const firstEdit = requests.find(item => item.name === 'versioned draft edit succeeds').request const editReplay = requests.find(item => item.name === 'original edit key and frozen payload replay successfully').request assert.deepEqual(editReplay, firstEdit) const firstCancel = requests.find(item => item.name === 'cancel owned draft with reason').request const cancelReplay = requests.find(item => item.name === 'original cancellation key payload and version replay successfully').request assert.deepEqual(cancelReplay, firstCancel) const newCancel = requests.find(item => item.name === 'repeat cancellation cannot add history').request assert.notEqual(newCancel.headers['Idempotency-Key'], firstCancel.headers['Idempotency-Key']) assert.ok(newCancel.body.expectedVersion > firstCancel.body.expectedVersion) assert.ok(report.orderMutationRequests.every(item => !('token' in item))) assert.ok(requests.some(item => item.name === 'edit missing version is rejected')) assert.ok(requests.some(item => item.name === 'cancel missing key is rejected')) }) for (const fault of ['replay-write', 'rejection-drift']) test(`F06 refuses false success when ${fault}`, async () => { const { r } = mutationHarness(fault) await assert.rejects(() => r.orderMutationEvidenceModule(), /unchanged/) }) test('full order collection detects leaked rows, duplicated pages and truncated results', async () => { for (const records of [[{ orderId: 'expected' }, { orderId: 'leaked' }], [{ orderId: 'expected' }, { orderId: 'expected' }]]) { const r = runtime({ merchantToken: 'owner', apiStep: async (_module, _name, _request, validate) => { validate({ json: { code: '200', data: { page: 1, total: 2, records } } }) } }) await assert.rejects(() => r.importOrderSet('rollback evidence', ['expected'])) } const r = runtime({ merchantToken: 'owner', apiStep: async (_module, _name, _request, validate) => { validate({ json: { code: '200', data: { page: 1, total: 201, records: [{ orderId: 'only-one' }] } } }) } }) await assert.rejects(() => r.importOrderSet('complete pagination'), /intermediate/) }) function importHarness(fault = '') { const report = { resources: { orderIds: [], tenantId: 'tenant' } }, orders = new Map(), requests = [] const masterData = { receiving: { id: 'domestic', warehouseName: '国内仓', warehouseCode: 'CN' }, destination: { id: 'fba', warehouseName: '目的仓', warehouseCode: 'US' }, channel: { channelName: '海运渠道', channelCode: 'SEA' } } let nextKey = 0, r const resultItem = (index, success, orderId) => Object.fromEntries(Object.entries({ index, clientRowId: `excel-row-${index + 3}`, success, orderId: success ? orderId : null, orderNo: success ? `FL${orderId}` : null, errorCode: success ? null : 'A0422', errorMessage: success ? null : 'cargo required' }).filter(([, value]) => value !== null)) const responseData = (mode, items) => ({ mode, batchNo: 'batch', sourceFileId: 'source-file', errorReportFileId: 'error-file', result: { total: items.length, succeeded: items.filter(item => item.success).length, failed: items.filter(item => !item.success).length, items } }) const addDraft = (id, cells) => orders.set(id, { order: { id, orderNo: `FL${id}`, version: 0, status: 'DRAFT', tenantId: 'tenant', customerRemark: cells[30], referenceId: cells[27], receivingWarehouseId: 'domestic', destinationWarehouseId: 'fba', channelCode: 'SEA' }, cargoes: [{ skuNo: cells[18], packageCount: 2 }], parties: [], internalNotes: [], statusHistory: [] }) const cells = (values, row) => values.map((value, index) => `${r.orderXmlEncode(value)}`).join('') r = runtime({ report, marker: 'contract', merchantToken: 'owner', orderAcceptanceFixture: { masterData, payload: { pricingTaxMode: 'TAX_INCLUDED' } }, newIdempotencyKey: () => `key-${++nextKey}`, apiStep: async (_module, name, request, validate) => { requests.push({ name, path: request.path, key: request.headers?.['Idempotency-Key'] }) let code = '200', data = null, bytes = null if (request.path.endsWith('/template')) { const template = templateFixture(r) const headers = Array.from({ length: 31 }, (_, index) => index === 0 ? '运输方式 *' : index === 30 ? '客户备注' : `字段${index}`) template.set('xl/worksheets/sheet1.xml', `${cells(['订单基础'], 1)}${cells(headers, 2)}`) template.set('xl/worksheets/sheet2.xml', `${cells(['国内仓|CN', '目的仓|US', '海运渠道|SEA'], 1)}`) bytes = r.orderZipWrite(template) } else if (request.path.includes('/error-reports/')) { const physicalRow = fault === 'wrong-error-row' ? '4.0' : '3.0' bytes = r.orderZipWrite(new Map([['xl/worksheets/sheet1.xml', `${cells(['Excel行号', '错误代码', '错误说明'], 1)}${cells(['3', 'A0422', 'cargo required'], 2).replace(//, `${physicalRow}`)}`]])) } else if (request.method === 'POST') { const file = request.body.get('file'), body = Buffer.from(await file.arrayBuffer()) if (name.startsWith('PARTIAL')) { const parsed = r.orderSheetRows(r.orderZipRead(body)).slice(2).map(row => row.cells.map(cell => cell.text)) if (!orders.has('second')) addDraft('second', parsed[1]) data = responseData('PARTIAL', [resultItem(0, false), resultItem(1, true, 'second')]) } else if (name.startsWith('ATOMIC retry')) { const parsed = r.orderSheetRows(r.orderZipRead(body)).slice(2).map(row => row.cells.map(cell => cell.text)) addDraft('first', parsed[0]); data = responseData('ATOMIC', [resultItem(0, true, 'first'), resultItem(1, true, 'second')]) } else if (name.startsWith('ATOMIC later')) { code = 'A0409' if (fault === 'leaked-first-row') { const parsed = r.orderSheetRows(r.orderZipRead(body)).slice(2).map(row => row.cells.map(cell => cell.text)) addDraft('leaked-first', parsed[0]) } if (fault === 'changed-existing-row') orders.get('second').order.customerRemark = 'incorrectly-overwritten' } else code = name === 'reject over five MiB' ? 'A0400' : 'A0422' } else if (request.path.includes('?page=')) { data = { page: 1, total: orders.size, records: [...orders.keys()].map(orderId => ({ orderId })) } } else data = structuredClone(orders.get(request.path.split('/').at(-1))) const response = { status: 200, headers: new Map([['content-type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']]), bytes, json: { code, data, message: code === 'A0400' ? '上传文件超过服务允许大小' : undefined } } validate(response); return response }, }) return { r, report, requests } } test('F04 runs actual import orchestration with the same seed/conflict/retry key and records limitations', async () => { const { r, report, requests } = importHarness() await r.orderExcelImportModule() const keys = requests.filter(item => item.key && /PARTIAL preserves|PARTIAL same key|ATOMIC later|ATOMIC retry/.test(item.name)).map(item => item.key) assert.equal(keys.length, 4); assert.equal(new Set(keys).size, 1) assert.deepEqual(report.resources.orderIds, ['second', 'first']) assert.ok(report.orderImportLimitations.some(item => item.includes('remote source uploads'))) assert.ok(requests.some(item => item.name === 'forged option adds no orders: complete order page 1')) }) for (const fault of ['leaked-first-row', 'changed-existing-row']) test(`F04 rejects apparent ATOMIC failure with ${fault}`, async () => { const { r } = importHarness(fault) await assert.rejects(() => r.orderExcelImportModule(), /unchanged/) }) test('F04 still rejects a numeric error row pointing to the successful row', async () => { const { r } = importHarness('wrong-error-row') await assert.rejects(() => r.orderExcelImportModule(), /actual Excel error row/) })