diff --git a/scripts/admin-test-env-acceptance.mjs b/scripts/admin-test-env-acceptance.mjs index d7995a53b..6fe8976f8 100644 --- a/scripts/admin-test-env-acceptance.mjs +++ b/scripts/admin-test-env-acceptance.mjs @@ -459,6 +459,7 @@ export function parseArguments(argv) { waitSplitRandomValue: Number(values.get('wait-split-random-value') || values.get('wait-split-sequence') || 1), prepareDropshipManualCount: values.get('prepare-dropship-manual-count') === 'true', prepareMeasurementReview: values.get('prepare-measurement-review') === 'true', + verifyNonIsoContainer: values.get('verify-non-iso-container') === 'true', verifyPalletLocationGuide: values.has('verify-pallet-location-guide'), routeMode: values.get('route-mode') || 'fixed', quiet: values.get('quiet') === 'true', @@ -495,6 +496,11 @@ export function validateExecutionOptions(options) { if (options.environment && !['test', 'gray'].includes(options.environment)) throw new Error('Only test or explicit gray acceptance is supported') if (options.f40TaxMode && !['BUY_DECLARATION', 'TAX_REFUND'].includes(options.f40TaxMode)) throw new Error('f40-tax-mode 必须为 BUY_DECLARATION 或 TAX_REFUND') if (options.prepareDomesticPdaH5 && (options.requestedModules?.length !== 1 || options.requestedModules[0] !== 'phase5-root-fulfillment')) throw new Error('prepare-domestic-pda-h5 仅允许单独指定 phase5-root-fulfillment') + if (options.verifyNonIsoContainer && (options.environment !== 'test' + || options.requestedModules?.length !== 1 || options.requestedModules[0] !== 'phase3-container-loading' + || options.verifyPalletLocationGuide)) { + throw new Error('verify-non-iso-container 仅允许 TEST 单独柜号链,不能混用库位块删除探针') + } if (options.prepareMeasurementReview && (options.environment !== 'test' || options.requestedModules?.length !== 1 || options.requestedModules[0] !== 'inbound-measurement' || options.waitSplitCount !== 1 || options.prepareDomesticPdaH5 || options.prepareDropshipManualCount)) { diff --git a/scripts/admin-test-env-modules/README.md b/scripts/admin-test-env-modules/README.md index 18941ad47..ec8ed97e4 100644 --- a/scripts/admin-test-env-modules/README.md +++ b/scripts/admin-test-env-modules/README.md @@ -451,7 +451,7 @@ plan/item 版本、分配箱数及总数投影全部零漂移。脚本不从当 `phase3-pda-convergence` 同时回查 `/tasks/pending` 与稳定 task detail:两者的 `workflowStatus`、`itemCount`、`pendingItemCount` 必须来自同一任务明细事实。全拣任务必须在两处均为 `AWAITING_REVIEW`,可执行证据 GET,但派生 `actions=[]`,不得重复发送 batch;操作历史必须恰有一次有效 `BATCH`。若 pending 仍按 assignment 返回 `IN_PROGRESS`,该轮以真实 HTTP 失败阻断,不由脚本或前端改写状态。 -`phase3-container-loading` 使用非 ISO 柜号 `JZXH10231043` 验证关联与预装确认,PDA 领取前再纠正为本轮 `TEST-…-NOISO` 柜号,继续完成拣货、五类合成装柜证据及装柜完成,保留空号拒绝和作业后禁改校验;不修改既有实际作业单。跨服务接收须按本轮来源柜及最终柜号另行回查,不能仅凭 PDA 完成视为海外消费通过。 +`phase3-container-loading` 使用非 ISO 柜号 `JZXH10231043` 验证关联与预装确认,PDA 领取前再纠正为本轮 `TEST-…-NOISO` 柜号,继续完成拣货、五类合成装柜证据及装柜完成,保留空号拒绝和作业后禁改校验;不修改既有实际作业单。仅验证柜号链时,从总入口使用 `--modules phase3-container-loading --verify-non-iso-container true`,跳过跨渠道旁路分配和移除并明确记录该覆盖缺口;不添加整票库位块删除探针。跨服务接收须按本轮来源柜及最终柜号另行回查,不能仅凭 PDA 完成视为海外消费通过。 部署后需要定向验证该完整链时,模块顺序固定为: diff --git a/scripts/admin-test-env-modules/phase3-container-loading.mjs b/scripts/admin-test-env-modules/phase3-container-loading.mjs index ce2648956..fe96cd333 100644 --- a/scripts/admin-test-env-modules/phase3-container-loading.mjs +++ b/scripts/admin-test-env-modules/phase3-container-loading.mjs @@ -238,7 +238,10 @@ export async function run(context) { const channelIsolation = selectPlatformChannelIsolationPair( context.createdResources?.platformLogisticsChannels, context.marker, warehouseId, channelCode) - if (!channelIsolation.pair) { + if (context.options?.verifyNonIsoContainer) { + context.addCoverageGap(MODULE, OPTIONS.scenario, '跨渠道分配及移除', + '本轮仅验证非 ISO 柜号履约链,不创建或删除旁路分配', 'out-of-scope', { blocking: false }) + } else if (!channelIsolation.pair) { context.addStep(MODULE, '两个真实有效渠道的柜次隔离 fixture', null, false, `${channelIsolation.reason}; originWarehouseId=${warehouseId}, primaryChannelCode=${channelCode}`, OPTIONS) } else { diff --git a/scripts/admin-test-env-modules/phase3-container-regression-contract.test.mjs b/scripts/admin-test-env-modules/phase3-container-regression-contract.test.mjs index 579927d24..e2410e4c0 100644 --- a/scripts/admin-test-env-modules/phase3-container-regression-contract.test.mjs +++ b/scripts/admin-test-env-modules/phase3-container-regression-contract.test.mjs @@ -3,6 +3,7 @@ import { readFileSync } from 'node:fs' import test from 'node:test' import { controlledPhotoDownload } from './phase3-container-overview.mjs' +import { parseArguments, validateExecutionOptions } from '../admin-test-env-acceptance.mjs' const read = (path) => readFileSync(new URL(path, import.meta.url), 'utf8') const overviewOpenApi = read('../../firstleg/src/main/resources/openapi/phase3-container-overview-v1.yaml') @@ -24,6 +25,18 @@ const phase3LoadingAcceptance = read('phase3-loading.mjs') const truckAcceptance = read('truck-appointments.mjs') const matrix = read('../../../docs/国内货柜履约/归档/货柜管理全链验收矩阵-2026-08-13.md') +test('non-ISO HTTP scope excludes unrelated deletion probes and keeps non-ISO completion facts', () => { + const options = parseArguments(['--modules', 'phase3-container-loading', '--verify-non-iso-container', 'true', + '--gateway', 'https://acceptance.invalid', '--username', 'test', '--password', 'test', + '--pda-username', 'pda', '--pda-password', 'test']) + assert.equal(validateExecutionOptions(options).verifyNonIsoContainer, true) + assert.throws(() => validateExecutionOptions({ ...options, verifyPalletLocationGuide: true }), /删除探针/) + assert.throws(() => validateExecutionOptions({ ...options, requestedModules: ['phase3-loading'] }), /单独柜号链/) + assert.match(containerLoadingAcceptance, /const realContainerNo = 'JZXH10231043'/) + assert.match(containerLoadingAcceptance, /const replacementContainerNo = `TEST-\$\{context.marker\}-NOISO`/) + assert.match(containerLoadingAcceptance, /if \(context.options\?\.verifyNonIsoContainer\)[\s\S]*?addCoverageGap[\s\S]*?else if \(!channelIsolation.pair\)/) +}) + test('container acceptance reads the canonical domestic workbench route', () => { assert.match(containerLoadingAcceptance, /const DOMESTIC_CONTAINERS = `\$\{CONTAINERS\}\/domestic`/) assert.match(containerLoadingAcceptance, /function containerRecord\(value\) \{ return value\?\.container \}/)