fix(server): pay webhook 兜底补行不再漏停用用户(修静默丢钱)+ 未知事件日志 + PAY_BIZ_SECRET 启动守卫
- webhook 兜底路径(台账缺行按 biz_ref 定位用户)去掉 status='active' 过滤, 与正常路径(row.UserID 直接开通不看状态)对齐:钱已实收,不因用户被停用 (banned)而拒绝补行开通,避免 500→pay 12 次重投后死信→静默丢钱。 - 未知 event_type 分支加 slog.Warn,便于将来 pay 侧误注册无 handler 的事件 类型时能被观测到。 - PAY_BASE_URL 已设但 PAY_BIZ_SECRET 为空时 log.Fatal 拒绝启动,避免出站 签名失败+入站验签全 401 的静默瘫痪。 - InsertFromWebhookTx 不再把 channel 冒充 method 写入台账(payload 无 method 字段可复原,留空并加注释,消除台账观感误导)。 新增 TestWebhook_MissingLedgerFallsBackEvenWhenUserSuspended 覆盖 #1: 台账缺行 + 目标用户 banned 时,兜底补行仍成功开通并回 SUCCESS。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
This commit is contained in:
@@ -78,12 +78,14 @@ func (s *Store) LockByOutTradeNoTx(ctx context.Context, tx *sql.Tx, outTradeNo s
|
||||
}
|
||||
|
||||
// InsertFromWebhookTx 兜底补台账(下单后本地写失败的孤儿单,webhook 按 biz_ref 修复)。
|
||||
// 注意:webhookEvent payload 无 method 字段(用户选的支付方式,如 alipay/wxpay)可复原,
|
||||
// 只有 channel(结算渠道);method 留空,不能拿 channel 冒充——语义不同,避免台账观感误导。
|
||||
func (s *Store) InsertFromWebhookTx(ctx context.Context, tx *sql.Tx, userID int64, bizRef, sku, outTradeNo, channel string) (int64, error) {
|
||||
now := time.Now().UTC()
|
||||
res, err := tx.ExecContext(ctx,
|
||||
`INSERT INTO pay_purchases (user_id, biz_ref, sku, out_trade_no, method, status, channel, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, 'created', ?, ?, ?)`,
|
||||
userID, bizRef, sku, outTradeNo, channel, channel, now, now)
|
||||
userID, bizRef, sku, outTradeNo, "", channel, now, now)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("pay.Store.InsertFromWebhookTx: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user