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) {
return SettleNotFound, nil
}
return SettleNotFound, err
// 读库瞬时失败是可重试态(SettleFailed),不能与"查无此单"(终态,ack 即弃)
// 混淆——否则按 result 决定 ack 的调用方会让渠道停止重投,已付单永不入账。
return SettleFailed, err
}
// 金额/币种核对:币种须一致,实付须 ≥ 应收(允许 crypto 多付,拒少付)。
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{
Raw: raw, Headers: headers,
})
if err != nil {
// 验签失败等:400 让渠道按策略重投(或人工排障)。
// 按 SettleResult(而非只看 err)分终态/可重试:amount_mismatch 是终态——
// 重投同一回调永远解决不了,必须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)
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) {