优化
This commit is contained in:
@@ -2,7 +2,7 @@ import assert from 'node:assert/strict'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import test from 'node:test'
|
||||
|
||||
import { approvedInboundReady } from './orders.mjs'
|
||||
import { approvedInboundReady, verifyOrderApprovalReplay } from './orders.mjs'
|
||||
|
||||
const tenantId = '10001'
|
||||
const orderId = '20001'
|
||||
@@ -48,3 +48,76 @@ test('orders acceptance polls approval convergence instead of only inbound id vi
|
||||
assert.doesNotMatch(source, /MEASURABLE_STATUSES\.has\(summary\?\.processStatus\)/)
|
||||
assert.doesNotMatch(source, /if \(success\(response\) && response\.body\?\.data\?\.summary\?\.inboundId\)/)
|
||||
})
|
||||
|
||||
function approvalReplayContext(mutate = () => {}, approvalCode = 'A0409') {
|
||||
const inboundId = '40001'; const inboundCode = 'AT-APPROVAL'
|
||||
const state = {
|
||||
order: { order: { id: orderId, status: 'APPROVED', inboundCode, version: 2 },
|
||||
cargoes: [], parties: [], internalNotes: [], statusHistory: [{ id: 'history-order', action: 'APPROVED' }] },
|
||||
task: { id: '30001', tenantId, orderId, status: 'WAIT_MEASURE' },
|
||||
inbound: { summary: { id: inboundId, tenantId, inboundCode, version: 2, processStatus: 'WAIT_MEASURE' },
|
||||
statusHistory: [{ id: 'history-inbound', action: 'ORDER_APPROVED' }], files: [], palletLocations: [] },
|
||||
rows: [{ id: inboundId, tenantId, orderId, inboundCode }],
|
||||
}
|
||||
const calls = []; const checks = []
|
||||
const context = { marker: 'APPROVAL-REPLAY', createdResources: { orders: {} },
|
||||
request: async (method, requestPath, body, token, headers) => {
|
||||
calls.push({ method, requestPath, body, token, headers })
|
||||
if (method === 'POST') {
|
||||
assert.match(requestPath, /\/orders\/first-leg\/20001\/approve\?tenantId=10001$/)
|
||||
assert.equal(body, undefined); assert.equal(headers, undefined)
|
||||
mutate(state)
|
||||
return { http: 200, body: { code: approvalCode }, requestId: 'repeat-approve', traceId: 'trace-approve' }
|
||||
}
|
||||
let data
|
||||
if (requestPath.includes('/orders/first-leg/')) data = state.order
|
||||
else if (requestPath.includes('/tasks/by-order/')) data = state.task
|
||||
else if (requestPath.startsWith(`/api/platform/inbounds/${inboundId}?`)) data = state.inbound
|
||||
else if (requestPath.startsWith('/api/platform/inbounds?')) data = {
|
||||
records: state.rows, page: 1, size: 100, total: state.rows.length, pages: 1,
|
||||
}
|
||||
else throw new Error(`unexpected ${method} ${requestPath}`)
|
||||
return { http: 200, body: { code: '200', data: structuredClone(data) }, requestId: 'read', traceId: 'trace' }
|
||||
},
|
||||
apiSuccess: (_module, _name, response) => {
|
||||
assert.equal(response.http, 200); assert.equal(response.body.code, '200'); return response.body.data
|
||||
},
|
||||
assert: (_module, name, _response, passed) => {
|
||||
checks.push({ name, passed }); assert.ok(passed, name)
|
||||
},
|
||||
}
|
||||
return { context, calls, checks, input: { tenantId, orderId, inboundId, inboundCode } }
|
||||
}
|
||||
|
||||
test('repeated approval requires A0409 and compares order, task, inbound identity, histories and unique count', async () => {
|
||||
const fixture = approvalReplayContext()
|
||||
const result = await verifyOrderApprovalReplay(fixture.context, fixture.input)
|
||||
assert.equal(result.rejected, true)
|
||||
assert.equal(result.unchanged, true)
|
||||
assert.equal(result.inboundCount, 1)
|
||||
assert.equal(result.orderHistoryCount, 1)
|
||||
assert.equal(result.inboundHistoryCount, 1)
|
||||
assert.equal(result.beforeDigest, result.afterDigest)
|
||||
assert.equal(fixture.calls.filter(call => call.method === 'POST').length, 1)
|
||||
assert.equal(fixture.context.createdResources.orders.approvalReplay, result)
|
||||
assert.equal(Object.hasOwn(result, 'order'), false)
|
||||
assert.match(result.beforeDigest, /^[a-f0-9]{64}$/)
|
||||
})
|
||||
|
||||
for (const [name, mutate] of [
|
||||
['extra approval history', state => state.order.statusHistory.push({ id: 'repeat-history', action: 'APPROVED' })],
|
||||
['changed inbound version', state => state.inbound.summary.version += 1],
|
||||
['extra inbound history', state => state.inbound.statusHistory.push({ id: 'repeat-inbound-history' })],
|
||||
['new fulfillment task', state => { state.task.id = '30002' }],
|
||||
['duplicate source inbound', state => state.rows.push({ ...state.rows[0], id: '40002' })],
|
||||
]) {
|
||||
test(`approval replay detects ${name} instead of accepting unchanged response status`, async () => {
|
||||
const fixture = approvalReplayContext(mutate)
|
||||
await assert.rejects(verifyOrderApprovalReplay(fixture.context, fixture.input), /零漂移|唯一入库事实有效/)
|
||||
})
|
||||
}
|
||||
|
||||
test('successful repeated approval is not accepted as a substitute for the formal conflict contract', async () => {
|
||||
const fixture = approvalReplayContext(() => {}, '200')
|
||||
await assert.rejects(verifyOrderApprovalReplay(fixture.context, fixture.input), /再次审核明确A0409/)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user