feat(douyin-mashida): 抖音码速达最小接入后端(消息建单/券码同步/兑换核销/退款作废)
- 签名:出网 md5(secret+Σ(名+值)+secret) 与推送 md5(secret+data+pub_time+topic+secret) 两套独立实现,含文档 golden 向量单测(与 91 大写 / affiliate_dash HMAC 都不通用) - 进单:trade_TradePaid 推送 → 验签 → webhook_events 幂等 → order.orderDetail → upsertOrderFromSource(provider=douyin_mashida / platform=doudian) - 精度:19 位订单号超出 JS 安全整数,JSON.parse 会把 p_id 抹成 ...000; 故解析后从原始 JSON 文本用正则抓回精确数字(单测同时证明"不修会错") - 券码:迁移 094 redeem_certificates((provider,order_id) 唯一做发券幂等) + DYC 券码生成 + coupons.syncV2 同步(子单号优先、父单兜底) - 兑换:POST /api/v1/redeem/lookup|confirm,按 orderNo+IP 限流; 核销成功后 order.message 通知买家(best-effort,失败只记错误日志) - 退款/取消:作废未核销券;券已核销时打 WARN 资损告警(已消费不可回滚) - 后台:GET/POST /api/v1/admin/platform-config/douyin-mashida, secret 出参置空 + 掩码,掩码回写不覆盖原值 - 消息路由挂在全局 body parser 之前(app.ts),验签必须用 body 原始字符串
This commit is contained in:
@@ -6,6 +6,7 @@ import ninetyoneRouter from './platform-config/ninetyone.js'
|
||||
import notificationsRouter from './platform-config/notifications.js'
|
||||
import fulfillmentRoutingRouter from './platform-config/fulfillment-routing.js'
|
||||
import affiliateDashRouter from './platform-config/affiliate-dash.js'
|
||||
import douyinMashidaRouter from './platform-config/douyin-mashida.js'
|
||||
import pddRouter from './platform-config/pdd.js'
|
||||
|
||||
const router = Router()
|
||||
@@ -17,5 +18,7 @@ router.use('/platform-config', ninetyoneRouter)
|
||||
router.use('/platform-config', fulfillmentRoutingRouter)
|
||||
router.use('/platform-config', affiliateDashRouter)
|
||||
router.use('/platform-config', pddRouter)
|
||||
// 抖音码速达:注册在 requireAdminRoles(['admin']) 之后,自动继承 admin 守卫
|
||||
router.use('/platform-config', douyinMashidaRouter)
|
||||
|
||||
export default router
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { Router } from 'express'
|
||||
|
||||
import {
|
||||
getAdminDouyinMashidaConfig,
|
||||
saveAdminDouyinMashidaConfig,
|
||||
} from '../../../services/admin/platform-config/douyin-mashida-service.js'
|
||||
import { createJsonHandler } from '../session.js'
|
||||
import type { JsonRecord } from '../../../types/json.js'
|
||||
|
||||
const router = Router()
|
||||
|
||||
router.get(
|
||||
'/douyin-mashida',
|
||||
createJsonHandler(() => getAdminDouyinMashidaConfig(), {
|
||||
successMessage: 'ok',
|
||||
errorMessage: '读取抖音码速达配置失败',
|
||||
scope: '[admin/platform-config/douyin-mashida]',
|
||||
}),
|
||||
)
|
||||
|
||||
router.post(
|
||||
'/douyin-mashida',
|
||||
createJsonHandler((req) => saveAdminDouyinMashidaConfig(req.body as JsonRecord), {
|
||||
successMessage: '抖音码速达配置已保存',
|
||||
errorMessage: '保存抖音码速达配置失败',
|
||||
scope: '[admin/platform-config/douyin-mashida]',
|
||||
audit: (_req, data) => {
|
||||
const config = data as JsonRecord
|
||||
|
||||
return {
|
||||
action: 'platform_douyin_mashida_config_updated',
|
||||
targetType: 'platform_config',
|
||||
targetId: 'douyin_mashida',
|
||||
// 审计只记摘要,绝不写密钥
|
||||
data: {
|
||||
enabled: config.enabled !== false,
|
||||
hasUid: Boolean(config.uid),
|
||||
hasSecret: Boolean(config.hasSecret),
|
||||
hasCertLink: Boolean(config.certLink),
|
||||
hasAfterVerifyLink: Boolean(config.afterVerifyLink),
|
||||
messageType: Number(config.messageType || 0),
|
||||
handledTopicCount: Array.isArray(config.handledTopics) ? config.handledTopics.length : 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
export default router
|
||||
Reference in New Issue
Block a user