test: prepare isolated gray domestic PDA H5 tasks without auto-picking

This commit is contained in:
2026-10-09 17:21:56 +08:00
parent 023b28e31f
commit 74bf0e73c5
7 changed files with 53 additions and 2 deletions
+2
View File
@@ -1,5 +1,7 @@
# Admin 测试环境 HTTP 模块
`phase5-root-fulfillment` 可由总入口显式 `--prepare-domestic-pda-h5 true` 仅准备本轮国内H5待拣任务。调用 `phase3-order-splitting.loadOneFragment` 到正式计划确认、待拣任务及箱唛就绪即返回,不领取、不拣货、不继续海外;结果固定 `PREPARED_NOT_VERIFIED`,不算全链验收。默认完整链不变,范围及授权见根脚本README。
`fleet-capacity-pool-schema-contract.test.mjs` 是离线数据库合同:验证发布与持久命令唯一约束、唯一商业履约来源、可空实际数量、服务与统一基线一致、非破坏性结构补齐及独立销售/调度权限;不访问环境、不证明真实履约已通过。
## 当前新增脚本的执行边界
@@ -136,3 +136,16 @@ test('booking fixture never invents supplier names without formal IDs', () => {
assert.doesNotMatch(source, /SPLIT-SHIPPING|SPLIT-AGENT/)
assert.doesNotMatch(source, /shippingCompanyName: `|bookingAgentName: `/)
})
test('H5 preparation stops after real labels but before claim and refuses already picked data', () => {
const checkpoint = source.indexOf('if (context.context?.prepareDomesticPdaH5)')
const claim = source.indexOf('const claim = await request', checkpoint)
assert.ok(checkpoint > source.indexOf('const labelResponse ='))
assert.ok(claim > checkpoint)
const boundary = source.slice(checkpoint, claim)
assert.match(boundary, /pickedPackageCount\) !== 0/)
assert.match(boundary, /throw new Error/)
assert.match(boundary, /return \{ preparedForH5: true/)
assert.doesNotMatch(boundary, /request\(/)
})
@@ -392,6 +392,14 @@ export async function loadOneFragment(context, state) {
`HTTP=${labelResponse.http}, contentType=${labelResponse.contentType || 'missing'}, bytes=${labelResponse.bytes?.length ?? 0}`, OPTIONS)
if (labelResponse.http !== 200 || !Number(labelResponse.bytes?.length)) return null
if (context.context?.prepareDomesticPdaH5) {
if (task?.taskStatus === 'COMPLETED' || !task.items?.length || task.items.some(row => Number(row.pickedPackageCount) !== 0))
throw new Error('H5准备只允许尚未拣货的新任务')
return { preparedForH5: true, taskId, planId, containerId, oceanBookingId,
warehouseId, sourceInboundId: id(candidate.inboundId), sourceOrderId,
containerNo: realContainerNo, taskNo: task.taskNo, items: task.items }
}
const claim = await request(context, 'POST', `${PDA}/tasks/${taskId}/claim`, {
expectedAssignmentVersion: 0, operationId: `${operationBase}-claim`,
})
@@ -400,6 +400,7 @@ async function fragment(context, source, rootOrderId, sequence) {
warehouseId: id(summary.warehouseId), warehouseName: summary.warehouseName,
sourcePackageCount: sequence === 0 ? 2 : 1, sequence,
})
if (context.context?.prepareDomesticPdaH5 && result?.preparedForH5) return result
check(context, 'F40 一箱来源通过真实 PDA 完成装柜', Boolean(result?.taskId && result?.sourceInboundId), `sequence=${sequence}`)
const current = await api(context, 'GET', '回查该片真实入仓来源',
query(`/api/platform/inbounds/${result.sourceInboundId}`, { tenantId: id(summary.tenantId) }))
@@ -618,6 +619,14 @@ async function runRootFulfillment(context) {
&& Number(scope.createdResources.inboundMeasurement.actualPackageCount) === 2, `root=${rootOrderId}`)
proof.currentStage = 'ROOT_LOAD_AND_SHIP'
const first = await fragment(scope, rootInbound, rootOrderId, 0)
if (scope.context.prepareDomesticPdaH5) {
check(scope, '国内H5待拣任务已准备且未执行拣货', first?.preparedForH5 === true && Boolean(first.taskId), 'PREPARED_NOT_VERIFIED')
proof.domesticPdaH5Fixture = first
proof.finalStatus = 'PREPARED_NOT_VERIFIED'
proof.currentStage = 'DOMESTIC_PDA_H5_READY'
proof.cleanup = 'Fresh customer/order/container/task retained for manual H5 execution; no picking, completion or overseas work executed'
return proof
}
proof.fragments.push(first)
proof.currentStage = 'REMAINDER_IDENTITY'
const tree = await api(scope, 'GET', '首柜 PDA 完成后读取正式余量树',