fix: restore phase five development acceptance chain
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { publishPlatformLogisticsChannels } from './ocean-booking-fixture.mjs'
|
||||
import { diffPushPreloadStability, projectPushPreloadStability } from './push-preload-stability.mjs'
|
||||
import { containerFieldGaps, loadingListFieldGaps, preloadFieldGaps } from './fulfillment-list-field-contract.mjs'
|
||||
import { ensureMatsonCarrierPartner } from './carrier-partner-fixture.mjs'
|
||||
import { iso6346ContainerNumber } from './iso6346-container-number.mjs'
|
||||
@@ -163,7 +162,7 @@ export async function run(context) {
|
||||
const realContainerNo = iso6346ContainerNumber(`${context.marker}-initial`)
|
||||
const wrongContainerNo = `TST-${suffix}-02`.slice(0, 64)
|
||||
const agentResponse = await context.request('GET',
|
||||
'/api/platform/v1/suppliers?tenantId=0&category=BOOKING&status=ACTIVE&page=1&size=20')
|
||||
'/api/platform/v1/suppliers?tenantId=0&category=BOOKING&status=ACTIVE&carrierCode=MATSON&page=1&size=20')
|
||||
const agentPage = context.apiSuccess(MODULE, '查询放舱所需 ACTIVE 订舱代理', agentResponse, '', OPTIONS)
|
||||
const bookingAgent = records(agentPage).find((item) => item?.category === 'BOOKING' && item?.status === 'ACTIVE')
|
||||
context.assert(MODULE, '放舱订舱使用真实启用供应商', agentResponse,
|
||||
@@ -259,8 +258,8 @@ export async function run(context) {
|
||||
`planStatus=${containerDetail?.planStatus || 'missing'}, channel=${containerDetail?.channelCode || 'missing'}`, OPTIONS)
|
||||
|
||||
const containerNo = id(containerDetail?.containerNo || containerDetail?.cabinetNo)
|
||||
const planResponse = await request(context, 'POST', `${SMART}/plans`, { bookingId: containerId, remark: context.marker })
|
||||
const plan = context.apiSuccess(MODULE, '创建智能装柜计划', planResponse, '', OPTIONS)
|
||||
const planResponse = await context.request('GET', `${SMART}/plans/by-booking/${encodeURIComponent(containerId)}`)
|
||||
const plan = context.apiSuccess(MODULE, '读取柜次创建时原子生成的智能装柜计划', planResponse, '', OPTIONS)
|
||||
const planId = id(plan?.id)
|
||||
context.assert(MODULE, '装柜计划与货柜关联且处于 EDITING', planResponse,
|
||||
Boolean(planId) && id(plan?.bookingId) === containerId && plan?.status === 'EDITING'
|
||||
@@ -268,9 +267,9 @@ export async function run(context) {
|
||||
`planId=${planId || 'missing'}, status=${plan?.status || 'missing'}`, OPTIONS)
|
||||
if (!planId) return
|
||||
|
||||
const planReplayResponse = await request(context, 'POST', `${SMART}/plans`, { bookingId: containerId, remark: 'replay' })
|
||||
const planReplay = context.apiSuccess(MODULE, '重放货柜装柜计划创建', planReplayResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '同一货柜重放返回同一计划', planReplayResponse,
|
||||
const planReplayResponse = await context.request('GET', `${SMART}/plans/by-booking/${encodeURIComponent(containerId)}`)
|
||||
const planReplay = context.apiSuccess(MODULE, '重复读取货柜唯一装柜计划', planReplayResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '同一货柜始终返回同一计划', planReplayResponse,
|
||||
id(planReplay?.id) === planId, `first=${planId}, replay=${id(planReplay?.id) || 'missing'}`, OPTIONS)
|
||||
|
||||
const assignPayload = {
|
||||
@@ -299,95 +298,28 @@ 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',
|
||||
const synchronizedDetailResponse = 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 postPushPlanResponse = await context.request('GET', `${SMART}/plans/${planId}`)
|
||||
const postPushPlan = context.apiSuccess(MODULE, '首次 push 后读取事务完成态柜次计划', postPushPlanResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '事务完成态计划版本与 bridge 一致且保持 EDITING', postPushPlanResponse,
|
||||
postPushPlan?.status === 'EDITING' && Number(postPushPlan?.version) === Number(pushedLink?.loadingPlanVersion)
|
||||
&& Number(postPushPlan?.version) > Number(assigned.version),
|
||||
`pushResponseVersion=${pushed?.version ?? 'missing'}, persistedVersion=${postPushPlan?.version ?? 'missing'}, bridgeVersion=${pushedLink?.loadingPlanVersion ?? 'missing'}`, OPTIONS)
|
||||
if (postPushPlan?.status !== 'EDITING' || !Number.isInteger(Number(postPushPlan?.version))) return
|
||||
const pushedTaskResponse = await context.request('GET',
|
||||
context.apiSuccess(MODULE, '分配后预装清单可见', synchronizedDetailResponse, '', OPTIONS)
|
||||
const synchronizedLinksResponse = await context.request('GET', `${SMART}/plans/${planId}/preloads`)
|
||||
const synchronizedLinks = context.apiSuccess(MODULE, '分配同步建立 bridge', synchronizedLinksResponse, '', OPTIONS)
|
||||
const synchronizedLink = Array.isArray(synchronizedLinks)
|
||||
? synchronizedLinks.find((item) => id(item.inboundId) === inboundId && id(item.loadingPlanId) === planId) : null
|
||||
context.assert(MODULE, '分配自动 bridge 保持预装和柜次稳定归属', synchronizedLinksResponse,
|
||||
Boolean(synchronizedLink?.id) && Number(synchronizedLink?.allocatedPackageCount) === 1,
|
||||
`linkId=${id(synchronizedLink?.id) || 'missing'}, preloadPlanId=${id(synchronizedLink?.preloadPlanId) || 'missing'}`, OPTIONS)
|
||||
if (!synchronizedLink?.id) return
|
||||
const synchronizedPlanResponse = await context.request('GET', `${SMART}/plans/${planId}`)
|
||||
const synchronizedPlan = context.apiSuccess(MODULE, '读取分配事务完成态柜次计划', synchronizedPlanResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '事务完成态计划版本与 bridge 一致且保持 EDITING', synchronizedPlanResponse,
|
||||
synchronizedPlan?.status === 'EDITING' && Number(synchronizedPlan?.version) === Number(synchronizedLink?.loadingPlanVersion),
|
||||
`persistedVersion=${synchronizedPlan?.version ?? 'missing'}, bridgeVersion=${synchronizedLink?.loadingPlanVersion ?? 'missing'}`, OPTIONS)
|
||||
if (synchronizedPlan?.status !== 'EDITING' || !Number.isInteger(Number(synchronizedPlan?.version))) return
|
||||
const synchronizedTaskResponse = 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 = projectPushPreloadStability({
|
||||
plan: postPushPlan, 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 = projectPushPreloadStability({
|
||||
plan: replayPlan, detail: replayDetail, links: replayLinks,
|
||||
task: { http: replayTaskResponse.http, code: codeOf(replayTaskResponse) },
|
||||
})
|
||||
const pushReplayDiff = diffPushPreloadStability(pushBaseline, pushReplaySnapshot)
|
||||
context.assert(MODULE, 'push exact replay 对计划版本历史关联任务零漂移', pushReplayResponse,
|
||||
pushReplayDiff.length === 0 && codeOf(replayTaskResponse) === 'A0404',
|
||||
`changed=${pushReplayDiff.join('|') || 'none'}; replayTask=${responseEvidence(replayTaskResponse)}`, OPTIONS)
|
||||
const pushSameKeyDifferentBody = await request(context, 'POST', pushRequest.path,
|
||||
{ expectedVersion: Number(postPushPlan.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 = projectPushPreloadStability({
|
||||
plan: rejectedPlan, detail: rejectedDetail, links: rejectedLinks,
|
||||
task: { http: rejectedTaskResponse.http, code: codeOf(rejectedTaskResponse) },
|
||||
})
|
||||
const rejectedDiff = diffPushPreloadStability(pushBaseline, rejectedSnapshot)
|
||||
context.assert(MODULE, '两类非法 push 后计划版本历史关联任务仍零漂移', rejectedTaskResponse,
|
||||
failure(pushSameKeyDifferentBody) && failure(pushNewKeyDuplicate)
|
||||
&& rejectedDiff.length === 0 && codeOf(rejectedTaskResponse) === 'A0404',
|
||||
`changed=${rejectedDiff.join('|') || 'none'}; sameKey=${responseEvidence(pushSameKeyDifferentBody)}; newKey=${responseEvidence(pushNewKeyDuplicate)}; task=${responseEvidence(rejectedTaskResponse)}`, OPTIONS)
|
||||
if (rejectedDiff.length !== 0 || codeOf(rejectedTaskResponse) !== 'A0404') return
|
||||
context.addStep(MODULE, '无真实柜号时 PDA 查询 A0404', synchronizedTaskResponse,
|
||||
synchronizedTaskResponse.http === 200 && codeOf(synchronizedTaskResponse) === 'A0404',
|
||||
responseEvidence(synchronizedTaskResponse), OPTIONS)
|
||||
|
||||
const unlinkedTaskResponse = await context.request('GET',
|
||||
`${PDA}/tasks?loadingPlanId=${encodeURIComponent(planId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
|
||||
Reference in New Issue
Block a user