test: extend eight-business acceptance flows and offline contracts

This commit is contained in:
2026-10-22 15:41:50 +08:00
parent 86889d7e0e
commit 080ca600e6
33 changed files with 1285 additions and 101 deletions
@@ -151,6 +151,39 @@ async function createRelabel(context, io, proof) {
Object.assign(fixture, { dispatchNo: created.dispatchNo, finalStatus: current.data.status, stage: current.data.stage, data: current.data })
proof.relabel = { dispatchNo: created.dispatchNo, status: 'CREATED_BEFORE_LOADING', sourceKeys: candidates.map(c => c.sourceKey), cartonMarksVerification: 'NOT_RUN_PUBLIC_DETAIL_OMITS_MARKS' }
}
/** 客户首页贴标原申请独立排车;不可借用旧PDA换标样本的通过结果。 */
export async function createClientRelabelDispatch(context, io, proof) {
const fixture = context.createdResources?.phase4OverseasClientServices?.relabelFulfillment
io.check('客户贴标排车前置为本轮已确认原申请', null, fixture?.marker === context.marker
&& fixture.status === 'READY_FOR_OUTBOUND' && fixture.execution?.status === 'HTTP_VERIFIED_READY_FOR_DISPATCH'
&& fixture.relabelNo && fixture.customerId && fixture.warehouseId && fixture.targetPalletIds?.length > 0
&& new Set(fixture.targetPalletIds.map(id)).size === fixture.targetPalletIds.length && !fixture.dispatchNo && !proof.clientRelabel)
const evidence = proof.clientRelabel = { marker: context.marker, relabelNo: fixture.relabelNo, status: 'CREATING' }
try {
const candidates = (await candidatePage(io, fixture.warehouseId,
{ orderNo: fixture.relabelNo, sourceStage: 'RELABEL', planIds: [] }))
.filter(c => c.selection?.sourceType === 'RELABEL' && c.selection.relabelNo === fixture.relabelNo
&& id(c.customerId) === id(fixture.customerId) && id(c.warehouseId) === id(fixture.warehouseId))
io.check('客户原申请目标托盘候选完整且唯一', null, candidates.length === fixture.targetPalletIds.length
&& new Set(candidates.map(c => id(c.selection.warehousePalletId))).size === candidates.length
&& candidates.every(c => fixture.targetPalletIds.map(id).includes(id(c.selection.warehousePalletId))))
const body = createBody(context.marker, 'CLIENT-RELABEL', candidates)
evidence.createRequest = body
const created = await io.command('POST', BASE, body, '客户贴标原申请创建独立排车')
io.check('客户原申请排车返回业务单号', null, typeof created?.dispatchNo === 'string' && created.dispatchNo.length > 0)
evidence.dispatchNo = created.dispatchNo
await replay(io, BASE, body, created, '客户原贴标申请排车创建重放')
const current = await readDispatch(io, created.dispatchNo)
io.check('客户贴标排车逐行匹配原申请实托与箱数', null, dispatchMatches(current, candidates))
Object.assign(fixture, { dispatchNo: created.dispatchNo, dispatchStage: current.data.stage })
Object.assign(evidence, { status: 'CREATED_BEFORE_LOADING', sourceKeys: candidates.map(c => c.sourceKey) })
await context.checkpoint()
} catch (error) {
evidence.status = 'FAILED'; evidence.failure = error.message
await context.checkpoint(); throw error
}
}
export async function run(context) {
context.createdResources ??= {}
if (context.createdResources.phase4OverseasDispatch?.requests?.some(r => !['GET', 'HEAD'].includes(r.method))) throw Error('本轮排车已经尝试写入,须审核原回执,禁止自动重建')
@@ -193,6 +226,7 @@ export async function run(context) {
sourceCandidates: selected, status: 'VERIFIED', loadingEvidenceStatus: 'NOT_RUN_MISSING_ACTUAL_MEASUREMENTS' })
io.check('交接Detail真实来源键和目的地守恒', null, same(proof.sourceKeys, sorted(selected.map(c => c.sourceKey))) && proof.finalStatus === 'ACTIVE' && proof.stage === 'BEFORE_LOADING')
await createRelabel(context, io, proof)
await createClientRelabelDispatch(context, io, proof)
await context.checkpoint()
} catch (error) {
if (error.notRun && !proof.requests.some(r => !['GET', 'HEAD'].includes(r.method))) return notRun(context, proof, error.message)