优化 affiliate_dash 核销时机:建单成功即核销(参考 feifei 给用户链接即核销)

- prepareAffiliateDashTask 建单成功(91 卡信息到手、链接可发放)立即核销行业电子凭证
- 核销失败不阻塞下单与链接发放(consumeStatus=failed, delivered 回调兜底补核销)
- sync delivered 分支 alreadyConsumed 短路,避免重复核销
- typecheck + 212 测试通过
This commit is contained in:
yml2213
2026-08-05 16:02:44 +08:00
parent 5ef1ed6018
commit 00d490a2cd
2 changed files with 59 additions and 4 deletions
@@ -15,6 +15,7 @@ import {
} from '../../platforms/affiliate-dash/order-service.js'
import { getAffiliateDashConfig } from '../../platforms/affiliate-dash/config.js'
import { consumeKuaishouIndustryVouchersForTask } from '../../platforms/kuaishou-industry/voucher-service.js'
import { buildKuaishouIndustryVoucherContext } from '../../platforms/kuaishou-industry/voucher-binding-service.js'
import type { TaskRow } from '../../../types/repository/rows.js'
export function isAffiliateDashTask(task: Partial<TaskRow> | null | undefined) {
@@ -75,6 +76,38 @@ export async function prepareAffiliateDashTask(task: TaskRow) {
clientOrderNo,
syncedAt: now,
})
// 核销时机优化:建单成功(91 卡信息到手、领取链接可发放)即核销行业电子凭证,
// 不再等 delivered 回调(参考 kuaishou-feifei「给用户链接即核销」)。
// 核销失败不阻塞下单与链接发放:consumeStatus=faileddelivered 回调兜底补核销。
const consumeResult = await consumeKuaishouIndustryVouchersForTask(task, {
source: 'affiliate_dash_order_created',
consumeTime: Date.now(),
})
const consumedVoucher = consumeResult.consumed[0] || null
let nextIndustryVoucher = taskContext.kuaishouIndustryVoucher
if (consumeResult.vouchers.length > 0) {
nextFlow.consumeStatus = consumeResult.ok ? 'success' : 'failed'
if (consumedVoucher) {
nextIndustryVoucher = buildKuaishouIndustryVoucherContext(
consumedVoucher,
taskContext.kuaishouIndustryVoucher,
now,
)
}
if (!consumeResult.ok) {
logIntegration('[affiliate-dash]', '建单成功但电子凭证核销失败,delivered 回调将兜底重试', {
taskId: task.id,
orderNo: order.orderNo,
voucherCount: consumeResult.vouchers.length,
failedCount: consumeResult.failed.length,
errorMessage: consumeResult.failed[0]?.errorMessage || '',
}, { level: 'warn' })
}
} else {
nextFlow.consumeStatus = 'not_required'
}
const updatedTask = await updateTask(task.id, {
task_status: TASK_STATUS.LINK_GENERATED,
user_action_status: 'pending_claim',
@@ -83,6 +116,7 @@ export async function prepareAffiliateDashTask(task: TaskRow) {
context_json: JSON.stringify({
...taskContext,
affiliateDash: nextFlow,
kuaishouIndustryVoucher: nextIndustryVoucher,
}),
updated_at: now,
})
@@ -153,10 +187,14 @@ export async function syncAffiliateDashTaskStatus(task: TaskRow) {
lastError = ''
break
case 'delivered': {
const consumeResult = await consumeKuaishouIndustryVouchersForTask(task, {
source: 'affiliate_dash_delivered',
consumeTime: Date.now(),
})
const alreadyConsumed =
nextFlow.consumeStatus === 'success' || nextFlow.consumeStatus === 'not_required'
const consumeResult = alreadyConsumed
? { ok: true, vouchers: [], consumed: [], failed: [] }
: await consumeKuaishouIndustryVouchersForTask(task, {
source: 'affiliate_dash_delivered',
consumeTime: Date.now(),
})
if (consumeResult.ok || consumeResult.vouchers.length === 0) {
nextTaskStatus = TASK_STATUS.REDEEMED
deliveryStatus = 'delivered'