import test from 'node:test' import assert from 'node:assert/strict' import { readFile } from 'node:fs/promises' import { parseArguments } from '../admin-test-env-acceptance.mjs' import { verifyWarehouseTransferReview } from './warehouse-transfer-review.mjs' const read = name => readFile(new URL(name, import.meta.url), 'utf8') test('merged scenarios remain in default and focused dependency chains', () => { const defaults = parseArguments([]).modules for (const module of ['phase4-overseas-client-services', 'phase4-overseas-dispatch', 'phase5-overseas-fulfillment']) { assert.ok(defaults.includes(module)) const focused = parseArguments(['--modules', module]).modules assert.ok(focused.indexOf('merchant-qualification-fixture') >= 0) assert.ok(focused.indexOf('phase4-overseas-pda-operations') < focused.indexOf(module)) } }) test('review helper refuses stale fixture before any request', async () => { const steps = [] await verifyWarehouseTransferReview({ marker: 'current', context: { merchantQualificationFixture: { marker: 'old' } }, addStep: (...args) => steps.push(args), requestOverseas: () => { throw Error('must not request') } }, 'token', '123', {}, 'T1') assert.equal(steps.length, 1) assert.equal(steps[0][3], false) assert.equal(steps[0][5].deploymentBlocker, true) }) test('transfer review integration covers both source types and known blank-reason failure', async () => { const source = await read('warehouse-transfer-review.mjs') const caller = await read('phase4-overseas-client-services.mjs') assert.match(caller, /return verifyWarehouseTransferReview\(context, token, order.row.customerId, body, transferNo\)/) for (const value of ['WAIT_PDA_RECEIVING', 'PENDING_ASSIGNMENT', 'WAIT_DELIVERY', 'CANCELLED', 'REJECTED', 'APPROVED', 'customerId=', 'rejected(denied, 403)', 'rejected(missingScope, 400)', 'rejected(reverse, 409)', 'rejected(emptyReason, 400)', "sourceLastlegOrderIds: []"]) assert.ok(source.includes(value), value) assert.doesNotMatch(source, /fetch\(|mysql|process\.env|\/internal\//) const controller = await read('../../lastleg-service/src/main/java/com/baiyue/lastleg/transfer/controller/WarehouseTransferController.java') assert.match(controller, /WAREHOUSE_TRANSFER_APPROVE/) }) test('draft and removal checks use actual IDs plus readback rather than snapshot-only success', async () => { const source = await read('phase4-overseas-dispatch.mjs') for (const value of ['drafts/containers', 'draftContainerId: containerId', 'container.palletIds', 'draft-locks/unlock', 'deletedDrafts', 'removableItem.id', 'removedDetail.data?.packageCount', 'freed.data.some']) assert.ok(source.includes(value), value) }) test('fulfillment checks PDF signature, platform replay and immutable pallets after transfer', async () => { const source = await read('phase5-overseas-fulfillment.mjs') for (const value of ['requestOverseasBinary', '/prints/bol', "=== '%PDF-'", '/transfer-delivery', 'adminReplay.data?.replayed', 'conflict(deniedRemove)', 'stable.data?.items?.map']) assert.ok(source.includes(value), value) }) test('return merge sources are actual consumed batches, not a synthetic MERGED identifier', async () => { const source = await read('phase4-overseas-return-receipt.mjs') assert.doesNotMatch(source, /sourceBatchNo === 'MERGED'/) for (const value of ['consumedBatches', 'new Set(actualBatches)', 'sourceReturnNo === returnNo', '客户箱号管理按实物箱分页', '标签包含SVG条码和当前箱号']) assert.ok(source.includes(value), value) })