import test from 'node:test' import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import { finishOrderLifecycle } from './orders.mjs' const input = { tenantId: '2105193679178272769', orderId: '2105193704449441794', firstLegDetailPath: '/original-order-detail' } function fixture(option, status, transitions) { const calls = []; const checks = [] const resources = { orders: { tenantId: input.tenantId, orderId: input.orderId, inboundId: '2105193705748041729', inboundCode: 'TEST-APPROVED', skuLines: [{ skuNo: 'SKU-A' }] }, ocrInbound: { tenantId: input.tenantId, inboundId: '2105193705748041729' } } const context = { context: { orderStopAtApproved: option }, createdResources: resources, async request(method, path) { calls.push({ method, path }); return { http: 200, body: { code: '200', data: method === 'GET' ? { order: { status }, statusHistory: transitions.map(toStatus => ({ toStatus })) } : {} } } }, apiSuccess(_module, _step, response) { assert.equal(response.body.code, '200'); return response.body.data }, assert(_module, step, _response, valid) { checks.push({ step, valid: Boolean(valid) }) }, } return { context, calls, checks, resources } } test('explicit approved stop checks raw Order and never sends accept or start; measurement resources survive', async () => { const f = fixture(true, 'APPROVED', ['DRAFT', 'PENDING_REVIEW', 'APPROVED']) const before = JSON.stringify(f.resources) await finishOrderLifecycle(f.context, input) assert.deepEqual(f.calls, [{ method: 'GET', path: input.firstLegDetailPath }]) assert.ok(f.checks.every(check => check.valid)) assert.equal(f.resources.orders.rawOrderStatus, 'APPROVED') assert.equal(f.resources.orders.stoppedAtApproved, true) delete f.resources.orders.rawOrderStatus; delete f.resources.orders.stoppedAtApproved assert.equal(JSON.stringify(f.resources), before) }) for (const option of [undefined, false, 'true']) { test(`only boolean true opts out of default accept/start: ${String(option)}`, async () => { const f = fixture(option, 'PROCESSING', ['APPROVED', 'ACCEPTED', 'PROCESSING']) await finishOrderLifecycle(f.context, input) assert.equal(f.calls.length, 3) assert.ok(f.calls[0].path.includes('/accept?')) assert.ok(f.calls[1].path.includes('/start?')) assert.deepEqual(f.calls.map(call => call.method), ['POST', 'POST', 'GET']) assert.ok(f.checks.every(check => check.valid)) assert.equal(f.resources.orders.rawOrderStatus, 'PROCESSING') }) } for (const [status, history] of [['PROCESSING', ['APPROVED', 'ACCEPTED', 'PROCESSING']], ['APPROVED', ['APPROVED', 'ACCEPTED']], ['APPROVED', ['PENDING_REVIEW']]]) { test(`approved stop rejects invalid raw status/history: ${status}/${history.join(',')}`, async () => { const f = fixture(true, status, history) await assert.rejects(finishOrderLifecycle(f.context, input), /原始APPROVED/) assert.equal(f.calls.length, 1) assert.ok(f.checks.some(check => !check.valid)) }) } test('approved stop runs after full approval replay, inbound readiness and shared measurement handoff', () => { const source = readFileSync(new URL('./orders.mjs', import.meta.url), 'utf8') const run = source.slice(source.indexOf('export async function run(')) const finish = run.lastIndexOf('await finishOrderLifecycle(') for (const fragment of ['await verifyOrderApprovalReplay(', '隔离入库单 marker 来源与可测量状态正确', 'context.createdResources.orders.inboundId = inboundId', 'context.context.createdInbound =', '履约任务与本轮订单和客户一致']) { assert.ok(run.indexOf(fragment) >= 0 && run.indexOf(fragment) < finish, fragment) } })