import test from 'node:test' import { relabelOutboundMarksMatch } from './phase5-overseas-fulfillment.mjs' import assert from 'node:assert/strict' import { readFile } from 'node:fs/promises' 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') const entry = await readFile(fileURLToPath(new URL('../admin-test-env-acceptance.mjs', import.meta.url)), 'utf8') 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'\]/) 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']) { assert.ok(modules.indexOf(prerequisite) >= 0 && modules.indexOf(prerequisite) < modules.indexOf('phase5-overseas-fulfillment'), prerequisite) } }) test('phase-five module covers dispatch edit, transfer, PDA pick/depart and delivery state', () => { for (const token of [ "const DISPATCH_BASE = '/api/platform/v1/last-leg/dispatches'", "const PDA_DISPATCH_BASE = '/api/pda/v1/last-leg/dispatches'", 'query(MERCHANT_DELIVERY_BASE, { dispatchNo })', '/items/${encodeURIComponent(id(item.dispatchItemId))}/pick', '/complete`', '/depart`', '/outbound-orders/${encodeURIComponent(outboundNo)}', '/delivery-orders/${encodeURIComponent(currentNo)}/status', ]) assert.ok(source.includes(token), token) assert.match(source, /WAIT_OUTBOUND/) assert.match(source, /WAIT_DELIVERY/) assert.match(source, /READY_TO_DEPART/) assert.match(source, /OUTBOUNDED/) assert.match(source, /DELIVERING/) assert.match(source, /expectedVersion: deliveryVersion/) assert.match(source, /transferDeliveries\(transferred\.data\)/) assert.match(source, /new Set\(destinationKeys\)\.size === deliveries\.length/) assert.match(source, /deliveries\.reduce\(\(sum, value\) => sum \+ Number\(value\?\.packageCount \|\| 0\), 0\)/) }) test('phase-five module proves the client delivery create, list and nested detail contract', () => { assert.match(source, /const MERCHANT_DELIVERY_BASE = '\/api\/merchant\/v1\/last-leg\/delivery-orders'/) assert.match(source, /loginMerchant\(context, customerId\)/) assert.match(source, /context\.options\?\.merchantUsername/) assert.match(source, /\/api\/merchant\/v1\/iam\/tenant\/profile/) assert.match(source, /id\(profile\?\.id\) === customerId/) assert.match(source, /客户创建派送并原子转出库单/) assert.match(source, /deliveryMethod: 'TRUCK_PALLET'/) assert.match(source, /fees: \[\{ feeType: 'DELIVERY_FEE', feeName: '派送费', direction: 'RECEIVABLE',\s*currency: 'USD', amount: 10/) 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/) }) test('phase-five module proves receipt-save completion, cross-region convergence, customer visit, exception and return', () => { for (const token of [ '/documents/RECEIPT/files', 'requestOverseasMultipart', "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', 'returnInbound?.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, /\/api\/platform\/v1\/orders\/\$\{encodeURIComponent\(sourceOrderId\)\}/) 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, 'TRANSFER'\)/) assert.match(source, /idempotencyKey: key\(context, 'DISPATCH-PICK'/) assert.match(source, /idempotencyKey: key\(context, 'DISPATCH-COMPLETE'\)/) assert.match(source, /idempotencyKey: key\(context, '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, /detail\.data\?\.outbound\?\.dispatchNo === relabel\.dispatchNo/) assert.match(source, /relabel\?\.marker !== context\.marker/) })