Files
baiyue-firstleg/scripts/admin-test-env-modules/us-truck-fulfillment.mjs
T
2026-10-22 14:37:59 +08:00

77 lines
5.1 KiB
JavaScript

const MODULE = 'phase4-overseas-business'
const OPTIONS = { scenario: 'us-truck-fulfillment', deploymentBlocker: true }
/** 沿用本轮独立卡车原单,以正式履约命令完成实收、分配和运输。 */
export async function verifyUsTruckFulfillment(context, proof) {
if (!proof || proof.marker !== context.marker || !proof.orderNo || !proof.customerId
|| context.createdResources?.phase4OverseasBusiness?.truck !== proof || proof.fulfillment
|| proof.finalStatus !== 'WAITING_INBOUND') throw Error('卡车履约必须使用本轮未执行的待入仓原单')
const evidence = proof.fulfillment = { status: 'RUNNING', requests: [] }
const base = `/api/platform/v1/last-leg/us-truck-orders/${encodeURIComponent(proof.orderNo)}`
const suffix = `?customerId=${encodeURIComponent(proof.customerId)}`
const check = (name, ok) => {
context.assert(MODULE, name, null, Boolean(ok), `orderNo=${proof.orderNo}`, OPTIONS)
if (!ok) throw Error(name)
}
const request = async (method, action, body) => {
const log = { method, action, status: 'SENDING' }
evidence.requests.push(log)
const response = await context.request(method, `${base}${action}${suffix}`, body)
Object.assign(log, { http: response?.http, code: response?.body?.code,
requestId: response?.requestId, traceId: response?.traceId })
const ok = response?.http === 200 && String(response?.body?.code) === '200'
log.status = ok ? 'SUCCEEDED' : !response?.http || response.http >= 500 || !response.body ? 'UNKNOWN_RESULT' : 'REJECTED'
context.apiSuccess(MODULE, `本土卡车${method} ${action || '详情'}`, response,
`HTTP=${response?.http}; requestId=${response?.requestId}; traceId=${response?.traceId}`, OPTIONS)
if (!ok) throw Error(`卡车履约请求失败,不自动重发: ${action}`)
return response.body.data
}
const identity = detail => check('卡车原单客户和版本有效', detail?.summary?.orderNo === proof.orderNo
&& String(detail.summary.customerId) === String(proof.customerId)
&& Number.isSafeInteger(detail.summary.version) && detail.summary.version >= 0)
try {
let current = await request('GET', '')
identity(current)
check('卡车实收前仍为本轮待入仓单', current.summary.status === 'WAITING_INBOUND'
&& current.remark?.startsWith(context.marker) && Number(current.summary.receivedPalletCount) === 0)
const packages = Number(current.summary.packageCount)
check('卡车实收箱数来自原订单且为有效正整数', Number.isSafeInteger(packages) && packages > 0)
const stages = [
['receive-pallets', 'WAITING_CONSOLIDATION'], ['allocate-pallets', 'ALLOCATED'],
['prepare-dispatch', 'PENDING_DISPATCH'], ['dispatch', 'DISPATCHED'],
['start-transit', 'IN_TRANSIT'], ['complete', 'COMPLETED'],
]
let palletId, palletNo
for (const [action, state] of stages) {
const beforeVersion = current.summary.version
const body = { version: beforeVersion, idempotencyKey: `${context.marker}-truck-${action}`, remark: context.marker }
if (action === 'receive-pallets') Object.assign(body, { actualPalletCount: 1, packageCount: packages, palletPackageCounts: [packages] })
if (action === 'allocate-pallets') body.palletIds = [palletId]
const next = await request('POST', `/${action}`, body)
identity(next)
check(`卡车${action}状态和版本正确`, next.summary.status === state && next.summary.version === beforeVersion + 1)
check('卡车原单实收托盘及箱数守恒', next.pallets?.length === 1 && Number(next.summary.receivedPalletCount) === 1
&& Number(next.pallets[0].packageCount) === packages && /^[1-9]\d*$/.test(String(next.pallets[0].id))
&& typeof next.pallets[0].palletNo === 'string' && next.pallets[0].palletNo.startsWith(`${proof.orderNo}-P`))
palletId ??= next.pallets[0].id
palletNo ??= next.pallets[0].palletNo
check('卡车履约复用原实收托盘', String(next.pallets[0].id) === String(palletId) && next.pallets[0].palletNo === palletNo
&& next.pallets[0].status === (action === 'receive-pallets' ? 'RECEIVED' : 'ALLOCATED')
&& Number(next.summary.allocatedPalletCount) === (action === 'receive-pallets' ? 0 : 1))
check('卡车履约写入对应操作历史', next.histories?.some(row => row.idempotencyKey === body.idempotencyKey
&& row.toStatus === state && row.fromStatus === current.summary.status))
const replay = await request('POST', `/${action}`, body)
check('卡车同键重放不重复收托或推进版本', JSON.stringify(replay) === JSON.stringify(next))
current = await request('GET', '')
check('卡车履约状态已持久化且回查一致', JSON.stringify(current) === JSON.stringify(next))
}
Object.assign(proof, { finalStatus: 'COMPLETED', version: current.summary.version, retained: true })
Object.assign(evidence, { status: 'HTTP_VERIFIED', palletId, palletNo, packages })
} catch (error) {
for (const log of evidence.requests) if (log.status === 'SENDING') log.status = 'UNKNOWN_RESULT'
evidence.status = 'FAILED'
evidence.failure = error.message
throw error
}
}