feat: close preload confirmation and loading flow
This commit is contained in:
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user