107 lines
6.5 KiB
JavaScript
107 lines
6.5 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import test from 'node:test'
|
|
|
|
import { fixtureInboundCode, orderPersistenceFacts, requestedOrderDestinationType, freezeOrderCommand, verifyPlatformDraftEdit } from './orders.mjs'
|
|
|
|
test('order command freezes original detail version/key and never accepts an absent version',()=>{
|
|
const detail={order:{version:3}},draft={customerRemark:'original'}
|
|
const command=freezeOrderCommand(detail,'key',{draft})
|
|
detail.order.version=8;draft.customerRemark='changed'
|
|
assert.deepEqual(command,{body:{draft:{customerRemark:'original'},expectedVersion:3},headers:{'Idempotency-Key':'key'}})
|
|
assert.ok(Object.isFrozen(command.body.draft))
|
|
for(const version of [undefined,null,'3',-1])assert.throws(()=>freezeOrderCommand({order:{version}},'key'))
|
|
})
|
|
|
|
test('Platform edit uses exact customer and admin identity; replay/stale/foreign writes preserve full facts',async()=>{
|
|
let detail={order:{id:'10',tenantId:'20',status:'DRAFT',version:3,customerRemark:'marker'},cargoes:[],parties:[],internalNotes:[],statusHistory:[]}
|
|
let saved
|
|
const writes=[]
|
|
const context={marker:'marker',token:'admin',createdResources:{orders:{}},apiSuccess(_m,_n,r){assert.equal(r.body.code,'200');return r.body.data},
|
|
assert(_m,name,_r,ok){assert.ok(ok,name)},async request(method,path,body,token,headers){
|
|
assert.equal(path,'/api/platform/v1/orders/first-leg/10?tenantId=20')
|
|
if(method==='GET')return {http:200,body:{code:'200',data:structuredClone(detail)}}
|
|
writes.push({body,token,headers})
|
|
let code='200'
|
|
if(token!=='admin')code='A0403'
|
|
else if(saved)code=saved.key===headers['Idempotency-Key']&&saved.payload===JSON.stringify(body)?'200':'A0409'
|
|
else {assert.equal(body.expectedVersion,3);saved={key:headers['Idempotency-Key'],payload:JSON.stringify(body)};detail.order.version++;detail.order.customerRemark=body.draft.customerRemark;detail.statusHistory.push({action:'UPDATE'})}
|
|
return {http:200,body:{code}}
|
|
}}
|
|
const result=await verifyPlatformDraftEdit(context,'20','10','merchant',{customerRemark:'marker'})
|
|
assert.equal(result.order.version,4);assert.equal(writes.length,5)
|
|
assert.deepEqual(writes[1],writes[2]);assert.equal(writes[0].token,'merchant')
|
|
})
|
|
|
|
const source = readFileSync(new URL('orders.mjs', import.meta.url), 'utf8')
|
|
|
|
test('fresh fixture obeys the authoritative inbound-code policy without changing global settings', () => {
|
|
assert.deepEqual(fixtureInboundCode({ mode: 'AUTO', manualEntryRequired: false }, 'batch-A'), {})
|
|
const policy = { mode: 'LEGACY_MANUAL', manualEntryRequired: true }
|
|
const first = fixtureInboundCode(policy, 'batch-A')
|
|
assert.deepEqual(first, fixtureInboundCode(policy, 'batch-A'))
|
|
assert.notEqual(first.inboundCode, fixtureInboundCode(policy, 'batch-B').inboundCode)
|
|
assert.match(first.inboundCode, /^AT[A-F0-9]{20}$/)
|
|
assert.ok(`${first.inboundCode}#9999-9999`.length <= 34)
|
|
for (const invalid of [null, {}, { mode: 'AUTO', manualEntryRequired: true }, { mode: 'UNKNOWN', manualEntryRequired: false }]) {
|
|
assert.throws(() => fixtureInboundCode(invalid, 'batch-A'), /入仓码策略/)
|
|
}
|
|
assert.match(source, /GET', `\$\{createPath\}\/inbound-code-policy`/)
|
|
})
|
|
|
|
test('order demo payload covers multi-box multi-SKU images and both destination families', () => {
|
|
for (const boxType of ['SMALL', 'MEDIUM', 'LARGE', 'EXTRA_LARGE']) {
|
|
assert.match(source, new RegExp(`boxType: '${boxType}'`))
|
|
}
|
|
assert.match(source, /cargoes: selectedBoxes\.map/)
|
|
assert.match(source, /productImageFileId/)
|
|
assert.equal(requestedOrderDestinationType({ context: { orderDestinationType: 'FBA' } }), 'FBA')
|
|
assert.equal(requestedOrderDestinationType({ context: { orderDestinationType: 'OVERSEAS' } }), 'OVERSEAS')
|
|
})
|
|
|
|
test('create and submit lifecycle covers replay payload conflict and zero drift', () => {
|
|
assert.match(source, /Client 创建订单幂等重放/)
|
|
assert.match(source, /Client 创建订单同键异载荷返回A0409/)
|
|
assert.match(source, /创建同键异载荷失败后订单全事实零漂移/)
|
|
assert.match(source, /Client 提交订单同键同载荷精确重放/)
|
|
assert.match(source, /已提交订单使用新键重复提交返回A0409/)
|
|
assert.match(source, /重复提交失败后订单状态货物与历史零漂移/)
|
|
assert.match(source, /orderPersistenceFacts\(draftAfterConflict\) === orderPersistenceFacts\(draft\)/)
|
|
assert.match(source, /orderPersistenceFacts\(submittedAfterFailure\) === orderPersistenceFacts\(submitted\)/)
|
|
})
|
|
|
|
test('admin internal notes use the current versioned collaborative remarks contract', () => {
|
|
assert.match(source, /context\.request\('PUT',[\s\S]*\/remarks\?tenantId=/)
|
|
assert.match(source, /expectedVersion:\s*Number\(firstLegDetail\?\.order\?\.version\)/)
|
|
assert.match(source, /internalRemark:\s*`\$\{context\.marker\} Admin 订单链路验收`/)
|
|
assert.doesNotMatch(source, /\/internal-notes/)
|
|
})
|
|
|
|
test('persistence fact comparison includes order cargo parties notes and history', () => {
|
|
const detail = {
|
|
order: { id: '1', status: 'DRAFT' }, cargoes: [{ skuNo: 'SKU-1' }],
|
|
parties: [{ role: 'SENDER' }], internalNotes: [{ content: 'note' }],
|
|
statusHistory: [{ toStatus: 'DRAFT' }],
|
|
}
|
|
const baseline = orderPersistenceFacts(detail)
|
|
assert.equal(orderPersistenceFacts(structuredClone(detail)), baseline)
|
|
assert.notEqual(orderPersistenceFacts({ ...detail, order: { ...detail.order, status: 'SUBMITTED' } }), baseline)
|
|
assert.notEqual(orderPersistenceFacts({ ...detail, cargoes: [{ skuNo: 'SKU-2' }] }), baseline)
|
|
assert.notEqual(orderPersistenceFacts({ ...detail, statusHistory: [...detail.statusHistory, { toStatus: 'SUBMITTED' }] }), baseline)
|
|
})
|
|
|
|
test('approval convergence is a hard WAIT_MEASURE prerequisite without coverage downgrade', () => {
|
|
assert.match(source, /审核后入库单与履约任务异步收敛/)
|
|
assert.match(source, /MEASURABLE_STATUSES/)
|
|
assert.match(source, /throw new Error\('订单审核后的入库单与履约任务未在30秒内收敛/)
|
|
assert.doesNotMatch(source, /审核后入库单与履约任务异步收敛[\s\S]{0,300}addCoverageGap/)
|
|
})
|
|
|
|
test('post-approval declaration update waits for authoritative fulfilment convergence', () => {
|
|
const approval = source.indexOf("Admin 审核通过本轮订单")
|
|
const declaration = source.indexOf("Admin 修改审核后客户申报资料")
|
|
const convergence = source.indexOf('const inboundResult = await waitForInbound')
|
|
assert.ok(approval >= 0 && convergence > approval && declaration > convergence)
|
|
assert.match(source, /APPROVED declaration edits fail closed against the authoritative Firstleg projection/)
|
|
})
|