import test from 'node:test' import assert from 'node:assert/strict' import { readFile } from 'node:fs/promises' import { fileURLToPath } from 'node:url' import { dispatchBusinessSnapshot } from './phase4-overseas-dispatch.mjs' const moduleUrl = new URL('./phase4-overseas-dispatch.mjs', import.meta.url) const source = await readFile(fileURLToPath(moduleUrl), 'utf8') test('phase4 overseas dispatch module freezes only stable platform query and smart pre-arrange paths', () => { for (const token of [ "const BASE = '/api/platform/v1/last-leg/dispatches'", "query(BASE, { page: 1, size: 20 })", '`${BASE}/candidates`', '`${BASE}/drafts`', '`${BASE}/drafts/snapshot`', '`${BASE}/draft-locks/lock`', '`${BASE}/pre-arrange`', '`${BASE}/draft-locks/release`', '`${BASE}/${encodeURIComponent(dispatchNo)}`', ]) assert.match(source, new RegExp(token.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))) for (const forbidden of ['/api/pda/', '/outbound', '/delivery', '/depart', '/cancel']) { assert.equal(source.includes(forbidden), false, `must exclude ${forbidden}`) } }) test('module uses marker-owned completed PDA pallets and never borrows historical candidates', () => { assert.match(source, /fixture\?\.marker !== context\.marker/) assert.match(source, /fixture\?\.finalStatus !== 'COMPLETED'/) assert.match(source, /fixture\.palletIds\.has\(id\(value\?\.warehousePalletId\)\)/) assert.match(source, /id\(value\?\.overseasWarehouseId\) === id\(fixture\.overseasWarehouseId\)/) assert.doesNotMatch(source, /candidates\[0\]/) }) test('ordinary dispatch selects one current-run pallet per destination for multi-FBA delivery proof', () => { assert.match(source, /const candidatesByDestination = new Map\(\)/) assert.match(source, /destinationWarehouseCode \|\| value\?\.fbaWarehouseCode/) assert.match(source, /selectedCandidates\.length >= 2/) assert.match(source, /planPalletIds, route: `\$\{context\.marker\}-ROUTE`/) assert.match(source, /Number\(arranged\.data\?\.palletCount\) === planPalletIds\.length/) }) test('module proves draft idempotency, lock isolation, editable pre-arrange replay and readback', () => { assert.match(source, /相同草稿快照重复保存/) assert.match(source, /同草稿重复锁定托盘幂等成功/) assert.match(source, /其他草稿锁定同一托盘返回A0409/) assert.match(source, /出库前同草稿重复预排复用原排车且业务快照不漂移/) assert.match(source, /重复释放草稿幂等成功/) assert.match(source, /排车详情按记录自身客户范围加载托盘明细/) assert.match(source, /response\?\.http === 409.*codeOf\(response\) === 'A0409'/s) }) test('module does not invent optimistic version or idempotency headers absent from DispatchRequests', () => { assert.doesNotMatch(source, /expectedVersion|recordVersion|Idempotency-Key/) assert.match(source, /PENDING_DEPARTURE/) assert.match(source, /data == null/) }) test('module records the marker-owned dispatch without attempting excluded cleanup actions', () => { assert.match(source, /createdResources\.phase4OverseasDispatch/) assert.match(source, /dispatchNo = dispatchNo/) assert.match(source, /finalStatus = arranged\.data\?\.status/) assert.match(source, /PENDING_DEPARTURE dispatch is retained as marker-owned acceptance evidence/) }) test('module prefers marker-owned relabel pallets and proves only new FBA carton marks are frozen', () => { assert.match(source, /phase4OverseasRelabel/) assert.match(source, /sourceStage === 'RELABEL'/) assert.match(source, /relabel\.targetPalletIds\.includes/) assert.match(source, /relabelCartonMarks/) assert.match(source, /!String\(value\?\.cartonMarks \|\| ''\)\.trim\(\)/) assert.match(source, /relabelNo: relabel\.relabelNo/) }) test('relabel settlement follows pre-arrange and does not replace the ordinary dispatch lifecycle', () => { assert.match(source, /await runRelabelDispatch\(context, relabel\)[\s\S]*if \(relabel.dispatchNo\) await settleRelabelFulfillment\(context, relabel\)/) const branch = source.slice(source.indexOf('const relabel = context.createdResources'), source.indexOf('const fixture = markerFixture(context)', source.indexOf('const relabel = context.createdResources'))) assert.doesNotMatch(branch, /\breturn\b/) assert.match(source, /Object.assign\(relabel, \{/) }) test('dispatch replay snapshot ignores regenerated item ids but detects business drift', () => { const a = { id: '1', dispatchNo: 'DS-1', status: 'PENDING_DEPARTURE', packageCount: 2, palletCount: 1, items: [{ id: '10', planPalletId: '20', warehousePalletId: '30', packageCount: 2 }] } const replay = { ...a, items: [{ ...a.items[0], id: '11' }] } assert.equal(dispatchBusinessSnapshot(a), dispatchBusinessSnapshot(replay)) for (const changed of [{ ...replay, id: '2' }, { ...replay, packageCount: 4 }, { ...replay, items: [{ ...a.items[0], warehousePalletId: '31' }] }]) { assert.notEqual(dispatchBusinessSnapshot(a), dispatchBusinessSnapshot(changed)) } assert.doesNotMatch(source, /item\?\.cartonMarks/) })