fix: validate overseas handover before settlement

This commit is contained in:
2026-09-01 23:20:34 +08:00
parent e19224c4b7
commit f4a3b58959
9 changed files with 89 additions and 24 deletions
+6 -4
View File
@@ -1299,10 +1299,12 @@ export class AcceptanceRun {
this.context.phase3LoadingRequireSharedOverflow = false
this.context.phase3LoadingIncrementalPackageCount = 2
this.context.phase3LoadingIncrementalDetailCount = 4
if (taxModes?.incremental) {
this.context.orderProfile = {
...(this.context.orderProfile || {}), taxMode: taxModes.incremental,
}
this.context.orderProfile = {
...(this.context.orderProfile || {}),
// The incremental order exercises partial/SKIP/PARTIAL mutations. Keep it STANDARD so a
// ONE_CLICK_DROPSHIP primary order remains a physically indivisible whole-pallet handover.
fulfillmentType: 'STANDARD',
...(taxModes?.incremental ? { taxMode: taxModes.incremental } : {}),
}
await this.executeModule('orders-phase3-loading-incremental-fixture', () => orders.run(this))
const measurement = await import(new URL('./admin-test-env-modules/inbound-measurement.mjs', import.meta.url))
@@ -226,15 +226,18 @@ export async function run(context) {
const loadingPlan = context.apiSuccess(MODULE, '读取柜次创建时原子生成的智能装柜计划', loadingPlanResponse, '', OPTIONS)
const loadingPlanId = id(loadingPlan?.id)
if (!loadingPlanId) return
const initialAssignmentCount = source?.fulfillmentType === 'ONE_CLICK_DROPSHIP'
? Number(candidate.availablePackageCount) : 1
const assignmentResponse = await request(context, 'POST', `${smartLoadingBase}/plans/${loadingPlanId}/assignments`, {
inboundId, inboundDetailId: id(candidate.inboundDetailId), packageCount: 1,
inboundId, inboundDetailId: id(candidate.inboundDetailId), packageCount: initialAssignmentCount,
expectedVersion: Number(loadingPlan.version), operationId: `${context.marker}-bridge-assign`.slice(0, 128),
})
const assignedLoadingPlan = context.apiSuccess(MODULE, '将本轮入库货物分配到柜次计划', assignmentResponse, '', OPTIONS)
context.assert(MODULE, '柜次计划明细和版本真实持久化', assignmentResponse,
assignedLoadingPlan?.items?.some?.((item) => id(item.inboundId) === inboundId && Number(item.packageCount) === 1)
assignedLoadingPlan?.items?.some?.((item) => id(item.inboundId) === inboundId
&& Number(item.packageCount) === initialAssignmentCount)
&& Number(assignedLoadingPlan?.version) === 1,
`loadingPlanId=${loadingPlanId}, version=${assignedLoadingPlan?.version ?? 'missing'}`, OPTIONS)
`loadingPlanId=${loadingPlanId}, assignedPackages=${initialAssignmentCount}, version=${assignedLoadingPlan?.version ?? 'missing'}`, OPTIONS)
const assignedItem = assignedLoadingPlan?.items?.find?.((item) => id(item.inboundId) === inboundId)
const orderRemarks = source || {}
@@ -279,11 +279,19 @@ async function convertReceivingContainers(context, producers) {
const summaries = success(summaryResponse) && Array.isArray(summaryResponse.body?.data?.records)
? summaryResponse.body.data.records : []
const summary = summaries.find((item) => id(item?.containerNo) === containerNo)
const totalOrders = Number(summary?.totalOrderCount)
const inboundCodes = Number(summary?.inboundCodeCount)
const existingPlans = Number(summary?.planCount)
const pendingPlans = Number(summary?.pendingPlanCount)
const convertible = nonBlank(summary?.sourceContainerBookingId)
&& totalOrders > 0 && inboundCodes === totalOrders
&& Number(summary?.missingInboundCodeCount) === 0
&& ((existingPlans === 0 && pendingPlans === totalOrders)
|| (summary?.allPlansReady === true && existingPlans === totalOrders && pendingPlans === 0))
context.addStep(MODULE, `读取待分配柜级摘要 ${containerNo}`, summaryResponse,
Boolean(summary?.eligible && nonBlank(summary?.sourceContainerBookingId)
&& Number(summary?.inboundCodeCount) > 0),
`sourceContainerBookingId=${id(summary?.sourceContainerBookingId) || 'missing'}, eligible=${summary?.eligible === true}, inboundCodes=${summary?.inboundCodeCount ?? 'missing'}; ${trace(summaryResponse)}`, OPTIONS)
if (!summary?.eligible || !nonBlank(summary?.sourceContainerBookingId)) return false
convertible,
`sourceContainerBookingId=${id(summary?.sourceContainerBookingId) || 'missing'}, allPlansReady=${summary?.allPlansReady === true}, orders=${totalOrders}, inboundCodes=${inboundCodes}, plans=${existingPlans}, pending=${pendingPlans}; ${trace(summaryResponse)}`, OPTIONS)
if (!convertible) return false
const body = { sourceContainerBookingId: id(summary.sourceContainerBookingId) }
const key = `${context.marker}-pda-convert-${containerNo}`.slice(0, 128)
const convertedResponse = await context.requestOverseas('POST',
@@ -295,11 +303,11 @@ async function convertReceivingContainers(context, producers) {
.flatMap((item) => Array.isArray(item?.lines) ? item.lines : [])
.map((line) => id(line?.inboundCode)).filter(nonBlank))
context.addStep(MODULE, `整柜转换为逐入仓码独立计划 ${containerNo}`, convertedResponse,
plans.length === Number(summary.inboundCodeCount)
plans.length === inboundCodes
&& plans.every((item) => Array.isArray(item?.lines) && item.lines.length > 0)
&& convertedInboundCodes.size === Number(summary.inboundCodeCount),
`plans=${plans.length}, inboundCodes=${convertedInboundCodes.size}, expected=${summary.inboundCodeCount}; ${trace(convertedResponse)}`, OPTIONS)
if (plans.length !== Number(summary.inboundCodeCount)) return false
&& convertedInboundCodes.size === inboundCodes,
`plans=${plans.length}, inboundCodes=${convertedInboundCodes.size}, expected=${inboundCodes}; ${trace(convertedResponse)}`, OPTIONS)
if (plans.length !== inboundCodes) return false
const replayResponse = await context.requestOverseas('POST',
'/api/platform/v1/last-leg/inbound-plans/convert-container', body,
{ 'Idempotency-Key': key }, context.overseasToken)
@@ -307,6 +315,15 @@ async function convertReceivingContainers(context, producers) {
success(replayResponse) && JSON.stringify(replayResponse.body?.data) === JSON.stringify(plans),
trace(replayResponse), OPTIONS)
if (!success(replayResponse)) return false
const progressResponse = await context.requestOverseas('GET',
`/api/platform/v1/last-leg/orders/container-summaries/${encodeURIComponent(summary.sourceContainerBookingId)}`,
undefined, {}, context.overseasToken)
const progress = success(progressResponse) ? progressResponse.body?.data?.summary : null
context.addStep(MODULE, `整柜转换后计划完整度闭环 ${containerNo}`, progressResponse,
progress?.allPlansReady === true && Number(progress?.planCount) === totalOrders
&& Number(progress?.pendingPlanCount) === 0,
`allPlansReady=${progress?.allPlansReady === true}, plans=${progress?.planCount ?? 'missing'}, pending=${progress?.pendingPlanCount ?? 'missing'}, plannedArrivalAt=${progress?.plannedArrivalAt || 'missing'}; ${trace(progressResponse)}`, OPTIONS)
if (progress?.allPlansReady !== true) return false
}
return true
}