test: extend eight-business acceptance flows and offline contracts
This commit is contained in:
@@ -47,6 +47,8 @@ export async function fulfillmentEvidenceContext(context) {
|
||||
await writeFile(`${path}.tmp`, `${JSON.stringify(redact({ ...evidence,
|
||||
fulfillment: context.createdResources.phase5OverseasFulfillment,
|
||||
looseboard: context.createdResources.phase4OverseasBusiness?.looseboard,
|
||||
clientRelabel: context.createdResources.phase4OverseasClientServices?.relabelFulfillment,
|
||||
pdaRelabel: context.createdResources.phase4OverseasRelabel,
|
||||
fleetTrips: context.createdResources.fleetTrips }), null, 2)}\n`, 'utf8')
|
||||
await rename(`${path}.tmp`, path)
|
||||
}
|
||||
@@ -844,26 +846,107 @@ export function relabelOutboundMarksMatch(detail, relabel) {
|
||||
&& Number(detail?.outbound?.packageCount) === expected.length
|
||||
}
|
||||
|
||||
async function verifyRelabelDispatchOutbound(context, relabel, token, warehouseId) {
|
||||
if (relabel?.marker !== context.marker || !nonBlank(relabel?.dispatchNo)) {
|
||||
blocker(context, '换标排车箱唛传递前置', '缺少本轮换标排车,不借用历史数据')
|
||||
return
|
||||
// 客户原贴标费用只读等待结算回执,不以派送成功推定扣费成功。
|
||||
export async function verifyClientRelabelSettlement(context, relabel, delay = () => new Promise(resolve => setTimeout(resolve, 1000))) {
|
||||
if (context.createdResources?.phase4OverseasClientServices?.relabelFulfillment !== relabel
|
||||
|| relabel?.marker !== context.marker || !nonBlank(relabel.sourceOrderNo)
|
||||
|| id(relabel.customerId) !== id(context.context?.merchantQualificationFixture?.tenantId)
|
||||
|| relabel.deliveryExecution?.closure?.status !== 'CARGO_COMPLETED_AND_RESOURCES_RELEASED'
|
||||
|| !nonBlank(relabel.outboundNo)) throw Error('贴标结算缺少本轮原申请已交付证据')
|
||||
const evidence = relabel.settlement = { status: 'POLLING', observations: [] }
|
||||
try {
|
||||
for (let attempt = 0; attempt < 31; attempt++) {
|
||||
await context.checkpoint()
|
||||
const result = await platform(context, 'GET', '客户原贴标申请结算回查',
|
||||
`${LASTLEG_BASE}/relabel-applications/${encodeURIComponent(relabel.relabelNo)}`)
|
||||
const application = result.data?.application
|
||||
const same = success(result.response) && application?.relabelNo === relabel.relabelNo
|
||||
&& application.customerOrderNo === relabel.sourceOrderNo && id(application.overseasWarehouseId) === id(relabel.warehouseId)
|
||||
&& Number(application.chargeAmount) === 0.01 && nonBlank(application.chargeCurrency)
|
||||
&& Boolean(application.customerConfirmedAt)
|
||||
context.assert(MODULE, '结算回执属于原贴标申请及原费用', result.response, same, `relabelNo=${relabel.relabelNo}`, OPTIONS)
|
||||
if (!same) throw Error('原贴标申请结算身份或金额不一致')
|
||||
evidence.observations.push({ walletStatus: application.walletStatus, chargeAmount: application.chargeAmount,
|
||||
chargeCurrency: application.chargeCurrency, requestId: result.response.requestId, traceId: result.response.traceId })
|
||||
await context.checkpoint()
|
||||
if (application.walletStatus === 'SETTLED') { evidence.status = 'SETTLED_HTTP_VERIFIED'; await context.checkpoint(); return evidence }
|
||||
if (!['FROZEN', 'SETTLE_PENDING'].includes(application.walletStatus)) throw Error(`贴标结算异常状态: ${application.walletStatus}`)
|
||||
if (attempt < 30) await delay()
|
||||
}
|
||||
throw Error('原贴标费用结算回执等待超时')
|
||||
} catch (error) { evidence.status = 'FAILED'; evidence.failure = error.message; await context.checkpoint(); throw error }
|
||||
}
|
||||
|
||||
// 原换标申请逐车完成,必须等前车释放复用资源,不能只出库不签收。
|
||||
export async function verifyRelabelDispatchOutbound(context, relabel, token, warehouseId, helpers = {
|
||||
prepare: prepareFleetTrip, pick: pickAll, load: confirmFleetLoading, read: readAutomaticDispatchDelivery,
|
||||
sign: saveReceiptAndComplete, finish: finishFleetTrip, settle: verifyClientRelabelSettlement,
|
||||
}) {
|
||||
if (relabel?.marker !== context.marker || !nonBlank(relabel?.dispatchNo) || !token || relabel.deliveryExecution
|
||||
|| ![context.createdResources?.phase4OverseasRelabel, context.createdResources?.phase4OverseasClientServices?.relabelFulfillment].includes(relabel)
|
||||
|| id(relabel.warehouseId ?? relabel.overseasWarehouseId) !== id(warehouseId)) throw Error('缺少本轮原换标排车、同仓PDA或履约已执行')
|
||||
const evidence = relabel.deliveryExecution = { status: 'RUNNING', marker: context.marker }
|
||||
const require = (name, passed) => {
|
||||
context.assert(MODULE, name, null, Boolean(passed), `relabelNo=${relabel.relabelNo}`, OPTIONS)
|
||||
if (!passed) throw Error(name)
|
||||
}
|
||||
const proof = await prepareFleetTrip(context, MODULE, relabel.dispatchNo, warehouseId)
|
||||
if (!await pickAll(context, token, relabel.dispatchNo)) return
|
||||
await confirmFleetLoading(context, MODULE, proof, token, relabel.loadingMeasurements)
|
||||
const transferred = await readAutomaticDispatchDelivery(context, relabel.dispatchNo)
|
||||
if (!transferred) return
|
||||
try {
|
||||
const proof = await helpers.prepare(context, MODULE, relabel.dispatchNo, warehouseId)
|
||||
evidence.tripNo = proof.tripNo
|
||||
require('原换标排车实际扫码完成', await helpers.pick(context, token, relabel.dispatchNo))
|
||||
await helpers.load(context, MODULE, proof, token, relabel.loadingMeasurements)
|
||||
const transferred = await helpers.read(context, relabel.dispatchNo)
|
||||
const customerId = id(relabel.customerId)
|
||||
const outboundNo = transferred.outbounds.find(row => id(row.customerId) === customerId)?.outboundNo
|
||||
if (!nonBlank(outboundNo)) { blocker(context, '换标排车客户出库', '全车安排结果缺少本轮换标客户出库单'); return }
|
||||
require('原换标排车生成唯一客户出库且派送无外来客户', transferred?.outbounds?.length === 1
|
||||
&& id(transferred.outbounds[0].customerId) === customerId && nonBlank(transferred.outbounds[0].outboundNo)
|
||||
&& transferred.deliveries?.length > 0 && new Set(transferred.deliveries.map(row => row.deliveryNo)).size === transferred.deliveries.length
|
||||
&& transferred.deliveries.every(row => id(row.customerId) === customerId && row.outboundNo === transferred.outbounds[0].outboundNo)
|
||||
&& transferred.deliveries.reduce((sum, row) => sum + Number(row.packageCount), 0) === relabel.relabelCartonMarks.length)
|
||||
const outboundNo = transferred.outbounds[0].outboundNo
|
||||
const detail = await platform(context, 'GET', '回查换标排车的真实出库箱唛',
|
||||
`${LASTLEG_BASE}/outbound-orders/${encodeURIComponent(outboundNo)}`)
|
||||
context.assert(MODULE, '排车出库快照精确保留全部新箱唛且无原箱唛或重复箱', detail.response,
|
||||
require('排车出库快照精确保留全部新箱唛且无原箱唛或重复箱',
|
||||
success(detail.response) && detail.data?.outbound?.outboundNo === outboundNo
|
||||
&& detail.data?.outbound?.dispatchNo === relabel.dispatchNo
|
||||
&& relabelOutboundMarksMatch(detail.data, relabel), trace(detail.response), OPTIONS)
|
||||
&& id(detail.data?.outbound?.customerId) === customerId && detail.data?.outbound?.status === 'OUTBOUNDED'
|
||||
&& relabelOutboundMarksMatch(detail.data, relabel))
|
||||
Object.assign(relabel, { outboundNo, deliveryNos: transferred.deliveries.map(row => row.deliveryNo).sort() })
|
||||
for (const [index, delivery] of transferred.deliveries.entries()) {
|
||||
const signed = await helpers.sign(context, delivery, customerId, index)
|
||||
require('原换标货物经正式签收完成派送', signed?.order?.status === 'DELIVERED'
|
||||
&& signed.order.deliveryNo === delivery.deliveryNo && id(signed.order.customerId) === customerId
|
||||
&& signed.order.outboundNo === outboundNo)
|
||||
}
|
||||
evidence.closure = await helpers.finish(context, MODULE, proof)
|
||||
require('原换标车签收后车辆司机均已释放', evidence.closure?.status === 'CARGO_COMPLETED_AND_RESOURCES_RELEASED')
|
||||
if (context.createdResources?.phase4OverseasClientServices?.relabelFulfillment === relabel) {
|
||||
const settled = await helpers.settle(context, relabel)
|
||||
require('客户原贴标申请费用已结算', settled?.status === 'SETTLED_HTTP_VERIFIED')
|
||||
}
|
||||
evidence.status = 'DELIVERED_HTTP_VERIFIED'
|
||||
await context.checkpoint()
|
||||
return evidence
|
||||
} catch (error) {
|
||||
evidence.status = 'FAILED'; evidence.failure = error.message
|
||||
await context.checkpoint(); throw error
|
||||
}
|
||||
}
|
||||
|
||||
// 主车结案后串行复用同仓PDA及车辆池,客户原申请与旧换标样本分别核验。
|
||||
async function finishRelabelDeliveries(context, mainTrip, warehouseId) {
|
||||
if (mainTrip.closure?.status !== 'CARGO_COMPLETED_AND_RESOURCES_RELEASED') throw Error('主车尚未释放,不能启动换标履约')
|
||||
const access = await resolvePickerAccess(context)
|
||||
const picker = access ? await createPicker(context, 95, warehouseId, access) : null
|
||||
try {
|
||||
if (!picker?.token) throw Error('换标完整履约缺少可复用同仓PDA')
|
||||
for (const original of [context.createdResources.phase4OverseasRelabel, context.createdResources.phase4OverseasClientServices?.relabelFulfillment]) {
|
||||
await verifyRelabelDispatchOutbound(context, original, picker.token, warehouseId)
|
||||
}
|
||||
} finally {
|
||||
await disablePicker(context, picker, 95)
|
||||
if (picker) picker.token = null
|
||||
await context.checkpoint()
|
||||
}
|
||||
}
|
||||
|
||||
async function loginMerchant(context, customerId) {
|
||||
@@ -1144,8 +1227,6 @@ export async function run(context) {
|
||||
context.assert(MODULE, '发车及重放库存和SHIP零额外扣减', ready.response, unchanged, trace(ready.response), OPTIONS)
|
||||
if (!unchanged) return
|
||||
}
|
||||
// 换标副场景仍核对真实新箱唛快照,执行同一原生装车前置。
|
||||
await verifyRelabelDispatchOutbound(context, context.createdResources?.phase4OverseasRelabel, picker.token, warehouseId)
|
||||
} finally {
|
||||
try { await disablePicker(context, picker, 5) }
|
||||
finally { if (picker) picker.token = null; await context.checkpoint() }
|
||||
@@ -1266,6 +1347,7 @@ export async function run(context) {
|
||||
// 默认验收在正常签收与回访完成后结案。旧异常子场景仅接受调用方明确授权的独立开关。
|
||||
if (context.context?.phase5TailVerification?.runReturnScenario !== true) {
|
||||
context.createdResources.phase5OverseasFulfillment.tripClosure = await finishFleetTrip(context, MODULE, tripProof)
|
||||
await finishRelabelDeliveries(context, tripProof, warehouseId)
|
||||
await verifyFleetTripFinance(context, MODULE, { tripNo: tripProof.tripNo, dispatchNos: [dispatchNo],
|
||||
businesses: deliveries.map(row => ({ customerId: id(row.customerId), deliveryNo: row.deliveryNo })), receiptsVisible: true })
|
||||
context.createdResources.phase5OverseasFulfillment.finalStatus = 'DELIVERED_WITH_COMPLETED_VISIT'
|
||||
@@ -1315,6 +1397,7 @@ export async function run(context) {
|
||||
exceptionNo: returnExceptionNo, outboundNo })
|
||||
context.createdResources.phase5OverseasFulfillment.returnReceipt = returnReceipt
|
||||
context.createdResources.phase5OverseasFulfillment.tripClosure = await finishFleetTrip(context, MODULE, tripProof)
|
||||
await finishRelabelDeliveries(context, tripProof, warehouseId)
|
||||
await verifyFleetTripFinance(context, MODULE, { tripNo: tripProof.tripNo, dispatchNos: [dispatchNo],
|
||||
businesses: deliveries.map(row => ({ customerId: id(row.customerId), deliveryNo: row.deliveryNo })), receiptsVisible: true })
|
||||
context.createdResources.phase5OverseasFulfillment.finalStatus = returnReceipt
|
||||
|
||||
Reference in New Issue
Block a user