新增 affiliate_dash 履约配置与商品映射(阶段 3)

- bootstrap CORE_PROFILES + routing ROUTABLE/DEFAULT_PRIORITY 接入 affiliate_dash
- planner 上下文 affiliateDash 块 + resolveDynamicAffiliateDashProfile
- product-resolution: 91 productNo→sku 映射匹配(skuMapping) + snapshot.affiliateDash
- prepare 前余额预检(getAffiliateDashWallet)
- AFFILIATE_DASH_SKU_MAPPING_JSON env 注入
- admin 后端接口(GET/POST 配置、match、products、wallet)+ 前端 Tabs 面板
- 联调:模拟 91 进单命中 affiliate_dash 路由, 未命中回退;前后端 typecheck + 212 测试通过
This commit is contained in:
yml2213
2026-08-05 15:08:41 +08:00
parent 867ffd2f3c
commit 3284fed7a1
16 changed files with 817 additions and 5 deletions
@@ -10,6 +10,7 @@ import type { JsonObject } from '../../../types/json.js'
import {
createAffiliateDashOrder,
getAffiliateDashOrder,
getAffiliateDashWallet,
type AffiliateDashOrder,
} from '../../platforms/affiliate-dash/order-service.js'
import { getAffiliateDashConfig } from '../../platforms/affiliate-dash/config.js'
@@ -60,6 +61,9 @@ export async function prepareAffiliateDashTask(task: TaskRow) {
const data = buildAffiliateDashOrderData(task, taskContext)
const buyerReference = String(task.platform_order_id || task.task_no || '').trim()
// 余额预检:钱包余额不足提前拦截(避免建单 400 后才降级);预检失败不阻塞下单
await preflightAffiliateDashWallet(flow.sku)
const order = await createAffiliateDashOrder({
clientOrderNo,
sku: flow.sku,
@@ -278,6 +282,31 @@ export function buildAffiliateDashClientOrderNo(task: TaskRow) {
return String(task.task_no || `OS-AD-${task.id}`).trim()
}
async function preflightAffiliateDashWallet(sku: string) {
try {
const wallet = await getAffiliateDashWallet()
if (wallet.availableBalance <= 0) {
throw createHttpError('affiliate-dash 钱包余额不足,请先充值', {
statusCode: 409,
errorCode: 'affiliate_dash_wallet_not_enough',
context: {
sku,
availableBalance: wallet.availableBalance,
currency: wallet.currency,
},
})
}
} catch (error) {
if ((error as { errorCode?: string })?.errorCode === 'affiliate_dash_wallet_not_enough') {
throw error
}
logIntegration('[affiliate-dash]', '余额预检失败(忽略,继续下单)', {
sku,
error: error instanceof Error ? error.message : String(error),
}, { level: 'warn' })
}
}
function buildAffiliateDashOrderData(task: TaskRow, context: Record<string, unknown>): JsonObject {
const identity = getClaimIdentityFromContext(context)
const data: JsonObject = {}