Files
baiyue-firstleg/scripts/admin-test-env-modules/inbound-measurement-box-code-contract.test.mjs
T

196 lines
11 KiB
JavaScript

import assert from 'node:assert/strict'
import { readFileSync } from 'node:fs'
import test from 'node:test'
import { completeDropshipPalletization } from './inbound-measurement.mjs'
const source = readFileSync(new URL('inbound-measurement.mjs', import.meta.url), 'utf8')
const read = (relativeUrl) => readFileSync(new URL(relativeUrl, import.meta.url), 'utf8')
const labelTests = read('../../firstleg/src/test/java/com/baiyue/firstleg/service/InboundCartonLabelServiceTest.java')
const measurementTests = read('../../firstleg/src/test/java/com/baiyue/firstleg/service/InboundMeasurementServiceTest.java')
const cartonTests = read('../../firstleg/src/test/java/com/baiyue/firstleg/service/CartonMeasurementServiceTest.java')
const reviewTests = read('../../firstleg/src/test/java/com/baiyue/firstleg/service/MeasurementReviewServiceTest.java')
test('measurement acceptance scans the stable box code frozen by first print', () => {
assert.match(source, /const boxCode = `\$\{inboundCode\}#\$\{originalPackageCount\}-1`/)
assert.doesNotMatch(source, /#V\d+#/)
})
test('reprint and Mojia scan share the same frozen box code variable', () => {
assert.match(source, /重复整单打印复用已冻结箱码映射[\s\S]*boxCode=\$\{boxCode\}/)
assert.match(source, /const firstScanResponse = await multipartRequest[\s\S]*boxCode, \.\.\.firstDimensions/)
})
test('measurement submission confirms weight evidence before submit', () => {
assert.match(source, /files\/measurements\/\$\{tenantId\}\/\$\{inboundId\}/)
assert.match(source, /\/weight-results\?\$\{query\(tenantId\)\}/)
assert.match(source, /\/weight-results\/\$\{created\.id\}\/confirm\?\$\{query\(tenantId\)\}/)
assert.match(source, /createConfirmedWeightEvidence[\s\S]*\/measurement\/submit/)
})
test('measurement fixture derives pallet resources from confirmed image count', () => {
assert.match(source, /waitSplitVariant\?\.palletCount \|\| 1/)
assert.match(source, /palletIds: warehouseResourcesReady\.palletIds/)
assert.match(source, /confirmedRows\.length === palletIds\.length/)
assert.doesNotMatch(source, /Math\.ceil\(Number\(totalVolumeCbm\)/)
assert.doesNotMatch(source, /Math\.ceil\(totalVolume \/ DEFAULT_PALLET_CAPACITY_CBM\)/)
})
test('volume ceiling removes binary floating point noise before scaling', () => {
assert.match(source, /Number\.EPSILON \* Math\.max\(1, Math\.abs\(value\)\) \* 4/)
})
test('measurement draft preserves server-calculated dimensions and the frozen coefficient mode', () => {
assert.match(source, /measuredItem\?\.calculatedOuterLengthCm \?\? measuredItem\?\.outerLengthCm/)
assert.match(source, /outerLengthCm: item\.outerLengthCm \?\? null/)
assert.match(source, /outerLengthCm: measuredItem\.outerLengthCm \?\? null/)
assert.match(source, /startsWith\('CUSTOMER_DIMENSION_'\)/)
assert.match(source, /\? 'ADD' : item\.coefficientMode \?\? null/)
assert.match(cartonTests, /getCalculationRuleVersion\(\)\)\s*\.isEqualTo\("ACTUAL_DIMENSION_V1"\)/)
})
test('demo package freezes repeated label printing and Mojia dimension replacement', () => {
assert.match(labelTests, /repeatedAndPartialPrintsReadFrozenMappingWithoutReallocation/)
assert.match(labelTests, /changedCargoKeepsTheFirstFrozenBoxCodes/)
assert.match(cartonTests, /repeatedScanReplacesDeviceValuesButPreservesManualCountAndOldImageIsDeleted/)
assert.match(source, /增量 fixture 形成动态真实独立货物测量明细/)
})
test('demo package covers OCR failure, manual confirmation, aggregation and stale versions', () => {
assert.match(source, /OCR无有效重量时转人工确认/)
assert.match(source, /称重旧版本确认被拒绝且不覆盖已确认结果/)
assert.match(source, /图片张数决定托数且净重汇总已落地/)
assert.match(measurementTests, /ocrFailureCreatesManualWeightThatCanBeAdjustedAndConfirmed/)
assert.match(measurementTests, /confirmingFifthPalletSeparatelyAggregatesGrossAndCargoNetWeight/)
assert.match(measurementTests, /confirmingWithStaleVersionDoesNotTreatRequestAsIdempotent/)
})
test('demo package keeps pallet pages bounded and historical snapshots read-only', () => {
assert.match(source, /weight-pallet-options[^\n]+page=1&size=20&keyword=/)
assert.match(source, /records\.length <= 20/)
assert.match(measurementTests, /detailUsesStoredPalletSnapshotAfterCandidateBecomesUnavailable/)
})
test('opt-in HTTP acceptance verifies whole-ticket slot identity and delete-to-empty semantics', () => {
assert.match(source, /verifyPalletLocationGuide/)
assert.match(source, /expectedWeightResultIds\.every/)
assert.match(source, /asId\(row\.reservationId\) === asId\(slot\.reservationId\)/)
assert.match(source, /逐张确认后回查整票库位块/)
assert.match(source, /扩容只追加且既有槽身份不漂移/)
assert.match(source, /verified\.slots\.length >= previous\.slots\.length && priorSlotsStable/)
assert.match(source, /\['RESERVED_EMPTY', 'BOUND', 'TRANSFERRED', 'RELEASED'\]/)
assert.match(source, /deleteSucceeded/)
assert.match(source, /retainedSlot\?\.slotStatus === 'RESERVED_EMPTY'/)
assert.match(source, /recreateConfirmedWeightEvidence/)
assert.match(source, /reboundSlot\?\.slotStatus === 'BOUND'/)
assert.match(source, /replacementWeightResultId/)
assert.match(source, /不批量停用普通库位制造容量不足/)
})
test('approval freezes measurement and requires quantity weight and volume conservation', () => {
assert.match(source, /审核及合托完成后箱码尺寸与图片快照不可再覆盖/)
assert.match(measurementTests, /approvedMeasurementCannotBeResubmittedOrMutateFrozenTotals/)
assert.match(reviewTests, /shouldApproveMultipleCargoLinesOnlyWhenAllFrozenTotalsMatch/)
assert.match(reviewTests, /shouldRejectApprovalWhenVolumeSnapshotDoesNotConserve/)
assert.match(source, /actualPackageCount[^\n]+originalPackageCount/)
assert.match(source, /actualGrossWeightKg[^\n]+weightEvidence\.grossWeightKg/)
assert.match(source, /actualNetWeightKg[^\n]+weightEvidence\.netWeightKg/)
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, /cartons\/resolve/)
assert.match(source, /cartons\/count/)
assert.match(source, /pallets\/create-and-bind/)
assert.match(source, /系统发码重放不新增托盘且业务码和计数稳定/)
assert.match(source, /拒绝创建没有空托或计数漂移/)
assert.doesNotMatch(source, /palletHash|palletDate/)
assert.match(source, /pallets\/\$\{palletId\}\/seal/)
assert.match(source, /重复清点操作按operationId幂等返回/)
assert.doesNotMatch(source, /pallets\/open/)
assert.doesNotMatch(source, /pallets\/\$\{palletId\}\/scan/)
assert.match(source, /dropship \? \['WAIT_PALLETIZE'\] : \['WAIT_SPLIT'\]/)
assert.match(source, /一件代发合托完成后进入智能分柜门禁/)
})
test('confirmed package count reconciles an uncertain transport result before retrying', () => {
assert.match(source, /async function updateConfirmedPackageCount/)
assert.match(source, /recoveredFromTransportFailure: true/)
assert.match(source, /Number\(detail\?\.version\) > Number\(body\.measurementVersion\)/)
assert.match(source, /await updateConfirmedPackageCount\(context, measurementPath/)
})
async function exerciseSystemPalletScenario(fault = '') {
const task = { taskId: '81', inboundId: '82', warehouseId: '83', taskStatus: 'CLAIMED',
totalCartons: 2, countedCartons: 0, boundCartons: 0, unboundCartons: 0, pallets: [] }
const seenCounts = new Map()
const seenCreates = new Set()
const checks = []
const response = (data, code = '200') => ({ http: 200, body: { code, data: structuredClone(data) } })
const context = {
marker: 'fixture-system-pallet',
apiSuccess(_module, name, result) {
assert.equal(result.body.code, '200', name)
return result.body.data
},
assert(_module, name, _response, condition) { checks.push({ name, passed: Boolean(condition) }) },
async request(method, path, body) {
if (path.includes('/pending?')) return response([task])
if (path.endsWith('/claim') || (method === 'GET' && path.includes('/tasks/81?'))) return response(task)
if (path.includes('/cartons/resolve?')) return response({ boxCode: new URL(path, 'http://fixture').searchParams.get('boxCode'), canCount: true, expectedSkuQuantity: 10 })
if (path.endsWith('/cartons/count')) {
if (seenCounts.has(body.operationId)) return seenCounts.get(body.operationId)
task.countedCartons += 1
const targetPallet = task.pallets.find(pallet => pallet.palletNo === body.palletNo)
if (body.palletNo) { task.boundCartons += 1; targetPallet.cartonCount += 1; targetPallet.version += 1 }
else task.unboundCartons += 1
const result = response({ ...task, carton: { boxCode: body.boxCode, expectedSkuQuantity: 10, actualSkuQuantity: 10,
discrepancyStatus: 'MATCH' }, pallet: body.palletNo ? targetPallet : null })
seenCounts.set(body.operationId, result)
return result
}
if (path.endsWith('/create-and-bind')) {
assert.deepEqual(Object.keys(body).sort(), ['operationId', 'warehouseId'])
if (seenCreates.has(body.operationId)) {
if (fault === 'duplicate-replay') task.pallets.push({ ...task.pallets[0], palletId: '999', palletNo: 'DP-260909-0999' })
return response(task)
}
if (!task.unboundCartons) {
if (fault === 'empty-pallet') task.pallets.push({ palletId: '998', palletNo: 'DP-260909-0998', cartonCount: 0, status: 'OPEN', version: 0 })
return response(null, 'A0409')
}
seenCreates.add(body.operationId)
task.pallets.push({ palletId: '84', palletNo: 'DP-260909-0001', cartonCount: task.unboundCartons, status: 'OPEN', version: 0 })
task.boundCartons += task.unboundCartons
task.unboundCartons = 0
return response(task)
}
if (path.endsWith('/84/seal')) {
task.taskStatus = 'COMPLETED'
task.pallets.forEach(pallet => { pallet.status = 'SEALED'; pallet.version += 1 })
return response(task)
}
throw new Error(`Unexpected scenario request: ${method} ${path}`)
},
}
const sealed = await completeDropshipPalletization(context, { inboundId: '82', inboundCode: 'CODE', warehouseId: '83', measurement: { actualPackageCount: 2 } })
assert.deepEqual(sealed.sealedCartonMarks, ['CODE#2-1', 'CODE#2-2'])
assert.deepEqual(sealed.sealedSourcePalletNos, ['DP-260909-0001'])
return checks
}
test('system-issued pallet HTTP scenario covers count, replay, empty rejection and completed replay', async () => {
const checks = await exerciseSystemPalletScenario()
assert.ok(checks.length >= 15)
assert.deepEqual(checks.filter(check => !check.passed), [])
})
test('system-issued pallet HTTP regression detects duplicate replay and orphan empty pallets', async () => {
const replayChecks = await exerciseSystemPalletScenario('duplicate-replay')
assert.ok(replayChecks.some(check => check.name.includes('系统发码重放不新增托盘') && !check.passed))
const emptyChecks = await exerciseSystemPalletScenario('empty-pallet')
assert.ok(emptyChecks.some(check => check.name.includes('拒绝创建没有空托或计数漂移') && !check.passed))
})