fix(order-service): 修复 Mock 工单未绑定自动发布配置

This commit is contained in:
yml2213
2026-11-04 12:58:34 +08:00
parent 3f7a3ab5d1
commit 0638582205
3 changed files with 125 additions and 4 deletions
@@ -29,6 +29,14 @@ import {
} from './mappers.js'
import { rememberAdminMockCustomShop } from './admin-mock-custom-shop-service.js'
import { resolveMockWorkOrderProductRule } from './mock-work-order-rule-match.js'
import {
getPublishedOrderServiceProfileSnapshotByCategory,
isOrderServiceMaterialRequired,
} from './order-service-profile-service.js'
import {
enqueueOrderServiceAutoPublish,
processDueOrderServiceAutoPublishJobs,
} from './order-service-auto-publish-service.js'
import { ensureWorkerPlatformDefaults } from './worker-platform-defaults.js'
import { normalizeWorkOrderTimeoutPolicy } from './work-order-timeout-policy.js'
@@ -63,8 +71,17 @@ export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
}
categoryId = Number(category.id)
}
const materialComplete = payload.materialComplete === true || payload.materialComplete === 'true'
const fields = normalizeRequirementFields(payload.fields)
const serviceProfile = categoryId
? await getPublishedOrderServiceProfileSnapshotByCategory(categoryId)
: null
const requestedMaterialComplete =
payload.materialComplete === true || payload.materialComplete === 'true'
const materialComplete =
requestedMaterialComplete ||
(serviceProfile ? !isOrderServiceMaterialRequired(serviceProfile.config) : false)
const fields = serviceProfile
? normalizeRequirementFields(serviceProfile.config.fields)
: normalizeRequirementFields(payload.fields)
const { platformOrderId, productName, shop } = input
// Mock 工单同样要挂到接单模板上:后台「同步模板价格」按 product_rule_id 精确匹配,
// 不绑定的话改模板价永远命中不到 Mock 单(真实单在 sync-worker-orders-service 已绑定)。
@@ -93,7 +110,7 @@ export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
complete: true,
submittedAt: now,
fields: fields.reduce<Record<string, string>>((result, field) => {
result[field.key] = String(field.mockValue || `${field.label}测试值`)
result[field.key] = resolveMockMaterialFieldValue(field)
return result
}, {}),
},
@@ -129,6 +146,17 @@ export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
giftCooldownMinutes: normalizeWorkOrderGiftCooldownMinutes(payload.giftCooldownMinutes),
materialJson: JSON.stringify(material),
requirementJson: JSON.stringify({ fields }),
serviceProfileId: serviceProfile?.profileId || null,
serviceProfileVersionId: serviceProfile?.versionId || null,
serviceProfileSnapshotJson: serviceProfile
? JSON.stringify({
profileId: serviceProfile.profileId,
categoryId: serviceProfile.categoryId,
versionId: serviceProfile.versionId,
versionNo: serviceProfile.versionNo,
config: serviceProfile.config,
})
: null,
now,
})
if (!workOrder) {
@@ -157,10 +185,44 @@ export async function createAdminMockWorkOrder(payload: JsonObject = {}) {
productRuleId: productRuleMatch.rule ? Number(productRuleMatch.rule.id) : 0,
productRuleKey: productRuleMatch.rule ? String(productRuleMatch.rule.rule_key || '') : '',
productRuleMatch: productRuleMatch.reason,
serviceProfileId: serviceProfile?.profileId || 0,
serviceProfileVersionId: serviceProfile?.versionId || 0,
}),
now,
})
return { order: mapWorkOrderAdmin(workOrder) }
let autoPublishQueued = false
if (materialComplete && serviceProfile?.config.autoPublish.enabled) {
const job = await enqueueOrderServiceAutoPublish({
workOrderId: Number(workOrder.id),
maxAttempts: serviceProfile.config.autoPublish.retryMax + 1,
})
autoPublishQueued = Boolean(job)
if (autoPublishQueued) {
void processDueOrderServiceAutoPublishJobs(1).catch(() => undefined)
}
}
return { order: mapWorkOrderAdmin(workOrder), autoPublishQueued }
}
const MOCK_FIELD_DEFAULT_VALUES: Record<string, string> = {
gameId: '10000001',
gameNickname: '测试角色',
serverZone: '微信区',
system: '安卓',
gameAccount: 'test_account',
roleLevel: '100',
contactPhone: '13800138000',
orderNote: 'Mock 订单备注',
}
function resolveMockMaterialFieldValue(field: {
key: string
label: string
validation?: 'none' | 'digits'
mockValue?: string
}) {
if (field.validation === 'digits') return '10000001'
return String(field.mockValue || MOCK_FIELD_DEFAULT_VALUES[field.key] || `${field.label}测试值`)
}
/** 本地 Mock 与真实订单保持相同的关键字段约束,避免生成无法追溯的测试工单。 */
@@ -893,6 +893,17 @@ test('本地 Mock 工单要求订单、店铺、商品与两个金额完整有
assert.deepEqual(resolveAdminMockWorkOrderInput(baseInput, shops).rewardAmount, 2500)
})
test('Mock 建单必须绑定已发布订单服务快照,并在资料完整时进入自动发布队列', async () => {
const { readFile } = await import('node:fs/promises')
const source = await readFile(
new URL('./admin-mock-work-order-service.ts', import.meta.url),
'utf8',
)
assert.match(source, /getPublishedOrderServiceProfileSnapshotByCategory/)
assert.match(source, /serviceProfileSnapshotJson/)
assert.match(source, /enqueueOrderServiceAutoPublish/)
})
test('排行榜打手名称仅展示首字符', () => {
assert.equal(maskWorkerLeaderboardDisplayName('张三'), '张****')
assert.equal(maskWorkerLeaderboardDisplayName('Alice'), 'A****')