补齐海外仓和私人地址正常及短少收货真实验收
This commit is contained in:
@@ -13,14 +13,16 @@ export function mixedReceivingSchedule(group) {
|
||||
|| dropship[0].task?.pallets?.length !== 2) throw new Error('混柜必须包含普通FBA、普通海外仓及一件代发双托三票')
|
||||
const [f, o, d] = [fba[0], overseas[0], dropship[0]]
|
||||
const fbaPallet = f.overseas.plan.pallets?.[0]?.palletNo
|
||||
const overseasPallet = o.overseas.plan.pallets?.[0]?.palletNo
|
||||
if (!fbaPallet || !overseasPallet || f.expectedCartonMarks.length < 2) throw new Error('混柜普通订单缺少真实托盘或分批箱数')
|
||||
const overseasPallets = o.overseas.plan.pallets || []
|
||||
if (!fbaPallet || overseasPallets.length !== 2 || overseasPallets.some(pallet => !pallet.palletNo)
|
||||
|| o.expectedCartonMarks.length !== 4 || f.expectedCartonMarks.length < 2) throw new Error('混柜普通订单缺少真实托盘或分批箱数')
|
||||
const palletStep = pallet => ({ record: d, path: 'pallet', count: pallet.cartons.filter(c =>
|
||||
String(c.inboundId) === String(d.source.inboundId)).length, body: { sourcePalletNo: pallet.palletNo } })
|
||||
return [
|
||||
{ record: f, path: 'bulk', count: 1, body: { inboundCode: f.source.inboundCode, palletCode: fbaPallet, packageCount: 1 } },
|
||||
palletStep(d.task.pallets[0]),
|
||||
...o.expectedCartonMarks.map(cartonMark => ({ record: o, path: 'carton', count: 1, body: { cartonMark, palletCode: overseasPallet } })),
|
||||
...o.expectedCartonMarks.map((cartonMark, index) => ({ record: o, path: 'carton', count: 1,
|
||||
body: { cartonMark, palletCode: overseasPallets[index === 3 ? 1 : 0].palletNo } })),
|
||||
{ record: f, path: 'bulk', count: f.expectedCartonMarks.length - 1,
|
||||
body: { inboundCode: f.source.inboundCode, palletCode: fbaPallet, packageCount: f.expectedCartonMarks.length } },
|
||||
palletStep(d.task.pallets[1]),
|
||||
@@ -79,3 +81,97 @@ export async function receiveMixedContainer({ group, call, check, request, marke
|
||||
check('混柜完成重放不重复入库', null, JSON.stringify(replay) === JSON.stringify(completed))
|
||||
return completed
|
||||
}
|
||||
|
||||
export async function receiveOverseasComplete({ record, call, adminCall, check, marker }) {
|
||||
const base = '/api/pda/v1/last-leg/receiving-containers/current'
|
||||
const inboundCode = record.source.inboundCode
|
||||
const plan = record.overseas.plan
|
||||
const pallet = plan.pallets[0]
|
||||
const expected = record.expectedCartonMarks.length
|
||||
check('普通海外仓全收场景具备四个真实箱码和预留托盘', null, expected === 4 && Boolean(pallet?.palletNo))
|
||||
for (const [index, cartonMark] of record.expectedCartonMarks.entries()) {
|
||||
const carton = await call('全收场景解析本柜箱码', 'POST', `${base}/cartons/resolve`, { cartonMark })
|
||||
check('全收箱码属于当前普通海外仓票', null, carton.inboundCode === inboundCode && carton.destinationType === 'OVERSEAS')
|
||||
const resolved = await call('全收场景校验预留托盘', 'POST', `${base}/pallets/resolve`, { inboundCode, palletCode: pallet.palletNo })
|
||||
check('全收预留托盘校验通过', null, resolved.compatible === true && resolved.palletCode === pallet.palletNo)
|
||||
const receipt = await call('全收场景逐箱实收', 'POST', `${base}/receipts/carton`,
|
||||
{ cartonMark, palletCode: pallet.palletNo, idempotencyKey: `${marker}-complete-carton-${index}` })
|
||||
check('全收本次只接收当前一箱', null, Number(receipt.acceptedPackages) === 1)
|
||||
}
|
||||
const body = { allowDifference: false, idempotencyKey: `${marker}-ordinary-complete` }
|
||||
const completed = await call('四箱全收后正常完成', 'POST', `${base}/complete`, body)
|
||||
check('四箱全收正常完成且无差异', null, completed.status === 'COMPLETED'
|
||||
&& Number(completed.receivedPackages) === expected && Number(completed.pendingPackages) === 0)
|
||||
const replay = await call('正常完成原键重放', 'POST', `${base}/complete`, body)
|
||||
check('正常完成重放不重复入库', null, JSON.stringify(replay) === JSON.stringify(completed))
|
||||
const finalPlan = await adminCall('回查全收最终计划', 'GET',
|
||||
`/api/platform/v1/last-leg/inbound-plans/${encodeURIComponent(plan.planNo)}?customerId=${encodeURIComponent(record.order.tenantId)}`)
|
||||
check('全收计划完成且应收实收均为四箱', null, finalPlan.status === 'COMPLETED'
|
||||
&& Number(finalPlan.expectedPackageCount) === expected && Number(finalPlan.pickedPackageCount) === expected)
|
||||
const stock = await call('回查全收可用库存', 'POST', '/api/pda/v1/last-leg/inventory/resolve', { code: inboundCode })
|
||||
check('全收库存只有本票实际收到的四箱', null, stock.queryCode === inboundCode && stock.items?.length > 0
|
||||
&& stock.items.every(row => row.inboundCode === inboundCode && String(row.customerId) === String(record.order.tenantId)
|
||||
&& row.locationId && plan.pallets.some(item => String(item.warehousePalletId) === String(row.palletId)))
|
||||
&& stock.items.reduce((sum, row) => sum + Number(row.availablePackages), 0) === expected)
|
||||
return { completed, plan: finalPlan, stock, receivingVerified: true, normalCompletionVerified: true }
|
||||
}
|
||||
|
||||
/** 逐箱短少只按本轮真实已收箱入库,验证后台确认、重放和库存归属。 */
|
||||
export async function receiveOverseasShortage({ record, call, adminCall, check, request, marker }) {
|
||||
const base = '/api/pda/v1/last-leg/receiving-containers/current'
|
||||
const inboundCode = record.source.inboundCode
|
||||
const plan = record.overseas.plan
|
||||
const pallet = plan.pallets[0]
|
||||
const expected = record.expectedCartonMarks.length
|
||||
const actual = expected - 1
|
||||
check('普通海外仓短少场景具备四个真实箱码和预留托盘', null, expected === 4 && Boolean(pallet?.palletNo))
|
||||
const before = await call('错误托盘校验前回查', 'GET', base)
|
||||
const wrong = await request('POST', `${base}/pallets/resolve`, { inboundCode, palletCode: `${marker}-UNRESERVED` })
|
||||
check('普通海外仓非本票预留托盘在校验时拒绝', wrong, wrong.body?.code === 'A0409')
|
||||
const unchanged = await call('错误托盘校验后回查', 'GET', base)
|
||||
check('错误托盘校验后实收零漂移', null, JSON.stringify(before) === JSON.stringify(unchanged))
|
||||
for (const [index, cartonMark] of record.expectedCartonMarks.slice(0, actual).entries()) {
|
||||
const carton = await call('短少场景解析本柜箱码', 'POST', `${base}/cartons/resolve`, { cartonMark })
|
||||
check('箱码属于当前普通海外仓票', null, carton.inboundCode === inboundCode && carton.destinationType === 'OVERSEAS')
|
||||
const resolved = await call('短少场景校验预留托盘', 'POST', `${base}/pallets/resolve`, { inboundCode, palletCode: pallet.palletNo })
|
||||
check('预留托盘校验通过', null, resolved.compatible === true && resolved.palletCode === pallet.palletNo)
|
||||
const body = { cartonMark, palletCode: pallet.palletNo, idempotencyKey: `${marker}-shortage-carton-${index}` }
|
||||
const receipt = await call('短少场景逐箱实收', 'POST', `${base}/receipts/carton`, body)
|
||||
check('本次只接收当前一箱', null, Number(receipt.acceptedPackages) === 1)
|
||||
const replay = await call('逐箱实收同键重放', 'POST', `${base}/receipts/carton`, body)
|
||||
check('逐箱重放不重复计数', null, JSON.stringify(receipt) === JSON.stringify(replay))
|
||||
const duplicate = await request('POST', `${base}/receipts/carton`, { ...body, idempotencyKey: `${body.idempotencyKey}-duplicate` })
|
||||
check('同箱新键重扫拒绝', duplicate, duplicate.body?.code === 'A0409')
|
||||
}
|
||||
const premature = await request('POST', `${base}/complete`, { allowDifference: false, idempotencyKey: `${marker}-shortage-normal-complete` })
|
||||
check('短少场景拒绝正常完成', premature, premature.body?.code === 'A0409')
|
||||
const completeBody = { allowDifference: true, idempotencyKey: `${marker}-shortage-onsite-complete` }
|
||||
const completed = await call('带短少结束现场收货', 'POST', `${base}/complete`, completeBody)
|
||||
check('现场结束保留短少一箱', null, completed.status === 'COMPLETED_WITH_DIFFERENCE'
|
||||
&& Number(completed.receivedPackages) === actual && Number(completed.pendingPackages) === 1)
|
||||
const completeReplay = await call('带短少结束同键重放', 'POST', `${base}/complete`, completeBody)
|
||||
check('现场结束重放稳定', null, JSON.stringify(completeReplay) === JSON.stringify(completed))
|
||||
const planPath = `/api/platform/v1/last-leg/inbound-plans/${encodeURIComponent(plan.planNo)}`
|
||||
const customerId = String(record.order.tenantId)
|
||||
const pending = await adminCall('读取短少待核平计划', 'GET', `${planPath}?customerId=${encodeURIComponent(customerId)}`)
|
||||
check('短少计划等待后台确认', null, pending.status === 'PENDING_RECONCILIATION'
|
||||
&& Number(pending.expectedPackageCount) === expected && Number(pending.pickedPackageCount) === actual
|
||||
&& Number.isInteger(pending.version))
|
||||
const confirmBody = { customerId, version: pending.version, expectedPackageCount: expected,
|
||||
receivedPackageCount: actual, reason: `${marker}逐箱核对短少一箱` }
|
||||
const headers = { 'Idempotency-Key': `${marker}-shortage-confirm` }
|
||||
const confirmed = await adminCall('后台确认普通海外仓短少入库', 'POST', `${planPath}/confirm-shortage`, confirmBody, headers)
|
||||
check('普通海外仓短少确认成功', null, confirmed.status === 'PARTIAL_INBOUND')
|
||||
const confirmReplay = await adminCall('后台短少确认同键重放', 'POST', `${planPath}/confirm-shortage`, confirmBody, headers)
|
||||
check('后台短少确认重放不重复入库', null, JSON.stringify(confirmReplay) === JSON.stringify(confirmed))
|
||||
const finalPlan = await adminCall('回查短少入库最终计划', 'GET', `${planPath}?customerId=${encodeURIComponent(customerId)}`)
|
||||
check('短少入库保留原应收及实际箱数', null, finalPlan.status === 'PARTIAL_INBOUND'
|
||||
&& Number(finalPlan.expectedPackageCount) === expected && Number(finalPlan.pickedPackageCount) === actual)
|
||||
const stock = await call('回查短少入库可用库存', 'POST', '/api/pda/v1/last-leg/inventory/resolve', { code: inboundCode })
|
||||
check('短少库存只有本票真实已收三箱', null, stock.queryCode === inboundCode && Array.isArray(stock.items)
|
||||
&& stock.items.length > 0 && stock.items.every(row => row.inboundCode === inboundCode
|
||||
&& String(row.customerId) === customerId && row.locationId
|
||||
&& plan.pallets.some(item => String(item.warehousePalletId) === String(row.palletId)))
|
||||
&& stock.items.reduce((sum, row) => sum + Number(row.availablePackages), 0) === actual)
|
||||
return { completed, plan: finalPlan, stock, receivingVerified: true, shortageVerified: true }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user