diff --git a/scripts/admin-test-env-modules/phase3-loading.mjs b/scripts/admin-test-env-modules/phase3-loading.mjs index a00338519..4c8d1d26e 100644 --- a/scripts/admin-test-env-modules/phase3-loading.mjs +++ b/scripts/admin-test-env-modules/phase3-loading.mjs @@ -373,7 +373,10 @@ export async function run(context) { if (!assignedItem?.id || !Number.isInteger(Number(assignedItem.version))) return const warehouseRemark = `${context.marker}-WAREHOUSE-REMARK` const warehouseRemarkPath = `${smartLoadingBase}/plans/${loadingPlanId}/items/${id(assignedItem.id)}/remarks` - const warehouseRemarkBody = Object.freeze({ warehouseRemark, + const warehouseRemarkBody = Object.freeze({ + internalRemark: assignedItem.internalRemark, + warehouseRemark, + customerServiceRemark: assignedItem.customerServiceRemark, expectedPlanVersion: Number(assignedLoadingPlan.version), expectedItemVersion: Number(assignedItem.version), operationId: `${context.marker}-${loadingPlanId}-warehouse-remark`.slice(0, 128) }) const remarkResponse = await request(context, 'PATCH', warehouseRemarkPath, warehouseRemarkBody) @@ -413,7 +416,10 @@ export async function run(context) { `planVersion=${afterStaleRemarkPlan?.version ?? 'missing'}, itemVersion=${afterStaleRemarkItem?.version ?? 'missing'}`, OPTIONS) const clearRemarkResponse = await request(context, 'PATCH', `${smartLoadingBase}/plans/${loadingPlanId}/items/${id(remarkedItem.id)}/remarks`, { - warehouseRemark: ' ', expectedPlanVersion: Number(remarkedPlan.version), + internalRemark: remarkedItem.internalRemark, + warehouseRemark: ' ', + customerServiceRemark: remarkedItem.customerServiceRemark, + expectedPlanVersion: Number(remarkedPlan.version), expectedItemVersion: Number(remarkedItem.version), operationId: `${context.marker}-${loadingPlanId}-warehouse-remark-clear`.slice(0, 128), }) const clearedPlan = context.apiSuccess(MODULE, 'EDITING 装柜明细空白仓库备注归一化为 null', clearRemarkResponse, '', OPTIONS) @@ -425,7 +431,10 @@ export async function run(context) { if (!clearedItem?.id) return const restoreRemarkResponse = await request(context, 'PATCH', `${smartLoadingBase}/plans/${loadingPlanId}/items/${id(clearedItem.id)}/remarks`, { - warehouseRemark, expectedPlanVersion: Number(clearedPlan.version), expectedItemVersion: Number(clearedItem.version), + internalRemark: clearedItem.internalRemark, + warehouseRemark, + customerServiceRemark: clearedItem.customerServiceRemark, + expectedPlanVersion: Number(clearedPlan.version), expectedItemVersion: Number(clearedItem.version), operationId: `${context.marker}-${loadingPlanId}-warehouse-remark-restore`.slice(0, 128), }) const persistedRemarkPlan = context.apiSuccess(MODULE, '恢复真实仓库备注供装柜完成事件下发', restoreRemarkResponse, '', OPTIONS) @@ -461,10 +470,13 @@ export async function run(context) { const pushedLinksResponse = await context.request('GET', `${smartLoadingBase}/plans/${loadingPlanId}/preloads`) const pushedLinks = context.apiSuccess(MODULE, '无号推送自动建立 bridge 关联', pushedLinksResponse, '', OPTIONS) const link = Array.isArray(pushedLinks) ? pushedLinks.find((item) => id(item.inboundId) === inboundId) : null + const allocatedPackages = (persistedRemarkPlan?.items || []) + .filter((item) => id(item.inboundId) === inboundId) + .reduce((sum, item) => sum + Number(item.packageCount || 0), 0) context.assert(MODULE, 'push 自动建立唯一预装关联且分配身份稳定', pushedLinksResponse, Boolean(link?.id) && id(link?.loadingPlanId) === loadingPlanId && id(link?.preloadPlanId) === planId - && Number(link?.allocatedPackageCount) === 1, - `linkId=${id(link?.id) || 'missing'}, preloadPlanId=${id(link?.preloadPlanId) || 'missing'}`, OPTIONS) + && Number(link?.allocatedPackageCount) === allocatedPackages, + `linkId=${id(link?.id) || 'missing'}, preloadPlanId=${id(link?.preloadPlanId) || 'missing'}, allocated=${link?.allocatedPackageCount ?? 'missing'}, expected=${allocatedPackages}`, OPTIONS) if (!link?.id) return const postPushPlanResponse = await context.request('GET', `${smartLoadingBase}/plans/${loadingPlanId}`) const postPushPlan = context.apiSuccess(MODULE, '首次 push 后读取事务完成态柜次计划', postPushPlanResponse, '', OPTIONS) diff --git a/scripts/admin-test-env-modules/phase4-overseas-pda-operations.mjs b/scripts/admin-test-env-modules/phase4-overseas-pda-operations.mjs index 2855f8c70..4f43ab24f 100644 --- a/scripts/admin-test-env-modules/phase4-overseas-pda-operations.mjs +++ b/scripts/admin-test-env-modules/phase4-overseas-pda-operations.mjs @@ -574,6 +574,16 @@ async function verifyRelabel(context, token, merchantToken, fixture) { const targets = [printedA.data, printedB.data] const beforeBySource = new Map() const movedFacts = [] + const sourceCodes = confirmed.items.map((itemDetail) => { + const sourcePositionId = id(itemDetail?.sourceInventoryPositionId) + return sourceLines.find((line) => id(line.position.positionId) === sourcePositionId)?.position?.palletNo || '' + }) + const sourceFrequency = sourceCodes.reduce((counts, sourceCode) => { + if (sourceCode) counts.set(sourceCode, (counts.get(sourceCode) || 0) + 1) + return counts + }, new Map()) + const splitSource = [...sourceFrequency.entries()].find(([, count]) => count >= 2)?.[0] || '' + let splitSourceMoves = 0 for (const [index, itemDetail] of confirmed.items.entries()) { const sourcePositionId = id(itemDetail?.sourceInventoryPositionId) const sourceLine = sourceLines.find((line) => id(line.position.positionId) === sourcePositionId) @@ -586,9 +596,8 @@ async function verifyRelabel(context, token, merchantToken, fixture) { `P5拆托${index + 1}前刷新来源托盘`)).data if (!sourceBefore) return false if (!beforeBySource.has(sourcePalletCode)) beforeBySource.set(sourcePalletCode, Number(sourceBefore.totalPackages)) - // A receives one carton, then B receives one and is reused as an occupied merge target. - // If the first two cartons share a source, the same source is split across A and B. - const targetSeed = index === 0 ? targets[0] : targets[1] + // Split one repeated source across A and B; all other cartons reuse occupied B as the merge target. + const targetSeed = sourcePalletCode === splitSource && splitSourceMoves++ === 0 ? targets[0] : targets[1] const targetBefore = (await resolvePallet(context, token, targetSeed.palletCode, `P5拆托${index + 1}前刷新目标托盘`)).data const reason = index === 0 ? null : `${context.marker}-场景${index + 1}` @@ -699,9 +708,11 @@ export async function run(context) { 'phase4-overseas-pda未交接本轮primary picker会话与已完成库存事实') return } - const fixture = handoff.completedFixtures.find((item) => Array.isArray(item?.inventory) + const fixturesByAuxiliaryCapacity = [...handoff.completedFixtures] + .sort((left, right) => (right?.auxiliaryPallets?.length || 0) - (left?.auxiliaryPallets?.length || 0)) + const fixture = fixturesByAuxiliaryCapacity.find((item) => Array.isArray(item?.inventory) && item.inventory.some((line) => Number(line?.availablePackages) > 1)) - || handoff.completedFixtures.find((item) => Array.isArray(item?.inventory) + || fixturesByAuxiliaryCapacity.find((item) => Array.isArray(item?.inventory) && item.inventory.some((line) => Number(line?.availablePackages) > 0)) if (!fixture) { blocker(context, 'P2-P5可操作库存', '本轮已完成柜没有可移动的真实库存位置')