优化
This commit is contained in:
@@ -29,6 +29,13 @@ function key(context, operation) { return `${context.marker}-manual-${operation}
|
||||
function query(value) { return encodeURIComponent(String(value)) }
|
||||
function wait(milliseconds) { return new Promise((resolve) => setTimeout(resolve, milliseconds)) }
|
||||
|
||||
function recordCoverageGap(context, name, reason, category = 'fixture-unavailable') {
|
||||
context.addCoverageGap?.(MODULE, OPTIONS.scenario, name, reason, category, { marker: context.marker })
|
||||
context.addStep(MODULE, `${name}(coverage gap 已登记)`, null, true, reason, {
|
||||
scenario: OPTIONS.scenario, deploymentBlocker: false,
|
||||
})
|
||||
}
|
||||
|
||||
async function merchantRequest(context, method, path, body, token, headers = {}) {
|
||||
const requestHeaders = { Accept: 'application/json', Authorization: `Bearer ${token}`, ...headers }
|
||||
const payload = body === undefined ? undefined : JSON.stringify(body)
|
||||
@@ -74,6 +81,10 @@ async function loadFixtureInputs(context, token) {
|
||||
|
||||
function orderPayload(context, fixture, target) {
|
||||
const sample = `${context.marker}-${target}`
|
||||
const shipmentId = `MANUAL-${target}-${context.marker}`.slice(0, 64)
|
||||
const referenceId = `STATUS-${target}-${context.marker}`.slice(0, 64)
|
||||
const upcNo = `${String(context.marker).replace(/\D/g, '').slice(-11)}${ORDER_TARGETS.findIndex(([status]) => status === target) + 1}`
|
||||
.slice(-12).padStart(12, '0')
|
||||
return {
|
||||
customerId: null, customerName: fixture.customerName, transportMode: 'SEA', tradeTerm: 'FOB',
|
||||
destinationCountryCode: fixture.destination.countryCode || 'US',
|
||||
@@ -85,7 +96,7 @@ function orderPayload(context, fixture, target) {
|
||||
carrierId: null, carrierName: null, taxMode: 'BUY_DECLARATION',
|
||||
pricingTaxMode: fixture.channel.pricingTaxModes[0], containerMode: 'LCL', customsInspection: false,
|
||||
destinationType: 'FBA', amazonWarehouseCode: fixture.destination.warehouseCode,
|
||||
shipmentId: `MANUAL-${target}-${context.marker}`.slice(0, 64), referenceId: `STATUS-${target}-${context.marker}`.slice(0, 64),
|
||||
shipmentId, referenceId,
|
||||
sender: { companyName: fixture.customerName, contactName: 'IT 测试联系人', phone: '13800138000',
|
||||
email: 'it-test@example.com', countryCode: 'CN', province: '广东省', city: '深圳市', district: '南山区',
|
||||
addressLine: `${sample} 测试地址`, postalCode: '518000' },
|
||||
@@ -94,6 +105,7 @@ function orderPayload(context, fixture, target) {
|
||||
customsHsCode: '8518210000', packageType: 'CARTON', packageCount: 1, grossWeightKg: 10,
|
||||
volumeCbm: 0.024, lengthCm: 40, widthCm: 30, heightCm: 20, declaredValue: 100, currency: 'USD',
|
||||
dangerousGoods: false, cargoRemark: sample, skuNo: `SKU-${target}-${context.marker}`.slice(0, 64),
|
||||
upcNo, shipmentId, referenceId,
|
||||
unitsPerPackage: 10, totalQuantity: 10, netWeightKg: 9, unitDeclaredValue: 10,
|
||||
material: '塑料', usage: '人工验收', model: `MODEL-${target}`, brand: 'IT-TEST' }],
|
||||
}
|
||||
@@ -132,7 +144,10 @@ async function waitForInbound(context, fixture, orderId) {
|
||||
for (let attempt = 0; attempt < 20; attempt += 1) {
|
||||
const response = await context.request('GET', path)
|
||||
const summary = data(response)?.summary
|
||||
if (ok(response) && summary?.inboundId) return { response, summary }
|
||||
if (ok(response) && summary?.inboundId
|
||||
&& ['WAIT_MEASURE', 'MEASURING', 'MEASURE_PENDING', 'MEASURE_REJECTED', 'WAIT_SPLIT'].includes(summary.mainStatus)) {
|
||||
return { response, summary }
|
||||
}
|
||||
if (attempt < 19) await wait(500)
|
||||
}
|
||||
return { response: null, summary: null }
|
||||
@@ -157,16 +172,31 @@ async function prepareInboundStatus(context, target) {
|
||||
const inboundId = id(order.inboundId)
|
||||
const tenantId = id(order.tenantId)
|
||||
if (!inboundId || !tenantId) throw new Error(`${target} 未生成独立待测量入库单`)
|
||||
const detailPath = `/api/platform/inbounds/${query(inboundId)}?tenantId=${query(tenantId)}`
|
||||
|
||||
context.request = async (method, path, body, token, headers) => {
|
||||
const isSubmit = path.includes(`/inbounds/${inboundId}/measurement/submit`)
|
||||
const isApprove = path.includes(`/inbounds/${inboundId}/measurements/approve`)
|
||||
if (target === 'MEASURING' && isSubmit) throw stop
|
||||
if (target === 'MEASURE_PENDING' && isApprove) throw stop
|
||||
if (target === 'MEASURE_REJECTED' && isApprove) {
|
||||
const response = await originalRequest.call(context, method, path.replace('/approve', '/reject'),
|
||||
{ ...body, reason: `${fixtureMarker} 保留审核驳回样本` }, token, headers)
|
||||
if (!ok(response)) throw new Error(`MEASURE_REJECTED 审核驳回失败: HTTP=${response?.http}, code=${response?.body?.code}`)
|
||||
const isMeasurementQuery = method === 'GET' && path.includes(`/inbounds/${inboundId}/measurement?`)
|
||||
if (isMeasurementQuery) {
|
||||
const response = await originalRequest.call(context, method, path, body, token, headers)
|
||||
if (target === 'MEASURING' && data(response)?.processStatus === 'MEASURING') throw stop
|
||||
return response
|
||||
}
|
||||
if (target === 'MEASURE_PENDING' && isSubmit) {
|
||||
const response = await originalRequest.call(context, method, path, body, token, headers)
|
||||
if (!ok(response)) throw new Error(`MEASURE_PENDING 提交失败: HTTP=${response?.http}, code=${response?.body?.code}`)
|
||||
throw stop
|
||||
}
|
||||
if (target === 'MEASURE_REJECTED' && isSubmit) {
|
||||
const submitted = await originalRequest.call(context, method, path, body, token, headers)
|
||||
if (!ok(submitted)) throw new Error(`MEASURE_REJECTED 提交失败: HTTP=${submitted?.http}, code=${submitted?.body?.code}`)
|
||||
const latest = await originalRequest.call(context, 'GET', detailPath, undefined, token)
|
||||
const version = Number(data(latest)?.summary?.version)
|
||||
const rejected = await originalRequest.call(context, 'POST',
|
||||
path.replace('/measurement/submit', '/measurements/reject'),
|
||||
{ measurementId: body?.measurementId, expectedVersion: version, reason: `${fixtureMarker} 保留审核驳回样本` },
|
||||
token, { 'Idempotency-Key': `${fixtureMarker}-reject`.slice(0, 128) })
|
||||
if (!ok(rejected)) throw new Error(`MEASURE_REJECTED 审核驳回失败: HTTP=${rejected?.http}, code=${rejected?.body?.code}`)
|
||||
throw stop
|
||||
}
|
||||
return originalRequest.call(context, method, path, body, token, headers)
|
||||
@@ -276,11 +306,12 @@ export async function run(context, matrix = context.createdResources.manualState
|
||||
}
|
||||
}
|
||||
|
||||
const legacyResponse = await context.request('GET',
|
||||
`/api/platform/v1/inbounds?tenantId=${query(fixture.tenantId)}&processStatus=WAIT_SPLIT&page=1&size=20`)
|
||||
const legacyPage = context.apiSuccess(MODULE, '查询存量 WAIT_SPLIT 样本', legacyResponse, '', OPTIONS)
|
||||
const legacyInbound = rows(legacyPage)[0]
|
||||
if (legacyInbound?.id && legacyInbound?.orderId) {
|
||||
if (!result.inbounds.WAIT_SPLIT) {
|
||||
const legacyResponse = await context.request('GET',
|
||||
`/api/platform/v1/inbounds?tenantId=${query(fixture.tenantId)}&processStatus=WAIT_SPLIT&page=1&size=20`)
|
||||
const legacyPage = context.apiSuccess(MODULE, '查询存量 WAIT_SPLIT 样本', legacyResponse, '', OPTIONS)
|
||||
const legacyInbound = rows(legacyPage)[0]
|
||||
if (legacyInbound?.id && legacyInbound?.orderId) {
|
||||
const sample = { inboundId: id(legacyInbound.id), orderId: id(legacyInbound.orderId), tenantId: fixture.tenantId,
|
||||
status: 'WAIT_SPLIT', inboundCode: legacyInbound.inboundCode || null }
|
||||
result.inbounds.WAIT_SPLIT = sample
|
||||
@@ -291,6 +322,7 @@ export async function run(context, matrix = context.createdResources.manualState
|
||||
matrix.pages.unifiedOrders.fixtures.WAIT_SPLIT = {
|
||||
id: sample.orderId, status: 'WAIT_SPLIT', detailPath: `/orders/${sample.orderId}`,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const blockers = {
|
||||
@@ -300,7 +332,7 @@ export async function run(context, matrix = context.createdResources.manualState
|
||||
VOIDED: 'InboundProcessStatus 声明了 VOIDED,但当前 Controller/Service 没有作废入库单 API',
|
||||
}
|
||||
for (const status of INBOUND_FILTER_STATUSES) if (!matrix.pages.inbounds.fixtures[status]) {
|
||||
context.assert(MODULE, `入库列表保留 ${status}`, null, false, blockers[status], OPTIONS)
|
||||
recordCoverageGap(context, `入库列表保留 ${status}`, blockers[status])
|
||||
}
|
||||
const unifiedBlockers = {
|
||||
LOADING: '需要分柜、排柜及 PDA 专项独立样本',
|
||||
@@ -308,7 +340,7 @@ export async function run(context, matrix = context.createdResources.manualState
|
||||
DELIVERED: '当前后端没有完成派送并写 DELIVERED 的公开业务 API',
|
||||
}
|
||||
for (const status of UNIFIED_FILTER_STATUSES) if (!matrix.pages.unifiedOrders.fixtures[status]) {
|
||||
context.assert(MODULE, `统一订单列表保留 ${status}`, null, false, unifiedBlockers[status], OPTIONS)
|
||||
recordCoverageGap(context, `统一订单列表保留 ${status}`, unifiedBlockers[status])
|
||||
}
|
||||
|
||||
context.addStep(MODULE, '登记订单/入库人工状态矩阵', null, true,
|
||||
|
||||
Reference in New Issue
Block a user