fix: 支持多SKU共箱整托装柜

This commit is contained in:
2026-09-16 21:22:18 +08:00
parent 1cd10a9d3b
commit 9ab1c328ba
9 changed files with 125 additions and 24 deletions
@@ -47,7 +47,12 @@ export async function runDomesticLinkRegression(context) {
return runWorkflow(context, false, false, true)
}
async function runWorkflow(context, stopBeforeOverseasPda, mixedContainer = false, linkRegression = false) {
export async function runPhysicalCartonRegression(context) {
return runWorkflow(context, false, false, false, true)
}
async function runWorkflow(context, stopBeforeOverseasPda, mixedContainer = false, linkRegression = false,
physicalCartonRegression = false) {
const marker = context.marker
const savedOptions = context.options.prepareDropshipManualCount
const savedContext = { ...context.context }
@@ -58,7 +63,7 @@ async function runWorkflow(context, stopBeforeOverseasPda, mixedContainer = fals
context.assert(MODULE, name, response, passed, details, OPTIONS)
if (!passed) throw new Error(name)
}
async function prepare(label, palletCount, mode = {}, destinationType = null) {
async function prepare(label, palletCount, mode = {}, destinationType = null, variant = {}) {
context.marker = `${marker}-${label}`
for (const key of ['orders', 'inboundMeasurement', 'ocrInbound', 'testInbound', 'dropshipManualCount']) {
delete context.createdResources[key]
@@ -67,7 +72,13 @@ async function runWorkflow(context, stopBeforeOverseasPda, mixedContainer = fals
context.context.orderDestinationType = destinationType || 'OVERSEAS'
context.context.orderFulfillmentType = destinationType ? 'STANDARD' : 'ONE_CLICK_DROPSHIP'
context.context.orderProfile = { taxMode: 'BUY_DECLARATION', pickupMethod: 'SELF_EXPRESS', containerMode: 'LCL' }
context.context.waitSplitVariant = { skuCount: 1, packageCountPerSku: 4, packageCounts: [4], palletCount }
const totalPackageCount = Number(variant.totalPackageCount || 4)
const skuCount = Number(variant.skuCount || 1)
context.context.waitSplitVariant = {
skuCount, packageCountPerSku: totalPackageCount,
packageCounts: Array.from({ length: skuCount }, () => totalPackageCount),
totalPackageCount, palletCount,
}
if (label.startsWith('MULTI-MERGE-')) {
context.context.waitSplitVariant.skuCodes = [`SKU-SHARED-${marker}`.slice(0, 64)]
}
@@ -101,6 +112,7 @@ async function runWorkflow(context, stopBeforeOverseasPda, mixedContainer = fals
Boolean(task) && !context.steps.slice(start).some((step) => !step.passed))
const record = { label, order: { ...context.createdResources.orders },
measurement: { ...context.createdResources.inboundMeasurement }, source: { ...source }, task,
expectedSkuCount: skuCount,
expectedCartonMarks: Array.from({ length: source.totalCartons }, (_, index) =>
`${source.inboundCode}#${source.totalCartons}-${index + 1}`) }
records.push(record)
@@ -116,6 +128,8 @@ async function runWorkflow(context, stopBeforeOverseasPda, mixedContainer = fals
task?.taskStatus === 'COMPLETED' && task.pallets?.length === expectedPallets
&& task.pallets.every((pallet) => pallet.status === 'SEALED')
&& cartons.length === record.expectedCartonMarks.length
&& cartons.every((carton) => Array.isArray(carton.skuLines)
&& carton.skuLines.length === (record.expectedSkuCount || 1))
&& JSON.stringify(cartons.map((carton) => carton.boxCode).sort())
=== JSON.stringify([...record.expectedCartonMarks].sort()))
record.task = task
@@ -177,9 +191,18 @@ async function runWorkflow(context, stopBeforeOverseasPda, mixedContainer = fals
=== group.reduce((sum, record) => sum + record.expectedCartonMarks.length, 0))
for (const record of group) {
const actual = detail.items.filter((item) => String(item.inboundId) === record.source.inboundId)
const packagesByPhysicalUnit = new Map()
for (const item of actual) {
const key = item.palletId == null ? `ITEM:${item.id}` : `PALLET:${item.palletId}`
packagesByPhysicalUnit.set(key, Math.max(packagesByPhysicalUnit.get(key) || 0,
Number(item.packageCount)))
}
check(`${record.label}${name}分配箱数与托盘身份正确`, null,
actual.reduce((sum, item) => sum + Number(item.packageCount), 0) === record.expectedCartonMarks.length
&& (!record.task || actual.every((item) => record.task.pallets.some((pallet) => String(pallet.palletId) === String(item.palletId)))))
[...packagesByPhysicalUnit.values()].reduce((sum, count) => sum + count, 0)
=== record.expectedCartonMarks.length
&& new Set(actual.map((item) => item.skuCode).filter(Boolean)).size === (record.expectedSkuCount || 1)
&& (!record.task || actual.every((item) => record.task.pallets.some((pallet) =>
String(pallet.palletId) === String(item.palletId)))))
}
}
for (const pallet of pallets) {
@@ -603,6 +626,26 @@ async function runWorkflow(context, stopBeforeOverseasPda, mixedContainer = fals
for (const record of group) record.outbound = { task: completed, selected, detail: outbound, completed: true }
}
try {
if (physicalCartonRegression) {
const scenarios = [
await prepare('PHYSICAL-20X2', 2, {}, null, { totalPackageCount: 20, skuCount: 2 }),
await prepare('PHYSICAL-5X3', 1, {}, null, { totalPackageCount: 5, skuCount: 3 }),
await prepare('PHYSICAL-7X2-MERGED', 2, { mergeToFirstPallet: true }, null,
{ totalPackageCount: 7, skuCount: 2 }),
]
for (const [index, record] of scenarios.entries()) await verify(record, index === 2 ? 1 : index === 0 ? 2 : 1)
const groups = scenarios.map((record) => [record])
for (const group of groups) await allocate(group)
context.createdResources.dropshipPalletMatrix.stage = 'PHYSICAL_CARTON_LOADING_COMPLETED'
for (const group of groups) await progressShipping(group)
context.createdResources.dropshipPalletMatrix.stage = 'PHYSICAL_CARTON_PICKUP_READY'
for (const group of groups) {
await convertOverseas(group)
await receiveOverseas(group)
}
context.createdResources.dropshipPalletMatrix.stage = 'PHYSICAL_CARTON_OUTBOUND_COMPLETED'
return
}
if (mixedContainer) {
const dropship = await prepare('MIXED-DROPSHIP', 2)
await verify(dropship, 2)