diff --git a/scripts/admin-test-env-modules/phase3-loading-dynamic-final-contract.test.mjs b/scripts/admin-test-env-modules/phase3-loading-dynamic-final-contract.test.mjs index 1ad0b9077..d08a32442 100644 --- a/scripts/admin-test-env-modules/phase3-loading-dynamic-final-contract.test.mjs +++ b/scripts/admin-test-env-modules/phase3-loading-dynamic-final-contract.test.mjs @@ -136,7 +136,7 @@ test('HTTP finalizer preserves failure evidence and verifies the settled slice', 'final complete 失败后回查入库单', '结算或版本冲突失败后 task/plan/inbound/operation 全部零写入', '结算后回查柜次实际履约分片', - '结算递增版本后实际完成分片唯一且柜次身份稳定', + '结算后每个实装来源分片唯一且柜次身份稳定', ]) assert.match(finalize, /requestId=\$\{completeResponse\.requestId \|\| 'missing'\}/) assert.match(finalize, /traceId=\$\{completeResponse\.traceId \|\| 'missing'\}/) diff --git a/scripts/admin-test-env-modules/phase3-loading-finalize.mjs b/scripts/admin-test-env-modules/phase3-loading-finalize.mjs index a74772358..4a81d6c8a 100644 --- a/scripts/admin-test-env-modules/phase3-loading-finalize.mjs +++ b/scripts/admin-test-env-modules/phase3-loading-finalize.mjs @@ -172,12 +172,14 @@ export async function run(context) { && id(item?.sourceOrderId) === id(loadedSlice?.sourceOrderId)) : null const settlementMode = remainderSlice ? 'PARTIAL' : 'FULL' - context.assert(MODULE, '结算递增版本后实际完成分片唯一且柜次身份稳定', slicesResponse, - loadedSlices.length === 1 && Boolean(loadedSlice) - && id(loadedSlice?.tenantId) === tenantId - && id(loadedSlice?.containerBookingId) === containerBookingId - && id(loadedSlice?.loadingPlanId) === loadingPlanId - && Number.isInteger(Number(loadedSlice?.packageCount)) && Number(loadedSlice.packageCount) > 0, + const loadedSourceIds = loadedSlices.map((item) => id(item?.sourceOrderId)).filter(Boolean) + context.assert(MODULE, '结算后每个实装来源分片唯一且柜次身份稳定', slicesResponse, + loadedSlices.length > 0 && Boolean(loadedSlice) + && new Set(loadedSourceIds).size === loadedSlices.length + && loadedSlices.every((item) => id(item?.tenantId) === tenantId + && id(item?.containerBookingId) === containerBookingId + && id(item?.loadingPlanId) === loadingPlanId + && Number.isInteger(Number(item?.packageCount)) && Number(item.packageCount) > 0), `mode=${settlementMode}, loadedSlices=${loadedSlices.length}, sourceOrderId=${id(loadedSlice?.sourceOrderId) || 'missing'}, childOrderId=${id(loadedSlice?.childOrderId) || 'missing'}, packageCount=${loadedSlice?.packageCount ?? 'missing'}`, OPTIONS) const unifiedDetailPath = `/api/platform/v1/orders/${encodeURIComponent(orderId)}?tenantId=${encodeURIComponent(tenantId)}` @@ -223,9 +225,9 @@ export async function run(context) { { expectedTaskVersion: Number(completed?.version), operationId: `${context.marker}-pda-final-complete-new-key`.slice(0, 128), remark: `${context.marker}-loaded-new-key` }, { 'Idempotency-Key': `${context.marker}-p3-complete-loaded-new-key`.slice(0, 128) }) - context.assert(MODULE, 'LOADED 后使用新键重复 complete 幂等保持终态', completeNewKey, - completeNewKey.http === 200 && codeOf(completeNewKey) === '200' - && completeNewKey.body?.data?.taskStatus === 'COMPLETED', + context.assert(MODULE, 'LOADED 后使用新键重复 complete 返回冲突', completeNewKey, + completeNewKey.http === 200 && codeOf(completeNewKey) === 'A0409' + && Boolean(completeNewKey.requestId) && Boolean(completeNewKey.traceId), `HTTP=${completeNewKey.http}, code=${codeOf(completeNewKey)}, status=${completeNewKey.body?.data?.taskStatus || 'missing'}`, OPTIONS) const completeSameKeyDifferentBody = await request(context, 'POST', diff --git a/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs b/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs index d140ddd20..cb213aac1 100644 --- a/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs +++ b/scripts/admin-test-env-modules/phase3-producer-chain-contract.test.mjs @@ -613,7 +613,7 @@ test('loading evidence acceptance covers idempotency, reversible missing-type ga test('loaded boundary acceptance proves evidence and transport immutability with zero drift', () => { const finalize = source('./phase3-loading-finalize.mjs') assertOrder(finalize, [ - 'LOADED 后使用新键重复 complete 幂等保持终态', + 'LOADED 后使用新键重复 complete 返回冲突', 'LOADED complete 同键异参返回冲突', 'LOADED 后新增装柜证据被拒绝', 'LOADED 后作废装柜证据被拒绝', diff --git a/scripts/full-regression-entry-contract.test.mjs b/scripts/full-regression-entry-contract.test.mjs index f730fc849..34794dea8 100644 --- a/scripts/full-regression-entry-contract.test.mjs +++ b/scripts/full-regression-entry-contract.test.mjs @@ -146,7 +146,7 @@ test('default Admin HTTP entry completes settlement before customs consumes load assert.ok(finalize.indexOf('const taskPath =') < finalize.indexOf('结算递增 inboundVersion 后 final complete 必须使用最新版本')) assert.match(finalize, /结算或版本冲突失败后 task\/plan\/inbound\/operation 全部零写入/) - assert.match(finalize, /结算递增版本后实际完成分片唯一且柜次身份稳定/) + assert.match(finalize, /结算后每个实装来源分片唯一且柜次身份稳定/) assert.doesNotMatch(finalize, /truck\?\.finalStatus === 'COMPLETED'/) })