fix: validate transfer rejection and align dispatch HTTP contracts

This commit is contained in:
2026-09-14 13:46:32 +08:00
parent a2ea0ba9e6
commit d8e2dc59ae
9 changed files with 120 additions and 13 deletions
@@ -48,6 +48,35 @@ async function merchant(context, token, method, name, path, body = undefined) {
return { response, data }
}
export function relabelOutboundMarksMatch(detail, relabel) {
const marks = (detail?.pallets || []).flatMap(item => String(item.cartonMarks || '')
.split(',').map(mark => mark.trim()).filter(Boolean))
const expected = relabel?.relabelCartonMarks || []
return expected.length > 0 && marks.length === expected.length
&& new Set(marks).size === marks.length && expected.every(mark => marks.includes(mark))
&& (relabel.sourceCartonMarks || []).every(mark => !marks.includes(mark))
&& Number(detail?.outbound?.packageCount) === expected.length
}
async function verifyRelabelDispatchOutbound(context, relabel, transferBody) {
if (relabel?.marker !== context.marker || !nonBlank(relabel?.dispatchNo)) {
blocker(context, '换标排车箱唛传递前置', '缺少本轮换标排车,不借用历史数据')
return
}
const transferred = await platform(context, 'POST', '本轮换标排车转派送并生成出库快照',
`${DISPATCH_BASE}/${encodeURIComponent(relabel.dispatchNo)}/transfer-delivery`,
{ ...transferBody, idempotencyKey: key(context, 'RELABEL-TRANSFER') })
const outboundNo = transferred.data?.outboundNo
if (!success(transferred.response) || !nonBlank(outboundNo)) return
const detail = await platform(context, 'GET', '回查换标排车的真实出库箱唛',
query(`${LASTLEG_BASE}/outbound-orders/${encodeURIComponent(outboundNo)}`, { page: 1, size: 200 }))
context.assert(MODULE, '排车出库快照精确保留全部新箱唛且无原箱唛或重复箱', detail.response,
success(detail.response) && detail.data?.outbound?.outboundNo === outboundNo
&& detail.data?.outbound?.dispatchNo === relabel.dispatchNo
&& relabelOutboundMarksMatch(detail.data, relabel), trace(detail.response), OPTIONS)
Object.assign(relabel, { outboundNo, deliveryNo: transferred.data?.deliveryNo })
}
async function loginMerchant(context, customerId) {
const merchantFixture = context.context?.merchantQualificationFixture
const credentials = nonBlank(merchantFixture?.username) && nonBlank(merchantFixture?.password)
@@ -187,6 +216,7 @@ export async function run(context) {
fees: [{ feeType: 'DELIVERY_FEE', feeName: '派送费', direction: 'RECEIVABLE',
currency: 'USD', amount: 10, remark: `${context.marker}-acceptance` }],
}
await verifyRelabelDispatchOutbound(context, context.createdResources?.phase4OverseasRelabel, transferBody)
const transferred = await merchant(context, merchantToken, 'POST', '客户创建派送并原子转出库单',
query(MERCHANT_DELIVERY_BASE, { dispatchNo }), transferBody)
const outboundNo = id(transferred.data?.outboundNo)