优化
This commit is contained in:
@@ -250,6 +250,10 @@ function usage() {
|
||||
--channel-code <code> 固定物流渠道编码
|
||||
--order-profile-mode <mode> 订单档案模式:fixed 或 randomized,默认fixed
|
||||
--wait-split-count <n> 同一客户创建的 WAIT_SPLIT 订单数,1-100,默认1
|
||||
--wait-split-package-count <n> 单票指定总箱数,1-1000;省略时使用既有轮换
|
||||
--wait-split-sequence <n> 单票全局序号,正整数,默认1
|
||||
--wait-split-random-value <n> 单票随机选择值,正整数,默认使用全局序号
|
||||
--route-mode <mode> 线路选择:fixed 或 random,默认fixed
|
||||
--manual-split-fixture-report <path> 人工分柜准备报告路径,仅只读核验模块使用
|
||||
--manual-split-plan-id <id> 人工操作产生的智能装柜计划 ID,仅只读核验模块使用
|
||||
--manual-preload-source-report <path> 人工推送预装前置或核验来源报告路径
|
||||
@@ -302,6 +306,11 @@ export function parseArguments(argv) {
|
||||
orderProfileMode: values.get('order-profile-mode') || 'fixed',
|
||||
waitSplitCount: Number(values.get('wait-split-count') || process.env.ADMIN_WAIT_SPLIT_COUNT
|
||||
|| (modules.includes('manual-order-splitting-fixture') ? 6 : 1)),
|
||||
waitSplitPackageCount: Number(values.get('wait-split-package-count') || 0),
|
||||
waitSplitSequence: Number(values.get('wait-split-sequence') || 1),
|
||||
waitSplitRandomValue: Number(values.get('wait-split-random-value') || values.get('wait-split-sequence') || 1),
|
||||
routeMode: values.get('route-mode') || 'fixed',
|
||||
quiet: values.get('quiet') === 'true',
|
||||
manualSplitFixtureReport: values.get('manual-split-fixture-report') || '',
|
||||
manualSplitPlanId: values.get('manual-split-plan-id') || '',
|
||||
manualPreloadSourceReport: values.get('manual-preload-source-report') || '',
|
||||
@@ -325,6 +334,16 @@ export function validateExecutionOptions(options) {
|
||||
if (!Number.isInteger(options.waitSplitCount) || options.waitSplitCount < 1 || options.waitSplitCount > 100) {
|
||||
throw new Error('wait-split-count必须是1-100的整数')
|
||||
}
|
||||
if (!Number.isInteger(options.waitSplitPackageCount) || options.waitSplitPackageCount < 0
|
||||
|| options.waitSplitPackageCount > 1000) {
|
||||
throw new Error('wait-split-package-count必须是1-1000的整数或0')
|
||||
}
|
||||
if (!Number.isInteger(options.waitSplitSequence) || options.waitSplitSequence < 1) {
|
||||
throw new Error('wait-split-sequence必须是正整数')
|
||||
}
|
||||
if (!Number.isInteger(options.waitSplitRandomValue) || options.waitSplitRandomValue < 1) {
|
||||
throw new Error('wait-split-random-value必须是正整数')
|
||||
}
|
||||
if (options.customerName && options.customerName.trim().length > 128) {
|
||||
throw new Error('customer-name不能超过128个字符')
|
||||
}
|
||||
@@ -338,7 +357,13 @@ export function validateExecutionOptions(options) {
|
||||
if (!['fixed', 'randomized'].includes(options.orderProfileMode)) {
|
||||
throw new Error('order-profile-mode必须为fixed或randomized')
|
||||
}
|
||||
if (options.orderProfileMode === 'randomized'
|
||||
if (!['fixed', 'random'].includes(options.routeMode)) {
|
||||
throw new Error('route-mode必须为fixed或random')
|
||||
}
|
||||
if (options.routeMode === 'random' && !options.originWarehouseName) {
|
||||
throw new Error('random线路必须固定起运仓名称')
|
||||
}
|
||||
if (options.orderProfileMode === 'randomized' && options.routeMode !== 'random'
|
||||
&& (!options.originWarehouseName || !options.channelName || !options.channelCode)) {
|
||||
throw new Error('randomized订单档案必须同时固定起运仓、渠道名称和渠道编码')
|
||||
}
|
||||
@@ -445,7 +470,8 @@ export function buildAcceptanceSummary(steps = [], modules = [], coverageGaps =
|
||||
export class AcceptanceRun {
|
||||
constructor(options) {
|
||||
this.options = options
|
||||
this.marker = `ADMIN-API-${new Date().toISOString().replace(/\D/g, '').slice(0, 17)}`
|
||||
const markerNamespace = String(options.markerNamespace || '').replace(/[^A-Za-z0-9_-]/g, '').slice(0, 12)
|
||||
this.marker = `ADMIN-API-${new Date().toISOString().replace(/\D/g, '').slice(0, 17)}${markerNamespace ? `-${markerNamespace}` : ''}`
|
||||
this.startedAt = new Date().toISOString()
|
||||
this.steps = []
|
||||
this.modules = []
|
||||
@@ -620,7 +646,9 @@ export class AcceptanceRun {
|
||||
}
|
||||
this.steps.push(step)
|
||||
if (step.deploymentBlocker) this.deploymentBlockers.push({ module, scenario: step.scenario, name, evidence, code: step.code, requestId: step.requestId, traceId: step.traceId })
|
||||
console.log(`[${step.passed ? 'PASS' : 'FAIL'}] [${module}${step.scenario ? `/${step.scenario}` : ''}] ${name}${evidence ? ` - ${evidence}` : ''}`)
|
||||
if (!this.options.quiet) {
|
||||
console.log(`[${step.passed ? 'PASS' : 'FAIL'}] [${module}${step.scenario ? `/${step.scenario}` : ''}] ${name}${evidence ? ` - ${evidence}` : ''}`)
|
||||
}
|
||||
return step.passed
|
||||
}
|
||||
|
||||
@@ -706,13 +734,33 @@ export class AcceptanceRun {
|
||||
{ code: 'LARGE', first: { length: 49.1, width: 39.1, height: 38.1 }, replacement: { length: 49.5, width: 39.5, height: 38.5 }, outer: { length: 54, width: 44, height: 44 } },
|
||||
{ code: 'EXTRA_LARGE', first: { length: 59.1, width: 49.1, height: 48.1 }, replacement: { length: 59.5, width: 49.5, height: 48.5 }, outer: { length: 64, width: 54, height: 54 } },
|
||||
]
|
||||
const skuCount = 1 + ((sequence - 1) % 4)
|
||||
const packageCountPerSku = 1 + (Math.floor((sequence - 1) / 4) % 5)
|
||||
const palletCount = 1 + ((sequence - 1) % 3)
|
||||
const grossWeightPerPalletKg = 45 + ((sequence - 1) % 6) * 15
|
||||
const randomValue = this.options.waitSplitRandomValue || sequence
|
||||
const requestedTotal = Number(this.options.waitSplitPackageCount || 0)
|
||||
const skuCount = requestedTotal > 0
|
||||
? 1 + (randomValue % Math.min(4, requestedTotal))
|
||||
: 1 + ((sequence - 1) % 4)
|
||||
const packageCountPerSku = requestedTotal > 0 ? 1 : 1 + (Math.floor((sequence - 1) / 4) % 5)
|
||||
const packageCounts = []
|
||||
if (requestedTotal > 0) {
|
||||
let remaining = requestedTotal
|
||||
let state = randomValue >>> 0
|
||||
for (let index = 0; index < skuCount - 1; index += 1) {
|
||||
state = (Math.imul(state, 1664525) + 1013904223) >>> 0
|
||||
const maximum = remaining - (skuCount - index - 1)
|
||||
const count = 1 + (state % maximum)
|
||||
packageCounts.push(count)
|
||||
remaining -= count
|
||||
}
|
||||
packageCounts.push(remaining)
|
||||
}
|
||||
const totalPackageCount = requestedTotal || skuCount * packageCountPerSku
|
||||
const palletCount = requestedTotal > 0 ? Math.ceil(totalPackageCount / 30) : 1 + (randomValue % 3)
|
||||
const grossWeightPerPalletKg = 45 + (randomValue % 6) * 15
|
||||
return {
|
||||
sequence, skuCount, packageCountPerSku, palletCount, grossWeightPerPalletKg,
|
||||
measurementProfile: dimensionProfiles[(sequence - 1) % dimensionProfiles.length],
|
||||
sequence, skuCount, packageCountPerSku, packageCounts,
|
||||
totalPackageCount,
|
||||
palletCount, grossWeightPerPalletKg,
|
||||
measurementProfile: dimensionProfiles[randomValue % dimensionProfiles.length],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -725,15 +773,16 @@ export class AcceptanceRun {
|
||||
['OVERSEAS', 'ONE_CLICK_DROPSHIP'],
|
||||
['PRIVATE', 'ONE_CLICK_DROPSHIP'],
|
||||
]
|
||||
const [destinationType, fulfillmentType] = combinations[(sequence * 5 + 1) % combinations.length]
|
||||
const randomValue = this.options.waitSplitRandomValue || sequence
|
||||
const [destinationType, fulfillmentType] = combinations[randomValue % combinations.length]
|
||||
const pickupMethods = ['PICKUP', 'SELF_EXPRESS', 'SELF_TRUCK']
|
||||
return {
|
||||
destinationType,
|
||||
fulfillmentType,
|
||||
pickupMethod: pickupMethods[(sequence * 7 + 2) % pickupMethods.length],
|
||||
taxMode: sequence % 2 === 0 ? 'TAX_REFUND' : 'BUY_DECLARATION',
|
||||
containerMode: sequence % 2 === 0 ? 'FULL_CONTAINER' : 'LCL',
|
||||
customsInspection: sequence % 4 === 0,
|
||||
pickupMethod: pickupMethods[Math.floor(randomValue / 7) % pickupMethods.length],
|
||||
taxMode: randomValue % 2 === 0 ? 'TAX_REFUND' : 'BUY_DECLARATION',
|
||||
containerMode: Math.floor(randomValue / 11) % 2 === 0 ? 'FULL_CONTAINER' : 'LCL',
|
||||
customsInspection: Math.floor(randomValue / 13) % 4 === 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,6 +802,8 @@ export class AcceptanceRun {
|
||||
originWarehouseName: this.options.originWarehouseName || '',
|
||||
channelName: this.options.channelName || '',
|
||||
channelCode: this.options.channelCode || '',
|
||||
randomize: this.options.routeMode === 'random',
|
||||
randomIndex: this.options.waitSplitRandomValue || sequence,
|
||||
destinationIndex: (sequence * 17 + 11),
|
||||
taxModeIndex: sequence - 1,
|
||||
}
|
||||
@@ -1421,7 +1472,10 @@ export class AcceptanceRun {
|
||||
process.env.MERCHANT_TEST_USERNAME = this.options.merchantUsername
|
||||
process.env.MERCHANT_TEST_PASSWORD = this.options.merchantPassword
|
||||
}
|
||||
if (this.options.waitSplitCount > 1) this.applyWaitSplitVariant(1)
|
||||
if (this.options.waitSplitCount > 1 || this.options.waitSplitPackageCount > 0
|
||||
|| this.options.orderProfileMode === 'randomized' || this.options.routeMode === 'random') {
|
||||
this.applyWaitSplitVariant(this.options.waitSplitSequence || 1)
|
||||
}
|
||||
const loginResponse = await this.request('POST', '/api/auth/login', { username: this.options.username, password: this.options.password }, '')
|
||||
const login = this.apiSuccess('authentication', '平台管理员登录', loginResponse)
|
||||
if (!login?.accessToken) this.fatal = '平台管理员登录失败,未执行业务模块'
|
||||
@@ -1508,7 +1562,8 @@ export class AcceptanceRun {
|
||||
} finally {
|
||||
if (restoreFixture) restoreFixture()
|
||||
}
|
||||
if (module === 'inbound-measurement' && this.captureWaitSplitFixture(1)) {
|
||||
if (module === 'inbound-measurement'
|
||||
&& this.captureWaitSplitFixture(this.options.waitSplitSequence || 1)) {
|
||||
await this.createAdditionalWaitSplitFixtures()
|
||||
}
|
||||
const laterOverseasModule = this.options.modules.slice(moduleIndex + 1)
|
||||
|
||||
Reference in New Issue
Block a user