This commit is contained in:
2026-08-14 10:57:05 +08:00
parent 66089f9b99
commit 91e781b3ff
16 changed files with 219 additions and 119 deletions
@@ -19,10 +19,53 @@ function data(r) { return String(r?.body?.code) === '200' ? r.body.data : null }
async function createBooking(context, suffix, key, master) { return request(context, 'POST', BASE, { expectedVersion: 0, data: oceanBookingDraft(context, suffix, master) }, { 'Idempotency-Key': key }) }
function step(context, name, r, pass, evidence, options = OPTIONS) { context.addStep(MODULE, name, r, pass, evidence, { ...options, deploymentBlocker: options.deploymentBlocker && !pass }) }
async function releaseLoadingBooking(context, containerFlow, suffix) {
const flowOceanBookingId = id(containerFlow?.oceanBookingId)
if (!flowOceanBookingId || !id(containerFlow?.containerBookingId) || !id(containerFlow?.loadingPlanId)) return null
const flowPath = `${BASE}/${flowOceanBookingId}`
let flowResponse = await request(context, 'GET', flowPath)
let flow = data(flowResponse)
context.apiSuccess(MODULE, '回读实际装货柜次所属订舱', flowResponse,
`oceanBookingId=${flowOceanBookingId}`, OPTIONS)
const allocationMatches = flow?.containerAllocations?.some?.((item) =>
id(item?.containerBookingId) === id(containerFlow.containerBookingId))
context.assert(MODULE, '实际装货柜次只绑定其所属订舱', flowResponse,
allocationMatches && id(flow?.oceanBooking?.customerId) === id(containerFlow?.tenantId),
`oceanBookingId=${flowOceanBookingId}, containerBookingId=${id(containerFlow.containerBookingId)}, allocations=${flow?.containerAllocations?.length ?? 'n/a'}`, OPTIONS)
if (allocationMatches && flow?.oceanBooking?.status === 'CONFIRMED') {
const flowRelease = await request(context, 'POST', `${flowPath}/release`, {
expectedVersion: Number(flow.oceanBooking.version), billOfLadingNo: `BL-FLOW-${suffix}`,
vesselName: `装货船-${suffix}`, voyageNo: `FV${suffix}`,
estimatedSailingAt: '2026-09-01T08:00:00', estimatedArrivalAt: '2026-09-20T08:00:00',
reason: context.marker,
}, { 'Idempotency-Key': `${context.marker}-ocean-flow-release`.slice(0, 128) })
context.apiSuccess(MODULE, '放舱实际装货柜次所属订舱', flowRelease, '', OPTIONS)
flowResponse = await request(context, 'GET', flowPath)
flow = data(flowResponse)
}
context.assert(MODULE, '实际装货柜次订舱已放舱供下游串联', flowResponse,
flow?.oceanBooking?.status === 'RELEASED'
&& flow?.containerAllocations?.some?.((item) => id(item?.containerBookingId) === id(containerFlow.containerBookingId)),
`status=${flow?.oceanBooking?.status || 'missing'}, containerBookingId=${id(containerFlow.containerBookingId)}`, OPTIONS)
return flow?.oceanBooking?.status === 'RELEASED' && allocationMatches ? {
id: flowOceanBookingId, customerId: id(flow.oceanBooking.customerId), marker: context.marker,
containerBookingId: id(containerFlow.containerBookingId), loadingPlanId: id(containerFlow.loadingPlanId),
finalStatus: 'RELEASED',
} : null
}
export async function run(context) {
const containerFlow = context.createdResources?.phase3Loading
|| context.createdResources?.phase3ContainerLoading
const suffix = context.marker.replace(/\D/g, '').slice(-10)
const existing = context.createdResources?.oceanBooking
if (existing?.marker === context.marker && existing?.finalStatus === 'RELEASED') {
if (!id(containerFlow?.containerBookingId)
|| id(existing.containerBookingId) === id(containerFlow.containerBookingId)) return
const reconciled = await releaseLoadingBooking(context, containerFlow, suffix)
if (reconciled) context.createdResources.oceanBooking = reconciled
return
}
const master = await resolveOceanBookingMaster(context, MODULE)
if (!master) return
const list = await request(context, 'GET', `${BASE}?page=1&size=5&keyword=${encodeURIComponent(context.marker)}`)
@@ -95,41 +138,8 @@ export async function run(context) {
loadingPlanId: null,
finalStatus: fd?.oceanBooking?.status || null,
}
const flowOceanBookingId = id(containerFlow?.oceanBookingId)
if (flowOceanBookingId && id(containerFlow?.containerBookingId) && id(containerFlow?.loadingPlanId)) {
const flowPath = `${BASE}/${flowOceanBookingId}`
let flowResponse = await request(context, 'GET', flowPath)
let flow = data(flowResponse)
context.apiSuccess(MODULE, '回读实际装货柜次所属订舱', flowResponse,
`oceanBookingId=${flowOceanBookingId}`, OPTIONS)
const allocationMatches = flow?.containerAllocations?.some?.((item) =>
id(item?.containerBookingId) === id(containerFlow.containerBookingId))
context.assert(MODULE, '实际装货柜次只绑定其所属订舱', flowResponse,
allocationMatches && id(flow?.oceanBooking?.customerId) === id(containerFlow?.tenantId),
`oceanBookingId=${flowOceanBookingId}, containerBookingId=${id(containerFlow.containerBookingId)}, allocations=${flow?.containerAllocations?.length ?? 'n/a'}`, OPTIONS)
if (allocationMatches && flow?.oceanBooking?.status === 'CONFIRMED') {
const flowRelease = await request(context, 'POST', `${flowPath}/release`, {
expectedVersion: Number(flow.oceanBooking.version), billOfLadingNo: `BL-FLOW-${suffix}`,
vesselName: `装货船-${suffix}`, voyageNo: `FV${suffix}`,
estimatedSailingAt: '2026-09-01T08:00:00', estimatedArrivalAt: '2026-09-20T08:00:00',
reason: context.marker,
}, { 'Idempotency-Key': `${context.marker}-ocean-flow-release`.slice(0, 128) })
context.apiSuccess(MODULE, '放舱实际装货柜次所属订舱', flowRelease, '', OPTIONS)
flowResponse = await request(context, 'GET', flowPath)
flow = data(flowResponse)
}
context.assert(MODULE, '实际装货柜次订舱已放舱供下游串联', flowResponse,
flow?.oceanBooking?.status === 'RELEASED'
&& flow?.containerAllocations?.some?.((item) => id(item?.containerBookingId) === id(containerFlow.containerBookingId)),
`status=${flow?.oceanBooking?.status || 'missing'}, containerBookingId=${id(containerFlow.containerBookingId)}`, OPTIONS)
if (flow?.oceanBooking?.status === 'RELEASED') {
downstreamBooking = {
id: flowOceanBookingId, customerId: id(flow.oceanBooking.customerId), marker: context.marker,
containerBookingId: id(containerFlow.containerBookingId), loadingPlanId: id(containerFlow.loadingPlanId),
finalStatus: 'RELEASED',
}
}
}
const releasedLoadingBooking = await releaseLoadingBooking(context, containerFlow, suffix)
if (releasedLoadingBooking) downstreamBooking = releasedLoadingBooking
context.createdResources.oceanBooking = downstreamBooking
const missingDetail = await request(context, 'GET', `${BASE}/999999999999999999`)
step(context, '不存在订舱详情安全失败', missingDetail, failure(missingDetail), `HTTP=${missingDetail.http}, code=${codeOf(missingDetail)}`)