Test #1

Merged
admin merged 1726 commits from test into main 2026-09-17 11:52:45 +08:00
2 changed files with 102 additions and 8 deletions
Showing only changes of commit 20eb524a51 - Show all commits
@@ -61,7 +61,7 @@ test('demo package keeps pallet pages bounded and historical snapshots read-only
})
test('approval freezes measurement and requires quantity weight and volume conservation', () => {
assert.match(source, /审核进入WAIT_SPLIT后箱码尺寸与图片快照不可再覆盖/)
assert.match(source, /审核及合托完成后箱码尺寸与图片快照不可再覆盖/)
assert.match(measurementTests, /approvedMeasurementCannotBeResubmittedOrMutateFrozenTotals/)
assert.match(reviewTests, /shouldApproveMultipleCargoLinesOnlyWhenAllFrozenTotalsMatch/)
assert.match(reviewTests, /shouldRejectApprovalWhenVolumeSnapshotDoesNotConserve/)
@@ -71,3 +71,13 @@ test('approval freezes measurement and requires quantity weight and volume conse
assert.match(source, /actualVolumeCbm[^\n]+totalVolume/)
assert.match(source, /volumeWeightKg[^\n]+volumeWeight/)
})
test('dropship measurement completes the formal palletization workflow before smart loading', () => {
assert.match(source, /pda-dropship\/tasks\/pending/)
assert.match(source, /pda-dropship\/tasks\/\$\{taskId\}\/claim/)
assert.match(source, /pallets\/open/)
assert.match(source, /pallets\/\$\{palletId\}\/scan/)
assert.match(source, /pallets\/\$\{palletId\}\/seal/)
assert.match(source, /dropship \? \['WAIT_PALLETIZE'\] : \['WAIT_SPLIT'\]/)
assert.match(source, /一件代发合托完成后进入智能分柜门禁/)
})
@@ -71,19 +71,85 @@ function randomlyReusePalletIds(pallets, palletCount, randomValue) {
pallets[(seed >>> (index % 31)) % pallets.length].id)
}
async function waitForCompletedMeasurement(context, measurementPath, attempts = 30) {
async function waitForCompletedMeasurement(context, measurementPath, expectedStatuses = ['WAIT_SPLIT'], attempts = 30) {
let response = null
let measurement = null
for (let attempt = 1; attempt <= attempts; attempt += 1) {
response = await context.request('GET', measurementPath)
measurement = response?.http === 200 && String(response?.body?.code) === '200'
? response.body.data : null
if (measurement?.processStatus === 'WAIT_SPLIT') return { response, measurement, attempts: attempt }
if (expectedStatuses.includes(measurement?.processStatus)) return { response, measurement, attempts: attempt }
if (attempt < attempts) await new Promise((resolve) => setTimeout(resolve, 1_000))
}
return { response, measurement, attempts }
}
async function completeDropshipPalletization(context, { inboundId, inboundCode, warehouseId, measurement }) {
const pendingResponse = await context.request('GET',
`/api/platform/v1/first-leg/pda-dropship/tasks/pending?keyword=${encodeURIComponent(inboundCode)}`)
const pending = context.apiSuccess(MODULE, '查询一件代发待合托任务', pendingResponse,
`inboundId=${inboundId}`, OPTIONS)
const task = (pending || []).find((item) => asId(item?.inboundId) === inboundId
&& asId(item?.warehouseId) === warehouseId)
context.assert(MODULE, '测量审核后生成当前入仓单唯一合托任务', pendingResponse,
Boolean(asId(task?.taskId)) && Number(task?.totalCartons) === Number(measurement?.actualPackageCount),
`taskId=${asId(task?.taskId) || 'missing'}, totalCartons=${task?.totalCartons ?? 'missing'}`, OPTIONS)
if (!task?.taskId) return null
const taskId = asId(task.taskId)
const claimResponse = await context.request('POST',
`/api/platform/v1/first-leg/pda-dropship/tasks/${taskId}/claim`, { warehouseId })
const claimed = context.apiSuccess(MODULE, '领取一件代发合托任务', claimResponse,
`taskId=${taskId}`, OPTIONS)
context.assert(MODULE, '合托任务绑定当前操作员且进入CLAIMED', claimResponse,
claimed?.taskStatus === 'CLAIMED' && asId(claimed?.inboundId) === inboundId,
`taskStatus=${claimed?.taskStatus ?? 'missing'}`, OPTIONS)
const openResponse = await context.request('POST',
`/api/platform/v1/first-leg/pda-dropship/tasks/${taskId}/pallets/open`, {
warehouseId, operationId: `${context.marker}-dropship-open`.slice(0, 128),
})
let pallet = context.apiSuccess(MODULE, '开启一件代发工作托盘', openResponse,
`taskId=${taskId}`, OPTIONS)
const palletId = asId(pallet?.palletId)
if (!palletId) return null
const totalCartons = Number(measurement?.actualPackageCount)
let scannedCartons = 0
for (let index = 0; index < totalCartons; index += 1) {
const boxCode = `${inboundCode}#${totalCartons}-${index + 1}`
const scanResponse = await context.request('POST',
`/api/platform/v1/first-leg/pda-dropship/tasks/${taskId}/pallets/${palletId}/scan`, {
warehouseId, boxCode, cartonCount: 1,
operationId: `${context.marker}-dropship-scan-${index + 1}`.slice(0, 128),
})
const scanned = context.apiSuccess(MODULE, `合托扫描第${index + 1}箱冻结箱唛`, scanResponse,
`boxCode=${boxCode}`, OPTIONS)
context.assert(MODULE, `第${index + 1}箱进入工作托盘`, scanResponse,
Number(scanned?.addedCartons) === 1 && asId(scanned?.pallet?.palletId) === palletId,
`added=${scanned?.addedCartons ?? 'missing'}, remaining=${scanned?.remainingCartons ?? 'missing'}`, OPTIONS)
pallet = scanned?.pallet || pallet
if (Number(scanned?.addedCartons) === 1) scannedCartons += 1
}
context.assert(MODULE, '一件代发工作托盘覆盖测量冻结的全部箱数', null,
totalCartons > 0 && scannedCartons === totalCartons,
`scanned=${scannedCartons}, expected=${totalCartons || 'missing'}`, OPTIONS)
const sealResponse = await context.request('POST',
`/api/platform/v1/first-leg/pda-dropship/tasks/${taskId}/pallets/${palletId}/seal`, {
warehouseId, expectedVersion: Number(pallet?.version),
operationId: `${context.marker}-dropship-seal`.slice(0, 128),
})
const sealed = context.apiSuccess(MODULE, '封托并完成一件代发合托任务', sealResponse,
`taskId=${taskId}, palletId=${palletId}`, OPTIONS)
context.assert(MODULE, '全部箱数封托后入仓单允许进入WAIT_SPLIT', sealResponse,
sealed?.taskStatus === 'COMPLETED'
&& Number(sealed?.allocatedCartons) === Number(sealed?.totalCartons)
&& sealed?.pallets?.every((item) => item?.palletStatus === 'COMPLETED'),
`taskStatus=${sealed?.taskStatus ?? 'missing'}, allocated=${sealed?.allocatedCartons ?? 'missing'}`, OPTIONS)
return sealed
}
async function provisionWarehouseResources(context, { inboundId, tenantId, warehouseId, palletCount }) {
if (!warehouseId || !Number.isInteger(palletCount) || palletCount < 1) return null
@@ -622,12 +688,15 @@ export async function run(context) {
// Measurement approval may enqueue pricing/inbound completion. Poll the
// public projection instead of treating the transient WAIT_PRICING state as
// a smart-loading candidate or manufacturing fixture state in the script.
const completed = await waitForCompletedMeasurement(context, measurementPath)
const finalResponse = completed.response
const finalMeasurement = context.apiSuccess(MODULE, '查询审核后的最终测量状态', finalResponse,
const dropship = context.createdResources?.orders?.fulfillmentType === 'ONE_CLICK_DROPSHIP'
let completed = await waitForCompletedMeasurement(context, measurementPath,
dropship ? ['WAIT_PALLETIZE'] : ['WAIT_SPLIT'])
let finalResponse = completed.response
let finalMeasurement = context.apiSuccess(MODULE, '查询审核后的最终测量状态', finalResponse,
`pollAttempts=${completed.attempts}`, OPTIONS)
context.assert(MODULE, '审核后入库与测量状态闭环且结果未变化', finalResponse,
finalMeasurement?.processStatus === 'WAIT_SPLIT' && finalMeasurement?.measureReviewStatus === 'APPROVED'
finalMeasurement?.processStatus === (dropship ? 'WAIT_PALLETIZE' : 'WAIT_SPLIT')
&& finalMeasurement?.measureReviewStatus === 'APPROVED'
&& finalMeasurement?.measurementStatus === 'APPROVED'
&& Number(finalMeasurement?.actualPackageCount) === originalPackageCount
&& closeTo(finalMeasurement?.actualGrossWeightKg, weightEvidence.grossWeightKg, 0.001)
@@ -636,11 +705,26 @@ export async function run(context) {
&& closeTo(finalMeasurement?.volumeWeightKg, volumeWeight),
`processStatus=${finalMeasurement?.processStatus ?? 'missing'}, measurementStatus=${finalMeasurement?.measurementStatus ?? 'missing'}, packages=${finalMeasurement?.actualPackageCount ?? 'missing'}, pallets=${weightEvidence.count}, grossWeight=${finalMeasurement?.actualGrossWeightKg ?? 'missing'}, netWeight=${finalMeasurement?.actualNetWeightKg ?? 'missing'}`, OPTIONS)
if (dropship && finalMeasurement?.processStatus === 'WAIT_PALLETIZE') {
await completeDropshipPalletization(context, {
inboundId, inboundCode, warehouseId: asId(summary?.warehouseId), measurement: finalMeasurement,
})
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, {
boxCode, ...replacement, machineNo: 'MJ-ADMIN-E2E-AFTER-APPROVAL',
measuredAt: new Date().toISOString().slice(0, 19),
})
context.assert(MODULE, '审核进入WAIT_SPLIT后箱码尺寸与图片快照不可再覆盖', approvedScanResponse,
context.assert(MODULE, '审核及合托完成后箱码尺寸与图片快照不可再覆盖', approvedScanResponse,
approvedScanResponse.http === 200 && String(approvedScanResponse.body?.code) === 'A0409',
`HTTP=${approvedScanResponse.http}, code=${approvedScanResponse.body?.code ?? 'missing'}, requestId=${approvedScanResponse.requestId || 'missing'}`,
OPTIONS)