test: verify pallet block settlement over HTTP
This commit is contained in:
@@ -78,6 +78,13 @@ async function request(context, method, path, body, headers = {}) {
|
||||
return { method, path, http: 0, body: null, raw: String(error), requestId: null, traceId: null }
|
||||
}
|
||||
}
|
||||
function blockResourceIdentity(resource) {
|
||||
return JSON.stringify({
|
||||
blockId: id(resource?.blockId), slotNo: Number(resource?.slotNo),
|
||||
reservationId: id(resource?.reservationId), locationId: id(resource?.locationId),
|
||||
sharedOverflow: resource?.sharedOverflow === true,
|
||||
})
|
||||
}
|
||||
|
||||
async function waitForCompletion(context, taskDetailPath, operationsPath, attempts = 90) {
|
||||
let taskResponse = null
|
||||
@@ -258,6 +265,59 @@ 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 expectedBlocks = [...(fixture.inventoryBlockSnapshots || []), fixture.partialBlockSnapshot]
|
||||
.filter((item) => item?.inboundId && Array.isArray(item?.resources) && item.resources.length > 0)
|
||||
.filter((item, index, all) => all.findIndex((candidate) => id(candidate.inboundId) === id(item.inboundId)) === index)
|
||||
const releasedOrTransferredBlocks = []
|
||||
for (const expected of expectedBlocks) {
|
||||
const sourceBlockResponse = await context.request('GET',
|
||||
`/api/platform/inbounds/${encodeURIComponent(id(expected.inboundId))}?tenantId=${encodeURIComponent(tenantId)}`)
|
||||
const sourceBlock = context.apiSuccess(MODULE, '完成后回查来源入仓单整票块状态', sourceBlockResponse, '', OPTIONS)
|
||||
const expectedIdentity = expected.resources.map(blockResourceIdentity).sort()
|
||||
const sourceLocations = sourceBlock?.palletLocations || []
|
||||
const sourceIdentity = sourceLocations.map(blockResourceIdentity).sort()
|
||||
const statuses = new Set(sourceLocations.map((item) => item?.allocationStatus))
|
||||
const transferred = statuses.size === 1 && statuses.has('TRANSFERRED')
|
||||
const released = statuses.size === 1 && statuses.has('RELEASED')
|
||||
let inheritedByRemainder = false
|
||||
if (transferred) {
|
||||
const sourceCode = String(sourceBlock?.summary?.inboundCode || expected.inboundCode || '').trim()
|
||||
const remainderPageResponse = await context.request('GET',
|
||||
`/api/platform/inbounds?tenantId=${encodeURIComponent(tenantId)}&inboundCode=${encodeURIComponent(`${sourceCode}-`)}&page=1&size=200`)
|
||||
const remainderPage = context.apiSuccess(MODULE, '查询部分拣货生成的余量入仓单', remainderPageResponse, '', OPTIONS)
|
||||
for (const row of remainderPage?.records || []) {
|
||||
if (id(row?.id) === id(expected.inboundId)) continue
|
||||
const remainderResponse = await context.request('GET',
|
||||
`/api/platform/inbounds/${encodeURIComponent(id(row?.id))}?tenantId=${encodeURIComponent(tenantId)}`)
|
||||
const remainder = remainderResponse?.http === 200 && codeOf(remainderResponse) === '200'
|
||||
? remainderResponse.body?.data : null
|
||||
const locations = remainder?.palletLocations || []
|
||||
if (locations.length > 0
|
||||
&& locations.every((item) => item?.allocationStatus === 'CONFIRMED')
|
||||
&& JSON.stringify(locations.map(blockResourceIdentity).sort()) === JSON.stringify(expectedIdentity)) {
|
||||
inheritedByRemainder = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
const identityStable = JSON.stringify(sourceIdentity) === JSON.stringify(expectedIdentity)
|
||||
const verified = identityStable && (released || (transferred && inheritedByRemainder))
|
||||
context.assert(MODULE, '整票块释放或原身份转移给余量入仓单', sourceBlockResponse, verified,
|
||||
`inboundId=${id(expected.inboundId)}, blockId=${expected.resources[0]?.blockId || 'missing'}, statuses=${[...statuses].join(',') || 'missing'}, identityStable=${identityStable}, inheritedByRemainder=${inheritedByRemainder}`, OPTIONS)
|
||||
releasedOrTransferredBlocks.push({ inboundId: id(expected.inboundId), released, transferred, verified })
|
||||
}
|
||||
const completedInventoryResponse = await context.request('GET',
|
||||
`${taskPath}/inventory-snapshot?warehouseId=${encodeURIComponent(id(fixture.warehouseId))}`)
|
||||
const completedInventory = context.apiSuccess(MODULE, '完成后回查 PDA 实时库存快照', completedInventoryResponse, '', OPTIONS)
|
||||
const completedInventoryReleased = expectedBlocks.length > 0
|
||||
&& expectedBlocks.every((expected) => {
|
||||
const current = completedInventory?.inbounds?.find?.((item) => id(item?.inboundId) === id(expected.inboundId))
|
||||
return Number(current?.availablePackageCount || 0) === 0 && (current?.resources || []).length === 0
|
||||
})
|
||||
context.assert(MODULE, '完成后的来源整票块不再作为 PDA 可用资源', completedInventoryResponse,
|
||||
completedInventoryReleased,
|
||||
`expectedBlocks=${expectedBlocks.length}, available=${(completedInventory?.inbounds || []).reduce((sum, item) => sum + Number(item?.availablePackageCount || 0), 0)}`, OPTIONS)
|
||||
|
||||
const slicesPath = `/api/platform/v1/orders/container-bookings/${encodeURIComponent(containerBookingId)}/fulfillment-slices?tenantId=${encodeURIComponent(tenantId)}`
|
||||
const slicesResponse = await context.request('GET', slicesPath)
|
||||
const slices = context.apiSuccess(MODULE, '结算后回查柜次实际履约分片', slicesResponse, '', OPTIONS)
|
||||
@@ -427,6 +487,8 @@ export async function run(context) {
|
||||
...buildFinalizeResource(fixture, finalData, completeResponse),
|
||||
settlementMode,
|
||||
settledOrderId: id(loadedSlice?.childOrderId) || orderId,
|
||||
inventoryBlockSettlementVerified: expectedBlocks.length > 0
|
||||
&& releasedOrTransferredBlocks.every((item) => item.verified) && completedInventoryReleased,
|
||||
}
|
||||
const producer = {
|
||||
marker: context.context?.phase4ProducerMatrixMarker || context.marker,
|
||||
|
||||
Reference in New Issue
Block a user