This commit is contained in:
2026-09-15 15:15:46 +08:00
parent 419950482f
commit cadc5a175e
28 changed files with 879 additions and 89 deletions
@@ -327,6 +327,93 @@ export async function run(context) {
{ ...mergeBody, weight: 3 }, {}, picker.token)
add(context, '合箱同键异载荷返回冲突', mergeConflict, conflict(mergeConflict))
}
const relabelCandidates = await overseas(context, merchantToken, 'GET', '客户查询本轮退货换标候选',
`${RETURN_ORDERS}/${encodeURIComponent(returnNo)}/relabel-candidates`)
const relabelCandidate = (Array.isArray(relabelCandidates.data) ? relabelCandidates.data : [])
.find(row => nonBlank(row?.cartonMark) && row?.status === 'AVAILABLE')
context.assert(MODULE, '退货换标候选来自本轮已签收可用箱', relabelCandidates.response,
Boolean(relabelCandidate) && relabelCandidate.sourceReturnNo === returnNo,
`cartonMark=${relabelCandidate?.cartonMark || 'missing'}`, OPTIONS)
if (relabelCandidate) {
const relabelBody = {
cartonMarks: [relabelCandidate.cartonMark], idempotencyKey: key(context, 'RELABEL'),
contactName: '退货换标验收', contactPhone: '13800000008', deliveryMethod: 'TRUCK', remark: context.marker,
}
const relabel = await overseas(context, merchantToken, 'POST', '客户从退货箱创建换标单',
`${RETURN_ORDERS}/${encodeURIComponent(returnNo)}/relabel`, relabelBody)
const relabelNo = id(relabel.data?.relabelNo)
context.assert(MODULE, '退货换标单绑定原退货单与选中箱', relabel.response,
nonBlank(relabelNo) && relabel.data?.returnNo === returnNo
&& relabel.data?.status === 'PENDING_PROCESSING'
&& relabel.data?.cartonMarks?.includes?.(relabelCandidate.cartonMark),
`relabelNo=${relabelNo || 'missing'}`, OPTIONS)
if (relabelNo) {
const form = new FormData()
form.append('file', new Blob([new TextEncoder().encode(`%PDF-1.4\n${context.marker}\n%%EOF`)],
{ type: 'application/pdf' }), `${suffix}-return-relabel.pdf`)
const uploaded = await context.requestOverseasMultipart('POST',
`/api/merchant/v1/last-leg/relabel-applications/${encodeURIComponent(relabelNo)}/files?scope=CARTON_TOTAL`,
form, {}, merchantToken)
add(context, '客户编辑退货换标总资料', uploaded, success(uploaded))
const relabelDetail = await overseas(context, merchantToken, 'GET', '客户回查退货换标资料修改',
`/api/merchant/v1/last-leg/relabel-applications/${encodeURIComponent(relabelNo)}`)
context.assert(MODULE, '退货换标详情持久化总资料且业务状态未漂移', relabelDetail.response,
relabelDetail.data?.application?.relabelNo === relabelNo
&& relabelDetail.data?.application?.status === 'PENDING_PROCESSING'
&& nonBlank(relabelDetail.data?.application?.totalFileId), trace(relabelDetail.response), OPTIONS)
context.createdResources.phase4OverseasReturnReceipt.relabelNo = relabelNo
}
}
const outboundCandidates = await overseas(context, context.overseasToken, 'GET', '平台查询本轮退货出库候选',
query('/api/platform/v1/last-leg/outbound-orders/return/candidates', {
customerId, overseasWarehouseId: warehouse.id,
}))
const outboundCandidate = (Array.isArray(outboundCandidates.data) ? outboundCandidates.data : [])
.find(row => row?.returnNo === returnNo && nonBlank(row?.cartonMark)
&& row.cartonMark !== relabelCandidate?.cartonMark && row.status === 'AVAILABLE')
context.assert(MODULE, '退货出库候选排除已冻结换标箱', outboundCandidates.response,
Boolean(outboundCandidate), `cartonMark=${outboundCandidate?.cartonMark || 'missing'}`, OPTIONS)
if (outboundCandidate) {
const outboundBody = {
recipient: `${context.marker} RETURN OUTBOUND`, overseasWarehouseId: warehouse.id,
returnNo, cartonMarks: [outboundCandidate.cartonMark], remark: context.marker,
idempotencyKey: key(context, 'OUTBOUND'),
}
const outbound = await overseas(context, context.overseasToken, 'POST', '平台创建独立退货出库单',
query('/api/platform/v1/last-leg/outbound-orders/return', { customerId }), outboundBody)
const taskNo = id(outbound.data?.taskNo)
const outboundNo = id(outbound.data?.outboundNo)
context.assert(MODULE, 'RETURN_OUTBOUND创建PDA待拣任务', outbound.response,
nonBlank(taskNo) && nonBlank(outboundNo) && outbound.data?.status === 'PENDING',
`outboundNo=${outboundNo || 'missing'}, taskNo=${taskNo || 'missing'}`, OPTIONS)
if (taskNo) {
const task = await overseas(context, picker.token, 'GET', 'PDA读取退货出库任务明细',
`/api/pda/v1/last-leg/outbound-tasks/${encodeURIComponent(taskNo)}`)
const taskItem = task.data?.items?.find?.(row => String(row?.cartonMarks || '').includes(outboundCandidate.cartonMark))
|| task.data?.items?.[0]
const pickBody = { outboundPalletItemId: taskItem?.outboundPalletItemId,
inventoryPositionId: null, packages: 1, cartonMarks: [outboundCandidate.cartonMark],
idempotencyKey: key(context, 'OUTBOUND-PICK') }
const picked = await overseas(context, picker.token, 'POST', 'PDA一次扫描退货箱完成拣货',
`/api/pda/v1/last-leg/outbound-tasks/${encodeURIComponent(taskNo)}/pick`, pickBody)
context.assert(MODULE, '退货出库拣货推进为PICKED且任务进行中', picked.response,
picked.data?.outboundNo === outboundNo && picked.data?.status === 'IN_PROGRESS', trace(picked.response), OPTIONS)
const completed = await overseas(context, picker.token, 'POST', 'PDA完成退货出库',
`/api/pda/v1/last-leg/outbound-tasks/${encodeURIComponent(taskNo)}/complete`,
{ idempotencyKey: key(context, 'OUTBOUND-COMPLETE') })
const outboundDetail = await overseas(context, context.overseasToken, 'GET', '平台回查退货出库最终状态',
query(`/api/platform/v1/last-leg/outbound-orders/${encodeURIComponent(outboundNo)}`, { customerId }))
context.assert(MODULE, 'RETURN_OUTBOUND真实完成且箱唛只出库一次', outboundDetail.response,
completed.data?.status === 'COMPLETED'
&& outboundDetail.data?.outbound?.outboundType === 'RETURN_OUTBOUND'
&& outboundDetail.data?.outbound?.status === 'OUTBOUNDED'
&& outboundDetail.data?.pallets?.some?.(row => row.cartonMarks === outboundCandidate.cartonMark
&& Number(row.pickedPackageCount) === 1), trace(outboundDetail.response), OPTIONS)
context.createdResources.phase4OverseasReturnReceipt.returnOutboundNo = outboundNo
}
}
} finally {
await disablePicker(context, picker, 91)
}
@@ -65,6 +65,9 @@ export async function verifyWarehouseTransferReview(context, token, customerId,
ok(result) && ok(detail) && detail.body.data?.status === expected
&& detail.body.data?.orderType === 'WAREHOUSE_TRANSFER'
&& detail.body.data?.orderStatus === expectedOrder
&& detail.body.data?.reviewDecision === `${decision}ED`.replace('APPROVEED', 'APPROVED')
&& detail.body.data?.reviewRemark === `${context.marker}-审核原因`
&& Boolean(detail.body.data?.reviewedBy) && Boolean(detail.body.data?.reviewedAt)
&& (detail.body.data?.pallets || []).length === 0, evidence(detail), OPTIONS)
context.createdResources.phase4OverseasClientServices[`transit${decision}`] = { transferNo: no, status: detail.body?.data?.status }
}