This commit is contained in:
2026-08-13 09:51:27 +08:00
parent 95849f248f
commit af75569c78
4 changed files with 33 additions and 14 deletions
@@ -397,7 +397,7 @@ export async function run(context) {
const finalResponse = await context.request('GET', measurementPath)
const finalMeasurement = context.apiSuccess(MODULE, '查询审核后的最终测量状态', finalResponse, '', OPTIONS)
context.assert(MODULE, '审核后入库与测量状态闭环且结果未变化', finalResponse,
finalMeasurement?.processStatus === 'INBOUNDED' && finalMeasurement?.measureReviewStatus === 'APPROVED'
finalMeasurement?.processStatus === 'WAIT_SPLIT' && finalMeasurement?.measureReviewStatus === 'APPROVED'
&& finalMeasurement?.measurementStatus === 'APPROVED'
&& Number(finalMeasurement?.actualPackageCount) === originalPackageCount
&& closeTo(finalMeasurement?.actualVolumeCbm, totalVolume)
@@ -24,10 +24,10 @@ test('所有写入均走订单生命周期 HTTP API 且不清理保留数据', (
assert.doesNotMatch(source, /cleanup|remove|unlink/i)
})
test('入库通过真实订单测量链保留四个测量态和 INBOUNDED', () => {
test('入库通过真实订单测量链保留测量态并最终进入 WAIT_SPLIT', () => {
assert.match(source, /result\.inbounds\.WAIT_MEASURE/)
assert.match(source, /processStatus: 'WAIT_MEASURE'/)
for (const status of ['MEASURING', 'MEASURE_PENDING', 'MEASURE_REJECTED', 'INBOUNDED']) {
for (const status of ['MEASURING', 'MEASURE_PENDING', 'MEASURE_REJECTED', 'WAIT_SPLIT']) {
assert.match(source, new RegExp(`'${status}'`))
}
assert.match(source, /\.\/inbound-measurement\.mjs/)
@@ -38,7 +38,9 @@ test('入库不可独立保留状态显式阻断', () => {
for (const status of ['WAIT_PRICING', 'FEE_CONFIRMING', 'INBOUNDING', 'VOIDED']) {
assert.match(source, new RegExp(`${status}:`))
}
assert.match(source, /AutomaticInboundCompletionService 在同一调用内立即从 INBOUNDING 推进 INBOUNDED/)
assert.match(source, /AutomaticInboundCompletionService 在同一调用内立即从 INBOUNDING 推进 WAIT_SPLIT/)
assert.match(source, /processStatus=INBOUNDED/)
assert.match(source, /查询存量 INBOUNDED 兼容样本/)
assert.match(source, /没有作废入库单 API/)
assert.match(source, /context\.assert\(MODULE, `入库列表保留 \$\{status\}`/)
})
@@ -49,7 +51,7 @@ test('统一订单声明合法可达状态并显式阻断废弃或无 API 状态
for (const status of ['INBOUNDED', 'WAIT_SPLIT', 'LOADING', 'LOADED', 'DELIVERED']) {
assert.match(source, new RegExp(`'${status}'`))
}
assert.match(source, /WAIT_SPLIT 标记为历史废弃状态/)
assert.doesNotMatch(source, /WAIT_SPLIT 标记为历史废弃状态/)
assert.match(source, /没有完成派送并写 DELIVERED 的公开业务 API/)
})
@@ -262,31 +262,47 @@ export async function run(context, matrix = context.createdResources.manualState
id: waitMeasure.orderId, status: 'WAIT_MEASURE', detailPath: `/orders/${waitMeasure.orderId}`,
}
for (const status of ['MEASURING', 'MEASURE_PENDING', 'MEASURE_REJECTED', 'INBOUNDED']) {
for (const status of ['MEASURING', 'MEASURE_PENDING', 'MEASURE_REJECTED', 'WAIT_SPLIT']) {
const sample = await prepareInboundStatus(context, status)
result.inbounds[status] = sample
matrix.pages.inbounds.fixtures[status] = {
id: sample.inboundId, status, detailPath: `/orders/${sample.orderId}`,
}
if (status === 'INBOUNDED') {
result.unifiedOrders.INBOUNDED = sample
matrix.pages.unifiedOrders.fixtures.INBOUNDED = {
if (status === 'WAIT_SPLIT') {
result.unifiedOrders.WAIT_SPLIT = sample
matrix.pages.unifiedOrders.fixtures.WAIT_SPLIT = {
id: sample.orderId, status, detailPath: `/orders/${sample.orderId}`,
}
}
}
const legacyResponse = await context.request('GET',
`/api/platform/v1/inbounds?tenantId=${query(fixture.tenantId)}&processStatus=INBOUNDED&page=1&size=20`)
const legacyPage = context.apiSuccess(MODULE, '查询存量 INBOUNDED 兼容样本', legacyResponse, '', OPTIONS)
const legacyInbound = rows(legacyPage)[0]
if (legacyInbound?.id && legacyInbound?.orderId) {
const sample = { inboundId: id(legacyInbound.id), orderId: id(legacyInbound.orderId), tenantId: fixture.tenantId,
status: 'INBOUNDED', inboundCode: legacyInbound.inboundCode || null }
result.inbounds.INBOUNDED = sample
result.unifiedOrders.INBOUNDED = sample
matrix.pages.inbounds.fixtures.INBOUNDED = {
id: sample.inboundId, status: 'INBOUNDED', detailPath: `/orders/${sample.orderId}`,
}
matrix.pages.unifiedOrders.fixtures.INBOUNDED = {
id: sample.orderId, status: 'INBOUNDED', detailPath: `/orders/${sample.orderId}`,
}
}
const blockers = {
WAIT_PRICING: '当前审核通过 API 直接写 INBOUNDED;仅异常放行开关路径可写 WAIT_PRICING',
WAIT_PRICING: '审核通过先进入 WAIT_PRICING,但自动计费与入库编排会继续推进,不能稳定停留',
FEE_CONFIRMING: '需要先取得可匹配的真实计价快照并停在费用确认前',
INBOUNDING: 'AutomaticInboundCompletionService 在同一调用内立即从 INBOUNDING 推进 INBOUNDED,无可暂停 API',
INBOUNDING: 'AutomaticInboundCompletionService 在同一调用内立即从 INBOUNDING 推进 WAIT_SPLIT,无可暂停 API',
VOIDED: 'InboundProcessStatus 声明了 VOIDED,但当前 Controller/Service 没有作废入库单 API',
}
for (const status of INBOUND_FILTER_STATUSES) if (!matrix.pages.inbounds.fixtures[status]) {
context.assert(MODULE, `入库列表保留 ${status}`, null, false, blockers[status], OPTIONS)
}
const unifiedBlockers = {
WAIT_SPLIT: '服务端已将 WAIT_SPLIT 标记为历史废弃状态,查询时统一归一为 INBOUNDED,不能再写入或返回',
LOADING: '需要分柜、排柜及 PDA 专项独立样本',
LOADED: '需要完成装柜证据和 PDA 门禁的专项独立样本',
DELIVERED: '当前后端没有完成派送并写 DELIVERED 的公开业务 API',
@@ -45,7 +45,7 @@ export async function run(context) {
const tenantId = id(source?.tenantId)
const inboundId = id(source?.inboundId)
if (!tenantId || !inboundId || source?.marker !== context.marker) {
context.addStep(MODULE, '取得独立柜次级 INBOUNDED fixture', null, false,
context.addStep(MODULE, '取得独立柜次级 WAIT_SPLIT fixture', null, false,
`fixture marker=${source?.marker || 'missing'}, current marker=${context.marker}`, OPTIONS)
return
}
@@ -56,7 +56,8 @@ export async function run(context) {
`tenantId=${tenantId}, inboundId=${inboundId}`, OPTIONS)
const warehouseId = id(inbound?.summary?.warehouseId)
context.assert(MODULE, '柜次候选入库单状态、测量和仓库门禁有效', inboundResponse,
inbound?.summary?.processStatus === 'INBOUNDED' && inbound?.summary?.measureReviewStatus === 'APPROVED'
['WAIT_SPLIT', 'INBOUNDED'].includes(inbound?.summary?.processStatus)
&& inbound?.summary?.measureReviewStatus === 'APPROVED'
&& Boolean(warehouseId),
`status=${inbound?.summary?.processStatus || 'missing'}, review=${inbound?.summary?.measureReviewStatus || 'missing'}, warehouseId=${warehouseId || 'missing'}`, OPTIONS)
if (!warehouseId) return