From 506cc698083040b54cddf7cb1fb4eed6202018c8 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Mon, 24 Aug 2026 14:01:02 +0800 Subject: [PATCH] test(phase3): provision dispatch and handoff evidence --- .../manual-state-ocean-trucking.mjs | 18 ++++++++++++++++++ .../phase3-order-splitting.mjs | 16 ++++++++-------- .../service-center-flow.mjs | 18 ++++++++++++++++++ 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/scripts/admin-test-env-modules/manual-state-ocean-trucking.mjs b/scripts/admin-test-env-modules/manual-state-ocean-trucking.mjs index d1b3f27df..c7e8d4d72 100644 --- a/scripts/admin-test-env-modules/manual-state-ocean-trucking.mjs +++ b/scripts/admin-test-env-modules/manual-state-ocean-trucking.mjs @@ -17,6 +17,21 @@ async function post(context, path, body, operation) { return context.request('POST', path, body, context.token, { 'Idempotency-Key': key(context, operation) }) } +async function uploadBillOfLading(context, appointmentId, index) { + const path = `${TRUCK_BASE}/${appointmentId}/attachments/upload?attachmentType=BILL_OF_LADING` + const form = new FormData() + const png = Uint8Array.from([137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,1,0,0,0,1,8,6,0,0,0,31,21,196,137,0,0,0,13,73,68,65,84,8,215,99,248,207,192,240,31,0,5,0,1,255,137,153,61,29,0,0,0,0,73,69,78,68,174,66,96,130]) + form.append('file', new Blob([png], { type: 'image/png' }), `${context.marker}-truck-${index}.png`) + const response = await fetch(`${context.options.gateway}${path}`, { + method: 'POST', headers: { Accept: 'application/json', Authorization: `Bearer ${context.token}` }, + body: form, signal: AbortSignal.timeout(60_000), + }) + const body = await response.json() + return { method: 'POST', path, http: response.status, body, + requestId: body?.requestId || response.headers.get('x-request-id'), + traceId: body?.traceId || response.headers.get('x-trace-id') } +} + function oceanPayload(context, template, index) { const source = template.oceanBooking return { expectedVersion: 0, data: { @@ -93,6 +108,9 @@ async function createTruck(context, oceanBooking, index) { const response = await context.request('POST', TRUCK_BASE, truckPayload(context, oceanBooking, carrier, index)) const value = context.apiSuccess(MODULE, `创建拖车状态样本 ${index}`, response, '', OPTIONS) if (!value?.id) throw new Error(`创建拖车样本 ${index} 失败`) + const billUpload = await uploadBillOfLading(context, id(value.id), index) + const billAttachment = context.apiSuccess(MODULE, `拖车状态样本 ${index} 上传提单附件`, billUpload, '', OPTIONS) + if (!billAttachment?.id) throw new Error(`拖车样本 ${index} 未上传有效提单附件`) return value } diff --git a/scripts/admin-test-env-modules/phase3-order-splitting.mjs b/scripts/admin-test-env-modules/phase3-order-splitting.mjs index baf5e0a44..d42339d61 100644 --- a/scripts/admin-test-env-modules/phase3-order-splitting.mjs +++ b/scripts/admin-test-env-modules/phase3-order-splitting.mjs @@ -348,6 +348,14 @@ async function loadOneFragment(context, state) { if (!taskId || !pickItem?.id) return null context.createdResources.phase3OrderSplitting.retainedAuditRecordIds.push(taskId) + const labelResponse = await context.requestBinary('POST', + `/api/platform/inbounds/${encodeURIComponent(id(candidate.inboundId))}/carton-label-pdf?tenantId=${encodeURIComponent(tenantId)}`) + context.assert(MODULE, `${sourceOrderNo} 进入 LOADING 前生成可交接箱唛池`, labelResponse, + labelResponse.http === 200 && String(labelResponse.contentType || '').toLowerCase().includes('pdf') + && Number(labelResponse.bytes?.length) > 0, + `HTTP=${labelResponse.http}, contentType=${labelResponse.contentType || 'missing'}, bytes=${labelResponse.bytes?.length ?? 0}`, OPTIONS) + if (labelResponse.http !== 200 || !Number(labelResponse.bytes?.length)) return null + const claim = await request(context, 'POST', `${PDA}/tasks/${taskId}/claim`, { expectedAssignmentVersion: 0, operationId: `${operationBase}-claim`, }) @@ -407,14 +415,6 @@ async function loadOneFragment(context, state) { `HTTP=${differentReplay.http}, code=${codeOf(differentReplay)}, requestId=${differentReplay.requestId || 'missing'}, traceId=${differentReplay.traceId || 'missing'}`, OPTIONS) } - const labelResponse = await context.requestBinary('POST', - `/api/platform/inbounds/${encodeURIComponent(id(candidate.inboundId))}/carton-label-pdf?tenantId=${encodeURIComponent(tenantId)}`) - context.assert(MODULE, `${sourceOrderNo} 完成前生成可交接箱唛池`, labelResponse, - labelResponse.http === 200 && String(labelResponse.contentType || '').toLowerCase().includes('pdf') - && Number(labelResponse.bytes?.length) > 0, - `HTTP=${labelResponse.http}, contentType=${labelResponse.contentType || 'missing'}, bytes=${labelResponse.bytes?.length ?? 0}`, OPTIONS) - if (labelResponse.http !== 200 || !Number(labelResponse.bytes?.length)) return null - if (!await ensureCompletionEvidence(context, tenantId, id(candidate.inboundId), operationBase)) return null const completePath = `${PDA}/tasks/${taskId}/complete` diff --git a/scripts/admin-test-env-modules/service-center-flow.mjs b/scripts/admin-test-env-modules/service-center-flow.mjs index f7a29b771..6564558ea 100644 --- a/scripts/admin-test-env-modules/service-center-flow.mjs +++ b/scripts/admin-test-env-modules/service-center-flow.mjs @@ -30,6 +30,21 @@ async function actionRequest(context, path, endpoint, version) { } } +async function uploadBillOfLading(context, appointmentId) { + const path = `${TRUCK}/${appointmentId}/attachments/upload?attachmentType=BILL_OF_LADING` + const form = new FormData() + const png = Uint8Array.from([137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,1,0,0,0,1,8,6,0,0,0,31,21,196,137,0,0,0,13,73,68,65,84,8,215,99,248,207,192,240,31,0,5,0,1,255,137,153,61,29,0,0,0,0,73,69,78,68,174,66,96,130]) + form.append('file', new Blob([png], { type: 'image/png' }), `${context.marker}-bill.png`) + const response = await fetch(`${context.options.gateway}${path}`, { + method: 'POST', headers: { Accept: 'application/json', Authorization: `Bearer ${context.token}` }, + body: form, signal: AbortSignal.timeout(60_000), + }) + const body = await response.json() + return { method: 'POST', path, http: response.status, body, + requestId: body?.requestId || response.headers.get('x-request-id'), + traceId: body?.traceId || response.headers.get('x-trace-id') } +} + export async function run(context) { const containerFlow = context.createdResources?.phase3Loading || context.createdResources?.phase3ContainerLoading @@ -114,6 +129,9 @@ export async function run(context) { `appointmentId=${appointmentId || 'missing'}, oceanBookingId=${appointment?.oceanBookingId || 'missing'}, containerBookingId=${appointment?.containerBookingId || 'n/a'}, loadingPlanId=${appointment?.loadingPlanId || 'n/a'}, version=${appointment?.version ?? 'missing'}`, OPTIONS) if (!appointmentId) return const path = `${TRUCK}/${appointmentId}` + const billUpload = await uploadBillOfLading(context, appointmentId) + const billAttachment = context.apiSuccess(MODULE, '跨服务拖车上传有效提单附件', billUpload, '', OPTIONS) + if (!billAttachment?.id) return let version = Number(appointment.version) for (const [name, endpoint, status] of [ ['提交跨链路预约', 'submit', 'PENDING_DISPATCH'],