优化
This commit is contained in:
@@ -295,6 +295,7 @@ function usage() {
|
||||
--wait-split-package-count <n> 单票指定总箱数,1-1000;省略时使用既有轮换
|
||||
--wait-split-sequence <n> 单票全局序号,正整数,默认1
|
||||
--wait-split-random-value <n> 单票随机选择值,正整数,默认使用全局序号
|
||||
--prepare-dropship-manual-count <true> 一件代发停在PDA清点前,不领取、不清点、不归托
|
||||
--verify-pallet-location-guide <true> 验证整票库位块、图片槽绑定与删除后 RESERVED_EMPTY
|
||||
--route-mode <mode> 线路选择:fixed 或 random,默认fixed
|
||||
--manual-split-fixture-report <path> 人工分柜准备报告路径,仅只读核验模块使用
|
||||
@@ -364,6 +365,7 @@ export function parseArguments(argv) {
|
||||
waitSplitPackageCount: Number(values.get('wait-split-package-count') || 0),
|
||||
waitSplitSequence: Number(values.get('wait-split-sequence') || 1),
|
||||
waitSplitRandomValue: Number(values.get('wait-split-random-value') || values.get('wait-split-sequence') || 1),
|
||||
prepareDropshipManualCount: values.get('prepare-dropship-manual-count') === 'true',
|
||||
verifyPalletLocationGuide: values.has('verify-pallet-location-guide'),
|
||||
routeMode: values.get('route-mode') || 'fixed',
|
||||
quiet: values.get('quiet') === 'true',
|
||||
@@ -423,6 +425,10 @@ export function validateExecutionOptions(options) {
|
||||
&& (!options.originWarehouseName || !options.channelName || !options.channelCode)) {
|
||||
throw new Error('randomized订单档案必须同时固定起运仓、渠道名称和渠道编码')
|
||||
}
|
||||
if (options.prepareDropshipManualCount
|
||||
&& (!options.modules.includes('orders') || !options.modules.includes('inbound-measurement'))) {
|
||||
throw new Error('prepare-dropship-manual-count要求同时执行orders和inbound-measurement模块')
|
||||
}
|
||||
if (options.waitSplitCount > 1) {
|
||||
const fixtureModules = new Set(['merchant-qualification-fixture', 'orders', 'inbound-measurement',
|
||||
'manual-order-splitting-fixture', 'coload-groups', 'firstleg-container-fee-allocation'])
|
||||
|
||||
@@ -128,17 +128,24 @@ export async function completeDropshipPalletization(context, { inboundId, inboun
|
||||
`/api/platform/v1/first-leg/pda-dropship/tasks/${taskId}/cartons/resolve?warehouseId=${warehouseId}&boxCode=${encodeURIComponent(boxCode)}`)
|
||||
const resolved = context.apiSuccess(MODULE, `解析第${index + 1}箱的冻结箱唛`, resolveResponse,
|
||||
`boxCode=${boxCode}`, OPTIONS)
|
||||
context.assert(MODULE, `第${index + 1}箱允许清点且每箱SKU数完整`, resolveResponse,
|
||||
resolved?.canCount === true && Number(resolved?.expectedSkuQuantity) > 0,
|
||||
`canCount=${resolved?.canCount ?? 'missing'}, expectedSkuQuantity=${resolved?.expectedSkuQuantity ?? 'missing'}`, OPTIONS)
|
||||
if (resolved?.canCount !== true || Number(resolved?.expectedSkuQuantity) < 1) continue
|
||||
const resolvedSkuLines = Array.isArray(resolved?.skuLines) ? resolved.skuLines : []
|
||||
context.assert(MODULE, `第${index + 1}箱允许清点且每箱SKU明细完整`, resolveResponse,
|
||||
resolved?.canCount === true && resolvedSkuLines.length > 0
|
||||
&& resolvedSkuLines.every((line) => asId(line?.inboundDetailId) && line?.skuCode
|
||||
&& Number(line?.expectedQuantity) > 0),
|
||||
`canCount=${resolved?.canCount ?? 'missing'}, skuLines=${resolvedSkuLines.length}`, OPTIONS)
|
||||
if (resolved?.canCount !== true || resolvedSkuLines.length < 1) continue
|
||||
|
||||
const countPayload = {
|
||||
warehouseId,
|
||||
boxCode,
|
||||
actualSkuQuantity: Number(resolved.expectedSkuQuantity),
|
||||
discrepancyAction: 'MATCH',
|
||||
discrepancyRemark: null,
|
||||
skuLines: resolvedSkuLines.map((line) => ({
|
||||
inboundDetailId: asId(line.inboundDetailId),
|
||||
skuCode: line.skuCode,
|
||||
actualQuantity: Number(line.expectedQuantity),
|
||||
discrepancyAction: 'MATCH',
|
||||
discrepancyRemark: null,
|
||||
})),
|
||||
palletNo: index === 0 ? null : generatedPallets[Math.min(index, generatedPallets.length - 1)].palletNo,
|
||||
operationId: `${context.marker}-dropship-count-${index + 1}`.slice(0, 128),
|
||||
}
|
||||
@@ -148,10 +155,11 @@ export async function completeDropshipPalletization(context, { inboundId, inboun
|
||||
`boxCode=${boxCode}`, OPTIONS)
|
||||
context.assert(MODULE, `第${index + 1}箱清点结果与冻结箱唛一致`, countResponse,
|
||||
counted?.carton?.boxCode === resolved?.boxCode
|
||||
&& Number(counted?.carton?.expectedSkuQuantity) === Number(resolved?.expectedSkuQuantity)
|
||||
&& Number(counted?.carton?.actualSkuQuantity) === Number(resolved?.expectedSkuQuantity)
|
||||
&& counted?.carton?.discrepancyStatus === 'MATCH',
|
||||
`cartonId=${asId(counted?.carton?.cartonId) || 'missing'}, discrepancy=${counted?.carton?.discrepancyStatus ?? 'missing'}`, OPTIONS)
|
||||
&& Array.isArray(counted?.carton?.skuLines)
|
||||
&& counted.carton.skuLines.length === resolvedSkuLines.length
|
||||
&& counted.carton.skuLines.every((line) => Number(line?.actualQuantity) === Number(line?.expectedQuantity)
|
||||
&& line?.discrepancyStatus === 'MATCH'),
|
||||
`cartonId=${asId(counted?.carton?.cartonId) || 'missing'}, skuLines=${counted?.carton?.skuLines?.length ?? 'missing'}`, OPTIONS)
|
||||
if (counted?.carton?.boxCode === resolved?.boxCode) {
|
||||
countedCartons += 1
|
||||
sealedCartonMarks.push(resolved.boxCode)
|
||||
@@ -1035,21 +1043,40 @@ export async function run(context) {
|
||||
let sealedCartonMarks = []
|
||||
let sealedSourcePalletNos = []
|
||||
if (dropship && finalMeasurement?.processStatus === 'WAIT_PALLETIZE') {
|
||||
const sealed = await completeDropshipPalletization(context, {
|
||||
inboundId, inboundCode, warehouseId: asId(summary?.warehouseId), measurement: finalMeasurement,
|
||||
})
|
||||
sealedCartonMarks = sealed?.taskStatus === 'COMPLETED' ? sealed.sealedCartonMarks : []
|
||||
sealedSourcePalletNos = sealed?.taskStatus === 'COMPLETED'
|
||||
? (sealed.sealedSourcePalletNos || []).filter(Boolean) : []
|
||||
completed = await waitForCompletedMeasurement(context, measurementPath, ['WAIT_SPLIT'], 10)
|
||||
finalResponse = completed.response
|
||||
finalMeasurement = context.apiSuccess(MODULE, '合托后回查一件代发入仓单', finalResponse,
|
||||
`pollAttempts=${completed.attempts}`, OPTIONS)
|
||||
context.assert(MODULE, '一件代发合托完成后进入智能分柜门禁', finalResponse,
|
||||
finalMeasurement?.processStatus === 'WAIT_SPLIT'
|
||||
&& finalMeasurement?.measureReviewStatus === 'APPROVED'
|
||||
&& finalMeasurement?.measurementStatus === 'APPROVED',
|
||||
`processStatus=${finalMeasurement?.processStatus ?? 'missing'}`, OPTIONS)
|
||||
if (context.options?.prepareDropshipManualCount) {
|
||||
const warehouseId = asId(summary?.warehouseId)
|
||||
const pendingResponse = await context.request('GET',
|
||||
`/api/platform/v1/first-leg/pda-dropship/tasks/pending?warehouseId=${warehouseId}&keyword=${encodeURIComponent(inboundCode)}`)
|
||||
const pending = context.apiSuccess(MODULE, '准备PDA人工清点任务', pendingResponse,
|
||||
`inboundId=${inboundId}`, OPTIONS)
|
||||
const task = (pending || []).find((item) => asId(item?.inboundId) === inboundId)
|
||||
context.assert(MODULE, '任务停在未领取、未清点、未归托状态', pendingResponse,
|
||||
Boolean(asId(task?.taskId)) && task?.taskStatus === 'PENDING'
|
||||
&& Number(task?.countedCartons) === 0 && Number(task?.boundCartons) === 0
|
||||
&& Number(task?.totalCartons) === Number(finalMeasurement?.actualPackageCount),
|
||||
`taskId=${asId(task?.taskId) || 'missing'}, status=${task?.taskStatus ?? 'missing'}, counted=${task?.countedCartons ?? 'missing'}`, OPTIONS)
|
||||
context.createdResources.dropshipManualCount = {
|
||||
taskId: asId(task?.taskId), inboundId, inboundCode, warehouseId,
|
||||
warehouseName: task?.warehouseName || null, totalCartons: Number(task?.totalCartons || 0),
|
||||
taskStatus: task?.taskStatus || null,
|
||||
}
|
||||
} else {
|
||||
const sealed = await completeDropshipPalletization(context, {
|
||||
inboundId, inboundCode, warehouseId: asId(summary?.warehouseId), measurement: finalMeasurement,
|
||||
})
|
||||
sealedCartonMarks = sealed?.taskStatus === 'COMPLETED' ? sealed.sealedCartonMarks : []
|
||||
sealedSourcePalletNos = sealed?.taskStatus === 'COMPLETED'
|
||||
? (sealed.sealedSourcePalletNos || []).filter(Boolean) : []
|
||||
completed = await waitForCompletedMeasurement(context, measurementPath, ['WAIT_SPLIT'], 10)
|
||||
finalResponse = completed.response
|
||||
finalMeasurement = context.apiSuccess(MODULE, '合托后回查一件代发入仓单', finalResponse,
|
||||
`pollAttempts=${completed.attempts}`, OPTIONS)
|
||||
context.assert(MODULE, '一件代发合托完成后进入智能分柜门禁', finalResponse,
|
||||
finalMeasurement?.processStatus === 'WAIT_SPLIT'
|
||||
&& finalMeasurement?.measureReviewStatus === 'APPROVED'
|
||||
&& finalMeasurement?.measurementStatus === 'APPROVED',
|
||||
`processStatus=${finalMeasurement?.processStatus ?? 'missing'}`, OPTIONS)
|
||||
}
|
||||
}
|
||||
|
||||
const approvedScanResponse = await multipartRequest(context, scanPath, {
|
||||
|
||||
@@ -402,6 +402,11 @@ function buildPayload(context, profile, master, productImageFileId, customerAddr
|
||||
? context.context.waitSplitVariant.packageCounts : []
|
||||
const selectedBoxes = BOXES.slice(0, skuCount)
|
||||
const orderProfile = context.context?.orderProfile || {}
|
||||
const dropship = String(context.context?.orderFulfillmentType || 'STANDARD').trim().toUpperCase()
|
||||
=== 'ONE_CLICK_DROPSHIP'
|
||||
const mixedPackageCount = Math.max(1,
|
||||
Number(context.context?.waitSplitVariant?.totalPackageCount || packageCountPerSku))
|
||||
const mixedPackingGroupNo = `MIX-${context.marker}`.slice(0, 32)
|
||||
const isPrivate = master.destinationType === 'PRIVATE'
|
||||
const pickupMethod = orderProfile.pickupMethod || 'SELF_EXPRESS'
|
||||
const receiver = isPrivate ? {
|
||||
@@ -411,7 +416,7 @@ function buildPayload(context, profile, master, productImageFileId, customerAddr
|
||||
addressLine: `${context.marker} 88 Randomized Test Ave`, postalCode: '11354',
|
||||
} : null
|
||||
return {
|
||||
fulfillmentType: String(context.context?.orderFulfillmentType || 'STANDARD').trim().toUpperCase(),
|
||||
fulfillmentType: dropship ? 'ONE_CLICK_DROPSHIP' : 'STANDARD',
|
||||
customerId: profile.id,
|
||||
customerName: companyName,
|
||||
transportMode: 'SEA', tradeTerm: 'FOB',
|
||||
@@ -441,14 +446,17 @@ function buildPayload(context, profile, master, productImageFileId, customerAddr
|
||||
cargoes: selectedBoxes.map((box, index) => {
|
||||
const volumeCbm = box.lengthCm * box.widthCm * box.heightCm / 1_000_000
|
||||
const unitsPerPackage = 10 + index
|
||||
const packageCount = Number(packageCounts[index] || packageCountPerSku)
|
||||
const packageCount = dropship ? mixedPackageCount : Number(packageCounts[index] || packageCountPerSku)
|
||||
const carton = dropship ? selectedBoxes[0] : box
|
||||
const cartonVolumeCbm = carton.lengthCm * carton.widthCm * carton.heightCm / 1_000_000
|
||||
return {
|
||||
skuNo: `SKU-${box.boxType}-${context.marker}`.slice(0, 64),
|
||||
cargoName: `${box.boxType} 测试产品`, cargoNameEn: `${box.boxType} test product`,
|
||||
hsCode: '8518210000', customsHsCode: '8518210000', packageType: 'CARTON',
|
||||
lengthCm: box.lengthCm, widthCm: box.widthCm, heightCm: box.heightCm,
|
||||
packingGroupNo: dropship ? mixedPackingGroupNo : null,
|
||||
lengthCm: carton.lengthCm, widthCm: carton.widthCm, heightCm: carton.heightCm,
|
||||
unitsPerPackage, packageCount, grossWeightKg: (10 + index) * packageCount,
|
||||
volumeCbm: volumeCbm * packageCount, totalQuantity: unitsPerPackage * packageCount,
|
||||
volumeCbm: cartonVolumeCbm * packageCount, totalQuantity: unitsPerPackage * packageCount,
|
||||
netWeightKg: (9 + index) * packageCount,
|
||||
unitDeclaredValue: 8.5, declaredValue: unitsPerPackage * packageCount * 8.5, currency: 'USD',
|
||||
material: '塑料 / Plastic', usage: '接口验收 / API acceptance',
|
||||
|
||||
@@ -518,13 +518,13 @@ foreach ($pdaApplication in $pdaApplications) {
|
||||
}
|
||||
}
|
||||
|
||||
# 海外 PDA 已开放拆柜收货、库内、换标和现场查询真实作业。
|
||||
# 海外 PDA 已开放拆柜收货、移库、托盘、换标和现场查询真实作业;库存盘点仅保留底层实现。
|
||||
$overseasWorkbenchPath = Join-Path $workspaceRoot 'apps/pda-overseas-uniapp/src/data/overseas-workbench.js'
|
||||
$overseasWorkbench = Read-RequiredText $overseasWorkbenchPath
|
||||
Assert-Matches $overseasWorkbench "(?s)name:\s*'拆柜收货'.{0,300}?available:\s*true" 'Overseas PDA 拆柜收货开关'
|
||||
Assert-Matches $overseasWorkbench "(?s)name:\s*'托盘管理'.{0,300}?available:\s*true.{0,200}?route:\s*'/pages/pallet/pallet'" 'Overseas PDA 托盘管理开关'
|
||||
Assert-NotContains $overseasWorkbench "key: 'stocktake'" 'Overseas PDA 隐藏库存盘点入口'
|
||||
foreach ($enabledOperation in @(
|
||||
@{ Name = '库存盘点'; Route = '/pages/stocktake/stocktake' },
|
||||
@{ Name = '商品移库'; Route = '/pages/move/move' },
|
||||
@{ Name = '换标收货'; Route = '/pages/relabel/relabel\?op=relabelReceive' },
|
||||
@{ Name = '换标执行'; Route = '/pages/relabel/relabel\?op=relabelExecute' },
|
||||
|
||||
Reference in New Issue
Block a user