This commit is contained in:
2026-08-18 16:09:52 +08:00
parent 82ee80226e
commit fa77170304
6 changed files with 92 additions and 82 deletions
@@ -136,7 +136,7 @@ export async function run(context) {
parties: [{ partyType: 'SHIPPER', partyName: `P3-SHIPPER-${suffix}` },
{ partyType: 'CONSIGNEE', partyName: `P3-CONSIGNEE-${suffix}` },
{ partyType: 'NOTIFY_PARTY', partyName: `P3-NOTIFY-${suffix}` }],
containers: [{ containerNo, containerType: '40HC', containerKind: 'FCL', capacityCbm: 76,
containerRequirements: [{ containerType: '40HC', containerKind: 'FCL', quantity: 1, capacityCbm: 76,
maxWeightKg: 28000 }],
}
const simulationResponse = await request(context, 'POST', '/api/platform/v1/containers', {
@@ -287,49 +287,41 @@ export async function run(context) {
const bookingCreateResponse = await request(context, 'POST', '/api/platform/v1/ocean-bookings',
{ expectedVersion: 0, data: bookingDraft },
{ 'Idempotency-Key': `${context.marker}-p3-booking-create`.slice(0, 128) })
const bookingConfirmed = context.apiSuccess(MODULE, '创建带渠道仓库快照的三期 CONFIRMED 订舱', bookingCreateResponse, '', OPTIONS)
const bookingId = id(bookingConfirmed?.oceanBooking?.id)
const bookingDraftResponse = context.apiSuccess(MODULE, '创建三期 DRAFT 订舱(不生成真实柜)', bookingCreateResponse, '', OPTIONS)
const bookingId = id(bookingDraftResponse?.oceanBooking?.id)
const draftVersion = Number(bookingDraftResponse?.oceanBooking?.version)
const releaseResponse = await request(context, 'POST', `/api/platform/v1/ocean-bookings/${bookingId}/release`,
{ expectedVersion: draftVersion, reason: context.marker },
{ 'Idempotency-Key': `${context.marker}-p3-booking-release`.slice(0, 128) })
const bookingConfirmed = context.apiSuccess(MODULE, '三期订舱 RELEASED 冻结运输快照', releaseResponse, '', OPTIONS)
const transportFields = ['billOfLadingNo', 'vesselName', 'voyageNo', 'estimatedSailingAt', 'estimatedArrivalAt']
const frozenTransport = Object.fromEntries(transportFields.map((field) => [field, bookingConfirmed?.oceanBooking?.[field]]))
const frozenTransportValid = transportFields.every((field) => frozenTransport[field] != null && String(frozenTransport[field]).trim() !== '')
const frozenTransportMatches = frozenTransportValid
&& transportFields.every((field) => String(frozenTransport[field]) === String(bookingDraft[field]))
const requirement = bookingConfirmed?.containers?.find?.((item) => item.containerNo === containerNo)
context.assert(MODULE, 'CONFIRMED 订舱回显完整且冻结五项运输快照', bookingCreateResponse,
Boolean(bookingId) && frozenTransportMatches && Boolean(requirement?.containerBookingId)
&& bookingConfirmed?.containers?.length === 1,
const requirement = bookingConfirmed?.containerRequirements?.find?.((item) => item.containerType === '40HC')
context.assert(MODULE, 'RELEASED 订舱回显完整冻结运输快照且无真实柜号', releaseResponse,
Boolean(bookingId) && bookingConfirmed?.oceanBooking?.status === 'RELEASED' && frozenTransportMatches
&& Boolean(requirement?.id) && (!bookingConfirmed?.containers || bookingConfirmed.containers.length === 0),
`bookingId=${bookingId || 'missing'}, status=${bookingConfirmed?.oceanBooking?.status || 'missing'}`, OPTIONS)
if (!bookingId || !requirement?.containerBookingId || !frozenTransportMatches) return
if (!bookingId || !requirement?.id || !frozenTransportMatches) return
const latestContainerResponse = await context.request('GET', `/api/platform/v1/containers/${containerBookingId}`)
const latestContainer = context.apiSuccess(MODULE, '合并前读取模拟柜最新版本', latestContainerResponse, '', OPTIONS)
const linkResponse = await request(context, 'POST', `/api/platform/v1/containers/${containerBookingId}/ocean-booking-link`, {
realContainerBookingId: id(requirement.containerBookingId), expectedVersion: Number(latestContainer?.version),
oceanBookingId: bookingId, requirementId: id(requirement.id), containerNo,
expectedVersion: Number(latestContainer?.version),
})
const linked = context.apiSuccess(MODULE, '模拟柜原地合并三期 CONFIRMED 真实订舱柜', linkResponse, '', OPTIONS)
const linked = context.apiSuccess(MODULE, '模拟柜原地关联三期 RELEASED 订舱需求并补真实柜号', linkResponse, '', OPTIONS)
context.assert(MODULE, '订舱关联保持柜次计划与真实柜号身份', linkResponse,
id(linked?.id) === containerBookingId && linked?.cabinetNo === simulation.cabinetNo
&& linked?.containerNo === containerNo && id(linked?.oceanBookingId) === bookingId,
`containerBookingId=${containerBookingId}, loadingPlanId=${loadingPlanId}`, OPTIONS)
if (id(linked?.id) !== containerBookingId) return
const confirmedBookingTaskResponse = await context.request('GET',
`${pdaBase}/tasks?loadingPlanId=${encodeURIComponent(loadingPlanId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
context.addStep(MODULE, '订舱已关联但未 RELEASED 仍无 PDA 任务', confirmedBookingTaskResponse,
confirmedBookingTaskResponse.http === 200 && codeOf(confirmedBookingTaskResponse) === 'A0404',
`HTTP=${confirmedBookingTaskResponse.http}, code=${codeOf(confirmedBookingTaskResponse)}`, OPTIONS)
const releaseResponse = await request(context, 'POST', `/api/platform/v1/ocean-bookings/${bookingId}/release`, {
expectedVersion: Number(bookingConfirmed?.oceanBooking?.version),
...frozenTransport, reason: context.marker,
}, { 'Idempotency-Key': `${context.marker}-p3-booking-release`.slice(0, 128) })
const bookingReleased = context.apiSuccess(MODULE, '三期订舱携带已冻结运输快照并放舱', releaseResponse, '', OPTIONS)
context.assert(MODULE, '三期订舱 RELEASED 后保持模拟柜关联身份', releaseResponse,
bookingReleased?.oceanBooking?.status === 'RELEASED'
&& bookingReleased?.containers?.some?.((item) => id(item.containerBookingId) === containerBookingId
&& item.containerNo === containerNo)
&& transportFields.every((field) => String(bookingReleased?.oceanBooking?.[field]) === String(frozenTransport[field])),
`status=${bookingReleased?.oceanBooking?.status || 'missing'}, containerBookingId=${containerBookingId}`, OPTIONS)
if (bookingReleased?.oceanBooking?.status !== 'RELEASED') return
context.assert(MODULE, '三期订舱 RELEASED 后保持模拟柜关联身份和运输快照', releaseResponse,
bookingConfirmed?.oceanBooking?.status === 'RELEASED'
&& id(linked?.oceanBookingId) === bookingId && linked?.containerNo === containerNo,
`status=${bookingConfirmed?.oceanBooking?.status || 'missing'}, containerBookingId=${containerBookingId}`, OPTIONS)
const unconfirmedTaskResponse = await context.request('GET',
`${pdaBase}/tasks?loadingPlanId=${encodeURIComponent(loadingPlanId)}&warehouseId=${encodeURIComponent(warehouseId)}`)