优化
This commit is contained in:
@@ -278,6 +278,13 @@ export async function run(context) {
|
||||
staleBatch.http === 200 && codeOf(staleBatch) === 'A0409',
|
||||
`HTTP=${staleBatch.http}, code=${codeOf(staleBatch)}`, OPTIONS)
|
||||
|
||||
const beforeInvalidTaskResponse = await context.request('GET',
|
||||
`${pdaBase}/tasks?containerNo=${encodeURIComponent(containerNo)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const beforeInvalidTask = context.apiSuccess(MODULE, '非法混合批次前读取 PDA 全量任务基线',
|
||||
beforeInvalidTaskResponse, '', OPTIONS)
|
||||
const beforeInvalidOperationsResponse = await context.request('GET', `${pdaBase}/tasks/${canonicalTaskId}/operations`)
|
||||
const beforeInvalidOperations = context.apiSuccess(MODULE, '非法混合批次前读取 PDA 操作历史基线',
|
||||
beforeInvalidOperationsResponse, '', OPTIONS)
|
||||
const invalidBatch = await request(context, 'POST', batchPath, {
|
||||
...batchPayload,
|
||||
items: [...batchPayload.items, {
|
||||
@@ -290,13 +297,19 @@ export async function run(context) {
|
||||
const unchangedAfterInvalidResponse = await context.request('GET',
|
||||
`${pdaBase}/tasks?containerNo=${encodeURIComponent(containerNo)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const unchangedAfterInvalid = context.apiSuccess(MODULE, '回查失败批次后的 PDA 任务快照', unchangedAfterInvalidResponse, '', OPTIONS)
|
||||
const unchangedItem = unchangedAfterInvalid?.items?.find?.((item) => id(item.id) === id(canonicalItem.id))
|
||||
context.assert(MODULE, '失败批次整批回滚且无明细部分写入', unchangedAfterInvalidResponse,
|
||||
unchangedAfterInvalid?.taskStatus === 'LOADING'
|
||||
&& Number(unchangedAfterInvalid?.version) === Number(batchPayload.expectedVersion)
|
||||
&& unchangedItem?.itemStatus === 'PENDING' && Number(unchangedItem?.pickedPackageCount) === 0
|
||||
&& Number(unchangedItem?.version) === Number(canonicalItem.version),
|
||||
`taskVersion=${unchangedAfterInvalid?.version ?? 'missing'}, itemStatus=${unchangedItem?.itemStatus || 'missing'}, picked=${unchangedItem?.pickedPackageCount ?? 'missing'}`, OPTIONS)
|
||||
const afterInvalidOperationsResponse = await context.request('GET', `${pdaBase}/tasks/${canonicalTaskId}/operations`)
|
||||
const afterInvalidOperations = context.apiSuccess(MODULE, '非法混合批次后回查 PDA 操作历史',
|
||||
afterInvalidOperationsResponse, '', OPTIONS)
|
||||
const itemSignature = (task) => JSON.stringify((task?.items || []).map((item) => ({
|
||||
id: id(item?.id), status: item?.itemStatus || null, picked: Number(item?.pickedPackageCount),
|
||||
version: Number(item?.version),
|
||||
})))
|
||||
context.assert(MODULE, '合法明细加非法明细失败后任务、全部明细和操作历史零写入', unchangedAfterInvalidResponse,
|
||||
unchangedAfterInvalid?.taskStatus === beforeInvalidTask?.taskStatus
|
||||
&& Number(unchangedAfterInvalid?.version) === Number(beforeInvalidTask?.version)
|
||||
&& itemSignature(unchangedAfterInvalid) === itemSignature(beforeInvalidTask)
|
||||
&& operationsSignature(afterInvalidOperations) === operationsSignature(beforeInvalidOperations),
|
||||
`taskVersion=${unchangedAfterInvalid?.version ?? 'missing'}, items=${itemSignature(unchangedAfterInvalid)}, operations=${afterInvalidOperations?.length ?? 'missing'}`, OPTIONS)
|
||||
|
||||
const merchantLogin = await context.request('POST', '/api/auth/login', {
|
||||
username: MERCHANT_USERNAME, password: MERCHANT_PASSWORD,
|
||||
@@ -581,6 +594,23 @@ export async function run(context) {
|
||||
if (!evidenceItem?.id) return
|
||||
evidenceItems.push(evidenceItem)
|
||||
|
||||
if (evidenceType === 'PHOTO_STEP_1') {
|
||||
const replay = await bindEvidence(context, base, tenantId, evidenceType, fileId, suffix)
|
||||
const replayData = context.apiSuccess(MODULE, '装柜证据绑定同键同参幂等重放', replay, '', OPTIONS)
|
||||
const replayItems = replayData?.evidences?.evidences?.filter?.((item) => item.evidenceType === evidenceType) || []
|
||||
context.assert(MODULE, '证据绑定重放返回同一记录且不重复追加', replay,
|
||||
replayItems.length === 1 && id(replayItems[0]?.id) === id(evidenceItem.id),
|
||||
`evidenceId=${id(replayItems[0]?.id) || 'missing'}, count=${replayItems.length}`, OPTIONS)
|
||||
const conflict = await request(context, 'POST', `${base}/loading/evidence?tenantId=${encodeURIComponent(tenantId)}`, {
|
||||
expectedVersion: 0, evidenceType, fileId,
|
||||
fileName: 'client-must-not-override.png', sealNo: null, remark: `${context.marker}-different`,
|
||||
}, { 'Idempotency-Key': `${context.marker}-p3-evidence-${evidenceType}`.slice(0, 128) })
|
||||
context.addStep(MODULE, '装柜证据绑定同键异参返回冲突', conflict,
|
||||
conflict.http === 200 && codeOf(conflict) === 'A0409'
|
||||
&& Boolean(conflict.requestId) && Boolean(conflict.traceId),
|
||||
`HTTP=${conflict.http}, code=${codeOf(conflict)}, requestId=${conflict.requestId || 'missing'}, traceId=${conflict.traceId || 'missing'}`, OPTIONS)
|
||||
}
|
||||
|
||||
const download = await context.requestBinary('GET', `/api/platform/v1/files/loading-evidence/${tenantId}/${inboundId}/${fileId}`)
|
||||
context.assert(MODULE, `下载本轮 ${evidenceType} 证据文件`, download,
|
||||
download.http === 200 && download.contentType.toLowerCase().includes('image/png') && download.bytes.length > 0,
|
||||
@@ -642,6 +672,100 @@ export async function run(context) {
|
||||
&& (item.status === 'VOID' || item.valid === false) && item.voidReason === `${context.marker}-wrong-photo`),
|
||||
`evidenceId=${id(voidTarget?.id) || 'missing'}, status=${voidTarget?.status || 'missing'}`, OPTIONS)
|
||||
|
||||
const missingTypeTarget = evidenceItems.find((item) => item.evidenceType === 'PHOTO_STEP_4')
|
||||
const missingTypePath = `${base}/loading/evidence/${encodeURIComponent(id(missingTypeTarget?.id))}/void?tenantId=${encodeURIComponent(tenantId)}`
|
||||
const staleMissingTypeVoid = missingTypeTarget
|
||||
? await request(context, 'POST', missingTypePath,
|
||||
{ expectedVersion: Number(missingTypeTarget.version) + 1, reason: `${context.marker}-stale-version` },
|
||||
{ 'Idempotency-Key': `${context.marker}-p3-evidence-void-stale`.slice(0, 128) })
|
||||
: voidResponse
|
||||
context.addStep(MODULE, '装柜证据作废旧版本返回冲突', staleMissingTypeVoid,
|
||||
Boolean(missingTypeTarget) && staleMissingTypeVoid.http === 200 && codeOf(staleMissingTypeVoid) === 'A0409',
|
||||
`HTTP=${staleMissingTypeVoid.http}, code=${codeOf(staleMissingTypeVoid)}`, OPTIONS)
|
||||
|
||||
const missingTypeVoidKey = `${context.marker}-p3-evidence-void-missing-type`.slice(0, 128)
|
||||
const missingTypeVoidBody = {
|
||||
expectedVersion: Number(missingTypeTarget?.version), reason: `${context.marker}-temporary-missing-type`,
|
||||
}
|
||||
const missingTypeVoid = missingTypeTarget
|
||||
? await request(context, 'POST', missingTypePath, missingTypeVoidBody,
|
||||
{ 'Idempotency-Key': missingTypeVoidKey })
|
||||
: voidResponse
|
||||
const missingTypeVoidData = context.apiSuccess(MODULE, '临时作废唯一 PHOTO_STEP_4 证据', missingTypeVoid, '', OPTIONS)
|
||||
context.assert(MODULE, '临时作废后 PHOTO_STEP_4 不再计入有效证据', missingTypeVoid,
|
||||
Boolean(missingTypeTarget) && missingTypeVoidData?.evidences?.evidences?.some?.((item) =>
|
||||
id(item.id) === id(missingTypeTarget.id) && item.status === 'VOID'),
|
||||
`evidenceId=${id(missingTypeTarget?.id) || 'missing'}`, OPTIONS)
|
||||
|
||||
const missingTypeVoidReplay = missingTypeTarget
|
||||
? await request(context, 'POST', missingTypePath, missingTypeVoidBody,
|
||||
{ 'Idempotency-Key': missingTypeVoidKey })
|
||||
: voidResponse
|
||||
context.assert(MODULE, '证据作废同键同参重放保持同一 VOID 结果', missingTypeVoidReplay,
|
||||
missingTypeVoidReplay.http === 200 && codeOf(missingTypeVoidReplay) === '200'
|
||||
&& missingTypeVoidReplay.body?.data?.evidences?.evidences?.some?.((item) =>
|
||||
id(item.id) === id(missingTypeTarget?.id) && item.status === 'VOID'),
|
||||
`HTTP=${missingTypeVoidReplay.http}, code=${codeOf(missingTypeVoidReplay)}`, OPTIONS)
|
||||
const missingTypeVoidConflict = missingTypeTarget
|
||||
? await request(context, 'POST', missingTypePath,
|
||||
{ ...missingTypeVoidBody, reason: `${context.marker}-different-void-reason` },
|
||||
{ 'Idempotency-Key': missingTypeVoidKey })
|
||||
: voidResponse
|
||||
context.addStep(MODULE, '证据作废同键异参返回冲突', missingTypeVoidConflict,
|
||||
missingTypeVoidConflict.http === 200 && codeOf(missingTypeVoidConflict) === 'A0409',
|
||||
`HTTP=${missingTypeVoidConflict.http}, code=${codeOf(missingTypeVoidConflict)}`, OPTIONS)
|
||||
const duplicateVoid = missingTypeTarget
|
||||
? await request(context, 'POST', missingTypePath, missingTypeVoidBody,
|
||||
{ 'Idempotency-Key': `${context.marker}-p3-evidence-void-duplicate`.slice(0, 128) })
|
||||
: voidResponse
|
||||
context.addStep(MODULE, '已作废证据使用新请求重复作废返回冲突', duplicateVoid,
|
||||
duplicateVoid.http === 200 && codeOf(duplicateVoid) === 'A0409',
|
||||
`HTTP=${duplicateVoid.http}, code=${codeOf(duplicateVoid)}`, OPTIONS)
|
||||
|
||||
const missingTypeComplete = await request(context, 'POST', `${base}/loading/complete?tenantId=${encodeURIComponent(tenantId)}`,
|
||||
{ expectedVersion: loadingVersion, remark: `${context.marker}-missing-photo-step-4` },
|
||||
{ 'Idempotency-Key': `${context.marker}-p3-complete-missing-photo-step-4`.slice(0, 128) })
|
||||
context.addStep(MODULE, '作废唯一证据类型后 LOADED 门禁拒绝', missingTypeComplete,
|
||||
missingTypeComplete.http === 200 && codeOf(missingTypeComplete) === 'A0409',
|
||||
`HTTP=${missingTypeComplete.http}, code=${codeOf(missingTypeComplete)}`, OPTIONS)
|
||||
|
||||
const replacementUpload = await uploadEvidence(context, tenantId, inboundId, 'PHOTO_STEP_4')
|
||||
const replacementFile = context.apiSuccess(MODULE, '补传缺失 PHOTO_STEP_4 真实文件', replacementUpload, '', OPTIONS)
|
||||
const replacementFileId = id(replacementFile?.fileId)
|
||||
const replacementBind = replacementFileId
|
||||
? await bindEvidence(context, base, tenantId, 'PHOTO_STEP_4', replacementFileId, suffix, 'PHOTO_STEP_4_RESTORE')
|
||||
: replacementUpload
|
||||
const replacementData = context.apiSuccess(MODULE, '补传恢复 PHOTO_STEP_4 有效证据', replacementBind, '', OPTIONS)
|
||||
context.assert(MODULE, '补传后五类有效证据恢复且旧 VOID 记录保留', replacementBind,
|
||||
Boolean(replacementFileId)
|
||||
&& replacementData?.evidences?.evidences?.some?.((item) => item.evidenceType === 'PHOTO_STEP_4'
|
||||
&& id(item.fileId) === replacementFileId && item.status !== 'VOID')
|
||||
&& replacementData?.evidences?.evidences?.some?.((item) => id(item.id) === id(missingTypeTarget?.id)
|
||||
&& item.status === 'VOID'),
|
||||
`replacementFileId=${replacementFileId || 'missing'}`, OPTIONS)
|
||||
|
||||
const customerEvidence = merchantToken
|
||||
? await request(context, 'GET', `${base}/loading/evidence?tenantId=${encodeURIComponent(tenantId)}`,
|
||||
undefined, { Authorization: `Bearer ${merchantToken}` })
|
||||
: merchantLogin
|
||||
context.addStep(MODULE, '客户身份无权访问平台装柜证据', customerEvidence,
|
||||
customerEvidence.http === 403 && codeOf(customerEvidence) === 'A0403'
|
||||
&& Boolean(customerEvidence.requestId) && Boolean(customerEvidence.traceId),
|
||||
`HTTP=${customerEvidence.http}, code=${codeOf(customerEvidence)}, requestId=${customerEvidence.requestId || 'missing'}, traceId=${customerEvidence.traceId || 'missing'}`, OPTIONS)
|
||||
const wrongTenantEvidence = await context.request('GET', `${base}/loading/evidence?tenantId=${encodeURIComponent(Number(tenantId) + 1)}`)
|
||||
context.addStep(MODULE, '错误客户作用域不可读取本轮装柜证据', wrongTenantEvidence,
|
||||
wrongTenantEvidence.http === 200 && codeOf(wrongTenantEvidence) === 'A0404',
|
||||
`HTTP=${wrongTenantEvidence.http}, code=${codeOf(wrongTenantEvidence)}`, OPTIONS)
|
||||
const wrongInboundEvidence = await context.request('GET',
|
||||
`/api/platform/v1/inbounds/999999999999999999/loading/evidence?tenantId=${encodeURIComponent(tenantId)}`)
|
||||
context.addStep(MODULE, '错误入库单不可读取本轮装柜证据', wrongInboundEvidence,
|
||||
wrongInboundEvidence.http === 200 && codeOf(wrongInboundEvidence) === 'A0404',
|
||||
`HTTP=${wrongInboundEvidence.http}, code=${codeOf(wrongInboundEvidence)}`, OPTIONS)
|
||||
|
||||
const postLoadedUpload = await uploadEvidence(context, tenantId, inboundId, 'PHOTO_STEP_2')
|
||||
const postLoadedFile = context.apiSuccess(MODULE, '预置 LOADED 后新增证据边界文件', postLoadedUpload, '', OPTIONS)
|
||||
const postLoadedFileId = id(postLoadedFile?.fileId)
|
||||
|
||||
const evidenceList = await context.request('GET', `${base}/loading/evidence?tenantId=${encodeURIComponent(tenantId)}`)
|
||||
const evidenceListData = context.apiSuccess(MODULE, '回查五类装柜证据列表', evidenceList, '', OPTIONS)
|
||||
context.assert(MODULE, '五类装柜证据完整且铅封号持久化', evidenceList,
|
||||
@@ -666,6 +790,9 @@ export async function run(context) {
|
||||
context.createdResources.phase3Loading = {
|
||||
tenantId, inboundId, preloadPlanId: planId, evidenceIds: evidenceItems.map((item) => id(item.id)),
|
||||
voidedEvidenceId: id(voidTarget?.id), evidenceTypes, sealNo: `SEAL-${suffix}`,
|
||||
missingTypeVoidedEvidenceId: id(missingTypeTarget?.id), replacementEvidenceFileId: replacementFileId,
|
||||
immutableEvidenceId: id(firstPhoto?.id), immutableEvidenceVersion: Number(firstPhoto?.version),
|
||||
postLoadedFileId,
|
||||
loadingPlanId, containerBookingId, containerNo, warehouseId, canonicalPdaTaskId: canonicalTaskId,
|
||||
pickingTaskId: canonicalTaskId, inboundVersion: loadingVersion,
|
||||
atomicBatchVerified: directPdaCompletion && atomicBatchReplayVerified,
|
||||
|
||||
Reference in New Issue
Block a user