fix: scope smart loading recommendations
This commit is contained in:
@@ -229,9 +229,11 @@ export async function run(context) {
|
||||
&& Number(item.availablePackageCount) > 0) : []
|
||||
let candidate = inboundCandidates[0]
|
||||
let dropshipCandidates = []
|
||||
let dropshipCandidatePath = null
|
||||
if (source?.fulfillmentType === 'ONE_CLICK_DROPSHIP') {
|
||||
const group = channelGroup(initial?.summary?.channelCode)
|
||||
const candidatePath = `${smartLoadingBase}/inbound-candidates?channelGroupCodes=${encodeURIComponent(group)}&warehouseId=${encodeURIComponent(warehouseId)}&customerId=${encodeURIComponent(tenantId)}&inboundCode=${encodeURIComponent(initial?.summary?.inboundCode || source?.inboundCode || '')}&orderStatuses=WAIT_SPLIT&page=1&size=20`
|
||||
dropshipCandidatePath = candidatePath
|
||||
const palletCandidatesResponse = await context.request('GET', candidatePath)
|
||||
const palletCandidatePage = context.apiSuccess(MODULE, '查询一件代发整托装柜候选', palletCandidatesResponse, '', OPTIONS)
|
||||
dropshipCandidates = Array.isArray(palletCandidatePage?.records)
|
||||
@@ -255,24 +257,112 @@ export async function run(context) {
|
||||
if (!loadingPlanId) return
|
||||
const dropshipAssignment = source?.fulfillmentType === 'ONE_CLICK_DROPSHIP'
|
||||
const initialAssignmentCount = dropshipAssignment
|
||||
? dropshipCandidates.filter((item) => id(item.palletId) === id(candidate.palletId))
|
||||
.reduce((total, item) => total + Number(item.availablePackageCount || 0), 0) : 1
|
||||
const assignmentPath = dropshipAssignment
|
||||
? `${smartLoadingBase}/plans/${loadingPlanId}/pallet-assignments`
|
||||
: `${smartLoadingBase}/plans/${loadingPlanId}/assignments`
|
||||
const assignmentBody = dropshipAssignment
|
||||
? { palletId: id(candidate.palletId), expectedVersion: Number(loadingPlan.version),
|
||||
operationId: `${context.marker}-${loadingPlanId}-bridge-assign-pallet`.slice(0, 128) }
|
||||
: { inboundId, inboundDetailId: id(candidate.inboundDetailId), packageCount: initialAssignmentCount,
|
||||
expectedVersion: Number(loadingPlan.version), operationId: `${context.marker}-${loadingPlanId}-bridge-assign`.slice(0, 128) }
|
||||
const assignmentResponse = await request(context, 'POST', assignmentPath, assignmentBody)
|
||||
const assignedLoadingPlan = context.apiSuccess(MODULE, '将本轮入库货物分配到柜次计划', assignmentResponse, '', OPTIONS)
|
||||
? dropshipCandidates.reduce((total, item) => total + Number(item.availablePackageCount || 0), 0) : 1
|
||||
let assignmentResponse
|
||||
let assignedLoadingPlan
|
||||
if (dropshipAssignment) {
|
||||
const assignmentPath = `${smartLoadingBase}/plans/${loadingPlanId}/pallet-assignments`
|
||||
let workingPlan = loadingPlan
|
||||
for (const [index, pallet] of dropshipCandidates.entries()) {
|
||||
const body = { palletId: id(pallet.palletId), expectedVersion: Number(workingPlan.version),
|
||||
operationId: `${context.marker}-${loadingPlanId}-bridge-assign-pallet-${id(pallet.palletId)}`.slice(0, 128) }
|
||||
assignmentResponse = await request(context, 'POST', assignmentPath, body)
|
||||
workingPlan = context.apiSuccess(MODULE, `逐托分配一件代发托盘${index + 1}/${dropshipCandidates.length}`,
|
||||
assignmentResponse, '', OPTIONS)
|
||||
if (!workingPlan) return
|
||||
if (index === 0 && dropshipCandidates.length > 1 && dropshipCandidatePath) {
|
||||
const remainingResponse = await context.request('GET', dropshipCandidatePath)
|
||||
const remainingPage = context.apiSuccess(MODULE, '分配首托后刷新同票剩余整托候选',
|
||||
remainingResponse, '', OPTIONS)
|
||||
const remainingIds = new Set((remainingPage?.records || []).map((item) => id(item?.palletId)))
|
||||
const expectedRemaining = dropshipCandidates.slice(1).map((item) => id(item.palletId))
|
||||
context.assert(MODULE, '一件代发分配首托后其余托盘仍可独立分配', remainingResponse,
|
||||
expectedRemaining.every((palletId) => remainingIds.has(palletId)),
|
||||
`remaining=${[...remainingIds].join(',') || 'missing'}, expected=${expectedRemaining.join(',')}`, OPTIONS)
|
||||
}
|
||||
}
|
||||
assignedLoadingPlan = workingPlan
|
||||
} else {
|
||||
const assignmentPath = `${smartLoadingBase}/plans/${loadingPlanId}/assignments`
|
||||
const assignmentBody = { inboundId, inboundDetailId: id(candidate.inboundDetailId),
|
||||
packageCount: initialAssignmentCount, expectedVersion: Number(loadingPlan.version),
|
||||
operationId: `${context.marker}-${loadingPlanId}-bridge-assign`.slice(0, 128) }
|
||||
assignmentResponse = await request(context, 'POST', assignmentPath, assignmentBody)
|
||||
assignedLoadingPlan = context.apiSuccess(MODULE, '将本轮入库货物分配到柜次计划', assignmentResponse, '', OPTIONS)
|
||||
}
|
||||
context.assert(MODULE, '柜次计划明细和版本真实持久化', assignmentResponse,
|
||||
assignedLoadingPlan?.items?.filter?.((item) => id(item.inboundId) === inboundId)
|
||||
.reduce((total, item) => total + Number(item.packageCount || 0), 0) === initialAssignmentCount
|
||||
&& Number(assignedLoadingPlan?.version) >= 1,
|
||||
`loadingPlanId=${loadingPlanId}, assignedPackages=${initialAssignmentCount}, version=${assignedLoadingPlan?.version ?? 'missing'}`, OPTIONS)
|
||||
|
||||
if (dropshipAssignment && dropshipCandidates.length > 1) {
|
||||
const firstPalletItem = assignedLoadingPlan?.items?.find?.((item) =>
|
||||
id(item.inboundId) === inboundId && id(item.palletId) === id(dropshipCandidates[0].palletId))
|
||||
const singleDelete = await request(context, 'DELETE',
|
||||
`${smartLoadingBase}/plans/${loadingPlanId}/items/${id(firstPalletItem?.id)}`, {
|
||||
expectedPlanVersion: Number(assignedLoadingPlan?.version),
|
||||
expectedItemVersion: Number(firstPalletItem?.version),
|
||||
operationId: `${context.marker}-${loadingPlanId}-reject-single-pallet-line-delete`.slice(0, 128),
|
||||
})
|
||||
context.assert(MODULE, '已封托托盘拒绝按单条装柜明细删除', singleDelete,
|
||||
singleDelete.http === 200 && codeOf(singleDelete) === 'A0409',
|
||||
`HTTP=${singleDelete.http}, code=${codeOf(singleDelete)}`, OPTIONS)
|
||||
|
||||
let emptiedPlan = assignedLoadingPlan
|
||||
for (const [index, pallet] of dropshipCandidates.entries()) {
|
||||
const removedResponse = await request(context, 'DELETE',
|
||||
`${smartLoadingBase}/plans/${loadingPlanId}/pallet-assignments/${id(pallet.palletId)}`, {
|
||||
expectedPlanVersion: Number(emptiedPlan.version),
|
||||
operationId: `${context.marker}-${loadingPlanId}-remove-whole-pallet-${id(pallet.palletId)}`.slice(0, 128),
|
||||
})
|
||||
emptiedPlan = context.apiSuccess(MODULE, `整托移除一件代发托盘${index + 1}/${dropshipCandidates.length}`,
|
||||
removedResponse, '', OPTIONS)
|
||||
if (!emptiedPlan) return
|
||||
}
|
||||
context.assert(MODULE, '逐托移除后本票装柜明细归零', assignmentResponse,
|
||||
!emptiedPlan.items?.some?.((item) => id(item.inboundId) === inboundId),
|
||||
`remaining=${emptiedPlan.items?.filter?.((item) => id(item.inboundId) === inboundId).length ?? 'missing'}`, OPTIONS)
|
||||
|
||||
const recommendResponse = await request(context, 'POST',
|
||||
`${smartLoadingBase}/plans/${loadingPlanId}/recommend`, {
|
||||
expectedVersion: Number(emptiedPlan.version),
|
||||
operationId: `${context.marker}-${loadingPlanId}-recommend-multi-pallet`.slice(0, 128),
|
||||
customerId: tenantId,
|
||||
inboundCode: initial?.summary?.inboundCode || source?.inboundCode,
|
||||
})
|
||||
const recommendedPlan = context.apiSuccess(MODULE, '智能推荐按整托重新加入一件代发多托',
|
||||
recommendResponse, '', OPTIONS)
|
||||
const expectedPalletIds = new Set(dropshipCandidates.map((item) => id(item.palletId)))
|
||||
const recommendedPalletIds = new Set((recommendedPlan?.items || [])
|
||||
.filter((item) => id(item.inboundId) === inboundId).map((item) => id(item.palletId)))
|
||||
context.assert(MODULE, '智能推荐保留同票全部封托托盘且不按箱拆分', recommendResponse,
|
||||
expectedPalletIds.size === dropshipCandidates.length
|
||||
&& [...expectedPalletIds].every((palletId) => recommendedPalletIds.has(palletId)),
|
||||
`expected=${[...expectedPalletIds].join(',')}, actual=${[...recommendedPalletIds].join(',') || 'missing'}`, OPTIONS)
|
||||
if (!recommendedPlan || ![...expectedPalletIds].every((palletId) => recommendedPalletIds.has(palletId))) return
|
||||
|
||||
const clearedResponse = await request(context, 'DELETE',
|
||||
`${smartLoadingBase}/plans/${loadingPlanId}/unpicked-items`, {
|
||||
expectedPlanVersion: Number(recommendedPlan.version),
|
||||
operationId: `${context.marker}-${loadingPlanId}-clear-recommendation`.slice(0, 128),
|
||||
})
|
||||
let exactPlan = context.apiSuccess(MODULE, '移除未拣并释放智能推荐临时分配',
|
||||
clearedResponse, '', OPTIONS)
|
||||
if (!exactPlan) return
|
||||
for (const [index, pallet] of dropshipCandidates.entries()) {
|
||||
assignmentResponse = await request(context, 'POST',
|
||||
`${smartLoadingBase}/plans/${loadingPlanId}/pallet-assignments`, {
|
||||
palletId: id(pallet.palletId), expectedVersion: Number(exactPlan.version),
|
||||
operationId: `${context.marker}-${loadingPlanId}-final-pallet-${id(pallet.palletId)}`.slice(0, 128),
|
||||
})
|
||||
exactPlan = context.apiSuccess(MODULE, `智能推荐回归后恢复本票整托${index + 1}/${dropshipCandidates.length}`,
|
||||
assignmentResponse, '', OPTIONS)
|
||||
if (!exactPlan) return
|
||||
}
|
||||
assignedLoadingPlan = exactPlan
|
||||
}
|
||||
|
||||
const assignedItem = assignedLoadingPlan?.items?.find?.((item) => id(item.inboundId) === inboundId)
|
||||
const orderRemarks = source || {}
|
||||
context.assert(MODULE, '装柜明细客户备注与最新内部备注来源精确且不冒用货物备注', assignmentResponse,
|
||||
@@ -690,16 +780,18 @@ export async function run(context) {
|
||||
|
||||
if (dropshipAssignment) {
|
||||
const palletUnits = Array.isArray(inventory?.units) ? inventory.units : []
|
||||
const expectedPallets = new Map(dropshipCandidates.map((item) =>
|
||||
[id(item.palletId), item.palletNo]))
|
||||
const taskUnitsValid = canonicalPickItems.every((item) => item.unitType === 'SEALED_PALLET'
|
||||
&& id(item.palletId) === id(candidate.palletId) && item.palletNo === candidate.palletNo
|
||||
&& expectedPallets.get(id(item.palletId)) === item.palletNo
|
||||
&& /^DP-[0-9]{6}-[0-9]{4}$/.test(item.palletNo) && item.indivisible === true)
|
||||
const inventoryUnitsValid = canonicalPickItems.every((item) => palletUnits.some((unit) =>
|
||||
id(unit.pickItemId) === id(item.id) && id(unit.loadingPlanItemId) === id(item.loadingPlanItemId)
|
||||
&& id(unit.inboundId) === id(item.inboundId) && unit.unitType === 'SEALED_PALLET'
|
||||
&& id(unit.palletId) === id(item.palletId) && unit.palletNo === item.palletNo && unit.indivisible === true))
|
||||
context.assert(MODULE, 'PDA task与inventory明确返回SEALED_PALLET及DP整托四字段', inventoryResponse,
|
||||
taskUnitsValid && inventoryUnitsValid,
|
||||
`taskUnits=${canonicalPickItems.length}, inventoryUnits=${palletUnits.length}`, OPTIONS)
|
||||
taskUnitsValid && inventoryUnitsValid && canonicalPickItems.length === expectedPallets.size,
|
||||
`taskUnits=${canonicalPickItems.length}, inventoryUnits=${palletUnits.length}, expectedPallets=${expectedPallets.size}`, OPTIONS)
|
||||
if (!taskUnitsValid || !inventoryUnitsValid) return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user