test: align container flow acceptance identities
This commit is contained in:
@@ -72,11 +72,17 @@ export async function run(context) {
|
||||
['evidenceId', 'fileId', 'status', 'downloadPath'].every((field) => photo[field] !== undefined),
|
||||
`fileId=${id(photo.fileId)}`, OPTIONS)
|
||||
const downloadPath = String(photo.downloadPath || '')
|
||||
if (photo.status === 'VOID') {
|
||||
context.assert(MODULE, `overview PDA 作废照片 ${index + 1} 无下载入口`, overviewResponse,
|
||||
!downloadPath,
|
||||
`fileId=${id(photo.fileId)}, status=${photo.status}, downloadPath=${downloadPath || 'none'}`, OPTIONS)
|
||||
continue
|
||||
}
|
||||
const controlledPath = downloadPath.startsWith('/api/')
|
||||
&& !downloadPath.startsWith('//') && !downloadPath.includes('://')
|
||||
if (!controlledPath) {
|
||||
if (photo.status !== 'ACTIVE' || !controlledPath) {
|
||||
context.assert(MODULE, `overview PDA 照片 ${index + 1} 下载路径受控`, overviewResponse, false,
|
||||
`fileId=${id(photo.fileId)}, downloadPath=${downloadPath || 'missing'}`, OPTIONS)
|
||||
`fileId=${id(photo.fileId)}, status=${photo.status || 'missing'}, downloadPath=${downloadPath || 'missing'}`, OPTIONS)
|
||||
continue
|
||||
}
|
||||
const download = await context.requestBinary('GET', downloadPath)
|
||||
|
||||
@@ -39,9 +39,14 @@ test('overview regression requires workflowStatus and distinguishes 100 percent
|
||||
assert.doesNotMatch(matrix, /PDA overview `workflowStatus` 缺失[\s\S]*BLOCKED_CONTRACT/)
|
||||
})
|
||||
|
||||
test('every overview photo uses its server-provided controlled downloadPath', () => {
|
||||
test('active overview photos download through controlled paths while void history has no download entry', () => {
|
||||
assert.match(overviewOpenApi, /\/api\/platform\/v1\/containers\/\{id\}\/pda\/photos\/\{fileId\}\/download/)
|
||||
assert.match(overviewAcceptance, /context\.requestBinary\('GET', downloadPath\)/)
|
||||
assert.match(overviewAcceptance, /photo\.status === 'VOID'/)
|
||||
assert.match(overviewAcceptance, /overview PDA 作废照片 \$\{index \+ 1\} 无下载入口/)
|
||||
assert.match(overviewAcceptance, /photo\.status !== 'ACTIVE' \|\| !controlledPath/)
|
||||
assert.match(overviewOpenApi, /status: \{type: string, enum: \[ACTIVE, VOID\]\}/)
|
||||
assert.match(overviewOpenApi, /downloadPath: \{type: string, nullable: true, description: '仅 ACTIVE 照片提供鉴权下载路径;VOID 历史照片为空'\}/)
|
||||
assert.equal(controlledPhotoDownload('/api/platform/v1/containers/7/pda/photos/23/download', {
|
||||
http: 200, bytes: new Uint8Array([1]), contentType: 'image/png',
|
||||
}), true)
|
||||
|
||||
@@ -393,7 +393,7 @@ export async function run(context) {
|
||||
`HTTP=${staleBatch.http}, code=${codeOf(staleBatch)}`, OPTIONS)
|
||||
|
||||
const beforeInvalidTaskResponse = await context.request('GET',
|
||||
`${pdaBase}/tasks?containerNo=${encodeURIComponent(containerNo)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
`${pdaBase}/tasks?loadingPlanId=${encodeURIComponent(loadingPlanId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const beforeInvalidTask = context.apiSuccess(MODULE, '非法混合批次前读取 PDA 全量任务基线',
|
||||
beforeInvalidTaskResponse, '', OPTIONS)
|
||||
const beforeInvalidOperationsResponse = await context.request('GET', `${pdaBase}/tasks/${canonicalTaskId}/operations`)
|
||||
@@ -409,7 +409,7 @@ export async function run(context) {
|
||||
invalidBatch.http === 200 && codeOf(invalidBatch) === 'A0409',
|
||||
`HTTP=${invalidBatch.http}, code=${codeOf(invalidBatch)}`, OPTIONS)
|
||||
const unchangedAfterInvalidResponse = await context.request('GET',
|
||||
`${pdaBase}/tasks?containerNo=${encodeURIComponent(containerNo)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
`${pdaBase}/tasks?loadingPlanId=${encodeURIComponent(loadingPlanId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const unchangedAfterInvalid = context.apiSuccess(MODULE, '回查失败批次后的 PDA 任务快照', unchangedAfterInvalidResponse, '', OPTIONS)
|
||||
const afterInvalidOperationsResponse = await context.request('GET', `${pdaBase}/tasks/${canonicalTaskId}/operations`)
|
||||
const afterInvalidOperations = context.apiSuccess(MODULE, '非法混合批次后回查 PDA 操作历史',
|
||||
@@ -492,7 +492,7 @@ export async function run(context) {
|
||||
}
|
||||
}
|
||||
const beforeMutationTaskResponse = await context.request('GET',
|
||||
`${pdaBase}/tasks?containerNo=${encodeURIComponent(containerNo)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
`${pdaBase}/tasks?loadingPlanId=${encodeURIComponent(loadingPlanId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const beforeMutationTask = context.apiSuccess(MODULE, '库存变化前读取 PDA 任务基线', beforeMutationTaskResponse, '', OPTIONS)
|
||||
const beforeMutationOperationsResponse = await context.request('GET', `${pdaBase}/tasks/${canonicalTaskId}/operations`)
|
||||
const beforeMutationOperations = context.apiSuccess(MODULE, '库存变化前读取 PDA 操作历史基线',
|
||||
@@ -519,7 +519,7 @@ export async function run(context) {
|
||||
`HTTP=${staleInventoryBatch.http}, code=${codeOf(staleInventoryBatch)}, message=${staleInventoryBatch.body?.message || 'missing'}`, OPTIONS)
|
||||
|
||||
const afterStaleTaskResponse = await context.request('GET',
|
||||
`${pdaBase}/tasks?containerNo=${encodeURIComponent(containerNo)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
`${pdaBase}/tasks?loadingPlanId=${encodeURIComponent(loadingPlanId)}&warehouseId=${encodeURIComponent(warehouseId)}`)
|
||||
const afterStaleTask = context.apiSuccess(MODULE, '旧库存快照冲突后回查 PDA 任务', afterStaleTaskResponse, '', OPTIONS)
|
||||
const afterStaleOperationsResponse = await context.request('GET', `${pdaBase}/tasks/${canonicalTaskId}/operations`)
|
||||
const afterStaleOperations = context.apiSuccess(MODULE, '旧库存快照冲突后回查 PDA 操作历史',
|
||||
|
||||
@@ -301,6 +301,8 @@ test('phase3 loading proves mixed-line rollback across task, all items and opera
|
||||
])
|
||||
assert.match(loading, /taskItemsSignature\(unchangedAfterInvalid\) === taskItemsSignature\(beforeInvalidTask\)/)
|
||||
assert.match(loading, /operationsSignature\(afterInvalidOperations\) === operationsSignature\(beforeInvalidOperations\)/)
|
||||
assert.doesNotMatch(loading, /tasks\?containerNo=/)
|
||||
assert.equal((loading.match(/tasks\?loadingPlanId=/g) || []).length >= 7, true)
|
||||
})
|
||||
|
||||
test('phase3 loading proves stale inventory zero-write for all items and completion audit', () => {
|
||||
@@ -362,6 +364,9 @@ test('downstream producers prefer the phase3Loading container fixture', () => {
|
||||
assert.doesNotMatch(ocean, /`\$\{context\.marker\}-\$\{endpoint\}`/)
|
||||
assert.match(ocean, /`\$\{context\.marker\}-ocean-\$\{endpoint\}`/)
|
||||
assert.match(serviceCenter, /if \(!allocationMatches\) return/)
|
||||
assert.match(serviceCenter, /const customerName = String\(oceanDetail\?\.oceanBooking\?\.customerName \|\| ''\)\.trim\(\)/)
|
||||
assert.match(serviceCenter, /customerId, customerName, carrierId: null/)
|
||||
assert.doesNotMatch(serviceCenter, /customerName: `服务中心链路客户-/)
|
||||
const schedules = source('./phase3-port-schedules.mjs')
|
||||
assert.match(schedules, /allocatedContainerBookingIds: \(detail\.containerAllocations \|\| \[\]\)/)
|
||||
assert.match(schedules, /ocean\.allocatedContainerBookingIds\?\.includes\(containerBookingId\)/)
|
||||
|
||||
@@ -49,8 +49,11 @@ export async function run(context) {
|
||||
const oceanResponse = await context.request('GET', `${OCEAN}/${ocean.id}`)
|
||||
const oceanDetail = context.apiSuccess(MODULE, '读取跨服务链路订舱真实客户归属', oceanResponse, `oceanBookingId=${ocean.id}`, OPTIONS)
|
||||
const customerId = id(oceanDetail?.oceanBooking?.customerId)
|
||||
context.assert(MODULE, '跨服务链路订舱客户归属有效', oceanResponse, Boolean(customerId), `customerId=${customerId || 'missing'}`, OPTIONS)
|
||||
if (!customerId) return
|
||||
const customerName = String(oceanDetail?.oceanBooking?.customerName || '').trim()
|
||||
context.assert(MODULE, '跨服务链路订舱客户归属有效', oceanResponse,
|
||||
Boolean(customerId) && Boolean(customerName),
|
||||
`customerId=${customerId || 'missing'}, customerName=${customerName || 'missing'}`, OPTIONS)
|
||||
if (!customerId || !customerName) return
|
||||
const linkContainer = (containerFlow?.finalStatus === 'COMPLETED' || containerFlow?.finalStatus === 'LOADED')
|
||||
&& id(containerFlow?.tenantId) === customerId
|
||||
&& Boolean(containerFlow?.containerBookingId)
|
||||
@@ -75,7 +78,7 @@ export async function run(context) {
|
||||
warehouseId: linkContainer
|
||||
? id(containerFlow.warehouseId)
|
||||
: id(context.createdResources?.warehouse?.id || context.context?.warehouseId || '193000000000000001'),
|
||||
customerId, customerName: `服务中心链路客户-${suffix}`, carrierId: null, carrierName: `链路承运商-${suffix}`,
|
||||
customerId, customerName, carrierId: null, carrierName: `链路承运商-${suffix}`,
|
||||
fleetContact: '链路车队联系人', fleetPhone: '13800000007', driverName: '链路司机', driverPhone: '13800000008',
|
||||
driverIdCard: null, vehicleNo: `粤D-${suffix.slice(-6)}`, storeName: `链路门店-${suffix}`, storeContact: '链路联系人',
|
||||
storePhone: '13800000009', storeAddress: '深圳市南山区链路地址', storeCity: '深圳市', storeZipcode: '518000',
|
||||
|
||||
Reference in New Issue
Block a user