docs(v2): P2 计划 settle 代码段同步 T5 修复(瞬时读库错误→SettleFailed)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013nMthbVEmQquxBRKb9Fj8u
This commit is contained in:
wangjia
2026-07-10 14:14:01 +08:00
parent 7a27a6223a
commit abf6a43b8c
@@ -1321,7 +1321,9 @@ func (g *Gateway) Settle(ctx context.Context, ev *provider.PaidEvent) (SettleRes
if errors.Is(err, store.ErrAttemptNotFound) { if errors.Is(err, store.ErrAttemptNotFound) {
return SettleNotFound, nil return SettleNotFound, nil
} }
return SettleNotFound, err // 读库瞬时失败是可重试态(SettleFailed),不能与"查无此单"(终态,ack 即弃)
// 混淆——否则按 result 决定 ack 的调用方会让渠道停止重投,已付单永不入账。
return SettleFailed, err
} }
// 金额/币种核对:币种须一致,实付须 ≥ 应收(允许 crypto 多付,拒少付)。 // 金额/币种核对:币种须一致,实付须 ≥ 应收(允许 crypto 多付,拒少付)。
if ev.PaidCurrency != att.Currency || ev.PaidAmountMinor < att.AmountMinor { if ev.PaidCurrency != att.Currency || ev.PaidAmountMinor < att.AmountMinor {
@@ -2158,13 +2160,19 @@ func (h *GatewayHandler) Callback(c *gin.Context) {
res, err := h.g.HandleCallback(c.Request.Context(), method, provider.CallbackInput{ res, err := h.g.HandleCallback(c.Request.Context(), method, provider.CallbackInput{
Raw: raw, Headers: headers, Raw: raw, Headers: headers,
}) })
if err != nil { // 按 SettleResult(而非只看 err)分终态/可重试:amount_mismatch 是终态——
// 验签失败等:400 让渠道按策略重投(或人工排障)。 // 重投同一回调永远解决不了,必须200 让渠道停投(差错单归 P6 对账/人工);
// SettleFailed/验签失败才是可重试态,回 400 让渠道重投。
switch {
case err == nil:
c.JSON(http.StatusOK, gin.H{"result": string(res)})
case res == gateway.SettleAmountMismatch:
log.Printf("[v2 callback] method=%s 金额/币种不符(终态,已受理停投): %v", method, err)
c.JSON(http.StatusOK, gin.H{"result": string(res)})
default:
log.Printf("[v2 callback] method=%s result=%s err=%v", method, res, err) log.Printf("[v2 callback] method=%s result=%s err=%v", method, res, err)
util.RespondError(c, http.StatusBadRequest, "callback_failed", "回调处理失败") util.RespondError(c, http.StatusBadRequest, "callback_failed", "回调处理失败")
return
} }
c.JSON(http.StatusOK, gin.H{"result": string(res)})
} }
func (h *GatewayHandler) writeCreateErr(c *gin.Context, action, method string, err error) { func (h *GatewayHandler) writeCreateErr(c *gin.Context, action, method string, err error) {