优化
This commit is contained in:
@@ -3,6 +3,13 @@ const OPTIONS = { scenario: 'phase3-loading-hard-gate-finalize', deploymentBlock
|
||||
|
||||
function id(value) { return value == null ? '' : String(value) }
|
||||
function codeOf(response) { return response?.body?.code == null ? 'missing' : String(response.body.code) }
|
||||
function evidenceSignature(data) {
|
||||
return JSON.stringify((data?.evidences || []).map((item) => ({
|
||||
id: id(item?.id), type: item?.evidenceType || null, fileId: id(item?.fileId),
|
||||
status: item?.status || null, version: Number(item?.version), sealNo: item?.sealNo || null,
|
||||
voidReason: item?.voidReason || null, voidedBy: id(item?.voidedBy), voidedAt: item?.voidedAt || null,
|
||||
})))
|
||||
}
|
||||
|
||||
export function buildFinalizeResource(fixture, finalData, completeResponse) {
|
||||
const observedStatus = finalData?.summary?.processStatus || fixture?.inboundStatus || 'UNKNOWN'
|
||||
@@ -86,5 +93,92 @@ export async function run(context) {
|
||||
&& item.operatorName && item.fromStatus === 'LOADING' && item.toStatus === 'LOADED'),
|
||||
`status=${finalData?.summary?.processStatus || 'missing'}, version=${finalData?.summary?.version ?? 'missing'}, histories=${finalData?.statusHistory?.length ?? 'n/a'}`, OPTIONS)
|
||||
|
||||
const evidencePath = `${base}/loading/evidence?tenantId=${encodeURIComponent(tenantId)}`
|
||||
const immutableEvidenceResponse = await context.request('GET', evidencePath)
|
||||
const immutableEvidence = context.apiSuccess(MODULE, '读取 LOADED 后不可变证据快照', immutableEvidenceResponse, '', OPTIONS)
|
||||
const planPath = `/api/platform/v1/first-leg/smart-loading/plans/${encodeURIComponent(id(fixture.loadingPlanId))}`
|
||||
const immutablePlanResponse = await context.request('GET', planPath)
|
||||
const immutablePlan = context.apiSuccess(MODULE, '读取 LOADED 后装柜计划快照', immutablePlanResponse, '', OPTIONS)
|
||||
const finalVersion = Number(finalData?.summary?.version)
|
||||
const historySignature = JSON.stringify((finalData?.statusHistory || []).map((item) => ({
|
||||
action: item?.action || null, from: item?.fromStatus || null, to: item?.toStatus || null,
|
||||
operatorId: id(item?.operatorId), occurredAt: item?.occurredAt || item?.createdAt || null,
|
||||
})))
|
||||
const immutableEvidenceSignature = evidenceSignature(immutableEvidence)
|
||||
const immutablePlanSignature = JSON.stringify({
|
||||
version: Number(immutablePlan?.version), status: immutablePlan?.status || null,
|
||||
containerNo: immutablePlan?.containerNo || null, voyageNo: immutablePlan?.voyageNo || null,
|
||||
items: (immutablePlan?.items || []).map((item) => ({ id: id(item?.id), frozenAt: item?.frozenAt || null })),
|
||||
})
|
||||
|
||||
const completeNewKey = await request(context, 'POST',
|
||||
`${base}/loading/complete?tenantId=${encodeURIComponent(tenantId)}`,
|
||||
{ expectedVersion: finalVersion, remark: `${context.marker}-loaded-new-key` },
|
||||
{ 'Idempotency-Key': `${context.marker}-p3-complete-loaded-new-key`.slice(0, 128) })
|
||||
context.assert(MODULE, 'LOADED 后使用新键重复 complete 幂等保持终态', completeNewKey,
|
||||
completeNewKey.http === 200 && codeOf(completeNewKey) === '200'
|
||||
&& completeNewKey.body?.data?.mainStatus === 'LOADED',
|
||||
`HTTP=${completeNewKey.http}, code=${codeOf(completeNewKey)}, status=${completeNewKey.body?.data?.mainStatus || 'missing'}`, OPTIONS)
|
||||
|
||||
const completeSameKeyDifferentBody = await request(context, 'POST',
|
||||
`${base}/loading/complete?tenantId=${encodeURIComponent(tenantId)}`,
|
||||
{ expectedVersion: version, remark: `${context.marker}-different-complete-body` },
|
||||
{ 'Idempotency-Key': `${context.marker}-p3-complete-after-downstream`.slice(0, 128) })
|
||||
context.addStep(MODULE, 'LOADED complete 同键异参返回冲突', completeSameKeyDifferentBody,
|
||||
completeSameKeyDifferentBody.http === 200 && codeOf(completeSameKeyDifferentBody) === 'A0409'
|
||||
&& Boolean(completeSameKeyDifferentBody.requestId) && Boolean(completeSameKeyDifferentBody.traceId),
|
||||
`HTTP=${completeSameKeyDifferentBody.http}, code=${codeOf(completeSameKeyDifferentBody)}, requestId=${completeSameKeyDifferentBody.requestId || 'missing'}, traceId=${completeSameKeyDifferentBody.traceId || 'missing'}`, OPTIONS)
|
||||
|
||||
const postLoadedEvidence = await request(context, 'POST', evidencePath, {
|
||||
expectedVersion: 0, evidenceType: 'PHOTO_STEP_2', fileId: fixture.postLoadedFileId,
|
||||
fileName: 'client-must-not-override.png', sealNo: null, remark: context.marker,
|
||||
}, { 'Idempotency-Key': `${context.marker}-p3-evidence-after-loaded`.slice(0, 128) })
|
||||
context.addStep(MODULE, 'LOADED 后新增装柜证据被拒绝', postLoadedEvidence,
|
||||
postLoadedEvidence.http === 200 && codeOf(postLoadedEvidence) === 'A0409'
|
||||
&& Boolean(postLoadedEvidence.requestId) && Boolean(postLoadedEvidence.traceId),
|
||||
`HTTP=${postLoadedEvidence.http}, code=${codeOf(postLoadedEvidence)}, requestId=${postLoadedEvidence.requestId || 'missing'}, traceId=${postLoadedEvidence.traceId || 'missing'}`, OPTIONS)
|
||||
|
||||
const postLoadedVoid = await request(context, 'POST',
|
||||
`${base}/loading/evidence/${encodeURIComponent(id(fixture.immutableEvidenceId))}/void?tenantId=${encodeURIComponent(tenantId)}`,
|
||||
{ expectedVersion: Number(fixture.immutableEvidenceVersion), reason: `${context.marker}-void-after-loaded` },
|
||||
{ 'Idempotency-Key': `${context.marker}-p3-evidence-void-after-loaded`.slice(0, 128) })
|
||||
context.addStep(MODULE, 'LOADED 后作废装柜证据被拒绝', postLoadedVoid,
|
||||
postLoadedVoid.http === 200 && codeOf(postLoadedVoid) === 'A0409'
|
||||
&& Boolean(postLoadedVoid.requestId) && Boolean(postLoadedVoid.traceId),
|
||||
`HTTP=${postLoadedVoid.http}, code=${codeOf(postLoadedVoid)}, requestId=${postLoadedVoid.requestId || 'missing'}, traceId=${postLoadedVoid.traceId || 'missing'}`, OPTIONS)
|
||||
|
||||
const immutableTransport = await request(context, 'PATCH',
|
||||
`/api/platform/v1/first-leg/loading-plans/${encodeURIComponent(id(fixture.loadingPlanId))}/transport?warehouseId=${encodeURIComponent(id(fixture.warehouseId))}`,
|
||||
{ containerNo: `MUTATE-${context.marker}`.slice(0, 64), voyageNo: 'MUTATE',
|
||||
expectedVersion: Number(immutablePlan?.version), operationReason: `${context.marker}-after-loaded` },
|
||||
{ 'Idempotency-Key': `${context.marker}-p3-transport-after-loaded`.slice(0, 128) })
|
||||
context.addStep(MODULE, 'LOADED 后运输信息修改被拒绝', immutableTransport,
|
||||
immutableTransport.http === 200 && codeOf(immutableTransport) === 'A0409'
|
||||
&& Boolean(immutableTransport.requestId) && Boolean(immutableTransport.traceId),
|
||||
`HTTP=${immutableTransport.http}, code=${codeOf(immutableTransport)}, requestId=${immutableTransport.requestId || 'missing'}, traceId=${immutableTransport.traceId || 'missing'}`, OPTIONS)
|
||||
|
||||
const afterBoundaryResponse = await context.request('GET', detailPath)
|
||||
const afterBoundary = context.apiSuccess(MODULE, '回查 LOADED 高风险边界后的入库快照', afterBoundaryResponse, '', OPTIONS)
|
||||
const afterEvidenceResponse = await context.request('GET', evidencePath)
|
||||
const afterEvidence = context.apiSuccess(MODULE, '回查 LOADED 高风险边界后的证据快照', afterEvidenceResponse, '', OPTIONS)
|
||||
const afterPlanResponse = await context.request('GET', planPath)
|
||||
const afterPlan = context.apiSuccess(MODULE, '回查 LOADED 高风险边界后的计划快照', afterPlanResponse, '', OPTIONS)
|
||||
const afterHistorySignature = JSON.stringify((afterBoundary?.statusHistory || []).map((item) => ({
|
||||
action: item?.action || null, from: item?.fromStatus || null, to: item?.toStatus || null,
|
||||
operatorId: id(item?.operatorId), occurredAt: item?.occurredAt || item?.createdAt || null,
|
||||
})))
|
||||
const afterPlanSignature = JSON.stringify({
|
||||
version: Number(afterPlan?.version), status: afterPlan?.status || null,
|
||||
containerNo: afterPlan?.containerNo || null, voyageNo: afterPlan?.voyageNo || null,
|
||||
items: (afterPlan?.items || []).map((item) => ({ id: id(item?.id), frozenAt: item?.frozenAt || null })),
|
||||
})
|
||||
context.assert(MODULE, 'LOADED 后拒绝与幂等请求保持状态、版本、证据、计划和审计零漂移', afterBoundaryResponse,
|
||||
afterBoundary?.summary?.processStatus === 'LOADED'
|
||||
&& Number(afterBoundary?.summary?.version) === finalVersion
|
||||
&& afterHistorySignature === historySignature
|
||||
&& evidenceSignature(afterEvidence) === immutableEvidenceSignature
|
||||
&& afterPlanSignature === immutablePlanSignature,
|
||||
`status=${afterBoundary?.summary?.processStatus || 'missing'}, version=${afterBoundary?.summary?.version ?? 'missing'}, histories=${afterBoundary?.statusHistory?.length ?? 'n/a'}, evidences=${afterEvidence?.evidences?.length ?? 'n/a'}, planVersion=${afterPlan?.version ?? 'missing'}`, OPTIONS)
|
||||
|
||||
context.createdResources.phase3Loading = buildFinalizeResource(fixture, finalData, completeResponse)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user