From 2c330bf9df4df39f78fae9155f5ab602667b48f3 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Sun, 18 Oct 2026 19:29:35 +0800 Subject: [PATCH] test(lastleg): derive merchant relabel scope from profile receipt --- .../dispatch-repair-acceptance-contract.test.mjs | 16 +++++++++++++++- .../dispatch-repair-acceptance.mjs | 7 +++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/scripts/admin-test-env-modules/dispatch-repair-acceptance-contract.test.mjs b/scripts/admin-test-env-modules/dispatch-repair-acceptance-contract.test.mjs index 1c67ca6b9..b7aab25aa 100644 --- a/scripts/admin-test-env-modules/dispatch-repair-acceptance-contract.test.mjs +++ b/scripts/admin-test-env-modules/dispatch-repair-acceptance-contract.test.mjs @@ -61,7 +61,7 @@ function producerReport() { event('GET', '/api/merchant/v1/iam/tenant/profile', undefined, { id: 'C' }, 'MERCHANT') event('POST', '/api/merchant/v1/last-leg/return-orders', { remark: 'CURRENT new return' }, { order: { returnNo: 'RT', overseasWarehouseId: 'W' } }, 'MERCHANT') event('GET', '/api/platform/v1/last-leg/return-inventory/cartons/BOX', undefined, { cartonMark: 'BOX', sourceReturnNo: 'RT', customerId: 'C', overseasWarehouseId: 'W', status: 'AVAILABLE', items: [{ skuCode: 'SKU-A', quantity: 3 }, { skuCode: 'SKU-B', quantity: 2 }] }) - event('POST', '/api/merchant/v1/last-leg/relabel-applications', { operationWarehouseId: 'W' }, { application: { relabelNo: 'RL-N', customerId: 'C', overseasWarehouseId: 'W' } }, 'MERCHANT') + event('POST', '/api/merchant/v1/last-leg/relabel-applications', { operationWarehouseId: 'W' }, { application: { relabelNo: 'RL-N', overseasWarehouseId: 'W' } }, 'MERCHANT') dispatch('NDP', [candidate(null, '601', null, { sourceStage: 'RELABEL', orderRefs: 'RL-N', returnCartonSource: true })], 'RL-N', 1) event('POST', '/api/platform/v1/last-leg/dispatches/NDP/transfer-delivery', {}, { outboundNo: 'O', deliveries: [{ deliveryNo: 'D' }] }) event('GET', '/api/platform/v1/last-leg/delivery-orders/D/return-inbound-options?customerId=C', undefined, [{ customerId: 'C', lastMileOrderId: '91', deliveryNo: 'D', outboundNo: 'O', returnSources: [{ returnCartonId: '81', cartonMark: 'BOX', inventoryPositionId: null }] }]) @@ -80,6 +80,20 @@ function context(handler = () => assert.fail('No request expected')) { } const execute = (ctx, fixtures) => verifyDispatchRepair(ctx, fixtures, { execute: true }) +test('merchant relabel summary derives omitted customer from authenticated profile receipt', async () => { + const ctx = context() + assert.equal((await execute(ctx, {})).status, 'PARTIAL_NOT_ALL_VERIFIED') + assert.equal(ctx.calls.length, 0) +}) + +test('an explicitly different relabel customer cannot borrow merchant profile scope', async () => { + const ctx = context(), report = producerReport() + report.requests.find(e => e.path === '/api/merchant/v1/last-leg/relabel-applications').result.application.customerId = 'OTHER' + writeProducer(ctx, report) + await assert.rejects(execute(ctx, {}), /Relabel producer scope mismatch/) + assert.equal(ctx.calls.length, 0) +}) + test('import/plan is zero-network and missing current fixtures never become a pass', async () => { const ctx = context(); assert.equal((await verifyDispatchRepair(ctx, {})).status, 'PLAN_ONLY'); assert.equal(ctx.calls.length, 0) const result = await execute(ctx, {}) diff --git a/scripts/admin-test-env-modules/dispatch-repair-acceptance.mjs b/scripts/admin-test-env-modules/dispatch-repair-acceptance.mjs index ba6952558..ef726f6a6 100644 --- a/scripts/admin-test-env-modules/dispatch-repair-acceptance.mjs +++ b/scripts/admin-test-env-modules/dispatch-repair-acceptance.mjs @@ -58,8 +58,11 @@ async function loadProducerResources(context) { } if (e.method === 'POST' && path === '/api/merchant/v1/last-leg/relabel-applications' && actors.has(e.actor)) { const a = data.application - must(a && id(a.customerId) === actors.get(e.actor) && id(a.overseasWarehouseId) === id(e.body?.operationWarehouseId), 'Relabel producer scope mismatch') - add('relabel', a.relabelNo, a.customerId, a.overseasWarehouseId, e) + const customerId = actors.get(e.actor) + must(a && (a.customerId === undefined || id(a.customerId) === customerId) + && id(a.overseasWarehouseId) === id(e.body?.operationWarehouseId), 'Relabel producer scope mismatch') + // Merchant summaries omit customerId; the authenticated profile receipt supplies its scope. + add('relabel', a.relabelNo, customerId, a.overseasWarehouseId, e) } if (e.method === 'POST' && path === '/api/merchant/v1/last-leg/return-orders' && actors.has(e.actor) && String(e.body?.remark).includes(context.marker)) add('return', data.order?.returnNo, actors.get(e.actor), data.order?.overseasWarehouseId, e)