diff --git a/apps/backend/src/services/fulfillment/routing-config-service.test.ts b/apps/backend/src/services/fulfillment/routing-config-service.test.ts index 9fd16087..2ad4f45f 100644 --- a/apps/backend/src/services/fulfillment/routing-config-service.test.ts +++ b/apps/backend/src/services/fulfillment/routing-config-service.test.ts @@ -94,6 +94,34 @@ test('resolveFulfillmentRoute 商品规则可以强制走 feifei', () => { assert.equal(result.reason, '命中商品路由规则') }) +test('resolveFulfillmentRoute 商品规则目标不可用时回退全局优先级', () => { + const result = resolveFulfillmentRoute({ + productName: '套装-糯粉咩咩', + candidates: [ + { executorKey: 'kuaishou_ct_assisted', available: true }, + { executorKey: 'kuaishou_feifei', available: true }, + { executorKey: 'affiliate_dash', available: false, reason: '未命中 affiliate-dash sku 映射' }, + ], + config: normalizeFulfillmentRoutingConfig({ + rules: [ + { + enabled: true, + productName: '套装-糯粉咩咩', + executorKey: 'affiliate_dash', + priority: 200, + }, + ], + }), + }) + + assert.equal(result.selectedExecutorKey, 'kuaishou_ct_assisted') + assert.equal(result.reason, '商品路由规则目标不可用,按全局优先级回退') + assert.deepEqual(result.skipped[0], { + executorKey: 'affiliate_dash', + reason: '未命中 affiliate-dash sku 映射', + }) +}) + test('resolveFulfillmentRoute 商品规则可以强制转人工', () => { const result = resolveFulfillmentRoute({ productName: '临时停用商品', diff --git a/apps/backend/src/services/fulfillment/routing-config-service.ts b/apps/backend/src/services/fulfillment/routing-config-service.ts index ba956b4a..9463e9d8 100644 --- a/apps/backend/src/services/fulfillment/routing-config-service.ts +++ b/apps/backend/src/services/fulfillment/routing-config-service.ts @@ -185,9 +185,22 @@ export function resolveFulfillmentRoute({ return selected } + const fallback = resolveByExecutorPriority({ + priority: normalizedConfig.defaultExecutorPriority.filter( + (executorKey) => executorKey !== matchedRule.executorKey, + ), + candidates: normalizedCandidates, + config: normalizedConfig, + skipped, + reasonPrefix: '商品路由规则目标不可用,按全局优先级回退', + }) + if (fallback.selectedExecutorKey) { + return fallback + } + return { ...selected, - reason: selected.reason || '商品路由规则目标通道不可用', + reason: selected.reason || '商品路由规则目标通道不可用,且未命中其他履约通道', } }