feat: close preload confirmation and loading flow

This commit is contained in:
2026-08-15 17:04:00 +08:00
parent 5b8e7d6989
commit a35794e918
34 changed files with 1194 additions and 512 deletions
@@ -233,6 +233,112 @@ export async function run(context) {
staleAssignResponse.http === 200 && ['A0409', '409'].includes(codeOf(staleAssignResponse)),
`HTTP=${staleAssignResponse.http}, code=${codeOf(staleAssignResponse)}`, OPTIONS)
const pushKey = `${context.marker}-container-push`.slice(0, 128)
const pushRequest = Object.freeze({
path: `${SMART}/plans/${planId}/push-preload`,
body: Object.freeze({ expectedVersion: Number(assigned.version) }),
headers: Object.freeze({ 'Idempotency-Key': pushKey }),
})
const pushResponse = await request(context, 'POST', pushRequest.path, pushRequest.body, pushRequest.headers)
const pushed = context.apiSuccess(MODULE, '无真实柜号推送预装计划成功', pushResponse, '', OPTIONS)
context.assert(MODULE, '无号 push 仅冻结 EDITING 计划且版本递增', pushResponse,
id(pushed?.id) === planId && pushed?.status === 'EDITING' && pushed?.containerNo == null
&& Number(pushed?.version) > Number(assigned.version),
`status=${pushed?.status || 'missing'}, version=${pushed?.version ?? 'missing'}`, OPTIONS)
if (pushed?.status !== 'EDITING') return
const pushedDetailResponse = await context.request('GET',
`${FIRST_LEG}/loading-plans/${planId}?warehouseId=${encodeURIComponent(warehouseId)}`)
const pushedDetail = context.apiSuccess(MODULE, '无号 push 后预装清单可见', pushedDetailResponse, '', OPTIONS)
const pushedLinksResponse = await context.request('GET', `${SMART}/plans/${planId}/preloads`)
const pushedLinks = context.apiSuccess(MODULE, '无号 push 自动建立 bridge', pushedLinksResponse, '', OPTIONS)
const pushedLink = Array.isArray(pushedLinks)
? pushedLinks.find((item) => id(item.inboundId) === inboundId && id(item.loadingPlanId) === planId) : null
context.assert(MODULE, 'push 自动 bridge 保持预装和柜次稳定归属', pushedLinksResponse,
Boolean(pushedLink?.id) && Number(pushedLink?.allocatedPackageCount) === 1,
`linkId=${id(pushedLink?.id) || 'missing'}, preloadPlanId=${id(pushedLink?.preloadPlanId) || 'missing'}`, OPTIONS)
if (!pushedLink?.id) return
const pushedTaskResponse = await context.request('GET',
`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
context.addStep(MODULE, '无号 push 成功后 PDA 查询 A0404', pushedTaskResponse,
pushedTaskResponse.http === 200 && codeOf(pushedTaskResponse) === 'A0404',
responseEvidence(pushedTaskResponse), OPTIONS)
const pushBaseline = JSON.stringify({
plan: pushed, detail: pushedDetail, links: pushedLinks,
task: { http: pushedTaskResponse.http, code: codeOf(pushedTaskResponse) },
})
const pushReplayResponse = await request(context, 'POST', pushRequest.path, pushRequest.body, pushRequest.headers)
context.apiSuccess(MODULE, '推送预装 exact replay', pushReplayResponse, '', OPTIONS)
const replayPlanResponse = await context.request('GET', `${SMART}/plans/${planId}`)
const replayPlan = context.apiSuccess(MODULE, '重放后回查柜次计划', replayPlanResponse, '', OPTIONS)
const replayDetailResponse = await context.request('GET',
`${FIRST_LEG}/loading-plans/${planId}?warehouseId=${encodeURIComponent(warehouseId)}`)
const replayDetail = context.apiSuccess(MODULE, '重放后回查预装历史', replayDetailResponse, '', OPTIONS)
const replayLinksResponse = await context.request('GET', `${SMART}/plans/${planId}/preloads`)
const replayLinks = context.apiSuccess(MODULE, '重放后回查 bridge', replayLinksResponse, '', OPTIONS)
const replayTaskResponse = await context.request('GET',
`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
const pushReplaySnapshot = JSON.stringify({
plan: replayPlan, detail: replayDetail, links: replayLinks,
task: { http: replayTaskResponse.http, code: codeOf(replayTaskResponse) },
})
context.assert(MODULE, 'push exact replay 对计划版本历史关联任务零漂移', pushReplayResponse,
pushBaseline === pushReplaySnapshot && codeOf(replayTaskResponse) === 'A0404',
`baselineBytes=${pushBaseline.length}, replayBytes=${pushReplaySnapshot.length}`, OPTIONS)
const pushSameKeyDifferentBody = await request(context, 'POST', pushRequest.path,
{ expectedVersion: Number(pushed.version) }, pushRequest.headers)
context.addStep(MODULE, 'push 同 key 异参拒绝', pushSameKeyDifferentBody,
failure(pushSameKeyDifferentBody), responseEvidence(pushSameKeyDifferentBody), OPTIONS)
const pushNewKeyDuplicate = await request(context, 'POST', pushRequest.path, pushRequest.body,
{ 'Idempotency-Key': `${context.marker}-container-push-duplicate`.slice(0, 128) })
context.addStep(MODULE, '已推送计划使用新 key 重复 push 拒绝', pushNewKeyDuplicate,
failure(pushNewKeyDuplicate), responseEvidence(pushNewKeyDuplicate), OPTIONS)
const rejectedPlanResponse = await context.request('GET', `${SMART}/plans/${planId}`)
const rejectedPlan = context.apiSuccess(MODULE, '非法 push 后回查柜次计划', rejectedPlanResponse, '', OPTIONS)
const rejectedDetailResponse = await context.request('GET',
`${FIRST_LEG}/loading-plans/${planId}?warehouseId=${encodeURIComponent(warehouseId)}`)
const rejectedDetail = context.apiSuccess(MODULE, '非法 push 后回查预装历史', rejectedDetailResponse, '', OPTIONS)
const rejectedLinksResponse = await context.request('GET', `${SMART}/plans/${planId}/preloads`)
const rejectedLinks = context.apiSuccess(MODULE, '非法 push 后回查 bridge', rejectedLinksResponse, '', OPTIONS)
const rejectedTaskResponse = await context.request('GET',
`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
const rejectedSnapshot = JSON.stringify({
plan: rejectedPlan, detail: rejectedDetail, links: rejectedLinks,
task: { http: rejectedTaskResponse.http, code: codeOf(rejectedTaskResponse) },
})
context.assert(MODULE, '两类非法 push 后计划版本历史关联任务仍零漂移', rejectedTaskResponse,
failure(pushSameKeyDifferentBody) && failure(pushNewKeyDuplicate)
&& pushBaseline === rejectedSnapshot && codeOf(rejectedTaskResponse) === 'A0404',
`baselineBytes=${pushBaseline.length}, rejectedBytes=${rejectedSnapshot.length}`, OPTIONS)
if (pushBaseline !== rejectedSnapshot || codeOf(rejectedTaskResponse) !== 'A0404') return
const realContainerNo = `TST-${suffix}`.slice(0, 64)
const transportResponse = await request(context, 'PATCH',
`${FIRST_LEG}/loading-plans/${planId}/transport?warehouseId=${encodeURIComponent(warehouseId)}`, {
containerNo: realContainerNo, voyageNo: `V-${suffix}`.slice(0, 64),
expectedVersion: Number(pushed.version), operationReason: context.marker,
}, { 'Idempotency-Key': `${context.marker}-preload-bind-container-no`.slice(0, 128) })
const transported = context.apiSuccess(MODULE, '预装 EDITING 清单绑定本轮真实柜号', transportResponse, '', OPTIONS)
context.assert(MODULE, '预装补号保持柜次和计划身份稳定', transportResponse,
transported?.summary?.containerNo === realContainerNo
&& id(transported?.summary?.planId) === planId
&& id(transported?.summary?.containerBookingId) === containerId,
`containerNo=${transported?.summary?.containerNo || 'missing'}, containerBookingId=${id(transported?.summary?.containerBookingId) || 'missing'}, loadingPlanId=${id(transported?.summary?.planId) || 'missing'}`, OPTIONS)
if (transported?.summary?.containerNo !== realContainerNo) return
const unlinkedTaskResponse = await context.request('GET',
`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
const unlinkedTaskAbsent = unlinkedTaskResponse.http === 200 && codeOf(unlinkedTaskResponse) === 'A0404'
context.addStep(MODULE, '已补号但未关联订舱不生成 PDA 任务', unlinkedTaskResponse,
unlinkedTaskAbsent, responseEvidence(unlinkedTaskResponse), OPTIONS)
if (!unlinkedTaskAbsent) return
const transportedContainerResponse = await context.request('GET', `${CONTAINERS}/${containerId}`)
const transportedContainer = context.apiSuccess(MODULE, '预装补号后读取模拟柜最新版本', transportedContainerResponse, '', OPTIONS)
if (!Number.isInteger(Number(transportedContainer?.version))) return
const bookingCreate = await request(context, 'POST', '/api/platform/v1/ocean-bookings',
{ expectedVersion: 0, data: bookingDraft }, { 'Idempotency-Key': `${context.marker}-loading-booking-create` })
const bookingCreated = context.apiSuccess(MODULE, '登记含渠道仓库和运输快照的已确认真实订舱', bookingCreate, '', OPTIONS)
@@ -264,7 +370,7 @@ export async function run(context) {
const wrongTypeRequirement = confirmedBooking?.containerRequirements?.find?.((item) => item.containerType !== primaryRequirement.containerType)
if (!requirement?.id || !wrongTypeRequirement?.id) return
const wrongTypeLinkResponse = await request(context, 'POST', `${CONTAINERS}/${containerId}/ocean-booking-link`, {
oceanBookingId: bookingId, requirementId: id(wrongTypeRequirement.id), expectedVersion: Number(containerDetail.version),
oceanBookingId: bookingId, requirementId: id(wrongTypeRequirement.id), expectedVersion: Number(transportedContainer.version),
})
context.addStep(MODULE, '箱型不匹配拒绝关联真实订舱柜', wrongTypeLinkResponse,
failure(wrongTypeLinkResponse), `HTTP=${wrongTypeLinkResponse.http}, code=${codeOf(wrongTypeLinkResponse)}`, OPTIONS)
@@ -303,7 +409,7 @@ export async function run(context) {
const beforeLinkItems = JSON.stringify(assigned.items?.map((item) => ({ id: id(item.id), inboundId: id(item.inboundId), packageCount: Number(item.packageCount) })) || [])
const linkResponse = await request(context, 'POST', `${CONTAINERS}/${containerId}/ocean-booking-link`, {
oceanBookingId: bookingId, requirementId: id(requirement.id), expectedVersion: Number(containerDetail.version),
oceanBookingId: bookingId, requirementId: id(requirement.id), expectedVersion: Number(transportedContainer.version),
})
const linkedContainer = context.apiSuccess(MODULE, '首次关联真实已确认订舱柜', linkResponse,
responseEvidence(linkResponse), OPTIONS)
@@ -334,41 +440,11 @@ export async function run(context) {
context.addStep(MODULE, '已有排货后拒绝解绑或换绑', unlinkAfterLoadingResponse,
failure(unlinkAfterLoadingResponse), `HTTP=${unlinkAfterLoadingResponse.http}, code=${codeOf(unlinkAfterLoadingResponse)}`, OPTIONS)
const missingContainerPushResponse = await request(context, 'POST', `${SMART}/plans/${planId}/push-preload`,
{ expectedVersion: Number(assigned.version) },
{ 'Idempotency-Key': `${context.marker}-container-push-without-container-no`.slice(0, 128) })
const missingContainerPushRejected = failure(missingContainerPushResponse)
context.addStep(MODULE, '无真实柜号拒绝推送预装计划', missingContainerPushResponse,
missingContainerPushRejected,
`HTTP=${missingContainerPushResponse.http}, code=${codeOf(missingContainerPushResponse)}, requestId=${missingContainerPushResponse.requestId || 'missing'}, traceId=${missingContainerPushResponse.traceId || 'missing'}`, OPTIONS)
if (!missingContainerPushRejected) return
const gatedTaskResponse = await context.request('GET',
`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
const gatedTaskAbsent = failure(gatedTaskResponse)
|| !id(gatedTaskResponse?.body?.id || gatedTaskResponse?.body?.data?.id)
context.addStep(MODULE, '无真实柜号推送失败后不生成 PDA 任务', gatedTaskResponse,
gatedTaskAbsent,
`HTTP=${gatedTaskResponse.http}, code=${codeOf(gatedTaskResponse)}, task=${id(gatedTaskResponse?.body?.id || gatedTaskResponse?.body?.data?.id) || 'none'}`, OPTIONS)
if (!gatedTaskAbsent) return
const transportResponse = await request(context, 'PATCH', `${CONTAINERS}/${containerId}/transport`, {
containerNo: `TST-${suffix}`.slice(0, 64), voyageNo: `V-${suffix}`.slice(0, 64),
version: Number(linkedContainer.version), reason: context.marker,
})
const transported = context.apiSuccess(MODULE, '在放舱前绑定本轮真实箱号', transportResponse, '', OPTIONS)
context.assert(MODULE, '绑定后柜次保留本轮箱号', transportResponse,
transported?.containerNo === `TST-${suffix}`.slice(0, 64)
&& id(transported?.id) === containerId && transported?.cabinetNo === linkedContainer.cabinetNo,
`containerNo=${transported?.containerNo || 'missing'}, containerBookingId=${id(transported?.id) || 'missing'}, loadingPlanId=${planId}`, OPTIONS)
if (transported?.containerNo !== `TST-${suffix}`.slice(0, 64)) return
const confirmedTaskResponse = await context.request('GET',
`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
const confirmedTaskAbsent = failure(confirmedTaskResponse)
|| !id(confirmedTaskResponse?.body?.id || confirmedTaskResponse?.body?.data?.id)
context.addStep(MODULE, '订舱 CONFIRMED 即使已有真实柜号也不开放 PDA 任务', confirmedTaskResponse,
confirmedTaskAbsent,
`HTTP=${confirmedTaskResponse.http}, code=${codeOf(confirmedTaskResponse)}, task=${id(confirmedTaskResponse?.body?.id || confirmedTaskResponse?.body?.data?.id) || 'none'}`, OPTIONS)
const confirmedTaskAbsent = confirmedTaskResponse.http === 200 && codeOf(confirmedTaskResponse) === 'A0404'
context.addStep(MODULE, '订舱已关联但未 RELEASED 不生成 PDA 任务', confirmedTaskResponse,
confirmedTaskAbsent, responseEvidence(confirmedTaskResponse), OPTIONS)
if (!confirmedTaskAbsent) return
const releaseResponse = await request(context, 'POST', `/api/platform/v1/ocean-bookings/${bookingId}/release`, {
@@ -383,29 +459,6 @@ export async function run(context) {
`status=${releasedBooking?.oceanBooking?.status || 'missing'}, containerBookingId=${containerId}, transportFrozen=${transportFields.every((field) => String(releasedBooking?.oceanBooking?.[field]) === String(frozenTransport[field]))}`, OPTIONS)
if (releasedBooking?.oceanBooking?.status !== 'RELEASED') return
const releasedContainerResponse = await context.request('GET', `${CONTAINERS}/${containerId}`)
const releasedContainer = context.apiSuccess(MODULE, '放舱后回查货柜运输版本', releasedContainerResponse, '', OPTIONS)
const pushKey = `${context.marker}-container-push`.slice(0, 128)
const pushRequest = Object.freeze({
path: `${SMART}/plans/${planId}/push-preload`,
body: Object.freeze({ expectedVersion: Number(assigned.version) }),
headers: Object.freeze({ 'Idempotency-Key': pushKey }),
})
const pushResponse = await request(context, 'POST', pushRequest.path, pushRequest.body, pushRequest.headers)
const pushed = context.apiSuccess(MODULE, '柜号与 RELEASED 订舱就绪后推送预装计划', pushResponse, '', OPTIONS)
context.assert(MODULE, '推送后计划保持 EDITING 且版本递增', pushResponse,
pushed?.status === 'EDITING' && Number(pushed?.version) === Number(assigned.version) + 1,
`status=${pushed?.status || 'missing'}, version=${pushed?.version ?? 'missing'}`, OPTIONS)
if (pushed?.status !== 'EDITING') return
const pushReplayResponse = await request(context, 'POST', pushRequest.path, pushRequest.body, pushRequest.headers)
const pushReplay = context.apiSuccess(MODULE, '推送预装 Idempotency-Key 重放', pushReplayResponse, '', OPTIONS)
context.assert(MODULE, '推送重放保持同一 EDITING 计划', pushReplayResponse,
id(pushReplay?.id) === planId && pushReplay?.status === 'EDITING'
&& Number(pushReplay?.version) === Number(pushed.version),
`planId=${id(pushReplay?.id) || 'missing'}, version=${pushReplay?.version ?? 'missing'}`, OPTIONS)
const preloadPageResponse = await context.request('GET',
`${FIRST_LEG}/loading-plans?warehouseId=${encodeURIComponent(warehouseId)}&keyword=${encodeURIComponent(containerNo)}&page=1&size=20`)
const preloadPage = context.apiSuccess(MODULE, '查询本轮预装清单', preloadPageResponse, '', OPTIONS)
@@ -413,20 +466,84 @@ export async function run(context) {
records(preloadPage).some((item) => id(item.planId) === planId && item.status === 'EDITING'),
`records=${records(preloadPage).length}`, OPTIONS)
const unconfirmedTaskResponse = await context.request('GET',
`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
context.addStep(MODULE, '订舱 RELEASED 但预装未 CONFIRMED 不生成 PDA 任务', unconfirmedTaskResponse,
unconfirmedTaskResponse.http === 200 && codeOf(unconfirmedTaskResponse) === 'A0404',
responseEvidence(unconfirmedTaskResponse), OPTIONS)
const confirmableResponse = await context.request('GET',
`${FIRST_LEG}/loading-plans/${planId}?warehouseId=${encodeURIComponent(warehouseId)}`)
const confirmable = context.apiSuccess(MODULE, '计划级确认前读取即时版本与就绪门禁', confirmableResponse, '', OPTIONS)
const confirmableVersion = Number(confirmable?.summary?.version)
context.assert(MODULE, '补号关联放舱后整份计划允许确认且 PDA 尚未创建', confirmableResponse,
Number.isInteger(confirmableVersion) && confirmable?.summary?.status === 'EDITING'
&& confirmable?.summary?.readiness?.canConfirm === true
&& confirmable?.summary?.readiness?.readyForPda === false
&& confirmable?.summary?.readiness?.pdaTaskId == null,
`version=${confirmable?.summary?.version ?? 'missing'}, canConfirm=${confirmable?.summary?.readiness?.canConfirm}, pdaTaskId=${id(confirmable?.summary?.readiness?.pdaTaskId) || 'none'}`, OPTIONS)
if (!Number.isInteger(confirmableVersion) || confirmable?.summary?.readiness?.canConfirm !== true) return
const confirmPath = `${FIRST_LEG}/loading-plans/${planId}/confirm`
const confirmBody = Object.freeze({ expectedVersion: confirmableVersion })
const confirmHeaders = Object.freeze({
'Idempotency-Key': `${context.marker}-container-plan-confirm`.slice(0, 128),
})
const confirmResponse = await request(context, 'POST', confirmPath, confirmBody, confirmHeaders)
const confirmedPreload = context.apiSuccess(MODULE, '计划级原子确认整份预装并触发唯一 PDA 任务', confirmResponse, '', OPTIONS)
const confirmedTaskId = id(confirmedPreload?.readiness?.pdaTaskId)
context.assert(MODULE, '计划确认返回 CONFIRMED、readyForPda 与唯一 taskId', confirmResponse,
id(confirmedPreload?.planId) === planId && id(confirmedPreload?.containerBookingId) === containerId
&& confirmedPreload?.confirmationStatus === 'CONFIRMED'
&& confirmedPreload?.readiness?.confirmationStatus === 'CONFIRMED'
&& confirmedPreload?.readiness?.readyForPda === true && Boolean(confirmedTaskId)
&& Number(confirmedPreload?.version) > confirmableVersion,
`confirmationStatus=${confirmedPreload?.confirmationStatus || 'missing'}, readyForPda=${confirmedPreload?.readiness?.readyForPda}, pdaTaskId=${confirmedTaskId || 'missing'}`, OPTIONS)
if (!confirmedTaskId || confirmedPreload?.confirmationStatus !== 'CONFIRMED') return
const confirmReplayResponse = await request(context, 'POST', confirmPath, confirmBody, confirmHeaders)
context.assert(MODULE, '计划级确认同键同参精确重放同一 taskId 与版本', confirmReplayResponse,
confirmReplayResponse.http === 200 && codeOf(confirmReplayResponse) === '200'
&& id(confirmReplayResponse.body?.data?.readiness?.pdaTaskId) === confirmedTaskId
&& Number(confirmReplayResponse.body?.data?.version) === Number(confirmedPreload.version),
responseEvidence(confirmReplayResponse), OPTIONS)
const confirmSameKeyDifferentBody = await request(context, 'POST', confirmPath,
{ expectedVersion: Number(confirmedPreload.version) }, confirmHeaders)
context.addStep(MODULE, '计划级确认同 key 异参返回冲突', confirmSameKeyDifferentBody,
confirmSameKeyDifferentBody.http === 200 && codeOf(confirmSameKeyDifferentBody) === 'A0409',
responseEvidence(confirmSameKeyDifferentBody), OPTIONS)
const confirmNewKeyDuplicate = await request(context, 'POST', confirmPath, confirmBody,
{ 'Idempotency-Key': `${context.marker}-container-plan-confirm-duplicate`.slice(0, 128) })
context.addStep(MODULE, '已确认计划使用新 key 重复确认返回冲突', confirmNewKeyDuplicate,
confirmNewKeyDuplicate.http === 200 && codeOf(confirmNewKeyDuplicate) === 'A0409',
responseEvidence(confirmNewKeyDuplicate), OPTIONS)
const confirmedInboundResponse = await context.request('GET',
`/api/platform/inbounds/${inboundId}?tenantId=${encodeURIComponent(tenantId)}`)
const confirmedInbound = context.apiSuccess(MODULE, '计划确认后 claim 前回查入库状态', confirmedInboundResponse, '', OPTIONS)
const confirmedPlanResponse = await context.request('GET', `${SMART}/plans/${planId}`)
const confirmedPlan = context.apiSuccess(MODULE, '计划确认后 claim 前回查柜次计划', confirmedPlanResponse, '', OPTIONS)
context.assert(MODULE, '计划确认后 task 待领取且 claim 前仍 WAIT_SPLIT/EDITING', confirmedPlanResponse,
confirmedInbound?.summary?.processStatus === 'WAIT_SPLIT' && confirmedPlan?.status === 'EDITING'
&& Number(confirmedPlan?.version) === Number(confirmedPreload.version),
`inbound=${confirmedInbound?.summary?.processStatus || 'missing'}, plan=${confirmedPlan?.status || 'missing'}`, OPTIONS)
if (confirmedInbound?.summary?.processStatus !== 'WAIT_SPLIT' || confirmedPlan?.status !== 'EDITING') return
const taskResponse = await context.request('GET',
`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
const task = context.apiSuccess(MODULE, '查询本轮柜次 PDA 拣货任务', taskResponse, '', OPTIONS)
const taskId = id(task?.id)
const pickItem = task?.items?.find?.((item) => id(item.loadingPlanItemId) === id(planItem.id))
context.assert(MODULE, 'PDA 任务、计划明细和待拣箱数关联正确', taskResponse,
Boolean(taskId) && id(task?.loadingPlanId) === planId
Boolean(taskId) && taskId === confirmedTaskId && id(task?.loadingPlanId) === planId
&& id(task?.containerBookingId) === containerId && Boolean(task?.cabinetNo)
&& task?.currentContainerNo === `TST-${suffix}`.slice(0, 64) && task?.taskStatus === 'LOADING'
&& task?.currentContainerNo === realContainerNo && task?.taskStatus === 'LOADING'
&& task?.workflowStatus === 'UNASSIGNED'
&& Boolean(pickItem?.id) && Number(pickItem?.plannedPackageCount) === 1,
`taskId=${taskId || 'missing'}, itemId=${id(pickItem?.id) || 'missing'}`, OPTIONS)
if (!taskId || !pickItem?.id) return
const releasedContainerResponse = await context.request('GET', `${CONTAINERS}/${containerId}`)
const releasedContainer = context.apiSuccess(MODULE, '任务生成后回查货柜运输版本', releasedContainerResponse, '', OPTIONS)
const stableIdentity = {
taskId, loadingPlanId: id(task.loadingPlanId), containerBookingId: id(task.containerBookingId),
cabinetNo: id(task.cabinetNo),