Files
baiyue-firstleg/scripts/admin-test-env-modules/mixed-container-receiving.mjs
T
2026-09-15 14:30:47 +08:00

82 lines
5.9 KiB
JavaScript

import { receivingProgressMatches } from './dropship-outbound-edge-cases.mjs'
export async function run(context) {
const { runMixedContainer } = await import('./dropship-pallet-matrix.mjs')
return runMixedContainer(context)
}
export function mixedReceivingSchedule(group) {
const fba = group.filter(r => r.order.fulfillmentType === 'STANDARD' && r.order.destinationType === 'FBA')
const overseas = group.filter(r => r.order.fulfillmentType === 'STANDARD' && r.order.destinationType === 'OVERSEAS')
const dropship = group.filter(r => r.order.fulfillmentType === 'ONE_CLICK_DROPSHIP')
if (group.length !== 3 || fba.length !== 1 || overseas.length !== 1 || dropship.length !== 1
|| 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 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 } })),
{ 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]),
]
}
export async function receiveMixedContainer({ group, call, check, request, marker }) {
const base = '/api/pda/v1/last-leg/receiving-containers/current'
const steps = mixedReceivingSchedule(group)
const expected = group.map(r => ({ inboundCode: r.source.inboundCode, total: r.expectedCartonMarks.length, received: 0 }))
for (const record of group.filter(r => r.order.fulfillmentType === 'ONE_CLICK_DROPSHIP' || r.order.destinationType === 'OVERSEAS')) {
const before = await call('混柜错误收货模式前回查', 'GET', base)
const invalid = await request('POST', `${base}/receipts/bulk`, {
inboundCode: record.source.inboundCode, palletCode: record.overseas.plan.pallets[0].palletNo,
packageCount: 1, idempotencyKey: `${marker}-forbid-bulk-${record.label}`,
})
check('普通海外仓和一件代发均不能绕过各自规则使用FBA批量收货', invalid, invalid.body?.code === 'A0409')
const after = await call('混柜错误收货模式拒绝后回查', 'GET', base)
check('混柜错误收货模式拒绝后零漂移', null, JSON.stringify(before) === JSON.stringify(after))
}
for (const [index, step] of steps.entries()) {
const before = await call('混柜交替收货前进度', 'GET', base)
check('混柜每步前逐票和柜级进度准确', null, receivingProgressMatches(before, expected))
const premature = await request('POST', `${base}/complete`,
{ allowDifference: false, idempotencyKey: `${marker}-early-${index}` })
check('混柜任一票未齐不得正常完成', premature, premature.body?.code === 'A0409')
const afterRejected = await call('混柜提前完成拒绝后回查', 'GET', base)
check('混柜提前完成拒绝后零漂移', null, JSON.stringify(afterRejected) === JSON.stringify(before))
const path = `${base}/receipts/${step.path}`
const body = { ...step.body, idempotencyKey: `${marker}-mixed-receive-${index}` }
const received = await call(`${step.record.label}交替收货`, 'POST', path, body)
check('混柜本次只收当前操作对应箱数', null, Number(received.acceptedPackages) === step.count)
const replay = await call('混柜收货同键重放', 'POST', path, body)
check('混柜同键重放结果稳定', null, JSON.stringify(replay) === JSON.stringify(received))
expected.find(row => row.inboundCode === step.record.source.inboundCode).received += step.count
const after = await call('混柜每步后逐票回查', 'GET', base)
check('混柜交替收货不串票不重计', null, receivingProgressMatches(after, expected))
const changedBody = step.path === 'pallet' ? { ...body, sourcePalletNo: `${body.sourcePalletNo}-CHANGED` }
: step.path === 'bulk' ? { ...body, packageCount: body.packageCount + 1 }
: { ...body, palletCode: `${body.palletCode}-CHANGED` }
const changed = await request('POST', path, changedBody)
check('混柜收货同键异载荷必须冲突', changed, changed.body?.code === 'A0409')
const duplicate = await request('POST', path, { ...body, idempotencyKey: `${body.idempotencyKey}-duplicate` })
check('混柜同货物新键重复操作不重复收货', duplicate, step.path === 'carton'
? duplicate.body?.code === 'A0409'
: duplicate.body?.code === '200' && duplicate.body?.data?.result === 'ALREADY_RECEIVED'
&& Number(duplicate.body?.data?.acceptedPackages) === 0)
const afterRetries = await call('混柜重复和冲突请求后回查全部票', 'GET', base)
check('混柜冲突及新键重复后全柜事实不变', null, JSON.stringify(afterRetries) === JSON.stringify(after))
}
const body = { allowDifference: false, idempotencyKey: `${marker}-mixed-complete` }
const completed = await call('混柜全部核平后正常完成入库', 'POST', `${base}/complete`, body)
check('混柜三票全收且普通完成', null,
completed.status === 'COMPLETED' && receivingProgressMatches(completed, expected))
const replay = await call('混柜入库完成重放', 'POST', `${base}/complete`, body)
check('混柜完成重放不重复入库', null, JSON.stringify(replay) === JSON.stringify(completed))
return completed
}