优化
This commit is contained in:
@@ -299,6 +299,102 @@ export function dispatchStockConservation(context, { customerId, warehouseId, di
|
||||
return { passed, proof, newLedger }
|
||||
}
|
||||
|
||||
// Completion follows the formal root and every real child; a signed shipment alone is not the aggregate.
|
||||
export async function verifyFulfillmentRootStatus(context, { sourceOrderId, customerId, merchantToken,
|
||||
pollAttempts = 45, pollIntervalMs = 1_000 }) {
|
||||
const rawPath = orderId => query(`/api/platform/v1/orders/first-leg/${encodeURIComponent(orderId)}`, { tenantId: customerId })
|
||||
const source = await platform(context, 'GET', '读取签收来源原始订单履约归属', rawPath(sourceOrderId))
|
||||
const sourceOrder = source.data?.order
|
||||
const rootOrderId = sourceOrder?.orderRole === 'MASTER' ? id(sourceOrder.id) : id(sourceOrder?.rootOrderId)
|
||||
const sourceOwned = success(source.response) && id(sourceOrder?.id) === sourceOrderId
|
||||
&& id(sourceOrder?.tenantId) === customerId && id(sourceOrder?.customerId) === customerId
|
||||
&& /^[1-9][0-9]*$/.test(rootOrderId)
|
||||
&& (sourceOrder.orderRole === 'MASTER' || (sourceOrder.orderRole === 'CHILD' && id(sourceOrder.parentOrderId) === rootOrderId))
|
||||
context.assert(MODULE, '签收来源订单属于本企业及唯一正式履约根', source.response, sourceOwned, `sourceOrderId=${sourceOrderId}, rootOrderId=${rootOrderId}`, OPTIONS)
|
||||
if (!sourceOwned) return null
|
||||
let root = rootOrderId === sourceOrderId ? source : await platform(context, 'GET', '读取原始履约根订单', rawPath(rootOrderId))
|
||||
const treeResult = await platform(context, 'GET', '读取签收后的完整正式履约树',
|
||||
query(`/api/platform/v1/orders/${encodeURIComponent(rootOrderId)}/fulfillment-tree`, { tenantId: customerId }))
|
||||
const tree = treeResult.data
|
||||
const rows = Array.isArray(tree?.children) ? tree.children : []
|
||||
const treeOrderIds = new Set([rootOrderId, ...rows.map(row => id(row.orderId))])
|
||||
const consumed = new Set(rows.filter(row => row.splitRole === 'LOADED').map(row => id(row.sourceOrderId)))
|
||||
const loaded = rows.filter(row => row.splitRole === 'LOADED').reduce((sum, row) => sum + Number(row.packageCount), 0)
|
||||
const remaining = rows.filter(row => row.splitRole === 'REMAINDER' && !consumed.has(id(row.orderId)))
|
||||
.reduce((sum, row) => sum + Number(row.packageCount), 0)
|
||||
const treeComplete = success(root.response) && success(treeResult.response)
|
||||
&& id(root.data?.order?.id) === rootOrderId && root.data.order.orderRole === 'MASTER'
|
||||
&& id(root.data.order.tenantId) === customerId && id(root.data.order.customerId) === customerId
|
||||
&& Array.isArray(root.data.statusHistory)
|
||||
&& id(tree?.parentOrderId) === rootOrderId && tree.parentOrderNo === root.data.order.orderNo
|
||||
&& Array.isArray(tree.children)
|
||||
&& ['originalPackageCount', 'cumulativeLoadedPackageCount', 'currentRemainderPackageCount'].every(field =>
|
||||
tree[field] !== null && tree[field] !== undefined && Number.isSafeInteger(Number(tree[field])) && Number(tree[field]) >= 0)
|
||||
&& loaded === Number(tree.cumulativeLoadedPackageCount) && remaining === Number(tree.currentRemainderPackageCount)
|
||||
&& loaded + remaining === Number(tree.originalPackageCount)
|
||||
&& rows.every(row => /^[1-9][0-9]*$/.test(id(row.orderId)) && /^[1-9][0-9]*$/.test(id(row.sourceOrderId))
|
||||
&& treeOrderIds.has(id(row.sourceOrderId))
|
||||
&& nonBlank(row.orderNo) && ['LOADED', 'REMAINDER'].includes(row.splitRole)
|
||||
&& (row.splitRole === 'LOADED' ? id(row.orderId) === id(row.sourceOrderId) : id(row.orderId) !== id(row.sourceOrderId))
|
||||
&& Number.isSafeInteger(Number(row.packageCount)) && Number(row.packageCount) > 0)
|
||||
&& (sourceOrderId === rootOrderId || rows.some(row => id(row.orderId) === sourceOrderId))
|
||||
context.assert(MODULE, '履约根及全部分片身份和树数量完整守恒', treeResult.response, treeComplete,
|
||||
`rootOrderId=${rootOrderId}, loaded=${loaded}, remaining=${remaining}, original=${tree?.originalPackageCount ?? 'missing'}`, OPTIONS)
|
||||
if (!treeComplete) return null
|
||||
const children = []
|
||||
const statuses = ['DRAFT', 'SUBMITTED', 'APPROVED', 'ACCEPTED', 'REJECTED', 'CANCELLED', 'PROCESSING', 'COMPLETED']
|
||||
for (const childId of [...new Set(rows.map(row => id(row.orderId)).filter(value => value !== rootOrderId))]) {
|
||||
const current = await platform(context, 'GET', '逐项读取真实履约子单完成事实', rawPath(childId))
|
||||
const child = current.data?.order
|
||||
const owned = success(current.response) && id(child?.id) === childId && id(child?.tenantId) === customerId
|
||||
&& id(child?.customerId) === customerId && child?.orderRole === 'CHILD'
|
||||
&& id(child?.rootOrderId) === rootOrderId && id(child?.parentOrderId) === rootOrderId
|
||||
&& rows.filter(row => id(row.orderId) === childId).every(row => row.orderNo === child.orderNo)
|
||||
&& statuses.includes(child?.status)
|
||||
context.assert(MODULE, '真实履约子单存在且客户根身份和状态有效', current.response, owned, `childOrderId=${childId}`, OPTIONS)
|
||||
if (!owned) return null
|
||||
children.push({ orderId: childId, orderNo: child.orderNo, status: child.status, rootOrderId })
|
||||
}
|
||||
const pendingChildren = children.filter(child => !['COMPLETED', 'CANCELLED'].includes(child.status))
|
||||
const rootDelivered = root.data.statusHistory?.some(row => row.action === 'OVERSEAS_DELIVERED') === true
|
||||
const expectedCompleted = rootDelivered && pendingChildren.length === 0
|
||||
const owned = context.createdResources.phase5OverseasFulfillment
|
||||
if (owned) owned.orderCompletionProof = { sourceOrderId, rootOrderId,
|
||||
tree: { parentOrderId: rootOrderId, parentOrderNo: tree.parentOrderNo, originalPackageCount: Number(tree.originalPackageCount),
|
||||
cumulativeLoadedPackageCount: loaded, currentRemainderPackageCount: remaining,
|
||||
children: rows.map(row => ({ orderId: id(row.orderId), orderNo: row.orderNo, sourceOrderId: id(row.sourceOrderId),
|
||||
splitRole: row.splitRole, packageCount: Number(row.packageCount) })) },
|
||||
children, rootDelivered, expectedCompleted, pendingChildOrderIds: pendingChildren.map(child => child.orderId) }
|
||||
const domestic = await poll(() => context.request('GET',
|
||||
query(`/api/platform/v1/orders/${encodeURIComponent(rootOrderId)}`, { tenantId: customerId })),
|
||||
response => success(response) && id(response.body?.data?.summary?.orderId) === rootOrderId
|
||||
&& (expectedCompleted ? response.body.data.summary.mainStatus === 'COMPLETED'
|
||||
: rootDelivered ? response.body.data.summary.mainStatus === 'DELIVERED'
|
||||
: nonBlank(response.body.data.summary.mainStatus) && response.body.data.summary.mainStatus !== 'COMPLETED'), pollAttempts, pollIntervalMs)
|
||||
if (expectedCompleted) root = await platform(context, 'GET', '全部有效分片结束后回查原始履约根', rawPath(rootOrderId))
|
||||
const rawPassed = success(root.response) && (expectedCompleted
|
||||
? root.data?.order?.status === 'COMPLETED' && root.data.statusHistory?.some(row => row.action === 'FULFILLMENT_COMPLETED')
|
||||
: statuses.includes(root.data?.order?.status) && root.data.order.status !== 'COMPLETED'
|
||||
&& !root.data.statusHistory?.some(row => row.action === 'FULFILLMENT_COMPLETED'))
|
||||
const platformPassed = success(domestic.result) && id(domestic.result?.body?.data?.summary?.orderId) === rootOrderId
|
||||
&& (expectedCompleted ? domestic.result.body.data.summary.mainStatus === 'COMPLETED'
|
||||
: rootDelivered ? domestic.result.body.data.summary.mainStatus === 'DELIVERED'
|
||||
: nonBlank(domestic.result.body.data.summary.mainStatus) && domestic.result.body.data.summary.mainStatus !== 'COMPLETED')
|
||||
context.assert(MODULE, expectedCompleted ? '全部有效子单签收后原始履约根COMPLETED' : '有效余量或根票未签收时原始履约根不得提前COMPLETED',
|
||||
root.response, rawPassed, `rootOrderId=${rootOrderId}, pendingChildren=${pendingChildren.map(row => row.orderNo).join(',')}`, OPTIONS)
|
||||
context.addStep(MODULE, expectedCompleted ? '同订单全部有效履约分片签收后统一订单进入COMPLETED' : '本票签收但有效余量未完时统一订单保留未完成状态',
|
||||
domestic.result, platformPassed, `rootOrderId=${rootOrderId}, pollRequests=${domestic.attempts}, mainStatus=${domestic.result?.body?.data?.summary?.mainStatus || 'missing'}`, OPTIONS)
|
||||
const customer = await merchant(context, merchantToken, 'GET', '客户读取本企业履约根真实完成状态', `/api/merchant/v1/orders/${encodeURIComponent(rootOrderId)}`)
|
||||
const customerPassed = success(customer.response) && id(customer.data?.summary?.orderId) === rootOrderId
|
||||
&& customer.data?.summary?.mainStatus === domestic.result?.body?.data?.summary?.mainStatus && platformPassed
|
||||
context.assert(MODULE, expectedCompleted ? '客户本企业全部履约完成后订单最终状态为COMPLETED' : '客户本企业仍有有效未完成履约时不得展示COMPLETED',
|
||||
customer.response, customerPassed, `rootOrderId=${rootOrderId}, mainStatus=${customer.data?.summary?.mainStatus || 'missing'}`, OPTIONS)
|
||||
if (owned) Object.assign(owned.orderCompletionProof, { rawRootStatus: root.data?.order?.status,
|
||||
platformMainStatus: domestic.result?.body?.data?.summary?.mainStatus, customerMainStatus: customer.data?.summary?.mainStatus,
|
||||
rawPassed: Boolean(rawPassed), platformPassed, customerPassed })
|
||||
return { rootOrderId, expectedCompleted, pendingChildren, passed: Boolean(rawPassed && platformPassed && customerPassed) }
|
||||
}
|
||||
|
||||
// A dedicated multi-fragment producer must supply these codes. Multiple FBA destinations alone are not proof.
|
||||
export async function verifyPartialOrderCompletion(context, { orderId, customerId, deliveredInboundCode, pendingInboundCodes }) {
|
||||
if (!id(orderId) || !id(customerId) || !nonBlank(deliveredInboundCode)
|
||||
@@ -1012,19 +1108,8 @@ export async function run(context) {
|
||||
blocker(context, '取得签收对应头程订单', '头程入仓详情缺少来源订单ID', domesticInbound.result)
|
||||
return
|
||||
}
|
||||
const domesticOrder = await poll(async () => context.request('GET',
|
||||
query(`/api/platform/v1/orders/${encodeURIComponent(sourceOrderId)}`, { tenantId: customerId })),
|
||||
(response) => success(response) && response.body?.data?.summary?.mainStatus === 'COMPLETED')
|
||||
context.addStep(MODULE, '同订单全部入仓签收后统一订单进入COMPLETED', domesticOrder.result,
|
||||
success(domesticOrder.result) && domesticOrder.result?.body?.data?.summary?.mainStatus === 'COMPLETED',
|
||||
`orderId=${sourceOrderId}, pollRequests=${domesticOrder.attempts}, mainStatus=${domesticOrder.result?.body?.data?.summary?.mainStatus || 'missing'}; ${trace(domesticOrder.result)}`, OPTIONS)
|
||||
context.createdResources.phase5OverseasFulfillment.sourceOrderId = sourceOrderId
|
||||
const customerCompletedOrder = await merchant(context, merchantToken, 'GET', '客户读取签收后的统一订单最终状态',
|
||||
`/api/merchant/v1/orders/${encodeURIComponent(sourceOrderId)}`)
|
||||
context.assert(MODULE, '客户本企业订单最终状态为COMPLETED', customerCompletedOrder.response,
|
||||
customerCompletedOrder.data?.summary?.mainStatus === 'COMPLETED'
|
||||
&& id(customerCompletedOrder.data?.summary?.orderId) === sourceOrderId,
|
||||
trace(customerCompletedOrder.response), OPTIONS)
|
||||
await verifyFulfillmentRootStatus(context, { sourceOrderId, customerId, merchantToken })
|
||||
const foreignMerchantToken = context.context?.phase5TailVerification?.foreignMerchantToken
|
||||
|| await createSignedDocumentIsolationCustomer(context)
|
||||
await verifyCustomerSignedDocuments(context, merchantToken,
|
||||
|
||||
Reference in New Issue
Block a user