This commit is contained in:
2026-10-22 11:56:47 +08:00
parent 5d71af1ac9
commit de96e47d74
71 changed files with 1296 additions and 332 deletions
@@ -4,7 +4,7 @@ import { verifyPalletLabels } from './phase3-loading-finalize.mjs'
import { stableLoadedCartonMarks } from './phase3-loading.mjs'
import { awaitProducerConsumption, convertReceivingContainers, runReceiving,
resolvePickerAccess, createPicker, disablePicker } from './phase4-overseas-pda.mjs'
import { pickAll, verifyDepartureReadiness, saveReceiptAndComplete, arrangeDispatchDelivery, fulfillmentEvidenceContext } from './phase5-overseas-fulfillment.mjs'
import { pickAll, verifyAutomaticDeparture, saveReceiptAndComplete, readAutomaticDispatchDelivery, fulfillmentEvidenceContext } from './phase5-overseas-fulfillment.mjs'
import { isDeepStrictEqual } from 'node:util'
import { assertTestDeliveryFaultProof } from '../test-delivery-fault-proof.mjs'
import { prepareTerminalDrayage } from './phase5-terminal-drayage.mjs'
@@ -484,11 +484,11 @@ async function fragment(context, source, rootOrderId, sequence) {
shippingReady: true, carrierScheduleQueryId: pickup.queryId, carrierLatestActualAt: pickup.latestActualAt,
palletLabelManifest, rootOrderId }
}
const F40_DISPATCH_DEPENDENCIES = { prepareFleetTrip, pickAll, confirmFleetLoading, arrangeDispatchDelivery,
verifyDepartureReadiness, saveReceiptAndComplete, finishFleetTrip, fulfillmentEvidenceContext }
const F40_DISPATCH_DEPENDENCIES = { prepareFleetTrip, pickAll, confirmFleetLoading, readAutomaticDispatchDelivery,
verifyAutomaticDeparture, saveReceiptAndComplete, finishFleetTrip, fulfillmentEvidenceContext }
export async function sendFragment(context, producer, picker, merchantToken, index, overrides = {}) {
const { prepareFleetTrip, pickAll, confirmFleetLoading, arrangeDispatchDelivery, verifyDepartureReadiness,
const { prepareFleetTrip, pickAll, confirmFleetLoading, readAutomaticDispatchDelivery, verifyAutomaticDeparture,
saveReceiptAndComplete, finishFleetTrip, fulfillmentEvidenceContext } = { ...F40_DISPATCH_DEPENDENCIES, ...overrides }
const customerId = id(producer.tenantId), warehouseId = id(picker.warehouseId)
context.marker = `${context.context.f40BaseMarker}-SEND-${index}`
@@ -529,8 +529,8 @@ export async function sendFragment(context, producer, picker, merchantToken, ind
dispatchProof.action = 'LOADING_COMPLETE'
const actualMeasurements = await resolveF40LoadingMeasurements(context, dispatchNo, producer, warehouseId)
await confirmFleetLoading(context, MODULE, tripProof, picker.token, actualMeasurements)
dispatchProof.action = 'ARRANGE_DELIVERY'
const transfer = await arrangeDispatchDelivery(context, dispatchNo)
dispatchProof.action = 'READ_AUTOMATIC_DELIVERY'
const transfer = await readAutomaticDispatchDelivery(context, dispatchNo)
check(context, 'F40 平台装车后一次安排本片完整客户派送', Boolean(transfer), `dispatch=${dispatchNo}`)
const deliveries = transfer.deliveries, outbounds = transfer.outbounds
check(context, 'F40 同客户同目的仓一片对应唯一出库与派送', deliveries?.length === 1 && outbounds?.length === 1
@@ -538,27 +538,18 @@ export async function sendFragment(context, producer, picker, merchantToken, ind
&& deliveries[0].outboundNo === outbounds[0].outboundNo && Number(deliveries[0].packageCount) === 1
&& deliveries[0].destination?.key === matches[0].destination.key, 'one-actual-customer-destination')
const outboundNo = outbounds[0].outboundNo
dispatchProof.arrangement = transfer.data?.result; dispatchProof.outboundNo = outboundNo
dispatchProof.arrangement = transfer.data?.documents; dispatchProof.outboundNo = outboundNo
dispatchProof.deliveryNo = deliveries[0].deliveryNo
const deliveryPath = query(`/api/platform/v1/last-leg/delivery-orders/${deliveries[0].deliveryNo}`, { customerId })
const detail = await api(context, 'GET', '核对派送实际 SKU 仅来自本片入仓码', deliveryPath)
check(context, 'F40 派送实际物品来源和一箱数量严格匹配', id(detail.order?.customerId) === customerId
&& detail.skus?.length > 0 && detail.skus.every(row => row.inboundCode === producer.inboundCode)
&& detail.skus.reduce((sum,row) => sum + Number(row.packageCount),0) === 1, `source=${producer.inboundCode}`)
dispatchProof.action = 'PDA_DEPART'
const ready = await verifyDepartureReadiness(context, picker.token, dispatchNo)
dispatchProof.action = 'VERIFY_AUTOMATIC_DEPARTURE'
const ready = await verifyAutomaticDeparture(context, picker.token, dispatchNo)
check(context, 'F40 双端当前公共版本发车门禁就绪', Boolean(ready), `dispatch=${dispatchNo}`)
const departBody = { recordVersion: wireVersion(ready.data.recordVersion),
idempotencyKey: `${context.marker}-DEPART`.slice(0,128), remark: context.marker }
const departed = await api(context, 'POST', 'F40 正式 PDA 实际发车', `${PDA}/${dispatchNo}/depart`, departBody, picker.token)
check(context, 'F40 本片原生发车进入DELIVERING并且真实出库一箱', departed.dispatchNo === dispatchNo
&& departed.status === 'ACTIVE' && departed.stage === 'DELIVERING' && Number(departed.result?.shippedPackages) === 1
&& departed.result?.deliveries?.length === 1 && departed.result.deliveries[0].deliveryNo === deliveries[0].deliveryNo, `dispatch=${dispatchNo}`)
const departureReplay = await api(context, 'POST', 'F40 实际发车原命令重放', `${PDA}/${dispatchNo}/depart`, departBody, picker.token)
check(context, 'F40 发车重放保留原公共版本及全部发运结果', departureReplay.replayed === true
&& String(departureReplay.recordVersion) === String(departed.recordVersion)
&& JSON.stringify(departureReplay.result) === JSON.stringify(departed.result), 'immutable-departure-result')
dispatchProof.departure = departed; dispatchProof.departureReplay = departureReplay; dispatchProof.stage = 'DELIVERING'
check(context, 'F40 自动发车真实出库一箱', Number(ready.data.counts?.shippedPackageCount) === 1, `dispatch=${dispatchNo}`)
dispatchProof.departure = ready.data; dispatchProof.loadingReplay = tripProof.loadingCommand?.replay; dispatchProof.stage = 'DELIVERING'
const outbound = await api(context, 'GET', '回查实际来源出库完成', `/api/platform/v1/last-leg/outbound-orders/${outboundNo}`)
check(context,'F40 实际出库单 OUTBOUNDED 且来源入仓码匹配', id(outbound.outbound?.customerId) === customerId
&& outbound.outbound?.outboundNo === outboundNo && outbound.outbound?.status === 'OUTBOUNDED'