test: align phase five dev acceptance flows
This commit is contained in:
@@ -4,7 +4,9 @@ const OCEAN = '/api/platform/v1/ocean-bookings'
|
||||
const TRUCK = '/api/platform/v1/truck-appointments'
|
||||
|
||||
function id(value) { return value == null ? '' : String(value) }
|
||||
function codeOf(response) { return response?.body?.code == null ? 'missing' : String(response.body.code) }
|
||||
const FORBIDDEN_TRUCK_FIELDS = ['customerId', 'customerName', 'containerBookingId', 'loadingPlanId',
|
||||
'cabinetNo', 'containerNo']
|
||||
function bookingLevel(value) { return value != null && FORBIDDEN_TRUCK_FIELDS.every((field) => !Object.hasOwn(value, field)) }
|
||||
|
||||
async function actionRequest(context, path, endpoint, version) {
|
||||
try {
|
||||
@@ -30,32 +32,12 @@ 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
|
||||
const ocean = containerFlow?.oceanBookingId
|
||||
? { id: id(containerFlow.oceanBookingId), finalStatus: 'RELEASED' }
|
||||
: context.createdResources?.oceanBooking
|
||||
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)
|
||||
@@ -65,14 +47,6 @@ export async function run(context) {
|
||||
const suffix = context.marker.replace(/\D/g, '').slice(-10)
|
||||
const oceanResponse = await context.request('GET', `${OCEAN}/${ocean.id}`)
|
||||
const oceanDetail = context.apiSuccess(MODULE, '读取跨服务链路已放舱订舱', oceanResponse, `oceanBookingId=${ocean.id}`, OPTIONS)
|
||||
const linkContainer = ['AWAITING_REVIEW', 'LOADED'].includes(containerFlow?.finalStatus)
|
||||
&& Boolean(containerFlow?.containerBookingId)
|
||||
&& Boolean(containerFlow?.loadingPlanId)
|
||||
if (!linkContainer) {
|
||||
context.addStep(MODULE, '本轮已放舱订舱必须关联真实柜和装柜计划', oceanResponse, false,
|
||||
`containerStatus=${containerFlow?.finalStatus || 'missing'}, containerBookingId=${id(containerFlow?.containerBookingId) || 'missing'}`, OPTIONS)
|
||||
return
|
||||
}
|
||||
const allocationMatches = oceanDetail?.containers?.some?.((item) =>
|
||||
id(item?.containerBookingId) === id(containerFlow.containerBookingId))
|
||||
context.assert(MODULE, '已放舱订舱保留本轮柜次分配', oceanResponse, allocationMatches,
|
||||
@@ -86,14 +60,9 @@ export async function run(context) {
|
||||
Boolean(carrier?.id && carrier?.name), `carrierId=${id(carrier?.id) || 'missing'}`, OPTIONS)
|
||||
if (!carrier) return
|
||||
const payload = {
|
||||
outboundOrderId: linkContainer ? id(containerFixture?.orderId) || null : null,
|
||||
oceanBookingId: ocean.id,
|
||||
containerBookingId: linkContainer ? id(containerFlow.containerBookingId) : null,
|
||||
loadingPlanId: linkContainer ? id(containerFlow.loadingPlanId) : null,
|
||||
warehouseId: linkContainer
|
||||
? id(containerFlow.warehouseId)
|
||||
: id(context.createdResources?.warehouse?.id || context.context?.warehouseId || '193000000000000001'),
|
||||
outboundOrderId: null, oceanBookingId: ocean.id, warehouseId: id(oceanDetail?.oceanBooking?.warehouseId),
|
||||
carrierId: id(carrier.id), carrierName: carrier.name,
|
||||
billOfLadingNo: oceanDetail?.oceanBooking?.billOfLadingNo,
|
||||
fleetContact: '链路车队联系人', fleetPhone: '13800000007', driverName: '链路司机', driverPhone: '13800000008',
|
||||
driverIdCard: null, vehicleNo: `粤D-${suffix.slice(-6)}`, storeName: `链路门店-${suffix}`, storeContact: '链路联系人',
|
||||
storePhone: '13800000009', storeAddress: '深圳市南山区链路地址', storeCity: '深圳市', storeZipcode: '518000',
|
||||
@@ -101,28 +70,18 @@ export async function run(context) {
|
||||
plannedLoadingAt: '2026-09-03T08:00:00', transitMinutes: 60, payableAmount: 1,
|
||||
currency: 'RMB', remark: context.marker, expectedVersion: 0,
|
||||
}
|
||||
if (linkContainer) {
|
||||
const missingContainerResponse = await context.request('POST', TRUCK, {
|
||||
...payload, containerBookingId: null, remark: `${context.marker}-missing-container`,
|
||||
})
|
||||
context.addStep(MODULE, '拖车关联装柜计划时缺失柜次被拒绝', missingContainerResponse,
|
||||
missingContainerResponse.http === 200 && codeOf(missingContainerResponse) !== '200',
|
||||
`HTTP=${missingContainerResponse.http}, code=${codeOf(missingContainerResponse)}`, OPTIONS)
|
||||
}
|
||||
context.assert(MODULE, '跨服务拖车创建请求仅使用订舱级协议', oceanResponse,
|
||||
bookingLevel(payload) && Boolean(payload.warehouseId && payload.billOfLadingNo),
|
||||
`fields=${Object.keys(payload).join(',')}`, OPTIONS)
|
||||
const response = await context.request('POST', TRUCK, payload)
|
||||
const appointment = context.apiSuccess(MODULE, '创建关联海运订舱的拖车预约', response, `oceanBookingId=${ocean.id}`, OPTIONS)
|
||||
const appointment = context.apiSuccess(MODULE, '创建订舱级跨服务拖车预约', response, `oceanBookingId=${ocean.id}`, OPTIONS)
|
||||
const appointmentId = id(appointment?.id)
|
||||
context.assert(MODULE, '拖车预约关联订舱、柜次、装柜计划、版本和审计字段完整', response,
|
||||
context.assert(MODULE, '拖车预约关联订舱、版本和审计字段完整且无柜次协议', response,
|
||||
Boolean(appointmentId) && id(appointment?.oceanBookingId) === id(ocean.id) && Number.isFinite(Number(appointment?.version))
|
||||
&& (!linkContainer || id(appointment?.containerBookingId) === id(containerFlow.containerBookingId)
|
||||
&& id(appointment?.loadingPlanId) === id(containerFlow.loadingPlanId))
|
||||
&& Boolean(appointment?.createdAt || appointment?.createdBy || appointment?.operatorName),
|
||||
`appointmentId=${appointmentId || 'missing'}, oceanBookingId=${appointment?.oceanBookingId || 'missing'}, containerBookingId=${appointment?.containerBookingId || 'n/a'}, loadingPlanId=${appointment?.loadingPlanId || 'n/a'}, version=${appointment?.version ?? 'missing'}`, OPTIONS)
|
||||
&& bookingLevel(appointment) && Boolean(appointment?.createdAt || appointment?.createdBy || appointment?.operatorName),
|
||||
`appointmentId=${appointmentId || 'missing'}, oceanBookingId=${appointment?.oceanBookingId || 'missing'}, 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'],
|
||||
@@ -144,9 +103,8 @@ export async function run(context) {
|
||||
const final = context.apiSuccess(MODULE, '回查跨服务链路安全终态', detail, '', OPTIONS)
|
||||
context.assert(MODULE, '跨服务链路终态持久化且关联订舱未漂移', detail,
|
||||
final?.status === 'COMPLETED' && id(final?.oceanBookingId) === id(ocean.id)
|
||||
&& (!linkContainer || id(final?.containerBookingId) === id(containerFlow.containerBookingId)
|
||||
&& id(final?.loadingPlanId) === id(containerFlow.loadingPlanId)),
|
||||
`status=${final?.status || 'missing'}, oceanBookingId=${final?.oceanBookingId || 'missing'}, containerBookingId=${final?.containerBookingId || 'n/a'}, loadingPlanId=${final?.loadingPlanId || 'n/a'}`, OPTIONS)
|
||||
&& bookingLevel(final),
|
||||
`status=${final?.status || 'missing'}, oceanBookingId=${final?.oceanBookingId || 'missing'}`, OPTIONS)
|
||||
|
||||
const historyResponse = await context.request('GET', `${TRUCK}/${appointmentId}/history`)
|
||||
const history = context.apiSuccess(MODULE, '查询跨服务链路拖车预约状态历史', historyResponse, '', OPTIONS)
|
||||
@@ -161,8 +119,6 @@ export async function run(context) {
|
||||
if (final?.status === 'COMPLETED') {
|
||||
context.createdResources.serviceCenterFlow = {
|
||||
appointmentId, oceanBookingId: ocean.id,
|
||||
containerBookingId: linkContainer ? id(containerFlow.containerBookingId) : null,
|
||||
loadingPlanId: linkContainer ? id(containerFlow.loadingPlanId) : null,
|
||||
marker: context.marker, finalStatus: 'COMPLETED',
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user