fix(finance): 重写履约路由迁移与统一渠道配置

重写 120/121 迁移,统一内部 SKU、渠道 id、config_json 和旧规则转换。

后台渠道配置改读统一渠道表,卡券与人工配置不再写旧规则。

增加安全渠道切换,并排除已关闭、失败或过期的历史任务载体。

按生产 119 基线重跑迁移、完整履约财务链路和严格预检。
This commit is contained in:
yml2213
2026-11-02 15:29:13 +08:00
parent 2f87445ed9
commit 6bf28489e0
31 changed files with 958 additions and 464 deletions
@@ -374,8 +374,8 @@ router.post(
errorMessage: '补齐卡券渠道规则失败',
scope: '[admin/cost-center/voucher-products/ensure-rules]',
audit: (_req, data) => ({
action: 'voucher_channel_rules_ensured',
targetType: 'sku_channel_rules',
action: 'voucher_internal_channels_ensured',
targetType: 'internal_sku_channels',
targetId: '',
data: data as Record<string, unknown>,
}),
@@ -14,6 +14,7 @@ import {
deleteChannelRule,
listChannelRules,
listPendingChannelGroups,
switchChannelForOrderItems,
unlockChannel,
upsertChannelRule,
} from '../../services/fulfillment/channel-assign-service.js'
@@ -143,6 +144,35 @@ router.post(
),
)
router.post(
'/fulfillment/switch',
requireAdminPermission('finance.config'),
createJsonHandler(
(req) => {
const body = bodyOf(req)
return switchChannelForOrderItems({
orderItemIds: Array.isArray(body.orderItemIds)
? body.orderItemIds.map((value: unknown) => Number(value))
: [Number(body.orderItemId)],
channel: String(body.channel || ''),
adminUserId: req.adminSession?.userId ?? null,
note: String(body.note || ''),
})
},
{
successMessage: '履约渠道已切换',
errorMessage: '切换履约渠道失败',
scope: '[admin/fulfillment/switch]',
audit: (req, data) => ({
action: 'fulfillment.switch_channel',
targetType: 'order_item',
targetId: String(bodyOf(req).orderItemId || ''),
data: { payload: bodyOf(req), result: data as Record<string, unknown> },
}),
},
),
)
router.get(
'/fulfillment/rules',
requireAdminPermission('finance.view'),
@@ -170,9 +200,7 @@ router.post(
const body = bodyOf(req)
return upsertChannelRule({
...(body.id ? { id: Number(body.id) } : {}),
provider: String(body.provider || ''),
shopId: String(body.shopId || ''),
matchKeyType: String(body.matchKeyType || 'sku_code'),
matchKeyType: String(body.matchKeyType || 'internal_sku'),
matchKey: String(body.matchKey || ''),
channel: String(body.channel || ''),
priority: Number(body.priority),
@@ -188,7 +216,7 @@ router.post(
scope: '[admin/fulfillment/rules]',
audit: (req, data) => ({
action: 'fulfillment.upsert_rule',
targetType: 'sku_channel_rule',
targetType: 'internal_sku_channel',
targetId: String((data as { id?: number })?.id || ''),
data: { payload: bodyOf(req) },
}),