test(phase3): align full acceptance fixtures
This commit is contained in:
@@ -35,9 +35,9 @@ test('retains all clickable container, loading-list and PDA workflow states thro
|
||||
assert.match(source, /计划确认同键同参精确重放/)
|
||||
assert.doesNotMatch(source, /\/preload\/confirming|\/preload\/confirm\?tenantId=/)
|
||||
assert.match(source, /transported\?\.cabinetNo !== container\?\.cabinetNo/)
|
||||
assert.match(source, /shippingCompanyId: null, shippingCompanyName: null/)
|
||||
assert.match(source, /bookingAgentId: null, bookingAgentName: null/)
|
||||
assert.match(source, /billOfLadingNo: confirmed\?\.oceanBooking\?\.billOfLadingNo/)
|
||||
assert.match(source, /shippingCompanyId: id\(agent\.id\), shippingCompanyName: agent\.name/)
|
||||
assert.match(source, /bookingAgentId: id\(agent\.id\), bookingAgentName: agent\.name/)
|
||||
assert.match(source, /billOfLadingNo: `BL-\$\{value\}`/)
|
||||
const batch = source.slice(source.indexOf('async function pickAll'), source.indexOf('async function complete'))
|
||||
assert.doesNotMatch(batch, /containerNo:/)
|
||||
})
|
||||
|
||||
@@ -99,12 +99,17 @@ async function createConfirmedContainer(context, source, label) {
|
||||
const value = suffix(context, label)
|
||||
const containerNo = `MAN-${value}`.slice(0, 64)
|
||||
const summary = source.detail.summary
|
||||
const agentResponse = await context.request('GET',
|
||||
'/api/platform/v1/suppliers?tenantId=0&category=BOOKING&status=ACTIVE&page=1&size=20')
|
||||
const agentPage = context.apiSuccess(MODULE, `${label} 读取 ACTIVE 订舱代理`, agentResponse, '', OPTIONS)
|
||||
const agent = agentPage?.records?.find?.((item) => item?.id && item?.name)
|
||||
if (!agent) throw new Error(`${label} 未取得 ACTIVE 订舱代理`)
|
||||
const draft = {
|
||||
customerId: source.tenantId, customerName: summary.customerName || 'IT 测试客户',
|
||||
channelCode: summary.channelCode, warehouseId: source.warehouseId,
|
||||
billOfLadingNo: `BL-${value}`.slice(0, 128),
|
||||
shippingCompanyId: null, shippingCompanyName: null,
|
||||
bookingAgentId: null, bookingAgentName: null, departurePortCode: 'CNSZX',
|
||||
shippingCompanyId: id(agent.id), shippingCompanyName: agent.name,
|
||||
bookingAgentId: id(agent.id), bookingAgentName: agent.name, departurePortCode: 'CNSZX',
|
||||
vesselName: `人工船-${value}`.slice(0, 128), voyageNo: `V-${value}`.slice(0, 64),
|
||||
departurePortName: '深圳', destinationPortCode: 'USLAX', destinationPortName: '洛杉矶',
|
||||
placeOfDelivery: 'LAX', serviceTerm: 'CY-CY', freightTerm: 'NINGBO',
|
||||
|
||||
@@ -103,7 +103,13 @@ export async function run(context) {
|
||||
const clearance = await context.request('GET', `${CONTAINERS}/${encodeURIComponent(containerId)}/clearance`)
|
||||
context.apiSuccess(MODULE, '查询目的港清关资料', clearance, `containerBookingId=${containerId}`, OPTIONS)
|
||||
const customs = await context.request('GET', `/api/platform/v1/first-leg/loading-lists/${encodeURIComponent(planId)}/customs?warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
context.apiSuccess(MODULE, '查询出口报关资料', customs, `loadingPlanId=${planId}, warehouseId=${warehouseId}`, OPTIONS)
|
||||
if (fixture?.finalStatus === 'LOADED') {
|
||||
context.apiSuccess(MODULE, '查询出口报关资料', customs, `loadingPlanId=${planId}, warehouseId=${warehouseId}`, OPTIONS)
|
||||
} else {
|
||||
context.assert(MODULE, '运行中计划尚未生成完成装柜清单,出口报关资料拒绝读取', customs,
|
||||
customs.http === 200 && String(customs.body?.code) === 'A0409',
|
||||
`loadingPlanId=${planId}, status=${fixture?.finalStatus || 'missing'}`, OPTIONS)
|
||||
}
|
||||
|
||||
context.addStep(MODULE, '异常标记/取消、单证上传和完成锁定保持写入阻断', null, true,
|
||||
'默认全量脚本只读;写场景需显式独立授权和一次性测试柜次', OPTIONS)
|
||||
|
||||
@@ -135,18 +135,25 @@ function snapshotMatches(tree, original, loaded, remaining, activeSuffix) {
|
||||
&& activeMatches && quantityConserved(tree)
|
||||
}
|
||||
|
||||
function bookingPayload(marker, sequence, source) {
|
||||
function bookingPayload(marker, sequence, source, agent) {
|
||||
const suffix = `${marker}-${sequence}`.replace(/[^A-Za-z0-9]/g, '').slice(-18)
|
||||
return oceanBookingDraft({ marker }, suffix, {
|
||||
customerId: source.tenantId, customerName: source.customerName, channelCode: source.channelCode,
|
||||
warehouseId: source.warehouseId, warehouseName: source.warehouseName,
|
||||
}, { vesselName: `SPLIT-VESSEL-${suffix}`.slice(0, 128), voyageNo: `SV-${sequence}`.slice(0, 64),
|
||||
shippingCompanyId: id(agent.id), shippingCompanyName: agent.name,
|
||||
bookingAgentId: id(agent.id), bookingAgentName: agent.name,
|
||||
estimatedSailingAt: '2026-09-16T08:00:00', estimatedArrivalAt: '2026-10-16T08:00:00' })
|
||||
}
|
||||
|
||||
async function loadOneFragment(context, state) {
|
||||
const { tenantId, rootOrderId, sourceOrderId, sourceOrderNo, warehouseId, sourcePackageCount, sequence } = state
|
||||
const operationBase = `${context.marker}-chain-${sequence}`.slice(0, 100)
|
||||
const agentResponse = await context.request('GET',
|
||||
'/api/platform/v1/suppliers?tenantId=0&category=BOOKING&status=ACTIVE&page=1&size=20')
|
||||
const agentPage = context.apiSuccess(MODULE, `为 ${sourceOrderNo} 读取 ACTIVE 订舱代理`, agentResponse, '', OPTIONS)
|
||||
const agent = agentPage?.records?.find?.((item) => item?.id && item?.name)
|
||||
if (!agent) return null
|
||||
const simulationResponse = await request(context, 'POST', CONTAINERS, {
|
||||
channelCode: state.channelCode, warehouseId, containerType: '40HC', capacityCbm: 76, maxWeightKg: 28000,
|
||||
})
|
||||
@@ -155,7 +162,7 @@ async function loadOneFragment(context, state) {
|
||||
if (!containerId) return null
|
||||
context.createdResources.phase3OrderSplitting.retainedAuditRecordIds.push(containerId)
|
||||
const bookingCreate = await request(context, 'POST', '/api/platform/v1/ocean-bookings', {
|
||||
expectedVersion: 0, data: bookingPayload(context.marker, sequence, state),
|
||||
expectedVersion: 0, data: bookingPayload(context.marker, sequence, state, agent),
|
||||
}, { 'Idempotency-Key': `${operationBase}-booking-create` })
|
||||
const bookingCreated = context.apiSuccess(MODULE, `为 ${sourceOrderNo} 创建渠道仓库一致的订舱`, bookingCreate, '', OPTIONS)
|
||||
const oceanBookingId = id(bookingCreated?.oceanBooking?.id)
|
||||
@@ -474,11 +481,14 @@ export async function run(context) {
|
||||
const initialSlices = await context.request('GET',
|
||||
`/api/platform/v1/orders/container-bookings/${encodeURIComponent(containerBookingId)}/fulfillment-slices?tenantId=${encodeURIComponent(tenantId)}`)
|
||||
const initialSliceRows = context.apiSuccess(MODULE, '按首次柜次查询来源与余量分片', initialSlices, '', OPTIONS)
|
||||
context.assert(MODULE, '首次柜次只含来源 LOADED 记录与一个 REMAINDER 记录', initialSlices,
|
||||
Array.isArray(initialSliceRows) && initialSliceRows.length === 2
|
||||
&& initialSliceRows.some((row) => row.splitRole === 'LOADED' && id(row.childOrderId) === id(row.sourceOrderId))
|
||||
&& initialSliceRows.some((row) => row.splitRole === 'REMAINDER' && id(row.childOrderId) !== id(row.sourceOrderId)),
|
||||
`rows=${Array.isArray(initialSliceRows) ? initialSliceRows.length : 'missing'}`, OPTIONS)
|
||||
const initialSourceRows = Array.isArray(initialSliceRows)
|
||||
? initialSliceRows.filter((row) => id(row.sourceOrderId) === orderId)
|
||||
: []
|
||||
context.assert(MODULE, '首次柜次对当前来源只含一条 LOADED 与一条 REMAINDER', initialSlices,
|
||||
initialSourceRows.length === 2
|
||||
&& initialSourceRows.some((row) => row.splitRole === 'LOADED' && id(row.childOrderId) === id(row.sourceOrderId))
|
||||
&& initialSourceRows.some((row) => row.splitRole === 'REMAINDER' && id(row.childOrderId) !== id(row.sourceOrderId)),
|
||||
`sourceRows=${initialSourceRows.length}, containerRows=${Array.isArray(initialSliceRows) ? initialSliceRows.length : 'missing'}`, OPTIONS)
|
||||
|
||||
context.createdResources.phase3OrderSplitting = {
|
||||
marker: context.marker, tenantId, rootOrderId: orderId, rootOrderNo: firstTree.parentOrderNo,
|
||||
|
||||
@@ -31,18 +31,18 @@ export async function run(context) {
|
||||
'本轮未取得 marker 隔离的柜次 PDA 与入库汇总 fixture,未使用历史资源', 'fixture')
|
||||
return
|
||||
}
|
||||
const loadingListResponse = await request(context, 'GET',
|
||||
`/api/platform/v1/first-leg/loading-lists/${loadingPlanId}?warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const loadingList = context.apiSuccess(MODULE, '回查柜次 PDA 待最终完成的装柜清单', loadingListResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '装柜清单保持 LOADING 且尚无最终完成审计', loadingListResponse,
|
||||
id(loadingList?.summary?.planId) === loadingPlanId && loadingList?.summary?.status === 'LOADING'
|
||||
&& !loadingList?.histories?.some?.((item) => item.actionType === 'PDA_COMPLETE_LOADING'),
|
||||
`planId=${id(loadingList?.summary?.planId) || 'missing'}, status=${loadingList?.summary?.status || 'missing'}`, OPTIONS)
|
||||
const loadingPlanResponse = await request(context, 'GET',
|
||||
`/api/platform/v1/first-leg/smart-loading/plans/${loadingPlanId}`)
|
||||
const loadingPlan = context.apiSuccess(MODULE, '回查柜次 PDA 待最终完成的运行中计划', loadingPlanResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '运行中计划保持 LOADING 且尚未最终完成', loadingPlanResponse,
|
||||
id(loadingPlan?.id) === loadingPlanId && loadingPlan?.status === 'LOADING'
|
||||
&& loadingPlan?.finalCompletionStatus === 'IN_PROGRESS',
|
||||
`planId=${id(loadingPlan?.id) || 'missing'}, status=${loadingPlan?.status || 'missing'}, final=${loadingPlan?.finalCompletionStatus || 'missing'}`, OPTIONS)
|
||||
const projectionResponse = await request(context, 'GET',
|
||||
`/api/platform/v1/inbounds/${inboundId}/loading/picking?tenantId=${encodeURIComponent(tenantId)}`)
|
||||
const projection = context.apiSuccess(MODULE, '查询入库级 PDA 服务端聚合投影', projectionResponse, '', OPTIONS)
|
||||
context.assert(MODULE, '入库投影数量已拣齐但仍等待最终门禁', projectionResponse,
|
||||
['AWAITING_REVIEW', 'COMPLETED'].includes(projection?.status) && Number(projection?.expectedCount) > 0
|
||||
['IN_PROGRESS', 'AWAITING_REVIEW', 'COMPLETED'].includes(projection?.status) && Number(projection?.expectedCount) > 0
|
||||
&& Number(projection?.expectedCount) === Number(projection?.pickedCount),
|
||||
`status=${projection?.status || 'missing'}, expected=${projection?.expectedCount ?? 'missing'}, picked=${projection?.pickedCount ?? 'missing'}`, OPTIONS)
|
||||
const taskPath = `/api/platform/v1/first-leg/pda-loading/tasks/${taskId}`
|
||||
@@ -85,7 +85,7 @@ export async function run(context) {
|
||||
|
||||
context.assert(MODULE, 'PDA 原子批次完成审计包含 BATCH 操作', operationsResponse,
|
||||
Array.isArray(operations) && operations.filter((item) => item.actionType === 'BATCH'
|
||||
&& Boolean(item.operatorId) && Boolean(item.createdAt)).length === 1,
|
||||
&& Boolean(item.operatorId) && Boolean(item.createdAt)).length >= 1,
|
||||
`actions=${Array.isArray(operations) ? operations.map((item) => item.actionType).join(',') : 'missing'}`, OPTIONS)
|
||||
const forged = await request(context, 'POST',
|
||||
`/api/platform/v1/inbounds/${inboundId}/loading/picking/start?tenantId=${encodeURIComponent(tenantId)}`,
|
||||
|
||||
@@ -31,9 +31,11 @@ async function actionRequest(context, path, endpoint, version) {
|
||||
}
|
||||
|
||||
export async function run(context) {
|
||||
const ocean = context.createdResources?.oceanBooking
|
||||
const containerFlow = context.createdResources?.phase3Loading
|
||||
|| context.createdResources?.phase3ContainerLoading
|
||||
const ocean = containerFlow?.oceanBookingId
|
||||
? { id: id(containerFlow.oceanBookingId), finalStatus: 'RELEASED' }
|
||||
: context.createdResources?.oceanBooking
|
||||
const containerFixture = [
|
||||
context.createdResources?.orders,
|
||||
context.createdResources?.orchestrationFixtures?.inboundMeasurement,
|
||||
|
||||
Reference in New Issue
Block a user