diff --git a/scripts/admin-test-env-modules/phase4-overseas-inbound-operations-contract.test.mjs b/scripts/admin-test-env-modules/phase4-overseas-inbound-operations-contract.test.mjs index 4f275d6a2..1d11cd6e0 100644 --- a/scripts/admin-test-env-modules/phase4-overseas-inbound-operations-contract.test.mjs +++ b/scripts/admin-test-env-modules/phase4-overseas-inbound-operations-contract.test.mjs @@ -8,8 +8,12 @@ const here = path.dirname(fileURLToPath(import.meta.url)) const source = fs.readFileSync(path.join(here, 'phase4-overseas-inbound-operations.mjs'), 'utf8') test('module covers the frozen Admin inbound-plan write surface', () => { - for (const value of ['/convert', '/pallets/supplement', '/fba-appointments/batch', + for (const value of ['/container-preview', '/convert-container', '/pallets/supplement', '/fba-appointments/batch', '/fba-appointments/${encodeURIComponent(appointmentNo)}']) assert.ok(source.includes(value), value) + assert.equal(source.includes("`${PLAN_BASE}/convert`"), false) + assert.match(source, /snapshotVersion/) + assert.match(source, /snapshotHash/) + assert.match(source, /'Idempotency-Key'/) assert.match(source, /重复转换返回同一入仓计划/) assert.match(source, /FBA预约同单号异载荷返回A0409/) assert.match(source, /appointmentStatus: 'CANCELLED'/) diff --git a/scripts/admin-test-env-modules/phase4-overseas-inbound-operations.mjs b/scripts/admin-test-env-modules/phase4-overseas-inbound-operations.mjs index a28ce8ee6..2341d9aea 100644 --- a/scripts/admin-test-env-modules/phase4-overseas-inbound-operations.mjs +++ b/scripts/admin-test-env-modules/phase4-overseas-inbound-operations.mjs @@ -15,8 +15,8 @@ function query(path, values) { } function key(context, operation) { return `${context.marker}:P4-INBOUND:${operation}`.slice(0, 255) } -async function request(context, method, name, path, body) { - const response = await context.requestOverseas(method, path, body) +async function request(context, method, name, path, body, headers = {}) { + const response = await context.requestOverseas(method, path, body, headers) context.addStep(MODULE, name, response, ok(response), trace(response), OPTIONS) return ok(response) ? response.body?.data : null } @@ -40,9 +40,20 @@ async function inboundAdminLifecycle(context) { `orderId=${id(order?.id) || 'missing'}, containerNo=${producer.containerNo}`, OPTIONS) if (!order?.id) return - const convertBody = { orderId: id(order.id), customerId } - const plan = await request(context, 'POST', '尾程入仓单转换为入仓计划', `${PLAN_BASE}/convert`, convertBody) - const replay = await request(context, 'POST', '重复转换返回同一入仓计划', `${PLAN_BASE}/convert`, convertBody) + const bookingId = id(producer.containerBookingId) + const preview = await request(context, 'GET', '预览第二柜待生成入仓计划', query(`${PLAN_BASE}/container-preview`, { + sourceContainerBookingId: bookingId, + })) + const convertBody = { sourceContainerBookingId: bookingId, + snapshotVersion: Number(preview?.snapshotVersion), snapshotHash: preview?.snapshotHash } + const convertHeaders = { 'Idempotency-Key': key(context, 'convert-container') } + const plans = await request(context, 'POST', '尾程入仓单转换为入仓计划', + `${PLAN_BASE}/convert-container`, convertBody, convertHeaders) + const replayedPlans = await request(context, 'POST', '重复转换返回同一入仓计划', + `${PLAN_BASE}/convert-container`, convertBody, convertHeaders) + const plan = (plans || []).find((item) => (item?.lines || []).some((line) => id(line?.orderId) === id(order.id))) + || plans?.[0] + const replay = (replayedPlans || []).find((item) => item?.planNo === plan?.planNo) || replayedPlans?.[0] context.assert(MODULE, '入仓计划转换天然幂等', null, Boolean(plan?.planNo) && replay?.planNo === plan.planNo, `first=${plan?.planNo || 'missing'}, replay=${replay?.planNo || 'missing'}`, OPTIONS) diff --git a/scripts/admin-test-env-modules/phase4-overseas-pda-contract.test.mjs b/scripts/admin-test-env-modules/phase4-overseas-pda-contract.test.mjs index 3170d1755..35543db25 100644 --- a/scripts/admin-test-env-modules/phase4-overseas-pda-contract.test.mjs +++ b/scripts/admin-test-env-modules/phase4-overseas-pda-contract.test.mjs @@ -128,6 +128,9 @@ test('PDA module covers the container-number receiving contract and excludes out assert.match(source, /rememberGeneratedPlans\(context, plans\)/) assert.match(source, /resolveGeneratedPallet\(context, inbound\)/) assert.match(source, /generatedPalletsByInbound/) + assert.match(source, /standardFba = matrix\?\.byDestinationType\?\.FBA\?\.find/) + assert.match(source, /item\?\.fulfillmentType !== 'ONE_CLICK_DROPSHIP'/) + assert.match(source, /const producers = \[dropship[\s\S]*?standardFba,/) assert.doesNotMatch(source, /创建当前柜实收托盘|创建当前柜实收库位|async function createPallet/) assert.match(source, /retained as acceptance evidence/) assert.match(source, /preferredProducer\?\.cartonMarks\?\.length/) diff --git a/scripts/admin-test-env-modules/phase4-overseas-pda.mjs b/scripts/admin-test-env-modules/phase4-overseas-pda.mjs index 04a7c437a..0fa01c902 100644 --- a/scripts/admin-test-env-modules/phase4-overseas-pda.mjs +++ b/scripts/admin-test-env-modules/phase4-overseas-pda.mjs @@ -833,7 +833,11 @@ export async function run(context) { } const matrix = context.createdResources?.phase4InboundProducerFixtures const dropship = matrix?.containers?.find((item) => item?.fulfillmentType === 'ONE_CLICK_DROPSHIP') - const producers = [dropship || matrix?.byDestinationType?.FBA?.[0], matrix?.byDestinationType?.OVERSEAS?.[0]] + const standardFba = matrix?.byDestinationType?.FBA?.find((item) => item?.fulfillmentType !== 'ONE_CLICK_DROPSHIP') + // The sealed dropship pallet proves the indivisible handover. A separate standard FBA + // fixture supplies multiple cartons for reversible split/merge/unbind and relabel checks. + const producers = [dropship || matrix?.byDestinationType?.FBA?.[0], standardFba, + matrix?.byDestinationType?.OVERSEAS?.[0]] .filter((item) => nonBlank(item?.containerNo)) const allProducers = Array.isArray(matrix?.containers) ? matrix.containers : producers if (allProducers.length) await awaitProducerConsumption(context, allProducers)