import test from 'node:test' import { relabelOutboundMarksMatch, inventoryQuantitySnapshot, inventorySnapshot, dispatchInventorySources, inventorySourcesPresent, dispatchStockConservation, verifyAutomaticDeparture, verifyPartialOrderCompletion, verifyFulfillmentRootStatus, createDeliveryReturn, completeReturnedException, returnedExceptionFactsMatch, verifyCustomerSignedDocuments, createSignedDocumentIsolationCustomer, dispatchDestinationConservation, dispatchOutboundMatches, continueDepartedFulfillment, pickAll, readAutomaticDispatchDelivery, fulfillmentEvidenceContext, verifyRelabelDispatchOutbound, verifyClientRelabelSettlement } from './phase5-overseas-fulfillment.mjs' import assert from 'node:assert/strict' import { readFile, mkdtemp, rm } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' import { fileURLToPath } from 'node:url' import { parseArguments } from '../admin-test-env-acceptance.mjs' const source = await readFile(fileURLToPath(new URL('./phase5-overseas-fulfillment.mjs', import.meta.url)), 'utf8') test('原出库客户归属沿正式关联派送明细核对并拒绝串客漏项数量漂移', () => { const reference = { outboundNo: 'CK-1', customerId: '101', packageCount: '7' } const deliveries = [{ deliveryNo: 'DL-1', outboundNo: 'CK-1', customerId: '101', packageCount: '3' }, { deliveryNo: 'DL-2', outboundNo: 'CK-1', customerId: '101', packageCount: '4' }] const detail = { outbound: { outboundNo: 'CK-1', dispatchNo: 'PC-1', status: 'OUTBOUNDED', packageCount: 7 }, deliveries: deliveries.map(row => ({ ...row, dispatchNo: 'PC-1', packageCount: Number(row.packageCount) })) } assert.equal(dispatchOutboundMatches(detail, reference, 'PC-1', deliveries), true) for (const change of [value => { value.deliveries[0].customerId = '102' }, value => { value.deliveries.pop() }, value => { value.deliveries[0].outboundNo = 'CK-2' }, value => { value.deliveries[0].dispatchNo = 'PC-2' }, value => { value.deliveries[1].deliveryNo = 'DL-1' }, value => { value.deliveries[1].packageCount = 3 }, value => { value.outbound.status = 'PICKED' }, value => { value.outbound.packageCount = 8 }]) { const value = structuredClone(detail); change(value) assert.equal(dispatchOutboundMatches(value, reference, 'PC-1', deliveries), false) } }) test('原发车接续拒绝外批次或已开始签收的证明且不发送请求', async () => { let calls = 0 const args = { customerId: '101', warehouseId: '42', dispatchNo: 'PC-1', tripProof: { dispatchNo: 'PC-1', warehouseId: '42' }, deliveries: [{}], outbounds: [{}], merchantToken: 'test-only' } for (const proof of [{ marker: 'other', dispatchNo: 'PC-1' }, { marker: 'batch', dispatchNo: 'PC-1', receiptFiles: [{}] }]) { await assert.rejects(continueDepartedFulfillment({ marker: 'batch', createdResources: { phase5OverseasFulfillment: proof }, request: async () => { calls++ } }, args), /原发车证明/) } assert.equal(calls, 0) }) for (const fault of ['', 'foreign customer', 'old marks', 'sign failure', 'resource held', 'settlement failed']) { test(`client original relabel delivery includes receipt and resource release: ${fault || 'normal'}`, async () => { const relabel = { marker: 'batch', relabelNo: 'RL-CLIENT', dispatchNo: 'DP-CLIENT', warehouseId: '42', customerId: '101', sourceCartonMarks: ['OLD'], relabelCartonMarks: ['NEW'] } const calls = [] const context = { marker: 'batch', createdResources: { phase4OverseasClientServices: { relabelFulfillment: relabel } }, checkpoint: async () => {}, assert(_m, name, _r, ok) { assert.ok(ok, name) }, apiSuccess(_m, _name, response) { return response.body.data }, async request(method, path) { calls.push('outbound') assert.equal(method, 'GET'); assert.ok(path.endsWith('/outbound-orders/OUT-1')) return { http: 200, body: { code: '200', data: { outbound: { outboundNo: 'OUT-1', dispatchNo: 'DP-CLIENT', status: 'OUTBOUNDED', packageCount: 1 }, deliveries: [{ deliveryNo: 'DE-1', outboundNo: 'OUT-1', dispatchNo: 'DP-CLIENT', customerId: '101', packageCount: 1 }], pallets: [{ cartonMarks: fault === 'old marks' ? 'OLD' : 'NEW' }] } } } } } const helpers = { async prepare(_c, _m, dispatch, warehouse) { calls.push('prepare'); assert.equal(dispatch, relabel.dispatchNo); assert.equal(warehouse, '42'); return { tripNo: 'TR-1' } }, async pick() { calls.push('pick'); return true }, async load() { calls.push('load') }, async read() { calls.push('read'); return { outbounds: [{ customerId: '101', outboundNo: 'OUT-1', packageCount: 1 }], deliveries: [{ customerId: fault === 'foreign customer' ? '102' : '101', outboundNo: 'OUT-1', deliveryNo: 'DE-1', packageCount: 1 }] } }, async sign() { calls.push('sign'); return { order: { status: fault === 'sign failure' ? 'DELIVERING' : 'DELIVERED', deliveryNo: 'DE-1', customerId: '101', outboundNo: 'OUT-1' } } }, async finish() { calls.push('finish'); return { status: fault === 'resource held' ? 'CHECKING' : 'CARGO_COMPLETED_AND_RESOURCES_RELEASED' } }, async settle() { calls.push('settle'); return { status: fault === 'settlement failed' ? 'FAILED' : 'SETTLED_HTTP_VERIFIED' } }, } if (fault) { await assert.rejects(verifyRelabelDispatchOutbound(context, relabel, 'pda', '42', helpers)) assert.equal(relabel.deliveryExecution.status, 'FAILED') if (['foreign customer', 'old marks'].includes(fault)) assert.equal(calls.includes('sign'), false) if (fault === 'sign failure') assert.equal(calls.includes('finish'), false) } else { await verifyRelabelDispatchOutbound(context, relabel, 'pda', '42', helpers) assert.equal(relabel.deliveryExecution.status, 'DELIVERED_HTTP_VERIFIED') assert.deepEqual(calls, ['prepare', 'pick', 'load', 'read', 'outbound', 'sign', 'finish', 'settle']) } const count = calls.length await assert.rejects(verifyRelabelDispatchOutbound(context, relabel, 'pda', '42', helpers)) assert.equal(calls.length, count) }) } for (const fault of ['', 'foreign order', 'wrong amount', 'pending', 'rejected']) { test(`原贴标结算只读回查: ${fault || 'settled'}`, async () => { const relabel = { marker: 'batch', relabelNo: 'RL-1', sourceOrderNo: 'WC-1', customerId: '101', warehouseId: '42', outboundNo: 'OUT-1', deliveryExecution: { closure: { status: 'CARGO_COMPLETED_AND_RESOURCES_RELEASED' } } } let calls = 0 const context = { marker: 'batch', context: { merchantQualificationFixture: { tenantId: '101' } }, createdResources: { phase4OverseasClientServices: { relabelFulfillment: relabel } }, checkpoint: async () => {}, assert() {}, apiSuccess(_m, _n, response) { return response.body.data }, async request(method, path) { assert.equal(method, 'GET'); assert.ok(path.endsWith('/relabel-applications/RL-1')); calls++ return { http: 200, body: { code: '200', data: { application: { relabelNo: 'RL-1', customerOrderNo: fault === 'foreign order' ? 'OTHER' : 'WC-1', overseasWarehouseId: '42', chargeAmount: fault === 'wrong amount' ? 1 : 0.01, chargeCurrency: 'USD', customerConfirmedAt: '2026-10-22T01:00:00', walletStatus: fault === 'pending' ? 'SETTLE_PENDING' : fault === 'rejected' ? 'SETTLE_FAILED' : calls === 1 ? 'SETTLE_PENDING' : 'SETTLED' } } } } } } if (fault) { await assert.rejects(verifyClientRelabelSettlement(context, relabel, async () => {})) assert.equal(relabel.settlement.status, 'FAILED') assert.equal(calls, fault === 'pending' ? 31 : 1) } else { await verifyClientRelabelSettlement(context, relabel, async () => {}) assert.equal(relabel.settlement.status, 'SETTLED_HTTP_VERIFIED'); assert.equal(calls, 2) } }) } test('relabel fleets run after main resource release and retain both original proofs in checkpoints', () => { const start = source.indexOf('export async function run(context)') const run = source.slice(start) assert.ok(run.indexOf('await finishRelabelDeliveries(') > run.indexOf('await finishFleetTrip(')) assert.equal(run.includes('await verifyRelabelDispatchOutbound('), false) assert.match(source, /clientRelabel: context.createdResources.phase4OverseasClientServices\?\.relabelFulfillment/) }) const entry = await readFile(fileURLToPath(new URL('../admin-test-env-acceptance.mjs', import.meta.url)), 'utf8') test('一箱实收从四箱派送退回仅保持RETURN_PENDING,全部实收才RETURNED,缺失收货或来源证据仍拒绝', () => { const expected = { customerId: '100', outboundNo: 'OB-1', deliveryNo: 'DL-1', inboundCode: 'IN-1', evidenceFileId: '91' } const detail = { order: { ...expected, status: 'COMPLETED', packageCount: 1, evidenceFileIds: ['91'] }, returnSources: [], returnReceipts: [{ receiptNo: 'RSR-1', receivedPackages: '1', receivedAt: '2026-10-06T01:00:00' }] } const delivery = { order: { customerId: '100', outboundNo: 'OB-1', deliveryNo: 'DL-1', packageCount: 4, status: 'RETURN_PENDING' } } assert.equal(returnedExceptionFactsMatch(detail, delivery, expected), true) assert.equal(returnedExceptionFactsMatch(detail, { order: { ...delivery.order, packageCount: 1, status: 'RETURNED' } }, expected), true) assert.equal(returnedExceptionFactsMatch(detail, { order: { ...delivery.order, status: 'RETURNED' } }, expected), false) assert.equal(returnedExceptionFactsMatch(detail, { order: { ...delivery.order, customerId: 'OTHER' } }, expected), false) for (const mutate of [v => { v.returnReceipts = [] }, v => { v.returnReceipts[0].receivedPackages = 2 }, v => { v.order.outboundNo = 'OB-OTHER' }, v => { v.order.evidenceFileIds = [] }, v => { v.returnSources = [{ maxReturnPackages: 1 }] }, v => { v.returnReceipts.push({ ...v.returnReceipts[0] }) }]) { const changed = structuredClone(detail); mutate(changed) assert.equal(returnedExceptionFactsMatch(changed, delivery, expected), false) } }) test('native route conserves source keys and destinations while same destination may contain multiple customers', () => { const fixture = { sourceKeys: ['PLAN:10', 'PLAN:11', 'PLAN:12'], destinationWarehouseCodes: ['ONT8', 'LAX9'] } const detail = { dispatchInfo: { route: 'ONT8,LAX9' }, orderDetails: [ { sourceKey: 'PLAN:10', customerId: '100', destinationFbaWarehouse: 'ONT8' }, { sourceKey: 'PLAN:11', customerId: '200', destinationFbaWarehouse: 'LAX9' }, { sourceKey: 'PLAN:12', customerId: '200', destinationFbaWarehouse: 'ONT8' }] } const deliveries = [{ customerId: '100', destination: { key: 'FBA:ONT8', warehouseCode: 'ONT8' } }, { customerId: '200', destination: { key: 'FBA:ONT8', warehouseCode: 'ONT8' } }, { customerId: '200', destination: { key: 'FBA:LAX9', warehouseCode: 'LAX9' } }] assert.equal(dispatchDestinationConservation(detail, fixture), true) assert.equal(dispatchDestinationConservation(detail, fixture, deliveries), true) for (const mutate of [value => { value.detail.dispatchInfo.route = 'ONT8' }, value => { value.detail.dispatchInfo.route = 'ONT8,ONT8,LAX9' }, value => { value.detail.orderDetails[1].destinationFbaWarehouse = 'OTHER' }, value => { value.detail.orderDetails[1].sourceKey = 'PLAN:99' }, value => { value.fixture.destinationWarehouseCodes.push('UNSELECTED') }, value => { value.deliveries.pop() }, value => { value.deliveries.push(value.deliveries[0]) }]) { const value = structuredClone({ detail, fixture, deliveries }); mutate(value) assert.equal(dispatchDestinationConservation(value.detail, value.fixture, value.deliveries), false) } }) test('phase-five fulfillment is a registered default HTTP module after the real phase-four dispatch fixture', () => { assert.match(entry, /CONFIGURED_MODULES[^\n]*'phase4-overseas-dispatch', 'phase5-overseas-fulfillment'/) assert.match(entry, /'phase5-overseas-fulfillment', \['phase4-overseas-dispatch', 'phase4-overseas-business'\]/) const modules = parseArguments(['--modules', 'phase5-overseas-fulfillment']).modules for (const prerequisite of ['merchant-qualification-fixture', 'phase3-loading', 'phase3-loading-finalize', 'phase4-overseas-pda', 'phase4-overseas-pda-operations', 'phase4-overseas-dispatch', 'phase4-overseas-business']) { assert.ok(modules.indexOf(prerequisite) >= 0 && modules.indexOf(prerequisite) < modules.indexOf('phase5-overseas-fulfillment'), prerequisite) } }) test('default looseboard attaches before stock snapshots and verifies its original order after signature', () => { const start = source.indexOf('export async function run(context)') const run = source.slice(start) assert.ok(run.indexOf('await attachLooseboardToTrip(') < run.indexOf('const sourceTask =')) assert.ok(run.indexOf('await verifyLooseboardDelivered(') > run.indexOf('const completedDeliveries =')) assert.match(source, /looseboard: context.createdResources.phase4OverseasBusiness\?\.looseboard/) assert.match(run, /sourceKeys: \[\.\.\.source.dispatch.sourceKeys, \.\.\.looseboard.proof.sourceKeys\]/) }) test('native fulfillment uses real public DTOs and scans before loading, arranging and departing', () => { for (const token of ["const DISPATCH_BASE = '/api/platform/v1/last-leg/dispatches'", "const PDA_DISPATCH_BASE = '/api/pda/v1/last-leg/dispatches'", 'value?.documents?.deliveries', 'value?.documents?.outbounds', 'recordVersion: version(detail.data.recordVersion)', 'positionId: id', 'ready.data.counts?.shippedPackageCount', 'outboundRef.outboundNo']) { if (token === 'positionId: id') assert.match(source, /positionId: source.position \? id\(source.position.positionId\)/) else assert.ok(source.includes(token), token) } assert.doesNotMatch(source, /READY_TO_DEPART|PENDING_DEPARTURE|DISPATCH-COMPLETE|\/items\/.*['"]DELETE['"]/) assert.match(source, /data.status === 'ACTIVE' && data.stage === 'DELIVERING'/) assert.doesNotMatch(source, /\/transfer-delivery|\/delivery-arrangement|\/depart`/) const run = source.slice(source.indexOf('export async function run')) assert.ok(run.indexOf('prepareFleetTrip(') < run.indexOf('await pickAll(')) assert.ok(run.indexOf('await pickAll(') < run.indexOf('await confirmFleetLoading(')) assert.ok(run.indexOf('await confirmFleetLoading(') < run.indexOf('await readAutomaticDispatchDelivery(')) assert.ok(run.indexOf('await readAutomaticDispatchDelivery(') < run.indexOf('await verifyAutomaticDeparture(')) assert.ok(run.indexOf('全部客户正常签收汇总整车DELIVERED') < run.indexOf('await finishFleetTrip(')) assert.ok(run.indexOf('await finishFleetTrip(') < run.indexOf('const returnRequest')) }) test('client reads its own native-arranged deliveries and full nested document contract', () => { assert.match(source, /loginMerchant\(context, customerId\)/) assert.match(source, /context.options\?.merchantUsername/) assert.match(source, /id\(profile\?.id\) === customerId/) assert.match(source, /客户分页回查自身派送单/) assert.match(source, /客户读取自身派送详情/) assert.match(source, /merchantDetail.data\?.order\?.deliveryNo/) assert.match(source, /merchantDetail.data\?.skus/) assert.match(source, /merchantDetail.data\?.fees/) assert.match(source, /merchantDetail.data\?.operations/) assert.doesNotMatch(source, /merchant\(context, merchantToken, 'POST'.*创建派送/) }) test('phase-five module proves receipt-save completion, cross-region convergence, customer visit, exception and return', () => { for (const token of [ '/documents/RECEIPT/files', 'requestMultipart', "category: 'RECEIPT'", 'SAVE-RECEIPT', 'RECEIPT_AUTO_COMPLETE', '/customer-visits/${encodeURIComponent(visitId)}', "visitResult: 'SATISFIED'", '/exception-orders', '/return-inbound-options', '/mark-return', "returnDirection: 'OVERSEAS_WAREHOUSE'", 'returnSources', 'outboundPalletItemId', 'inventoryPositionId', 'value.returnSources.some', 'returnCandidate?.deliveryNo === deliveryNo', "idempotencyKey: key(context, 'DELIVERY-RETURN')", '派送退回同键同载荷重放', 'RETURN_PENDING_WITH_COMPLETED_VISIT', ]) assert.ok(source.includes(token), token) assert.match(source, /saved\.data\?\.categories\?\.some/) assert.match(source, /completed\.data\?\.order\?\.status === 'DELIVERED'/) assert.match(source, /人工确认派送完成接口已移除/) assert.match(source, /query\('\/api\/platform\/inbounds'/) assert.match(source, /inboundCode: inbound\.inboundCode/) assert.match(source, /inboundSummary\?\.processStatus === 'DELIVERED'/) assert.match(source, /verifyFulfillmentRootStatus\(context, \{ sourceOrderId, customerId, merchantToken \}\)/) assert.match(source, /\/api\/platform\/v1\/orders\/\$\{encodeURIComponent\(rootOrderId\)\}/) assert.match(source, /\/fulfillment-tree/) assert.match(source, /mainStatus === 'COMPLETED'/) assert.doesNotMatch(source, /platform\(context, 'POST', '确认派送完成/) assert.match(source, /manualExceptionNo/) assert.match(source, /returnExceptionNo/) }) test('phase-five module uses marker-owned fixtures and always disables its temporary PDA identity', () => { assert.match(source, /dispatch\?\.marker !== context\.marker/) assert.match(source, /receiving\?\.marker !== context\.marker/) assert.match(source, /resolvePickerAccess\(context\)/) assert.match(source, /createPicker\(context, 5, warehouseId, access\)/) assert.match(source, /finally \{[\s\S]*disablePicker\(context, picker, 5\)[\s\S]*picker\.token = null/) assert.doesNotMatch(source, /8\.163\.|password\s*:\s*['"`]/) }) test('phase-five writes carry idempotency and record deployment blockers instead of passing empty fixtures', () => { assert.match(source, /idempotencyKey: key\(context, 'DISPATCH-PICK'/) assert.doesNotMatch(source, /DISPATCH-DEPART/) assert.match(source, /addCoverageGap\(MODULE, SCENARIO/) assert.match(source, /deploymentBlocker: true/) }) test('relabel marks are checked on the authoritative outbound DTO without weakening identity checks', () => { const relabel = { relabelCartonMarks: ['NEW-1', 'NEW-2'], sourceCartonMarks: ['OLD-1', 'OLD-2'] } const detail = { outbound: { packageCount: 2 }, pallets: [{ cartonMarks: 'NEW-1,NEW-2' }] } assert.equal(relabelOutboundMarksMatch(detail, relabel), true) for (const cartonMarks of ['', 'NEW-1', 'NEW-1,NEW-1', 'NEW-1,OLD-2', 'NEW-1,NEW-2,OTHER']) { assert.equal(relabelOutboundMarksMatch({ ...detail, pallets: [{ cartonMarks }] }, relabel), false) } assert.equal(relabelOutboundMarksMatch({ ...detail, outbound: { packageCount: 3 } }, relabel), false) assert.match(source, /dispatchOutboundMatches\(detail.data, transferred.outbounds\[0\], relabel.dispatchNo, transferred.deliveries\)/) assert.match(source, /relabel\?\.marker !== context\.marker/) }) test('unknown writes preserve the original command and stop instead of transport retry', () => { assert.match(source, /entry.status = 'UNKNOWN'/) assert.match(source, /存在未知写结果/) assert.doesNotMatch(source, /人工异常连接失败后使用同载荷重试/) assert.match(source, /manualExceptionBody/) }) test('quantity snapshots ignore timestamps but preserve every inventory bucket and source identity', () => { const original = { id: '1', inboundCode: 'IN-1', totalPackages: 5, availablePackages: 3, holdPackages: 2, allocatedPackages: 0, pickedPackages: 0, updatedAt: 'earlier' } assert.deepEqual(inventoryQuantitySnapshot([original]), inventoryQuantitySnapshot([{ ...original, updatedAt: 'later' }])) for (const field of ['id', 'inboundCode', 'totalPackages', 'availablePackages', 'holdPackages', 'allocatedPackages', 'pickedPackages']) { assert.notDeepEqual(inventoryQuantitySnapshot([original]), inventoryQuantitySnapshot([{ ...original, [field]: field === 'id' || field === 'inboundCode' ? 'different' : 99 }])) } }) function contextFor(request) { const assertions = [] const calls = [] return { marker: 'TAIL-CURRENT', options: { gateway: 'https://test.invalid' }, createdResources: {}, assertions, calls, async request(method, path, body, token) { calls.push({ method, path, body, token }); return request(method, path, body, token) }, apiSuccess(module, name, response) { assertions.push({ name, passed: response?.body?.code === '200' }); return response.body?.data }, assert(module, name, response, passed) { assertions.push({ name, passed }) }, addStep(module, name, response, passed) { assertions.push({ name, passed }) }, addCoverageGap(module, scenario, name) { assertions.push({ name, passed: false }) }, } } const ok = data => ({ http: 200, body: { code: '200', data } }) function deliveryReturnFixture() { return { lastMileOrderId: '9007199254740993', lastMileOrderNo: 'LM-1', inboundOrderId: '81', inboundCode: 'IN-A', customerId: '100', overseasWarehouseId: 'WH-1', deliveryNo: 'DL-1', outboundNo: 'OB-1', returnSources: [{ outboundPalletItemId: '51', inventoryPositionId: '61', returnCartonId: null, maxReturnPackages: 2 }] } } const returnScope = { customerId: '100', warehouseId: 'WH-1', deliveryNo: 'DL-1', outboundNo: 'OB-1' } for (const ordinaryInbound of ['81', null, undefined]) test(`phase5 mark-return sends the actual master key; inbound=${ordinaryInbound}`, async () => { const candidate = deliveryReturnFixture(); candidate.inboundOrderId = ordinaryInbound if (!ordinaryInbound) candidate.inboundCode = null const context = contextFor((method, path, body) => { if (method === 'GET') { assert.match(path, /return-inbound-options/); return ok([candidate]) } assert.equal(method, 'POST'); assert.match(path, /mark-return/) assert.equal(body.lastMileOrderId, candidate.lastMileOrderId) assert.equal(Object.hasOwn(body, 'inboundOrderId'), false) assert.deepEqual(body.items, [{ outboundPalletItemId: '51', inventoryPositionId: '61', packageCount: 1 }]) assert.equal(body.returnDirection, 'OVERSEAS_WAREHOUSE') assert.ok(body.idempotencyKey) return ok({ exceptionNo: 'EX-1', status: 'PENDING', version: 0 }) }) const result = await createDeliveryReturn(context, returnScope) assert.equal(result.returned.data.exceptionNo, 'EX-1') assert.equal(context.calls.filter(row => row.method === 'POST').length, 1) assert.deepEqual(context.assertions.filter(row => !row.passed), []) }) test('phase5 keeps the selected master and its own source together when candidates share no inbound relation', async () => { const first = deliveryReturnFixture(); first.inboundOrderId = null; first.inboundCode = null; first.returnSources = [] const selected = { ...deliveryReturnFixture(), lastMileOrderId: '9007199254740995', lastMileOrderNo: 'LM-2', inboundOrderId: null, inboundCode: null, returnSources: [{ outboundPalletItemId: '52', inventoryPositionId: '62', maxReturnPackages: 1 }] } const context = contextFor((method, path, body) => { if (method === 'GET') return ok([first, selected]) assert.equal(body.lastMileOrderId, selected.lastMileOrderId) assert.equal(Object.hasOwn(body, 'inboundOrderId'), false) assert.deepEqual(body.items, [{ outboundPalletItemId: '52', inventoryPositionId: '62', packageCount: 1 }]) return ok({ exceptionNo: 'EX-2' }) }) await createDeliveryReturn(context, returnScope) assert.equal(context.calls.filter(row => row.method === 'POST').length, 1) }) for (const [name, mutate] of [ ['missing-master', row => { delete row.lastMileOrderId }], ['zero-master', row => { row.lastMileOrderId = '0' }], ['foreign-customer', row => { row.customerId = 'OTHER' }], ['foreign-warehouse', row => { row.overseasWarehouseId = 'OTHER' }], ['wrong-delivery', row => { row.deliveryNo = 'DL-OTHER' }], ['wrong-outbound', row => { row.outboundNo = 'OB-OTHER' }], ['missing-source', row => { row.returnSources = [] }], ['missing-position', row => { row.returnSources[0].inventoryPositionId = null }], ['ambiguous-source-type', row => { row.returnSources[0].returnCartonId = '701' }], ]) test(`phase5 refuses ${name} before any mark-return write even with an inbound ID`, async () => { const candidate = deliveryReturnFixture(); mutate(candidate) const context = contextFor((method) => { assert.equal(method, 'GET'); return ok([candidate]) }) assert.equal(await createDeliveryReturn(context, returnScope), null) assert.equal(context.calls.length, 1) assert.ok(context.assertions.some(row => !row.passed)) }) test('the phase5 lifecycle calls the tested request path and replays its exact returned body', () => { assert.match(source, /const returnRequest = await createDeliveryReturn\(context, \{ customerId, warehouseId, deliveryNo, outboundNo \}\)/) assert.match(source, /const \{ returned, returnBody \} = returnRequest/) assert.doesNotMatch(source, /inboundOrderId:\s*id\(returnCandidate/) assert.match(source, /lastMileOrderId: id\(returnCandidate\.lastMileOrderId\)/) }) test('partial completion rejects different Orders and an already delivered pending fragment', async () => { for (const second of [{ orderId: 'OTHER', processStatus: 'WAIT_SHIP' }, { orderId: 'ORDER', processStatus: 'DELIVERED' }]) { const context = contextFor((method, path) => ok({ records: path.includes('inboundCode=IN-A') ? [{ inboundCode: 'IN-A', orderId: 'ORDER', processStatus: 'DELIVERED' }] : [{ inboundCode: 'IN-B', ...second }] })) assert.equal(await verifyPartialOrderCompletion(context, { orderId: 'ORDER', customerId: '100', deliveredInboundCode: 'IN-A', pendingInboundCodes: ['IN-B'] }), false) assert.equal(context.calls.some(call => call.path.startsWith('/api/platform/v1/orders/')), false) } }) test('partial completion verifies an unfinished valid sibling and catches premature COMPLETED', async () => { for (const mainStatus of ['IN_TRANSIT', 'COMPLETED']) { const context = contextFor((method, path) => path.startsWith('/api/platform/v1/orders/') ? ok({ summary: { mainStatus } }) : ok({ records: [{ inboundCode: path.includes('inboundCode=IN-A') ? 'IN-A' : 'IN-B', orderId: 'ORDER', processStatus: path.includes('inboundCode=IN-A') ? 'DELIVERED' : 'WAIT_SHIP' }] })) assert.equal(await verifyPartialOrderCompletion(context, { orderId: 'ORDER', customerId: '100', deliveredInboundCode: 'IN-A', pendingInboundCodes: ['IN-B'] }), mainStatus !== 'COMPLETED') } }) test('same dispatch-return exception reaches actual restored inventory and retries without another ledger row', async () => { for (const initialStatus of ['PENDING', 'PROCESSING']) { let completed = false let version = initialStatus === 'PROCESSING' ? 1 : 0 let uploads = 0 const source = { outboundPalletItemId: '51', inventoryPositionId: '61', maxReturnPackages: 1 } const context = contextFor((method, path, body) => { if (path.includes('/inventory/balances/1/positions')) return ok(path.includes('palletNo=') ? (completed ? [{ id: '3', balanceId: '1', customerId: '100', overseasWarehouseId: 'WH-1', inboundCode: 'IN-A', palletId: '71', palletNo: 'RET-TAIL-CURRENT', warehouseLocationId: '72', totalPackages: 1, availablePackages: 1, holdPackages: 0, allocatedPackages: 0, pickedPackages: 0, receivingPackages: 0 }] : []) : [{ id: '61', balanceId: '1', customerId: '100', overseasWarehouseId: 'WH-1', inboundCode: 'IN-A', palletNo: 'SOURCE', totalPackages: 8, availablePackages: 8, holdPackages: 0, allocatedPackages: 0, pickedPackages: 0, receivingPackages: 0 }, ...(completed ? [{ id: '3', balanceId: '1', customerId: '100', overseasWarehouseId: 'WH-1', inboundCode: 'IN-A', palletId: '71', palletNo: 'RET-TAIL-CURRENT', warehouseLocationId: '72', totalPackages: 1, availablePackages: 1, holdPackages: 0, allocatedPackages: 0, pickedPackages: 0, receivingPackages: 0 }] : [])]) if (path.includes('/inventory/balances')) { const balance = { id: '1', customerId: '100', overseasWarehouseId: 'WH-1', totalPackages: completed ? 9 : 8, availablePackages: completed ? 9 : 8, holdPackages: 0, allocatedPackages: 0, pickedPackages: 0, receivingPackages: 0, inTransitPackages: 0, procurementPackages: 0 }; return ok(path.includes('/balances/1?') ? balance : { total: 1, records: [balance] }) } if (path.includes('/inventory/ledger')) return ok({ total: completed ? 1 : 0, records: completed ? [{ id: '2', customerId: '100', inboundCode: 'IN-A', businessType: 'RETURN_STOCK_IN', businessOrderNo: 'EX-1', outboundOrderNo: 'OB-1', deltaPackages: 1, beforePackages: 0, afterPackages: 1 }] : [] }) if (path.includes('/locations')) return ok({ total: 1, records: [{ id: '72', locationCode: 'L-1' }] }) if (method === 'POST' && path.endsWith('/pallets')) return ok('71') if (path.endsWith('/pallets/71')) return ok({ id: '71', warehouseId: 'WH-1', palletCode: 'RET-TAIL-CURRENT', locationId: '72' }) if (path.includes('/start-processing')) { version = 1; return ok({ status: 'PROCESSING', version }) } if (path.includes('/complete')) { assert.deepEqual(body.receipts[0], { outboundPalletItemId: '51', inventoryPositionId: '61', receivedPackages: 1, targetPalletId: '71', targetPalletNo: 'RET-TAIL-CURRENT', targetLocationId: '72', targetLocationCode: 'L-1' }) const replayed = completed; completed = true return ok({ status: 'COMPLETED', restoredPackages: 1, inventoryAdjustmentId: '81', replayed }) } if (path.includes('/delivery-orders/')) return ok({ order: { status: 'RETURNED', outboundNo: 'OB-1', deliveryNo: 'DEL-1', customerId: '100', packageCount: 1 } }) return ok({ order: { status: completed ? 'COMPLETED' : initialStatus, exceptionType: 'RETURN', outboundNo: 'OB-1', inboundCode: 'IN-A', deliveryNo: 'DEL-1', customerId: '100', packageCount: 1, version, evidenceFileIds: ['91'] }, returnSources: completed ? [] : [source], returnReceipts: completed ? [{ receiptNo: 'RSR-CURRENT', receivedPackages: 1, receivedAt: '2026-10-06T00:00:00' }] : [] }) }) context.requestMultipart = async () => { uploads += 1; return ok({ fileId: '91' }) } context.createdResources.phase5OverseasFulfillment = { marker: context.marker, returnExceptionNo: 'EX-1', outboundNo: 'OB-1', inventoryProof: { sourceBalanceIds: ['1'] } } const resume = initialStatus === 'PROCESSING' ? { targetPalletId: '71', targetPalletNo: 'RET-TAIL-CURRENT', evidenceFileId: '91', completeIdempotencyKey: 'ORIGINAL-COMPLETE' } : null const result = await completeReturnedException(context, { customerId: '100', warehouseId: 'WH-1', exceptionNo: 'EX-1', outboundNo: 'OB-1', resume }) assert.equal(result?.restoredPackages, 1) assert.deepEqual(context.assertions.filter(row => !row.passed), []) assert.equal(context.calls.filter(call => call.path.includes('/complete')).length, 2) if (initialStatus === 'PROCESSING') { assert.equal(context.calls.some(call => call.method === 'POST' && call.path.endsWith('/pallets')), false) assert.equal(context.calls.some(call => call.path.includes('/start-processing')), false) assert.equal(uploads, 0) assert.ok(context.calls.filter(call => call.path.includes('/complete')).every(call => call.body.idempotencyKey === 'ORIGINAL-COMPLETE')) } assert.equal(context.createdResources.phase5OverseasFulfillment.returnReceiptAttempt.evidenceFileId, '91') } }) test('PROCESSING continuation without the original pallet and evidence remains blocked without creating replacements', async () => { const context = contextFor(() => ok({ order: { status: 'PROCESSING', exceptionType: 'RETURN', outboundNo: 'OB-1', version: 1 }, returnSources: [{ outboundPalletItemId: '51', inventoryPositionId: '61', maxReturnPackages: 1 }] })) context.createdResources.phase5OverseasFulfillment = { marker: context.marker, returnExceptionNo: 'EX-1', outboundNo: 'OB-1', inventoryProof: { sourceBalanceIds: ['1'] } } assert.equal(await completeReturnedException(context, { customerId: '100', warehouseId: 'WH-1', exceptionNo: 'EX-1', outboundNo: 'OB-1' }), null) assert.equal(context.calls.length, 1) assert.ok(context.assertions.some(row => !row.passed)) }) test('failed same-exception completion still checks zero inventory drift and retains the original resume evidence', async () => { const context = contextFor((method, path) => { if (path.includes('/inventory/ledger')) return ok({ records: [], total: 0 }) if (path.includes('/inventory/balances')) { const balance = { id: '1', customerId: '100', overseasWarehouseId: 'WH-1', totalPackages: 1, availablePackages: 1, holdPackages: 0, allocatedPackages: 0, pickedPackages: 0, receivingPackages: 0, inTransitPackages: 0, procurementPackages: 0 } return ok(path.includes('/positions') ? [{ ...balance, id: '61', balanceId: '1', inboundCode: 'IN-A' }] : path.includes('/balances/1?') ? balance : { records: [balance], total: 1 }) } if (path.includes('/locations')) return ok({ records: [{ id: '72', locationCode: 'L-1' }], total: 1 }) if (path.endsWith('/pallets/71')) return ok({ id: '71', warehouseId: 'WH-1', palletCode: 'RET-TAIL-CURRENT', locationId: '72' }) if (path.includes('/complete')) return { http: 200, body: { code: 'A0400', message: 'Source rejected' } } return ok({ order: { status: 'PROCESSING', exceptionType: 'RETURN', outboundNo: 'OB-1', inboundCode: 'IN-A', version: 1 }, returnSources: [{ outboundPalletItemId: '51', inventoryPositionId: '61', maxReturnPackages: 1 }] }) }) context.createdResources.phase5OverseasFulfillment = { marker: context.marker, returnExceptionNo: 'EX-1', outboundNo: 'OB-1', inventoryProof: { sourceBalanceIds: ['1'] } } const resume = { targetPalletId: '71', targetPalletNo: 'RET-TAIL-CURRENT', evidenceFileId: '91', completeIdempotencyKey: 'ORIGINAL-COMPLETE' } assert.equal(await completeReturnedException(context, { customerId: '100', warehouseId: 'WH-1', exceptionNo: 'EX-1', outboundNo: 'OB-1', resume }), null) assert.equal(context.calls.filter(call => call.path.includes('/inventory/balances')).length, 6) assert.equal(context.calls.filter(call => call.path.includes('/inventory/ledger')).length, 2) assert.ok(context.assertions.some(row => row.name === '退回实收失败后库存及流水保持不变并保留原续验资料' && row.passed)) assert.equal(context.createdResources.phase5OverseasFulfillment.returnReceiptAttempt.evidenceFileId, '91') assert.equal(context.createdResources.phase5OverseasFulfillment.returnReceiptAttempt.completeIdempotencyKey, 'ORIGINAL-COMPLETE') assert.equal(context.calls.some(call => call.method === 'POST' && !call.path.includes('/complete')), false) }) test('customer receipt acceptance downloads exact bytes and rejects a foreign customer without a platform fallback', async () => { const context = contextFor((method, path, body, token) => path.endsWith('/iam/tenant/profile') ? ok({ id: token === 'FOREIGN' ? '200' : '100' }) : token === 'FOREIGN' ? { http: 404, body: { code: 'A0404' } } : ok({ deliveryNo: 'DEL-1', files: [{ fileId: '91' }] })) const previousFetch = globalThis.fetch globalThis.fetch = async (url, options) => options.headers.Authorization === 'Bearer FOREIGN' ? new Response(JSON.stringify({ code: 'A0404' }), { status: 404, headers: { 'content-type': 'application/json' } }) : new Response('CURRENT-RECEIPT', { status: 200, headers: { 'content-type': 'application/octet-stream' } }) try { assert.equal(await verifyCustomerSignedDocuments(context, 'OWN', [{ deliveryNo: 'DEL-1', fileId: '91', content: 'CURRENT-RECEIPT' }], 'FOREIGN'), true) assert.deepEqual(context.assertions.filter(row => !row.passed), []) assert.equal(context.calls.some(call => call.path.includes('/api/platform/')), false) } finally { globalThis.fetch = previousFetch } }) test('SIGNED-B fixture keeps primary options and credentials unchanged and records no password or token', async () => { const context = contextFor((method, path, body, token) => { assert.equal(path, '/api/auth/login') assert.equal(token, '') assert.deepEqual(body, { loginId: 'SECONDARY', password: 'SECONDARY-IN-MEMORY' }) return ok({ accessToken: 'SECONDARY-TOKEN' }) }) context.options.customerName = 'PRIMARY' context.context = { merchantQualificationFixture: { tenantId: '100', username: 'PRIMARY', password: 'PRIMARY-IN-MEMORY' } } context.createdResources.phase5OverseasFulfillment = { marker: context.marker } const primary = context.context.merchantQualificationFixture const options = context.options const create = async (secondary, flags) => { assert.equal(flags.publishEnvironment, false) assert.equal(secondary.marker, `${context.marker}-SIGNED-B`) assert.notEqual(secondary.options, context.options) assert.notEqual(secondary.context, context.context) assert.notEqual(secondary.createdResources, context.createdResources) assert.equal(secondary.options.customerName, '') secondary.context.merchantQualificationFixture = { tenantId: '200', tenantName: 'SECONDARY', username: 'SECONDARY', password: 'SECONDARY-IN-MEMORY', marker: secondary.marker } // Even unexpected producer fields cannot enter the report's explicit metadata whitelist. secondary.createdResources.merchantQualificationFixture = { ...secondary.context.merchantQualificationFixture, token: 'UNEXPECTED' } } assert.equal(await createSignedDocumentIsolationCustomer(context, { create }), 'SECONDARY-TOKEN') assert.equal(context.options, options) assert.equal(context.options.customerName, 'PRIMARY') assert.equal(context.context.merchantQualificationFixture, primary) assert.equal(context.context.phase5TailVerification.foreignMerchantToken, 'SECONDARY-TOKEN') const report = JSON.stringify(context.createdResources) assert.doesNotMatch(report, /password|token|IN-MEMORY|UNEXPECTED|SECONDARY-TOKEN/) assert.equal(context.createdResources.phase5OverseasFulfillment.signedDocumentIsolationCustomer.marker, 'TAIL-CURRENT-SIGNED-B') assert.deepEqual(context.assertions.filter(row => !row.passed), []) }) test('incomplete SIGNED-B producer remains a blocker and never logs in as the primary customer', async () => { const context = contextFor(() => { throw new Error('must not log in') }) context.context = { merchantQualificationFixture: { tenantId: '100', username: 'PRIMARY', password: 'PRIMARY-IN-MEMORY' } } context.createdResources.phase5OverseasFulfillment = { marker: context.marker } const token = await createSignedDocumentIsolationCustomer(context, { create: async () => {} }) assert.equal(token, null) assert.equal(context.calls.length, 0) assert.ok(context.assertions.some(row => !row.passed)) assert.equal(context.context.phase5TailVerification, undefined) }) function inventoryFixture() { const position = (positionId, inboundCode, packages) => ({ id: positionId, balanceId: '1', customerId: '100', overseasWarehouseId: 'WH-1', inboundCode, inboundOrderId: `ORDER-${inboundCode}`, palletId: `PALLET-${positionId}`, palletNo: `P-${positionId}`, batchNo: 'B-1', warehouseLocationId: 'LOCATION-1', warehouseLocationCode: 'L-1', totalPackages: packages, availablePackages: packages, holdPackages: 0, allocatedPackages: 0, pickedPackages: 0, receivingPackages: 0 }) return { balance: { id: '1', customerId: '100', overseasWarehouseId: 'WH-1', skuCode: 'MIXED', totalPackages: 9, availablePackages: 9, holdPackages: 0, allocatedPackages: 0, pickedPackages: 0, receivingPackages: 0, inTransitPackages: 4, procurementPackages: 2 }, positions: [position('11', 'IN-A', 3), position('12', 'IN-A-1', 2), position('13', 'IN-B', 4)] } } function inventoryContext(fixture) { return contextFor((method, path) => path.includes('/positions') ? ok(fixture.positions) : path.includes('/balances/1?') ? ok(fixture.balance) : ok({ records: [fixture.balance], total: 1 })) } test('inventory evidence resolves missing Balance inboundCode through exact positions and retains an independent shared balance', async () => { const fixture = inventoryFixture() const context = inventoryContext(fixture) const snapshot = await inventorySnapshot(context, '100', 'WH-1', ['IN-A', 'IN-A', 'IN-B'], 'stock', ['1']) assert.equal(snapshot.length, 1) assert.equal(snapshot[0].id, '1') assert.equal(snapshot[0].totalPackages, 7) assert.deepEqual(snapshot[0].inboundCodes, ['IN-A', 'IN-B']) assert.deepEqual(snapshot[0].matchingPositionIds, ['11', '13']) assert.equal(snapshot[0].balance.totalPackages, 9) assert.equal(snapshot[0].balance.inTransitPackages, 4) assert.equal(snapshot[0].balance.procurementPackages, 2) assert.equal(snapshot[0].positions.length, 3) assert.deepEqual(context.assertions.filter(row => !row.passed), []) assert.equal(context.calls.filter(call => call.path.includes('/positions')).length, 1) const childOnly = inventoryFixture() childOnly.positions = [childOnly.positions[1]] childOnly.balance.totalPackages = 2; childOnly.balance.availablePackages = 2 const childSnapshot = await inventorySnapshot(inventoryContext(childOnly), '100', 'WH-1', ['IN-A'], 'stock', ['1']) assert.equal(childSnapshot[0].totalPackages, 0) assert.deepEqual(childSnapshot[0].matchingPositionIds, []) }) test('inventory evidence rejects foreign balances and positions, mismatched balance IDs, duplicate identities, and broken bucket reconciliation', async () => { for (const mutate of [ fixture => { fixture.balance.customerId = 'OTHER' }, fixture => { fixture.balance.overseasWarehouseId = 'OTHER' }, fixture => { fixture.positions[0].customerId = 'OTHER' }, fixture => { fixture.positions[0].overseasWarehouseId = 'OTHER' }, fixture => { fixture.positions[0].balanceId = 'OTHER' }, fixture => { fixture.positions[0].id = fixture.positions[1].id }, fixture => { fixture.positions[0].inboundCode = '' }, fixture => { fixture.positions[0].receivingPackages = 1 }, fixture => { fixture.balance.inTransitPackages = null }, fixture => { delete fixture.positions[0].receivingPackages }, fixture => { fixture.balance.availablePackages = 8 }, ]) { const fixture = inventoryFixture(); mutate(fixture) const context = inventoryContext(fixture) assert.equal(await inventorySnapshot(context, '100', 'WH-1', ['IN-A'], 'stock', ['1']), null) assert.ok(context.assertions.some(row => !row.passed)) } }) test('inventory evidence captures zero drift independently for every balance bucket, position identity, and unselected sibling position', async () => { const fixture = inventoryFixture() const original = await inventorySnapshot(inventoryContext(fixture), '100', 'WH-1', ['IN-A'], 'stock', ['1']) for (const field of ['inTransitPackages', 'procurementPackages']) { const changed = inventoryFixture(); changed.balance[field] += 1 assert.notDeepEqual(await inventorySnapshot(inventoryContext(changed), '100', 'WH-1', ['IN-A'], 'stock', ['1']), original) } for (const field of ['palletId', 'palletNo', 'batchNo', 'warehouseLocationId', 'warehouseLocationCode', 'inboundOrderId']) { const changed = inventoryFixture(); changed.positions[2][field] = 'DIFFERENT' assert.notDeepEqual(await inventorySnapshot(inventoryContext(changed), '100', 'WH-1', ['IN-A'], 'stock', ['1']), original) } for (const field of ['holdPackages', 'allocatedPackages', 'pickedPackages', 'receivingPackages']) { const changed = inventoryFixture(); changed.positions[2][field] += 1; changed.balance[field] += 1 assert.notDeepEqual(await inventorySnapshot(inventoryContext(changed), '100', 'WH-1', ['IN-A'], 'stock', ['1']), original) } }) test('departure requires independent matching native stage, shared version, reconciled picks and both action gates', async () => { const valid = { dispatchNo: 'DS-1', status: 'ACTIVE', stage: 'DELIVERING', recordVersion: '9007199254740993', pickingReconciled: true, counts: { packageCount: 2, shippedPackageCount: 2 } } for (const change of [null, { stage: 'LOADING' }, { stage: 'AFTER_LOADING' }, { status: 'CANCELLED' }, { dispatchNo: 'OTHER' }, { recordVersion: '9007199254740994' }, { pickingReconciled: false }, { counts: { packageCount: 2, shippedPackageCount: 1 } }]) { const context = contextFor((method, path) => ok(path.startsWith('/api/pda/') ? valid : { ...valid, ...change })) assert.equal(Boolean(await verifyAutomaticDeparture(context, 'PDA', 'DS-1')), change == null) assert.equal(context.calls.length, 2) assert.equal(context.calls.some(call => call.method !== 'GET'), false) } }) test('G05 freezes actual PDA balance IDs and measures raw sources independently from grouped representatives without inbound filters', async () => { const task = { dispatchNo: 'DS-1', warehouseId: 'WH-1', items: [ { positions: [{ positionId: '11', balanceId: '1' }, { positionId: '12', balanceId: '2' }, { positionId: '11', balanceId: '1' }] }] } assert.deepEqual(dispatchInventorySources(task, 'DS-1', 'WH-1'), { sourceBalanceIds: ['1', '2'], sourcePositionIds: ['11', '12'], sourcePositionBalances: [{ positionId: '11', balanceId: '1' }, { positionId: '12', balanceId: '2' }] }) assert.equal(dispatchInventorySources(task, 'OTHER', 'WH-1'), null) assert.equal(dispatchInventorySources(task, 'DS-1', 'OTHER'), null) assert.equal(dispatchInventorySources({ ...task, items: [{ positions: [{ positionId: '11' }] }] }, 'DS-1', 'WH-1'), null) let shipped = false const source = balanceId => ({ id: balanceId, customerId: '100', overseasWarehouseId: 'WH-1', destinationWarehouseCode: 'FBA', skuCode: 'MIXED', totalPackages: balanceId === '1' ? 3 : 6, availablePackages: balanceId === '1' ? 3 : 6, holdPackages: 0, allocatedPackages: 0, pickedPackages: 0, receivingPackages: 0, inTransitPackages: 0, procurementPackages: 0 }) const context = contextFor((method, path) => { assert.equal(new URL(`https://test.invalid${path}`).searchParams.has('inboundCode'), false) const match = path.match(/balances\/(1|2)(\/positions)?\?/) if (!match) return ok({ records: [{ ...source(shipped ? '99' : '1'), totalPackages: shipped ? 3 : 12, availablePackages: shipped ? 3 : 12 }], total: 1 }) const balance = source(match[1]) if (match[2]) return ok([{ ...balance, id: match[1] === '1' ? '11' : '12', balanceId: match[1], inboundCode: 'IN-A', totalPackages: shipped ? 0 : balance.totalPackages, availablePackages: shipped ? 0 : balance.availablePackages }]) return shipped ? { http: 404, body: { code: 'A0404' } } : ok(balance) }) const frozenSources = dispatchInventorySources(task, 'DS-1', 'WH-1') const frozenIds = frozenSources.sourceBalanceIds const before = await inventorySnapshot(context, '100', 'WH-1', ['IN-A'], 'before', frozenIds) assert.equal(inventorySourcesPresent(before, frozenSources.sourcePositionBalances), true) assert.equal(inventorySourcesPresent(before, [{ positionId: '11', balanceId: '2' }]), false) assert.equal(inventorySourcesPresent(before, [{ positionId: 'UNKNOWN', balanceId: '1' }]), false) assert.equal(before.reduce((sum, row) => sum + row.totalPackages, 0), 9) assert.equal(before.reduce((sum, row) => sum + row.balance.totalPackages, 0), 9) assert.equal(before[0].globalGroups[0].totalPackages, 12) shipped = true const after = await inventorySnapshot(context, '100', 'WH-1', ['IN-A'], 'after', frozenIds) assert.equal(inventorySourcesPresent(after, frozenSources.sourcePositionBalances), true) assert.equal(after.reduce((sum, row) => sum + row.totalPackages, 0), 0) assert.equal(after.reduce((sum, row) => sum + row.balance.totalPackages, 0), 0) assert.equal(after[0].globalGroups[0].totalPackages, 3) assert.deepEqual(after, await inventorySnapshot(context, '100', 'WH-1', ['IN-A'], 'replay', frozenIds)) assert.deepEqual(context.assertions.filter(row => !row.passed), []) }) test('source snapshot never treats unknown or incompletely proven raw 404 as zero inventory', async () => { const missing = { http: 404, body: { code: 'A0404' } } for (const mode of ['unknown', 'positions-failure', 'position-nonzero', 'group-not-decreased']) { let absent = false const fixture = inventoryFixture() fixture.balance.inTransitPackages = 0; fixture.balance.procurementPackages = 0 const context = contextFor((method, path) => { if (path.includes('/positions')) { if (absent && mode === 'positions-failure') return missing return ok(fixture.positions.map(row => absent && mode !== 'position-nonzero' ? { ...row, totalPackages: 0, availablePackages: 0 } : row)) } if (path.includes('/balances/1?')) return absent ? missing : ok(fixture.balance) return ok({ total: absent && mode !== 'group-not-decreased' ? 0 : 1, records: absent && mode !== 'group-not-decreased' ? [] : [fixture.balance] }) }) if (mode !== 'unknown') assert.ok(await inventorySnapshot(context, '100', 'WH-1', ['IN-A'], 'before', ['1'])) absent = true assert.equal(await inventorySnapshot(context, '100', 'WH-1', ['IN-A'], 'after', ['1']), null) assert.ok(context.assertions.some(row => !row.passed)) } const context = contextFor(() => { throw new Error('Missing fixed IDs cannot issue HTTP reads') }) assert.equal(await inventorySnapshot(context, '100', 'WH-1', ['IN-A'], 'stock'), null) }) function representativePalletConservationFixture() { const quantities = [1, 3, 1, 3, 1] const codes = ['IN-A', 'IN-A-OTHER', 'IN-B', 'IN-B-OTHER', 'IN-C'] const references = quantities.map((_, index) => ({ balanceId: String(index + 1), positionId: String(index + 11) })) const groups = packages => [{ id: 'GROUP', customerId: '100', overseasWarehouseId: 'WH-1', skuCode: 'MIXED', totalPackages: packages, availablePackages: packages, holdPackages: 0, allocatedPackages: 0, pickedPackages: 0, receivingPackages: 0, inTransitPackages: 0, procurementPackages: 0 }] const snapshot = after => quantities.map((quantity, index) => { const balanceId = String(index + 1) const position = { id: String(index + 11), balanceId, customerId: '100', overseasWarehouseId: 'WH-1', inboundCode: codes[index], palletNo: index < 2 ? 'P-A' : index < 4 ? 'P-B' : 'P-C', totalPackages: after ? 0 : quantity, availablePackages: after ? 0 : quantity, holdPackages: 0, allocatedPackages: 0, pickedPackages: 0, receivingPackages: 0 } const leftover = { ...position, id: '99', palletNo: 'UNSELECTED', totalPackages: 3, availablePackages: 3 } const positions = index === 4 ? [position, leftover] : [position] const exact = positions.filter(row => ['IN-A', 'IN-B', 'IN-C'].includes(row.inboundCode)) const total = positions.reduce((sum, row) => sum + row.totalPackages, 0) return { id: balanceId, totalPackages: exact.reduce((sum, row) => sum + row.totalPackages, 0), balance: { id: balanceId, totalPackages: total }, positions, globalGroups: groups(after ? 3 : 12) } }) const ledger = quantities.map((quantity, index) => ({ id: String(index + 101), customerId: '100', overseasWarehouseId: 'WH-1', businessType: 'SHIP', businessOrderNo: 'DS-1', outboundOrderNo: 'DS-1', inboundCode: codes[index], palletNo: index < 2 ? 'P-A' : index < 4 ? 'P-B' : 'P-C', beforePackages: quantity, deltaPackages: -quantity, afterPackages: 0 })) return { customerId: '100', warehouseId: 'WH-1', dispatchNo: 'DS-1', expectedPackages: 9, sourcePositionBalances: references, stockBefore: snapshot(false), stockAfter: snapshot(true), ledgerBefore: [], ledgerAfter: ledger } } test('G05 MIN inbound-code display does not filter real same-pallet sources: positions9→0/raw12→3/groups12→3/SHIP-9', () => { const fixture = representativePalletConservationFixture() const context = contextFor(() => { throw new Error('Offline arithmetic cannot issue HTTP') }) context.createdResources.phase5OverseasFulfillment = { inventoryProof: {} } assert.equal(fixture.stockBefore.reduce((sum, row) => sum + row.totalPackages, 0), 6) assert.equal(fixture.stockAfter.reduce((sum, row) => sum + row.totalPackages, 0), 3) const result = dispatchStockConservation(context, fixture) assert.equal(result.passed, true) assert.deepEqual(result.proof.totals, { positionBefore: 9, positionAfter: 0, rawBefore: 12, rawAfter: 3, groupBefore: 12, groupAfter: 3, ledgerShipped: 9, expectedPackages: 9 }) assert.equal(result.proof.ledgerRowChecks.length, 5) assert.deepEqual(context.assertions.filter(row => !row.passed), []) const saved = context.createdResources.phase5OverseasFulfillment.inventoryProof assert.deepEqual(saved.snapshots.beforePick, fixture.stockBefore) assert.deepEqual(saved.ledgers.afterPick, fixture.ledgerAfter) assert.ok(JSON.stringify(saved).includes('IN-A-OTHER')) assert.doesNotMatch(JSON.stringify(saved), /password|accessToken|Bearer|base64/) }) test('G05 failures still independently review and preserve raw, group, each SHIP quantity/source, and unselected positions', () => { for (const mutate of [ fixture => { fixture.stockAfter[0].positions[0].id = 'WRONG-POSITION' }, fixture => { fixture.stockAfter[0].balance.totalPackages = 1 }, fixture => { for (const row of fixture.stockAfter) row.globalGroups[0].totalPackages = 4 }, fixture => { fixture.ledgerAfter[0].deltaPackages = -2 }, fixture => { fixture.ledgerAfter[0].customerId = 'OTHER' }, fixture => { fixture.ledgerAfter[0].overseasWarehouseId = 'OTHER' }, fixture => { fixture.ledgerAfter[0].outboundOrderNo = 'OTHER' }, fixture => { fixture.ledgerAfter[0].palletNo = 'UNSELECTED' }, fixture => { fixture.stockAfter[4].positions[1].availablePackages = 2 }, ]) { const fixture = representativePalletConservationFixture(); mutate(fixture) const context = contextFor(() => { throw new Error('Offline only') }) context.createdResources.phase5OverseasFulfillment = { inventoryProof: {} } const result = dispatchStockConservation(context, fixture) assert.equal(result.passed, false) assert.equal(context.assertions.length, 9) assert.equal(Object.keys(result.proof.checks).length, 8) assert.equal(result.proof.ledgerRowChecks.length, 5) assert.deepEqual(context.createdResources.phase5OverseasFulfillment.inventoryProof.snapshots.afterPick, fixture.stockAfter) assert.deepEqual(context.createdResources.phase5OverseasFulfillment.inventoryProof.ledgers.afterPick, fixture.ledgerAfter) } }) function rootCompletionFixture({ childStatus = 'PROCESSING', rootStatus = 'PROCESSING', rootDelivered = true, fullyLoaded = false, mainStatus = rootStatus === 'COMPLETED' ? 'COMPLETED' : 'DELIVERED', sourceOrderId = '1001' } = {}) { const root = { order: { id: '1001', tenantId: '100', customerId: '100', orderRole: 'MASTER', rootOrderId: '1001', orderNo: 'FL1001', status: rootStatus }, statusHistory: [ ...(rootDelivered ? [{ action: 'OVERSEAS_DELIVERED' }] : []), ...(rootStatus === 'COMPLETED' ? [{ action: 'FULFILLMENT_COMPLETED' }] : [])] } const child = { order: { id: '1002', tenantId: '100', customerId: '100', orderRole: 'CHILD', rootOrderId: '1001', parentOrderId: '1001', orderNo: 'FL1001-1', status: childStatus } } const tree = { parentOrderId: '1001', parentOrderNo: 'FL1001', originalPackageCount: 4, cumulativeLoadedPackageCount: fullyLoaded ? 4 : 1, currentRemainderPackageCount: fullyLoaded ? 0 : 3, children: [{ orderId: '1001', orderNo: 'FL1001', splitRole: 'LOADED', sourceOrderId: '1001', packageCount: 1 }, { orderId: '1002', orderNo: 'FL1001-1', splitRole: 'REMAINDER', sourceOrderId: '1001', packageCount: 3 }, ...(fullyLoaded ? [{ orderId: '1002', orderNo: 'FL1001-1', splitRole: 'LOADED', sourceOrderId: '1002', packageCount: 3 }] : [])] } const context = contextFor((method, path) => { if (path.includes('/fulfillment-tree')) return ok(tree) if (path.includes('/first-leg/1002')) return ok(child) if (path.includes('/first-leg/1001')) return ok(root) return ok({ summary: { orderId: '1001', mainStatus } }) }) context.createdResources.phase5OverseasFulfillment = {} return { root, child, tree, context, args: { sourceOrderId, customerId: '100', merchantToken: 'ONLY-IN-MEMORY', pollAttempts: 1, pollIntervalMs: 0 } } } test('real root1 signed plus effective remainder3 keeps raw PROCESSING and both platform/client DELIVERED', async () => { const fixture = rootCompletionFixture() const result = await verifyFulfillmentRootStatus(fixture.context, fixture.args) assert.equal(result.passed, true) assert.equal(result.expectedCompleted, false) assert.deepEqual(result.pendingChildren.map(row => row.orderId), ['1002']) assert.deepEqual(fixture.context.assertions.filter(row => !row.passed), []) const proof = fixture.context.createdResources.phase5OverseasFulfillment.orderCompletionProof assert.equal(proof.tree.originalPackageCount, 4) assert.equal(proof.tree.currentRemainderPackageCount, 3) assert.deepEqual(proof.pendingChildOrderIds, ['1002']) assert.doesNotMatch(JSON.stringify(proof), /ONLY-IN-MEMORY|password|accessToken|Bearer/) }) test('missing, foreign, unknown or omitted real child cannot be treated as all fulfillment completed', async () => { for (const mutate of [ fixture => { fixture.child.order = null }, fixture => { fixture.child.order.customerId = 'FOREIGN' }, fixture => { fixture.child.order.rootOrderId = 'OTHER' }, fixture => { fixture.child.order.parentOrderId = 'OTHER' }, fixture => { fixture.child.order.orderNo = 'WRONG' }, fixture => { fixture.child.order.status = undefined }, fixture => { fixture.child.order.status = 'UNKNOWN' }, fixture => { fixture.tree.children.pop() }, fixture => { fixture.tree.children = undefined }, ]) { const fixture = rootCompletionFixture(); mutate(fixture) assert.equal(await verifyFulfillmentRootStatus(fixture.context, fixture.args), null) assert.ok(fixture.context.assertions.some(row => !row.passed)) assert.equal(fixture.context.calls.some(call => call.path.startsWith('/api/merchant/')), false) } }) test('draft, rejected and pending child stay effective, and a premature root COMPLETED still fails', async () => { for (const childStatus of ['DRAFT', 'SUBMITTED', 'APPROVED', 'ACCEPTED', 'REJECTED', 'PROCESSING']) { const fixture = rootCompletionFixture({ childStatus, rootStatus: 'COMPLETED' }) const result = await verifyFulfillmentRootStatus(fixture.context, fixture.args) assert.equal(result.expectedCompleted, false) assert.equal(result.passed, false) assert.equal(result.pendingChildren.length, 1) assert.ok(fixture.context.assertions.some(row => !row.passed)) } }) test('actual completed child or explicit CANCELLED permits completion only with root own receipt and raw completion fact', async () => { for (const childStatus of ['COMPLETED', 'CANCELLED']) { const fixture = rootCompletionFixture({ childStatus, rootStatus: 'COMPLETED', fullyLoaded: childStatus === 'COMPLETED' }) const result = await verifyFulfillmentRootStatus(fixture.context, fixture.args) assert.equal(result.expectedCompleted, true) assert.equal(result.passed, true) assert.deepEqual(result.pendingChildren, []) assert.deepEqual(fixture.context.assertions.filter(row => !row.passed), []) } const fixture = rootCompletionFixture({ childStatus: 'COMPLETED', fullyLoaded: true, rootDelivered: false }) const result = await verifyFulfillmentRootStatus(fixture.context, fixture.args) assert.equal(result.expectedCompleted, false) assert.equal(result.passed, true) }) test('receipt of a real child resolves and checks its owning root instead of completing the child as the aggregate', async () => { const fixture = rootCompletionFixture({ childStatus: 'COMPLETED', rootStatus: 'COMPLETED', fullyLoaded: true, sourceOrderId: '1002' }) const result = await verifyFulfillmentRootStatus(fixture.context, fixture.args) assert.equal(result.rootOrderId, '1001') assert.equal(result.passed, true) assert.ok(fixture.context.calls.some(call => call.path === '/api/merchant/v1/orders/1001')) assert.equal(fixture.context.calls.some(call => call.path === '/api/merchant/v1/orders/1002'), false) }) test('all fragments completed still requires raw aggregate history and matching platform/customer completion', async () => { const missingHistory = rootCompletionFixture({ childStatus: 'COMPLETED', rootStatus: 'COMPLETED', fullyLoaded: true }) missingHistory.root.statusHistory = [{ action: 'OVERSEAS_DELIVERED' }] assert.equal((await verifyFulfillmentRootStatus(missingHistory.context, missingHistory.args)).passed, false) const notProjected = rootCompletionFixture({ childStatus: 'COMPLETED', rootStatus: 'COMPLETED', fullyLoaded: true, mainStatus: 'DELIVERED' }) assert.equal((await verifyFulfillmentRootStatus(notProjected.context, notProjected.args)).passed, false) const foreignProjection = rootCompletionFixture({ childStatus: 'COMPLETED', rootStatus: 'COMPLETED', fullyLoaded: true }) const originalRequest = foreignProjection.context.request foreignProjection.context.request = async (...args) => args[1].startsWith('/api/merchant/') ? ok({ summary: { orderId: '1002', mainStatus: 'COMPLETED' } }) : originalRequest(...args) assert.equal((await verifyFulfillmentRootStatus(foreignProjection.context, foreignProjection.args)).passed, false) }) test('native PDA scans use exact current versions including zero, immutable replay and stale-version rejection without implicit loading', async () => { const values = ['0', '9007199254740993', '9007199254740994'] let currentVersion = values[0], picked = 0, firstBody, firstResult const context = contextFor((method, path, body) => { if (method === 'GET') return ok({ dispatchNo: 'DS-1', status: 'ACTIVE', stage: 'LOADING', recordVersion: currentVersion, pickingReconciled: picked === 2, counts: { packageCount: 2, pickedPackageCount: picked }, items: [{ dispatchItemId: '9007199254740995', customerId: '100', scheduledPackages: 2, pickedPackages: picked, positions: [{ positionId: '9007199254740996', balanceId: '9007199254740997', availablePackages: 1 }, { positionId: '9007199254740998', balanceId: '9007199254740999', availablePackages: 1 }] }] }) assert.match(path, /items\/9007199254740995\/pick$/) assert.equal(Object.hasOwn(body, 'expectedVersion'), false) assert.equal(typeof body.positionId, 'string') if (body.idempotencyKey.endsWith('-STALE')) { assert.equal(body.recordVersion, '0'); return { http: 200, body: { code: 'A0409' } } } if (firstBody?.idempotencyKey === body.idempotencyKey) { assert.deepEqual(body, firstBody); return ok({ ...firstResult, replayed: true }) } assert.equal(body.recordVersion, currentVersion) picked += 1; currentVersion = values[picked] firstBody = structuredClone(body) firstResult = { dispatchNo: 'DS-1', status: 'ACTIVE', stage: 'LOADING', recordVersion: currentVersion, result: { dispatchItemId: '9007199254740995', pickedPackages: picked }, counts: { pickedPackageCount: picked } } return ok(firstResult) }) assert.equal(await pickAll(context, 'PDA-IN-MEMORY', 'DS-1'), true) assert.equal(picked, 2) assert.equal(context.calls.some(call => /loading-complete|\/complete|\/depart/.test(call.path)), false) assert.deepEqual(context.assertions.filter(row => !row.passed), []) }) test('normal relabel scans each original carton using explicit ten-unit SKU verification and actual shared position', async () => { const values = ['0', '9007199254740993', '9007199254740994'] let currentVersion = values[0], picked = 0, firstBody, firstResult const context = contextFor((method, path, body) => { if (path.includes('/relabel-applications/')) return ok({ application: { relabelNo: 'TB-1', overseasWarehouseId: '42' }, items: [1, 2].map(n => ({ cartonMark: 'BOX-' + n, sourceInventoryPositionId: '9007199254740996', notifiedPackageCount: 1, operationType: 'CARTON_AND_SKU', skuItems: [{ skuCode: 'OLD', newSkuCode: 'NEW', quantity: 10 }] })) }) if (method === 'GET') return ok({ dispatchNo: 'DS-1', status: 'ACTIVE', stage: 'LOADING', recordVersion: currentVersion, pickingReconciled: picked === 2, counts: { packageCount: 2, pickedPackageCount: picked }, items: [{ dispatchItemId: '9007199254740995', customerId: '100', sourceBusinessType: 'RELABEL_ORDER', sourceBusinessNo: 'TB-1', scheduledPackages: 2, pickedPackages: picked, positions: [{ positionId: '9007199254740996', balanceId: '9007199254740997', availablePackages: 2 - picked }] }] }) assert.match(path, /items\/9007199254740995\/pick$/) assert.equal(Object.hasOwn(body, 'expectedVersion'), false) assert.equal(typeof body.positionId, 'string') if (body.idempotencyKey.endsWith('-STALE')) { assert.equal(body.recordVersion, '0'); return { http: 200, body: { code: 'A0409' } } } if (firstBody?.idempotencyKey === body.idempotencyKey) { assert.deepEqual(body, firstBody); return ok({ ...firstResult, replayed: true }) } assert.equal(body.recordVersion, currentVersion); assert.equal(body.packages, 1); assert.equal(body.productQuantity, 10); assert.equal(body.cartonMark, 'BOX-' + (picked + 1)) picked += 1; currentVersion = values[picked] firstBody = structuredClone(body) firstResult = { dispatchNo: 'DS-1', status: 'ACTIVE', stage: 'LOADING', recordVersion: currentVersion, result: { dispatchItemId: '9007199254740995', pickedPackages: picked }, counts: { pickedPackageCount: picked } } return ok(firstResult) }) context.createdResources.phase4OverseasRelabel = { marker: context.marker, relabelNo: 'TB-1', customerId: '100', overseasWarehouseId: '42' } assert.equal(await pickAll(context, 'PDA-IN-MEMORY', 'DS-1'), true) assert.equal(picked, 2) assert.equal(context.calls.some(call => /loading-complete|\/complete|\/depart/.test(call.path)), false) assert.deepEqual(context.assertions.filter(row => !row.passed), []) }) function automaticDispatch(recordVersion = '0') { return { dispatchNo: 'DS-1', recordVersion, status: 'ACTIVE', stage: 'DELIVERING', pickingReconciled: true, counts: { packageCount: 2, pickedPackageCount: 2, shippedPackageCount: 2 }, documents: { outbounds: ['100', '200'].map(customerId => ({ customerId, outboundNo: `OB-${customerId}`, status: 'OUTBOUNDED', packageCount: 1 })), deliveries: ['100', '200'].map(customerId => ({ customerId, outboundNo: `OB-${customerId}`, deliveryNo: `DL-${customerId}`, destination: { key: 'FBA:ONT8' }, status: 'DELIVERING', packageCount: 1 })) } } } test('automatic delivery reader preserves customer grouping and performs no writes', async () => { for (const recordVersion of ['0', '9007199254740993']) { const current = automaticDispatch(recordVersion) const context = contextFor((method, path) => { assert.equal(method, 'GET'); assert.ok(path.endsWith('/DS-1')); return ok(current) }) const result = await readAutomaticDispatchDelivery(context, 'DS-1') assert.equal(result.data.recordVersion, recordVersion) assert.deepEqual(result.outbounds.map(row => row.outboundNo), ['OB-100', 'OB-200']) assert.equal(context.calls.length, 1) } }) test('automatic delivery reader rejects incomplete departure and customer or quantity drift', async () => { for (const mutate of [v => { v.stage = 'AFTER_LOADING' }, v => { v.status = 'CANCELLED' }, v => { v.documents.deliveries[0].customerId = '999' }, v => { v.documents.outbounds[0].packageCount = 2 }, v => { v.documents.deliveries = [] }, v => { v.documents.deliveries[1].deliveryNo = 'DL-100' }, v => { v.counts.shippedPackageCount = 1 }, v => { v.documents.outbounds[0].status = 'WAIT_OUTBOUND' }]) { const current = automaticDispatch(); mutate(current) const context = contextFor(method => { assert.equal(method, 'GET'); return ok(current) }) assert.equal(await readAutomaticDispatchDelivery(context, 'DS-1'), null) assert.ok(context.assertions.some(row => !row.passed)) } }) test('automatic delivery cannot hide duplicated customer or destination groups behind conserved totals', async () => { for (const sameOutbound of [false, true]) { const current = automaticDispatch() current.documents.outbounds[1].customerId = '100' current.documents.deliveries[1].customerId = '100' if (sameOutbound) { current.documents.outbounds.pop() current.documents.outbounds[0].packageCount = 2 current.documents.deliveries[1].outboundNo = 'OB-100' } else current.documents.deliveries[1].destination.key = 'FBA:ONT9' const context = contextFor(method => { assert.equal(method, 'GET'); return ok(current) }) assert.equal(await readAutomaticDispatchDelivery(context, 'DS-1'), null) } }) test('automatic delivery accepts canonical Long quantities and rejects coercible non-quantities', async () => { for (const quantity of ['1', true, '01', '1e0', ' 1 ', '9007199254740993']) { const current = automaticDispatch() current.documents.deliveries[0].packageCount = quantity const context = contextFor(method => { assert.equal(method, 'GET'); return ok(current) }) assert.equal(Boolean(await readAutomaticDispatchDelivery(context, 'DS-1')), quantity === '1') } }) for (const [name, outcome] of [ ['transport', { http: 0, body: { code: '' } }], ['infrastructure', { http: 503, body: { code: 'S0503' } }], ['malformed success', { http: 200, body: { code: '200', data: null } }], ['missing business response', { http: 200, body: {} }], ]) test(`write intent persists and ${name} stops commands and checkpoint restarts`, async () => { const dir = await mkdtemp(join(tmpdir(), 'phase5-contract-')) try { const context = contextFor(async (method, path, body) => { const saved = JSON.parse(await readFile(context.createdResources.phase5OverseasFulfillment.checkpointPath, 'utf8')) assert.equal(saved.requests.at(-1).status, 'SENDING') assert.equal(saved.requests.at(-1).body.recordVersion, '0') assert.equal(saved.requests.at(-1).body.idempotencyKey, body.idempotencyKey) assert.equal(JSON.stringify(saved).includes('SECRET-CREDENTIAL'), false) return { ...outcome, requestId: 'REQ-UNKNOWN', traceId: 'TRACE-UNKNOWN' } }) context.options.output = join(dir, 'report.json') context.createdResources.phase5OverseasFulfillment = {} const scoped = await fulfillmentEvidenceContext(context) const body = { recordVersion: '0', idempotencyKey: 'ORIGINAL-COMMAND', password: 'SECRET-CREDENTIAL' } await assert.rejects(scoped.request('POST', '/api/platform/v1/last-leg/dispatches/DS-1/depart', body), /结果未知/) await assert.rejects(scoped.request('POST', '/api/platform/v1/last-leg/dispatches/DS-1/depart', { ...body, idempotencyKey: 'NEW-KEY' }), /未知写结果/) assert.equal(context.calls.length, 1) const saved = JSON.parse(await readFile(context.createdResources.phase5OverseasFulfillment.checkpointPath, 'utf8')) assert.equal(saved.status, 'UNKNOWN'); assert.equal(saved.requests[0].status, 'UNKNOWN') assert.equal(saved.requests[0].requestId, 'REQ-UNKNOWN') await assert.rejects(fulfillmentEvidenceContext(context), /已存在本轮履约检查点/) } finally { await rm(dir, { recursive: true, force: true }) } }) test('default normal completion returns before exception writes; explicit legacy return stays after its original receipt guards and before closure', () => { const run = source.slice(source.indexOf('export async function run')) const start = run.indexOf('if (context.context?.phase5TailVerification?.runReturnScenario !== true)') const exception = run.indexOf('const manualExceptionBody') assert.ok(start > run.indexOf("savedVisit.data?.visit?.status !== 'COMPLETED'")) const normalBranch = run.slice(start, exception) assert.ok(normalBranch.includes("finalStatus = 'DELIVERED_WITH_COMPLETED_VISIT'")) assert.match(normalBranch, /await finishFleetTrip/) assert.match(normalBranch, /return\s*}/) assert.doesNotMatch(normalBranch, /createDeliveryReturn|completeReturnedException|exception-orders|mark-return/) const explicitBranch = run.slice(exception) assert.ok(explicitBranch.indexOf('const returnReceipt = await completeReturnedException') < explicitBranch.indexOf('await finishFleetTrip')) assert.match(source, /const sourceBalanceIds = owned.inventoryProof\?.sourceBalanceIds/) assert.match(source, /原returnSource位置必须存在于正式排车冻结真实余额中/) })