feat(phase3): 收口父子单与全链路验收
This commit is contained in:
@@ -1,11 +1,52 @@
|
||||
import { registerPendingContract } from './_phase3-pending-contract.mjs'
|
||||
const MODULE = 'phase3-outbound-aggregate'
|
||||
const OPTIONS = { scenario: 'outbound-aggregate', deploymentBlocker: true }
|
||||
const BASE = '/api/platform/v1/first-leg/outbound-dispatches'
|
||||
|
||||
function id(value) { return value == null ? '' : String(value) }
|
||||
function codeOf(response) { return response?.body?.code == null ? 'missing' : String(response.body.code) }
|
||||
function rejected(response) {
|
||||
return [400, 401, 403, 404, 409, 503].includes(response?.http)
|
||||
|| (response?.http === 200 && codeOf(response) !== '200')
|
||||
}
|
||||
function ordered(items) {
|
||||
return items.every((item, index) => index === 0
|
||||
|| String(items[index - 1]?.occurredAt || '') <= String(item?.occurredAt || ''))
|
||||
}
|
||||
|
||||
export async function run(context) {
|
||||
registerPendingContract(context, {
|
||||
module: 'phase3-outbound-aggregate', scenario: 'outbound-aggregate', name: '出仓单/柜次主聚合与整体时间线',
|
||||
reason: '出仓主聚合与整体时间线契约已实现并推送,待目标提交部署且 phase3-outbound-dispatch 真实 HTTP 通过后删除此项', category: 'deployment-validation-pending',
|
||||
fixtures: ['orders', 'phase3Loading', 'phase3ContainerLoading', 'oceanBooking', 'truckAppointment'],
|
||||
contractSource: 'PlatformOutboundDispatchController / phase3-outbound-dispatch-v1.yaml',
|
||||
assertions: ['marker 所属主单与柜次关联唯一', '时间线按真实动作有序且含审计字段', '跨客户 ID 不可见'],
|
||||
})
|
||||
const fixture = context.createdResources?.phase3OutboundDispatch
|
||||
if (!fixture?.inboundId || !fixture?.containerBookingId || fixture.marker !== context.marker) {
|
||||
context.addCoverageGap(MODULE, OPTIONS.scenario, '出仓单/柜次主聚合与整体时间线',
|
||||
'本轮未取得 phase3-outbound-dispatch 的 marker 隔离聚合,未使用历史资源', 'fixture')
|
||||
return
|
||||
}
|
||||
const selector = `inboundId=${encodeURIComponent(fixture.inboundId)}&containerBookingId=${encodeURIComponent(fixture.containerBookingId)}`
|
||||
const response = await context.request('GET', `${BASE}/detail?${selector}`)
|
||||
const detail = context.apiSuccess(MODULE, '复核出仓主聚合与统一时间线', response, selector, OPTIONS)
|
||||
const aggregate = detail?.aggregate
|
||||
const timeline = Array.isArray(detail?.timeline) ? detail.timeline : []
|
||||
const expectedModules = ['INBOUND', 'LOADING_PLAN', 'PDA_PICK', 'LOADING_EVIDENCE',
|
||||
'OCEAN_BOOKING', 'TRUCK_APPOINTMENT', 'OUTBOUND_DISPATCH']
|
||||
context.assert(MODULE, '聚合唯一关联本轮订单、入库单、柜次和客户', response,
|
||||
id(aggregate?.orderId) === id(fixture.orderId) && id(aggregate?.tenantId) === id(fixture.tenantId)
|
||||
&& id(aggregate?.inboundId) === id(fixture.inboundId)
|
||||
&& id(aggregate?.containerBookingId) === id(fixture.containerBookingId),
|
||||
`orderId=${id(aggregate?.orderId) || 'missing'}, inboundId=${id(aggregate?.inboundId) || 'missing'}, containerBookingId=${id(aggregate?.containerBookingId) || 'missing'}`, OPTIONS)
|
||||
context.assert(MODULE, '统一时间线有序且各子流程包含审计字段', response,
|
||||
timeline.length > 0 && ordered(timeline)
|
||||
&& expectedModules.every((module) => timeline.some((item) => item.module === module))
|
||||
&& timeline.every((item) => Boolean(item.action) && Boolean(item.occurredAt)),
|
||||
`timeline=${timeline.length}, modules=${[...new Set(timeline.map((item) => item.module))].join(',')}`, OPTIONS)
|
||||
|
||||
const other = context.createdResources?.phase3ContainerLoading
|
||||
if (other?.inboundId && other?.containerBookingId
|
||||
&& (id(other.inboundId) !== id(fixture.inboundId) || id(other.containerBookingId) !== id(fixture.containerBookingId))) {
|
||||
const forged = await context.request('GET', `${BASE}/detail?inboundId=${encodeURIComponent(fixture.inboundId)}&containerBookingId=${encodeURIComponent(other.containerBookingId)}`)
|
||||
context.addStep(MODULE, '伪造跨资源入库单与柜次组合不可匹配', forged, rejected(forged),
|
||||
`HTTP=${forged.http}, code=${codeOf(forged)}`, OPTIONS)
|
||||
}
|
||||
|
||||
context.addCoverageGap(MODULE, OPTIONS.scenario, '报关与船期历史并入统一时间线',
|
||||
'当前 OutboundDispatchReadMapper 时间线仅聚合入库、装柜计划、PDA、证据、订舱、拖车和出仓历史,未公开报关与船期历史投影',
|
||||
'contract-gap')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user