Merge remote-tracking branch 'origin/test' into dev
# Conflicts: # lastleg-service/src/main/java/com/baiyue/lastleg/inboundplan/pda/gateway/WarehouseResourceGateway.java # scripts/admin-test-env-modules/phase3-container-documents-contract.test.mjs # scripts/admin-test-env-modules/phase4-overseas-pda.mjs
This commit is contained in:
@@ -163,29 +163,42 @@ export async function disablePicker(context, picker, index) {
|
||||
context.addStep(MODULE, `finally停用海外PDA仓库操作员${index}`, response, disabled, trace(response), OPTIONS)
|
||||
}
|
||||
|
||||
async function createPallet(context, inbound, index) {
|
||||
const warehouseId = id(inbound?.overseasWarehouseId)
|
||||
if (!longId(warehouseId)) return null
|
||||
const suffix = markerSuffix(context)
|
||||
const locationCode = `PDA-${suffix}-${index + 1}`.slice(0, 64)
|
||||
const location = await context.requestOverseas('POST', `/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/locations`, {
|
||||
zoneCode: `PDA-${index + 1}`, locationCode,
|
||||
locationType: 'STORAGE', maxLoadKg: 5000, status: 'IDLE', remark: `${context.marker}-receiving`,
|
||||
})
|
||||
context.addStep(MODULE, `创建当前柜实收库位${index + 1}`, location, success(location), trace(location), OPTIONS)
|
||||
const locationId = id(location?.body?.data)
|
||||
if (!longId(locationId)) return null
|
||||
context.createdResources.phase4OverseasPda.locationIds.push(locationId)
|
||||
const palletCode = `PDA-${suffix}-${index + 1}`.slice(0, 128)
|
||||
const unitPrice = Number((1.01 + index).toFixed(2))
|
||||
const pallet = await context.requestOverseas('POST', `/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/pallets`, {
|
||||
palletCode, palletType: '木托盘', capacityCbm: 10, unitPrice, status: 'IDLE', locationId,
|
||||
remark: `${context.marker}-receiving-retained`,
|
||||
fbaWarehouseCode: inbound.destinationType === 'FBA' ? inbound.fbaWarehouseCode : null,
|
||||
})
|
||||
context.addStep(MODULE, `创建当前柜实收托盘${index + 1}`, pallet, success(pallet), trace(pallet), OPTIONS)
|
||||
const palletId = id(pallet?.body?.data)
|
||||
return longId(palletId) ? { warehouseId, locationId, locationCode, palletId, palletCode, unitPrice, retained: true } : null
|
||||
function rememberGeneratedPlans(context, plans) {
|
||||
if (!Array.isArray(plans)) return
|
||||
for (const plan of plans) {
|
||||
const inboundCode = id(plan?.lines?.[0]?.inboundCode)
|
||||
if (!nonBlank(inboundCode)) continue
|
||||
const generated = Array.isArray(plan?.pallets) ? plan.pallets : []
|
||||
context.createdResources.phase4OverseasPda.generatedPalletsByInbound[inboundCode] = generated.map((pallet) => ({
|
||||
warehouseId: id(plan?.overseasWarehouseId),
|
||||
locationId: id(pallet?.warehouseLocationId),
|
||||
palletId: id(pallet?.warehousePalletId),
|
||||
palletCode: id(pallet?.palletNo),
|
||||
unitPrice: Number(pallet?.unitPrice || 0),
|
||||
retained: true,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveGeneratedPallet(context, inbound) {
|
||||
const candidates = context.createdResources.phase4OverseasPda.generatedPalletsByInbound[inbound.inboundCode] || []
|
||||
const pallet = candidates[0]
|
||||
if (!pallet || !longId(pallet.palletId) || !nonBlank(pallet.palletCode)) return null
|
||||
const warehouseId = id(inbound?.overseasWarehouseId || pallet.warehouseId)
|
||||
const listed = await context.requestOverseas('GET',
|
||||
`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/pallets?page=1&size=10&keyword=${encodeURIComponent(pallet.palletCode)}`)
|
||||
const stored = records(listed?.body?.data).find((row) => id(row?.id) === pallet.palletId && row?.palletCode === pallet.palletCode)
|
||||
const locations = stored && longId(stored?.locationId)
|
||||
? await context.requestOverseas('GET',
|
||||
`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/locations?page=1&size=200`)
|
||||
: null
|
||||
const location = records(locations?.body?.data).find((row) => id(row?.id) === id(stored?.locationId))
|
||||
const resolved = success(listed) && success(locations) && stored && longId(stored?.locationId) && nonBlank(location?.locationCode)
|
||||
context.addStep(MODULE, `复用入仓码${inbound.inboundCode}自动计划托盘`, listed, resolved,
|
||||
`palletCode=${pallet.palletCode}, palletId=${pallet.palletId}, locationId=${id(stored?.locationId) || 'missing'}, locationCode=${location?.locationCode || 'missing'}; ${trace(listed)}`, OPTIONS)
|
||||
if (!resolved) return null
|
||||
return { ...pallet, warehouseId, locationId: id(stored.locationId), locationCode: location.locationCode,
|
||||
unitPrice: Number(stored.unitPrice || pallet.unitPrice || 0) }
|
||||
}
|
||||
|
||||
async function verifyWarehouseQueries(context, token, inboundCode, pallet, destinationType) {
|
||||
@@ -203,6 +216,14 @@ async function verifyWarehouseQueries(context, token, inboundCode, pallet, desti
|
||||
&& inventoryItems.every((item) => nonBlank(item?.skuCode) && Number(item?.availablePackages) > 0),
|
||||
`skuCodes=${[...new Set(inventoryItems.map((item) => item?.skuCode).filter(nonBlank))].join('|') || 'missing'}, availablePackages=${inventoryItems.reduce((total, item) => total + Number(item?.availablePackages || 0), 0)}; ${trace(inventory.response)}`, OPTIONS)
|
||||
|
||||
const location = await pda(context, token, 'POST', '完成入库后扫码查询库位',
|
||||
'/api/pda/v1/last-leg/locations/resolve', { code: pallet.locationCode })
|
||||
context.assert(MODULE, '库位查询返回当前仓真实占用汇总', location.response,
|
||||
success(location.response) && id(location.data?.locationId) === pallet.locationId
|
||||
&& location.data?.locationCode === pallet.locationCode
|
||||
&& Number(location.data?.occupiedPackages) > 0 && Number(location.data?.inventoryPositionCount) > 0,
|
||||
`locationId=${id(location.data?.locationId) || 'missing'}; ${trace(location.response)}`, OPTIONS)
|
||||
|
||||
const resolvedPallet = await pda(context, token, 'POST', '完成入库后扫码查询托盘内容',
|
||||
'/api/pda/v1/last-leg/pallets/resolve', { code: pallet.palletCode })
|
||||
context.assert(MODULE, '托盘查询返回当前位置与库存明细', resolvedPallet.response,
|
||||
@@ -212,22 +233,6 @@ async function verifyWarehouseQueries(context, token, inboundCode, pallet, desti
|
||||
&& Number(resolvedPallet.data?.occupiedPackages) > 0,
|
||||
`palletId=${id(resolvedPallet.data?.palletId) || 'missing'}; ${trace(resolvedPallet.response)}`, OPTIONS)
|
||||
|
||||
const palletDetail = await context.requestOverseas('GET',
|
||||
`/api/platform/v1/warehouse-admin/${encodeURIComponent(pallet.warehouseId)}/pallets/${encodeURIComponent(pallet.palletId)}`)
|
||||
context.addStep(MODULE, '完成入库后读取托盘计费单价', palletDetail,
|
||||
success(palletDetail) && Number(palletDetail.body?.data?.unitPrice) > 0,
|
||||
`palletId=${pallet.palletId}, unitPrice=${palletDetail.body?.data?.unitPrice ?? 'missing'}; ${trace(palletDetail)}`, OPTIONS)
|
||||
if (Number(palletDetail.body?.data?.unitPrice) > 0) pallet.unitPrice = Number(palletDetail.body.data.unitPrice)
|
||||
|
||||
const locationCode = resolvedPallet.data?.locationCode || pallet.locationCode
|
||||
const location = await pda(context, token, 'POST', '完成入库后扫码查询库位',
|
||||
'/api/pda/v1/last-leg/locations/resolve', { code: locationCode })
|
||||
context.assert(MODULE, '库位查询返回当前仓真实占用汇总', location.response,
|
||||
success(location.response) && id(location.data?.locationId) === pallet.locationId
|
||||
&& location.data?.locationCode === locationCode
|
||||
&& Number(location.data?.occupiedPackages) > 0 && Number(location.data?.inventoryPositionCount) > 0,
|
||||
`locationId=${id(location.data?.locationId) || 'missing'}; ${trace(location.response)}`, OPTIONS)
|
||||
|
||||
const history = await pda(context, token, 'GET', '查询当前仓管PDA作业历史',
|
||||
'/api/pda/v1/last-leg/operations?page=1&size=50')
|
||||
const historyRows = records(history.data)
|
||||
@@ -314,64 +319,59 @@ async function convertReceivingContainers(context, producers) {
|
||||
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 previewResponse = await context.requestOverseas('GET',
|
||||
`/api/platform/v1/last-leg/inbound-plans/container-preview?sourceContainerBookingId=${encodeURIComponent(summary.sourceContainerBookingId)}`,
|
||||
const bookingId = id(summary.sourceContainerBookingId)
|
||||
const previewPath = `/api/platform/v1/last-leg/inbound-plans/container-preview?sourceContainerBookingId=${encodeURIComponent(bookingId)}`
|
||||
const previewResponse = await context.requestOverseas('GET', previewPath,
|
||||
undefined, {}, context.overseasToken)
|
||||
const preview = success(previewResponse) ? previewResponse.body?.data : null
|
||||
const previewReady = preview?.ready === true
|
||||
&& Number.isInteger(Number(preview?.snapshotVersion)) && Number(preview.snapshotVersion) >= 0
|
||||
&& /^[0-9a-f]{64}$/.test(String(preview?.snapshotHash || ''))
|
||||
&& Number(preview?.pendingOrderCount) === pendingPlans
|
||||
context.addStep(MODULE, `预览整柜原子转换快照 ${containerNo}`, previewResponse,
|
||||
previewReady,
|
||||
`ready=${preview?.ready === true}, version=${preview?.snapshotVersion ?? 'missing'}, hash=${nonBlank(preview?.snapshotHash) ? 'present' : 'missing'}, pending=${preview?.pendingOrderCount ?? 'missing'}; ${trace(previewResponse)}`, OPTIONS)
|
||||
if (!previewReady) return false
|
||||
const body = {
|
||||
sourceContainerBookingId: id(summary.sourceContainerBookingId),
|
||||
snapshotVersion: Number(preview.snapshotVersion),
|
||||
snapshotHash: String(preview.snapshotHash),
|
||||
context.addStep(MODULE, `读取PDA前柜级计划与自动托盘预览 ${containerNo}`, previewResponse,
|
||||
preview?.ready === true && Number(preview?.totalOrderCount) === totalOrders
|
||||
&& Number(preview?.pendingOrderCount) === pendingPlans,
|
||||
`orders=${preview?.totalOrderCount ?? 'missing'}, pendingOrders=${preview?.pendingOrderCount ?? 'missing'}, pendingPallets=${preview?.pendingPalletCount ?? 'missing'}; ${trace(previewResponse)}`,
|
||||
OPTIONS)
|
||||
if (preview?.ready !== true) return false
|
||||
if (pendingPlans > 0) {
|
||||
const body = { sourceContainerBookingId: bookingId,
|
||||
snapshotVersion: Number(preview.snapshotVersion), snapshotHash: String(preview.snapshotHash) }
|
||||
const key = `${context.marker}-pda-convert-${containerNo}`.slice(0, 128)
|
||||
const convertedResponse = await context.requestOverseas('POST',
|
||||
'/api/platform/v1/last-leg/inbound-plans/convert-container', body,
|
||||
{ 'Idempotency-Key': key }, context.overseasToken)
|
||||
const plans = success(convertedResponse) && Array.isArray(convertedResponse.body?.data)
|
||||
? convertedResponse.body.data : []
|
||||
const convertedInboundCodes = new Set(plans
|
||||
.flatMap((item) => Array.isArray(item?.lines) ? item.lines : [])
|
||||
.map((line) => id(line?.inboundCode)).filter(nonBlank))
|
||||
context.addStep(MODULE, `整柜转换为逐入仓码独立计划及实体托盘 ${containerNo}`, convertedResponse,
|
||||
plans.length === inboundCodes
|
||||
&& plans.every((item) => Array.isArray(item?.lines) && item.lines.length > 0
|
||||
&& Array.isArray(item?.pallets) && item.pallets.length > 0
|
||||
&& item.pallets.every((pallet) => nonBlank(pallet?.palletNo) && longId(id(pallet?.warehousePalletId))))
|
||||
&& convertedInboundCodes.size === inboundCodes,
|
||||
`plans=${plans.length}, inboundCodes=${convertedInboundCodes.size}, expected=${inboundCodes}; ${trace(convertedResponse)}`, OPTIONS)
|
||||
if (plans.length !== inboundCodes) return false
|
||||
rememberGeneratedPlans(context, plans)
|
||||
const replayResponse = await context.requestOverseas('POST',
|
||||
'/api/platform/v1/last-leg/inbound-plans/convert-container', body,
|
||||
{ 'Idempotency-Key': key }, context.overseasToken)
|
||||
context.addStep(MODULE, `整柜转换幂等重放零新增 ${containerNo}`, replayResponse,
|
||||
success(replayResponse) && JSON.stringify(replayResponse.body?.data) === JSON.stringify(plans),
|
||||
trace(replayResponse), OPTIONS)
|
||||
if (!success(replayResponse)) return false
|
||||
} else {
|
||||
const retainedPlans = context.createdResources?.phase4TailOrderControls?.generatedPlans
|
||||
rememberGeneratedPlans(context, retainedPlans)
|
||||
context.addStep(MODULE, `复用尾程控制已生成的整柜计划与实体托盘 ${containerNo}`, previewResponse,
|
||||
summary?.allPlansReady === true && existingPlans === totalOrders
|
||||
&& Number(preview?.existingPlannedPalletCount) > 0,
|
||||
`plans=${existingPlans}, plannedPallets=${preview?.existingPlannedPalletCount ?? 'missing'}; ${trace(previewResponse)}`,
|
||||
OPTIONS)
|
||||
}
|
||||
const key = `${context.marker}-pda-convert-${containerNo}`.slice(0, 128)
|
||||
const convertedResponse = await context.requestOverseas('POST',
|
||||
'/api/platform/v1/last-leg/inbound-plans/convert-container', body,
|
||||
{ 'Idempotency-Key': key }, context.overseasToken)
|
||||
const plans = success(convertedResponse) && Array.isArray(convertedResponse.body?.data)
|
||||
? convertedResponse.body.data : []
|
||||
const convertedInboundCodes = new Set(plans
|
||||
.flatMap((item) => Array.isArray(item?.lines) ? item.lines : [])
|
||||
.map((line) => id(line?.inboundCode)).filter(nonBlank))
|
||||
const reservedPalletsByInbound = {}
|
||||
for (const plan of plans) {
|
||||
const reserved = Array.isArray(plan?.pallets) ? plan.pallets.find((item) =>
|
||||
longId(item?.warehousePalletId) && longId(item?.warehouseLocationId)
|
||||
&& longId(item?.warehouseResourceLockId)
|
||||
&& ['RESERVED', 'ASSIGNED', 'LOCKED'].includes(item?.assignmentStatus)) : null
|
||||
for (const line of Array.isArray(plan?.lines) ? plan.lines : []) {
|
||||
if (reserved && nonBlank(line?.inboundCode)) reservedPalletsByInbound[id(line.inboundCode)] = {
|
||||
palletId: id(reserved.warehousePalletId), palletCode: reserved.palletNo,
|
||||
locationId: id(reserved.warehouseLocationId), retained: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
context.addStep(MODULE, `整柜转换为逐入仓码独立计划 ${containerNo}`, convertedResponse,
|
||||
plans.length === inboundCodes
|
||||
&& plans.every((item) => Array.isArray(item?.lines) && item.lines.length > 0)
|
||||
&& convertedInboundCodes.size === inboundCodes,
|
||||
`plans=${plans.length}, inboundCodes=${convertedInboundCodes.size}, reserved=${Object.keys(reservedPalletsByInbound).length}, expected=${inboundCodes}; ${trace(convertedResponse)}`, OPTIONS)
|
||||
if (plans.length !== inboundCodes || convertedInboundCodes.size !== inboundCodes) return false
|
||||
producer.receivingPalletsByInbound = reservedPalletsByInbound
|
||||
const replayResponse = await context.requestOverseas('POST',
|
||||
'/api/platform/v1/last-leg/inbound-plans/convert-container', body,
|
||||
{ 'Idempotency-Key': key }, context.overseasToken)
|
||||
context.addStep(MODULE, `整柜转换幂等重放零新增 ${containerNo}`, replayResponse,
|
||||
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,
|
||||
context.addStep(MODULE, `PDA前整柜计划完整度闭环 ${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)
|
||||
@@ -636,19 +636,14 @@ async function runReceiving(context, token, secondaryToken, merchantToken, prefe
|
||||
if (!success(afterResolve.response) || receivingSnapshot(afterResolve.data) !== beforeResolve) return
|
||||
const pallets = new Map()
|
||||
for (const [index, inbound] of current.data.inbounds.entries()) {
|
||||
const reservedPallet = preferredProducer?.receivingPalletsByInbound?.[inbound.inboundCode]
|
||||
const pallet = reservedPallet || await createPallet(context, inbound, index)
|
||||
if (reservedPallet) context.addStep(MODULE, `${inbound.destinationType}复用整柜转换预留托盘`, null,
|
||||
longId(reservedPallet.palletId) && nonBlank(reservedPallet.palletCode)
|
||||
&& longId(reservedPallet.locationId),
|
||||
`inboundCode=${inbound.inboundCode}, palletCode=${reservedPallet.palletCode}`, OPTIONS)
|
||||
const pallet = await resolveGeneratedPallet(context, inbound)
|
||||
if (!pallet) {
|
||||
blockerGap(context, `${inbound.destinationType}入仓码${inbound.inboundCode}实物托盘`,
|
||||
`无法在实际海外收货仓 ${inbound.overseasWarehouseId || 'missing'} 创建可解析真实托盘;目的仓 ${inbound.destinationWarehouseId || 'missing'} 不得代替物理仓`, 'warehouse-resource')
|
||||
blockerGap(context, `${inbound.destinationType}入仓码${inbound.inboundCode}自动计划托盘`,
|
||||
`按柜确认没有为该入仓码留下可解析的实体托盘;禁止在PDA收货时临时新建脱离计划的托盘`, 'warehouse-resource')
|
||||
continue
|
||||
}
|
||||
pallets.set(inbound.inboundCode, pallet)
|
||||
if (!reservedPallet) context.createdResources.phase4OverseasPda.palletIds.push(pallet.palletId)
|
||||
context.createdResources.phase4OverseasPda.palletIds.push(pallet.palletId)
|
||||
const resolved = await pda(context, token, 'POST', `解析${inbound.destinationType}实物托盘`,
|
||||
'/api/pda/v1/last-leg/receiving-containers/current/pallets/resolve', { palletCode: pallet.palletCode, inboundCode: inbound.inboundCode })
|
||||
context.assert(MODULE, `${inbound.destinationType}托盘目的模式匹配`, resolved.response,
|
||||
@@ -700,6 +695,14 @@ async function runReceiving(context, token, secondaryToken, merchantToken, prefe
|
||||
context.addStep(MODULE, '完成后current返回404正常空态', after, notFound(after), trace(after), OPTIONS)
|
||||
context.createdResources.phase4OverseasPda.finalStatus = completed.data?.status || null
|
||||
if (context.createdResources.phase4OverseasPda.finalStatus === 'COMPLETED') {
|
||||
const physicalPallets = [...new Map([...pallets.values()]
|
||||
.map((item) => [id(item.palletId), item])).values()]
|
||||
context.createdResources.phase4OverseasPda.completedContainerFacts.push({
|
||||
containerNo,
|
||||
containerBookingId: id(preferredProducer?.containerBookingId),
|
||||
expectedPalletCost: physicalPallets.reduce((sum, item) => sum + Number(item.unitPrice || 0), 0),
|
||||
palletIds: physicalPallets.map((item) => item.palletId),
|
||||
})
|
||||
const order = await captureCompletedOrder(context, containerNo, preferredProducer?.tenantId)
|
||||
for (const inbound of current.data.inbounds.filter((item) => pallets.has(item.inboundCode))) {
|
||||
const warehouseFacts = await verifyWarehouseQueries(context, token, inbound.inboundCode,
|
||||
@@ -712,14 +715,6 @@ async function runReceiving(context, token, secondaryToken, merchantToken, prefe
|
||||
})
|
||||
}
|
||||
}
|
||||
const physicalPallets = [...new Map([...pallets.values()]
|
||||
.map((item) => [id(item.palletId), item])).values()]
|
||||
context.createdResources.phase4OverseasPda.completedContainerFacts.push({
|
||||
containerNo,
|
||||
containerBookingId: id(preferredProducer?.containerBookingId),
|
||||
expectedPalletCost: physicalPallets.reduce((sum, item) => sum + Number(item.unitPrice || 0), 0),
|
||||
palletIds: physicalPallets.map((item) => item.palletId),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -729,6 +724,7 @@ export async function run(context) {
|
||||
palletIds: [], locationIds: [], finalStatus: null, pickerMembershipIds: [], completedContainers: [],
|
||||
completedContainerFacts: [],
|
||||
overseasWarehouseId: null, overseasWarehouseName: null,
|
||||
generatedPalletsByInbound: {},
|
||||
cleanup: 'Shared warehouse, pallets and locations used by completed inventory are retained as acceptance evidence',
|
||||
}
|
||||
const merchantToken = await loginMerchantForNegativeProbe(context)
|
||||
@@ -756,7 +752,6 @@ export async function run(context) {
|
||||
primary: primary ? { membershipId: primary.membershipId, username: primary.username, token: primary.token } : null,
|
||||
secondary: secondary ? { membershipId: secondary.membershipId, username: secondary.username, token: secondary.token } : null,
|
||||
overseasWarehouseId: sharedWarehouse.id,
|
||||
merchantToken,
|
||||
completedFixtures: [],
|
||||
cleanup,
|
||||
}
|
||||
@@ -773,7 +768,7 @@ export async function run(context) {
|
||||
if (allProducers.length) await awaitProducerConsumption(context, allProducers)
|
||||
if (producers.length && !(await convertReceivingContainers(context, producers))) {
|
||||
blockerGap(context, '实际处理柜整柜转换门禁',
|
||||
'目标柜未能通过正式平台convert-container逐入仓码生成独立计划')
|
||||
'目标柜未能通过正式柜级预览与确认形成逐入仓码计划及实体托盘')
|
||||
return
|
||||
}
|
||||
if (producers.length && !(await awaitPickupReadyCandidates(context, primary.token, producers, allProducers))) {
|
||||
|
||||
Reference in New Issue
Block a user