From 8a65f18fce5f0e56f2180ead384bccb7a5a7d778 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Tue, 11 Aug 2026 18:03:44 +0800 Subject: [PATCH] test(admin): complete phase3 producer fixtures --- .../admin-test-env-modules/ocean-bookings.mjs | 9 ++++- .../admin-test-env-modules/phase3-customs.mjs | 39 +++++++++++++++++++ .../phase3-producer-chain-contract.test.mjs | 16 +++++++- .../service-center-flow.mjs | 7 +++- 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/scripts/admin-test-env-modules/ocean-bookings.mjs b/scripts/admin-test-env-modules/ocean-bookings.mjs index f89126656..70059ba49 100644 --- a/scripts/admin-test-env-modules/ocean-bookings.mjs +++ b/scripts/admin-test-env-modules/ocean-bookings.mjs @@ -39,7 +39,8 @@ export async function run(context) { context.apiSuccess(MODULE, '创建隔离海运订舱', createResponse, `key=${key}`, OPTIONS) context.assert(MODULE, '订舱 DTO 字段、DRAFT 和9类关联字段完整', createResponse, Boolean(bookingId) && detail?.oceanBooking?.status === 'DRAFT' && detail?.parties?.length === 3 && detail?.containerRequirements?.length === 1, `bookingId=${bookingId || 'missing'}, parties=${detail?.parties?.length ?? 'n/a'}, requirements=${detail?.containerRequirements?.length ?? 'n/a'}`, OPTIONS) if (!bookingId) return - context.createdResources.oceanBooking = { id: bookingId, customerId: '10001', marker: context.marker, finalStatus: 'RELEASED' } + context.createdResources.oceanBooking = { id: bookingId, customerId: '10001', marker: context.marker, + containerBookingId: null, loadingPlanId: null, finalStatus: 'DRAFT' } const replay = await createBooking(context, suffix, key) context.assert(MODULE, '创建 Idempotency-Key 重放返回同一订舱', replay, String(data(replay)?.oceanBooking?.id) === bookingId, `first=${bookingId}, replay=${id(data(replay)?.oceanBooking?.id)}`, OPTIONS) const path = `${BASE}/${bookingId}` @@ -84,6 +85,12 @@ export async function run(context) { fd?.oceanBooking?.status === 'RELEASED' && fd.histories?.length >= 5 && fd.histories.every((h) => h.operatorName) && (!containerFlow || fd?.containerAllocations?.some?.((item) => id(item?.containerBookingId) === id(containerFlow.containerBookingId))), `status=${fd?.oceanBooking?.status || 'missing'}, histories=${fd?.histories?.length ?? 'n/a'}, allocations=${fd?.containerAllocations?.length ?? 'n/a'}`, OPTIONS) + context.createdResources.oceanBooking = { + id: bookingId, customerId: id(fd?.oceanBooking?.customerId), marker: context.marker, + containerBookingId: containerFlow ? id(containerFlow.containerBookingId) : null, + loadingPlanId: containerFlow ? id(containerFlow.loadingPlanId) : null, + finalStatus: fd?.oceanBooking?.status || null, + } const missingDetail = await request(context, 'GET', `${BASE}/999999999999999999`) step(context, '不存在订舱详情安全失败', missingDetail, failure(missingDetail), `HTTP=${missingDetail.http}, code=${codeOf(missingDetail)}`) } diff --git a/scripts/admin-test-env-modules/phase3-customs.mjs b/scripts/admin-test-env-modules/phase3-customs.mjs index daf923696..08c6d38fc 100644 --- a/scripts/admin-test-env-modules/phase3-customs.mjs +++ b/scripts/admin-test-env-modules/phase3-customs.mjs @@ -69,6 +69,7 @@ async function detail(context, caseId) { export function selectCustomsFlow(createdResources) { const fixtures = [ + createdResources?.orders, createdResources?.orchestrationFixtures?.inboundMeasurement, createdResources?.orchestrationFixtures?.phase3Container, ].filter(Boolean) @@ -84,6 +85,43 @@ export function selectCustomsFlow(createdResources) { return { fixture: null, container: null } } +async function ensureServiceCenterFlow(context, container) { + const containerBookingId = id(container?.containerBookingId) + const loadingPlanId = id(container?.loadingPlanId) + let ocean = context.createdResources?.oceanBooking + if (ocean?.finalStatus !== 'RELEASED' + || id(ocean?.containerBookingId) !== containerBookingId + || id(ocean?.loadingPlanId) !== loadingPlanId) { + const oceanBookings = await import(new URL('./ocean-bookings.mjs', import.meta.url)) + await oceanBookings.run(context) + ocean = context.createdResources?.oceanBooking + } + if (ocean?.finalStatus !== 'RELEASED' + || id(ocean?.containerBookingId) !== containerBookingId + || id(ocean?.loadingPlanId) !== loadingPlanId) { + context.addStep(MODULE, '报关前订舱已放舱并绑定实际装柜柜次', null, false, + `oceanStatus=${ocean?.finalStatus || 'missing'}, oceanContainer=${id(ocean?.containerBookingId) || 'missing'}, containerBookingId=${containerBookingId || 'missing'}`, OPTIONS) + return false + } + + let truck = context.createdResources?.serviceCenterFlow + if (truck?.finalStatus !== 'COMPLETED' + || id(truck?.oceanBookingId) !== id(ocean.id) + || id(truck?.containerBookingId) !== containerBookingId + || id(truck?.loadingPlanId) !== loadingPlanId) { + const serviceCenter = await import(new URL('./service-center-flow.mjs', import.meta.url)) + await serviceCenter.run(context) + truck = context.createdResources?.serviceCenterFlow + } + const ready = truck?.finalStatus === 'COMPLETED' + && id(truck?.oceanBookingId) === id(ocean.id) + && id(truck?.containerBookingId) === containerBookingId + && id(truck?.loadingPlanId) === loadingPlanId + context.addStep(MODULE, '报关前拖车已完成并绑定实际装柜柜次', null, ready, + `truckStatus=${truck?.finalStatus || 'missing'}, truckContainer=${id(truck?.containerBookingId) || 'missing'}, containerBookingId=${containerBookingId || 'missing'}`, OPTIONS) + return ready +} + export async function run(context) { const { fixture, container } = selectCustomsFlow(context.createdResources) const tenantId = id(fixture?.tenantId) @@ -97,6 +135,7 @@ export async function run(context) { `tenantId=${tenantId || 'missing'}, parentOrderId=${parentOrderId || 'missing'}, inboundId=${inboundId || 'missing'}, containerBookingId=${containerBookingId || 'missing'}, loadingPlanId=${loadingPlanId || 'missing'}, containerStatus=${container?.finalStatus || 'missing'}`, OPTIONS) return } + if (!await ensureServiceCenterFlow(context, container)) return const slicesPath = `/api/platform/v1/orders/container-bookings/${encodeURIComponent(containerBookingId)}/fulfillment-slices?tenantId=${encodeURIComponent(tenantId)}` const slicesResponse = await context.request('GET', slicesPath) 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 5a5016a18..91a9ce000 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 @@ -20,8 +20,8 @@ function assertOrder(value, snippets) { test('pairs customs source fixture with the matching loading container', () => { const resources = { + orders: { tenantId: 10001, orderId: 101, inboundId: 201 }, orchestrationFixtures: { - inboundMeasurement: { tenantId: 10001, orderId: 101, inboundId: 201 }, phase3Container: { tenantId: 10001, orderId: 102, inboundId: 202 }, }, phase3Loading: { tenantId: 10001, inboundId: 201, containerBookingId: 301 }, @@ -88,6 +88,20 @@ test('bridge loading starts through a real PDA batch before preload confirmation assert.match(value, /confirmed\?\.mainStatus === 'LOADING' && confirmed\?\.preloadPlan\?\.status === 'CONFIRMING'/) assert.match(value, /confirmed\?\.preloadPlan\?\.status === 'CONFIRMED'/) assert.doesNotMatch(value, /关联柜次计划进入 LOADING/) + assert.match(value, /confirmed\?\.mainStatus === 'LOADING'/) + assert.match(value, /confirmed\?\.preloadPlan\?\.status === 'CONFIRMING'/) + assert.match(value, /Number\(confirmed\?\.preloadPlan\?\.version\) === 2/) +}) + +test('customs provisions released booking and completed truck for the selected loading container', () => { + const value = source('./phase3-customs.mjs') + assertOrder(value, [ + 'selectCustomsFlow(context.createdResources)', + 'if (!await ensureServiceCenterFlow(context, container)) return', + 'const slicesPath =', + ]) + assert.match(value, /oceanBookings\.run\(context\)/) + assert.match(value, /serviceCenter\.run\(context\)/) }) test('downstream producers prefer the phase3Loading container fixture', () => { diff --git a/scripts/admin-test-env-modules/service-center-flow.mjs b/scripts/admin-test-env-modules/service-center-flow.mjs index da84a3c8b..f18753a07 100644 --- a/scripts/admin-test-env-modules/service-center-flow.mjs +++ b/scripts/admin-test-env-modules/service-center-flow.mjs @@ -34,8 +34,11 @@ export async function run(context) { const ocean = context.createdResources?.oceanBooking const containerFlow = context.createdResources?.phase3Loading || context.createdResources?.phase3ContainerLoading - const containerFixture = context.createdResources?.orchestrationFixtures?.inboundMeasurement - || context.createdResources?.orchestrationFixtures?.phase3Container + const containerFixture = [ + context.createdResources?.orders, + context.createdResources?.orchestrationFixtures?.inboundMeasurement, + context.createdResources?.orchestrationFixtures?.phase3Container, + ].find((item) => id(item?.inboundId) === id(containerFlow?.inboundId)) if (!ocean?.id || ocean.finalStatus !== 'RELEASED') { context.addStep(MODULE, '跨服务链路前置订舱终态可用', null, false, '本轮海运订舱模块未返回 RELEASED 隔离记录,未伪造关联拖车预约', OPTIONS)