优化
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import { dirname, resolve } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const SCENARIO = 'mojia-measurement'
|
||||
const DEFAULT_IMAGE = resolve(
|
||||
dirname(fileURLToPath(import.meta.url)), '..', '..', 'apps', 'pda-uniapp', 'static', 'c7.png')
|
||||
|
||||
function success(response) {
|
||||
return response?.http === 200 && String(response?.body?.code) === '200'
|
||||
}
|
||||
|
||||
function data(response) {
|
||||
return response?.body?.data ?? null
|
||||
}
|
||||
|
||||
function record(run, name, response, passed, evidence = '') {
|
||||
return run.addStep(SCENARIO, name, response, passed, evidence)
|
||||
}
|
||||
|
||||
function responseOf(http, body, raw = null) {
|
||||
return {
|
||||
method: 'POST',
|
||||
path: null,
|
||||
http,
|
||||
body,
|
||||
raw,
|
||||
requestId: body?.requestId ?? null,
|
||||
traceId: body?.traceId ?? null,
|
||||
}
|
||||
}
|
||||
|
||||
async function multipartRequest(run, path, fields, imagePath) {
|
||||
const form = new FormData()
|
||||
form.set('data', JSON.stringify(fields))
|
||||
form.set('image', new Blob([await readFile(imagePath)], { type: 'image/png' }), 'mojia-e2e.png')
|
||||
try {
|
||||
const response = await fetch(`${run.options.gateway}${path}`, {
|
||||
method: 'POST',
|
||||
headers: { Accept: 'application/json', Authorization: `Bearer ${run.token}` },
|
||||
body: form,
|
||||
signal: AbortSignal.timeout(30_000),
|
||||
})
|
||||
const text = await response.text()
|
||||
let body = null
|
||||
try { body = text ? JSON.parse(text) : null } catch { /* Keep raw response for the report. */ }
|
||||
return {
|
||||
method: 'POST', path, http: response.status, body,
|
||||
raw: body === null ? text.slice(0, 500) : null,
|
||||
requestId: body?.requestId ?? response.headers.get('x-request-id'),
|
||||
traceId: body?.traceId ?? response.headers.get('x-trace-id'),
|
||||
}
|
||||
} catch (error) {
|
||||
return responseOf(0, null, error instanceof Error ? error.message : String(error))
|
||||
}
|
||||
}
|
||||
|
||||
function requireData(run, name, response, evidence = '') {
|
||||
record(run, name, response, success(response) && data(response) !== null, evidence)
|
||||
if (!success(response) || data(response) === null) {
|
||||
throw new Error(`${name} failed: code=${response?.body?.code}, message=${response?.body?.message}`)
|
||||
}
|
||||
return data(response)
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the internal platform simulation for the MoJia carton measurement flow.
|
||||
* The final external MoJia key/signature contract is intentionally not defined here.
|
||||
*
|
||||
* @param {object} run Existing AcceptanceRun instance from admin-test-env-acceptance.mjs.
|
||||
* @param {object} [options]
|
||||
* @param {string|number} [options.tenantId] Customer scope for selecting the test inbound.
|
||||
* @param {string|number} [options.inboundId] Explicit WAIT_MEASURE inbound, preferred for CI.
|
||||
* @param {string} [options.imagePath] PNG/JPG evidence image path.
|
||||
*/
|
||||
export async function runMojiaMeasurementScenario(run, options = {}) {
|
||||
const tenantId = options.tenantId ?? process.env.MOJIA_TEST_TENANT_ID
|
||||
const imagePath = options.imagePath ?? process.env.MOJIA_TEST_IMAGE ?? DEFAULT_IMAGE
|
||||
let inboundId = options.inboundId ?? process.env.MOJIA_TEST_INBOUND_ID
|
||||
|
||||
if (!tenantId && !inboundId) {
|
||||
const response = responseOf(0, { code: 'DEPLOYMENT_BLOCKED', message: '缺少墨家测试 tenantId 或 inboundId' })
|
||||
record(run, '墨家测量测试数据配置', response, false, '请传入 MOJIA_TEST_TENANT_ID 或 MOJIA_TEST_INBOUND_ID')
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
if (!inboundId) {
|
||||
const response = await run.request(
|
||||
'GET', '/api/platform/inbounds?processStatus=WAIT_MEASURE&page=1&size=200')
|
||||
const rows = requireData(run, '查找墨家 WAIT_MEASURE 入库单', response)
|
||||
const candidate = rows.records?.find((row) => String(row.tenantId) === String(tenantId)
|
||||
&& row.totalPackageCount == null)
|
||||
if (!candidate) {
|
||||
record(run, '墨家测量测试数据配置', response, false,
|
||||
`tenantId=${tenantId} 下没有未冻结总箱数的 WAIT_MEASURE 入库单`)
|
||||
return false
|
||||
}
|
||||
inboundId = String(candidate.id)
|
||||
}
|
||||
|
||||
const detailPath = `/api/platform/inbounds/${inboundId}?tenantId=${tenantId}`
|
||||
const detailResponse = await run.request('GET', detailPath)
|
||||
const detail = requireData(run, '查询墨家测试入库单', detailResponse, `inboundId=${inboundId}`)
|
||||
const summary = detail.summary
|
||||
if (summary.processStatus !== 'WAIT_MEASURE' || summary.totalPackageCount != null) {
|
||||
record(run, '墨家测试入库单状态校验', detailResponse, false,
|
||||
`processStatus=${summary.processStatus}, totalPackageCount=${summary.totalPackageCount}`)
|
||||
return false
|
||||
}
|
||||
const resolvedTenantId = String(summary.tenantId ?? tenantId)
|
||||
|
||||
const printPath = `/api/platform/inbounds/${inboundId}/carton-label-pdf?tenantId=${resolvedTenantId}`
|
||||
const printResponse = await run.requestBinary('POST', printPath)
|
||||
record(run, '墨家测试生成稳定箱唛 PDF', printResponse,
|
||||
printResponse.http === 200 && printResponse.bytes?.length > 0
|
||||
&& printResponse.contentType?.toLowerCase().includes('application/pdf'),
|
||||
`inboundId=${inboundId}, bytes=${printResponse.bytes?.length ?? 0}`)
|
||||
|
||||
const afterPrintResponse = await run.request('GET', detailPath)
|
||||
const afterPrint = requireData(run, '回查墨家稳定箱号总数', afterPrintResponse)
|
||||
const printedTotal = Number(afterPrint.summary.totalPackageCount)
|
||||
if (!Number.isInteger(printedTotal) || printedTotal < 1) {
|
||||
throw new Error('打印后没有冻结原始总箱数')
|
||||
}
|
||||
const boxCode = `${afterPrint.summary.inboundCode}#${printedTotal}-1`
|
||||
const scanPath = `/api/platform/v1/first-leg/inbounds/${inboundId}/measurement/carton-scans?tenantId=${resolvedTenantId}`
|
||||
const firstFields = {
|
||||
boxCode, length: 60.1, width: 40.2, height: 30.3, weight: 12.5,
|
||||
machineNo: 'MJ-ADMIN-E2E-01', measuredAt: '2026-08-08T10:00:00',
|
||||
}
|
||||
const firstResponse = await multipartRequest(run, scanPath, firstFields, imagePath)
|
||||
const first = requireData(run, '墨家单箱首次测量上传', firstResponse, `boxCode=${boxCode}`)
|
||||
const firstPassed = first.created === true && first.confirmedPackageCount === 1
|
||||
&& String(first.boxCode) === boxCode
|
||||
record(run, '墨家单箱首次记录语义', firstResponse, firstPassed,
|
||||
`itemId=${first.itemId}, measurementId=${first.measurementId}`)
|
||||
if (!firstPassed) throw new Error('首次扫描没有创建单箱记录或默认箱数不是 1')
|
||||
|
||||
const countPath = `/api/platform/v1/first-leg/inbounds/${inboundId}/measurement/items/${first.itemId}/confirmed-package-count?tenantId=${resolvedTenantId}`
|
||||
const countResponse = await run.request('PUT', countPath, {
|
||||
measurementVersion: first.measurementVersion,
|
||||
confirmedPackageCount: printedTotal,
|
||||
})
|
||||
const counted = requireData(run, '人工确认墨家单箱代表箱数', countResponse,
|
||||
`confirmedPackageCount=${printedTotal}`)
|
||||
if (counted.confirmedPackageCount !== printedTotal) {
|
||||
throw new Error('人工确认箱数回显不一致')
|
||||
}
|
||||
|
||||
const rescanResponse = await multipartRequest(run, scanPath, {
|
||||
boxCode, length: 61.1, width: 41.2, height: 31.3, weight: 13.5,
|
||||
machineNo: 'MJ-ADMIN-E2E-02', measuredAt: '2026-08-08T10:01:00',
|
||||
}, imagePath)
|
||||
const rescan = requireData(run, '墨家同箱复测覆盖', rescanResponse)
|
||||
const rescanPassed = rescan.created === false
|
||||
&& String(rescan.itemId) === String(first.itemId)
|
||||
&& rescan.confirmedPackageCount === printedTotal
|
||||
&& Number(rescan.lengthCm) === 61.1
|
||||
record(run, '墨家同箱复测保留人工箱数', rescanResponse, rescanPassed,
|
||||
`itemId=${rescan.itemId}, confirmedPackageCount=${rescan.confirmedPackageCount}`)
|
||||
if (!rescanPassed) throw new Error('同箱复测没有覆盖设备值或覆盖人工箱数')
|
||||
|
||||
const submitPath = `/api/platform/v1/first-leg/inbounds/${inboundId}/measurement/submit?tenantId=${resolvedTenantId}`
|
||||
const submitResponse = await run.request('POST', submitPath, {
|
||||
measurementId: rescan.measurementId,
|
||||
version: rescan.measurementVersion,
|
||||
})
|
||||
const submitted = requireData(run, '提交墨家测量审核', submitResponse)
|
||||
const submittedPassed = submitted.processStatus === 'MEASURE_PENDING'
|
||||
&& submitted.measureReviewStatus === 'PENDING'
|
||||
record(run, '墨家测量进入待审核', submitResponse, submittedPassed,
|
||||
`processStatus=${submitted.processStatus}, reviewStatus=${submitted.measureReviewStatus}`)
|
||||
if (!submittedPassed) throw new Error('墨家测量提交后状态不正确')
|
||||
|
||||
const blockedResponse = await multipartRequest(run, scanPath, {
|
||||
boxCode, length: 99.1, width: 99.2, height: 99.3, weight: 99.4,
|
||||
machineNo: 'MJ-ADMIN-E2E-BLOCKED', measuredAt: '2026-08-08T10:02:00',
|
||||
}, imagePath)
|
||||
const blockedPassed = blockedResponse.body?.code === 'A0409'
|
||||
&& blockedResponse.body?.message?.includes('测量已提交')
|
||||
record(run, '提交后拒绝墨家设备覆盖', blockedResponse, blockedPassed,
|
||||
`code=${blockedResponse.body?.code}, message=${blockedResponse.body?.message ?? ''}`)
|
||||
if (!blockedPassed) throw new Error('提交后没有拒绝墨家设备覆盖')
|
||||
|
||||
run.context ??= {}
|
||||
run.context.mojiaMeasurement = {
|
||||
tenantId: resolvedTenantId, inboundId: String(inboundId), boxCode,
|
||||
measurementId: String(rescan.measurementId), itemId: String(rescan.itemId),
|
||||
}
|
||||
return true
|
||||
} catch (error) {
|
||||
const response = responseOf(0, null, error instanceof Error ? error.message : String(error))
|
||||
record(run, '墨家测量场景执行', response, false, response.raw)
|
||||
return false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user