fix: align payment recovery query refs and resume authority

This commit is contained in:
IanShaw027
2026-04-21 13:01:21 +08:00
parent 119f784d19
commit 276ce052a3
4 changed files with 212 additions and 10 deletions

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"log/slog"
"strconv"
"strings"
"time"
dbent "github.com/Wei-Shaw/sub2api/ent"
@@ -139,20 +140,18 @@ func (s *PaymentService) checkPaid(ctx context.Context, o *dbent.PaymentOrder) s
if err != nil {
return ""
}
// Use OutTradeNo as fallback when PaymentTradeNo is empty
// (e.g. EasyPay popup mode where trade_no arrives only via notify callback)
tradeNo := o.PaymentTradeNo
if tradeNo == "" {
tradeNo = o.OutTradeNo
queryRef := paymentOrderQueryReference(o, prov)
if queryRef == "" {
return ""
}
resp, err := prov.QueryOrder(ctx, tradeNo)
resp, err := prov.QueryOrder(ctx, queryRef)
if err != nil {
slog.Warn("query upstream failed", "orderID", o.ID, "error", err)
return ""
}
if resp.Status == payment.ProviderStatusPaid {
notificationTradeNo := o.PaymentTradeNo
if upstreamTradeNo := resp.TradeNo; upstreamTradeNo != "" && upstreamTradeNo != notificationTradeNo {
if upstreamTradeNo := strings.TrimSpace(resp.TradeNo); paymentOrderShouldPersistUpstreamTradeNo(queryRef, upstreamTradeNo, notificationTradeNo) {
if _, updateErr := s.entClient.PaymentOrder.Update().
Where(paymentorder.IDEQ(o.ID)).
SetPaymentTradeNo(upstreamTradeNo).
@@ -170,11 +169,57 @@ func (s *PaymentService) checkPaid(ctx context.Context, o *dbent.PaymentOrder) s
return checkPaidResultAlreadyPaid
}
if cp, ok := prov.(payment.CancelableProvider); ok {
_ = cp.CancelPayment(ctx, tradeNo)
_ = cp.CancelPayment(ctx, queryRef)
}
return ""
}
func paymentOrderQueryReference(order *dbent.PaymentOrder, prov payment.Provider) string {
if order == nil {
return ""
}
providerKey := ""
if prov != nil {
providerKey = strings.TrimSpace(prov.ProviderKey())
}
if providerKey == "" {
if snapshot := psOrderProviderSnapshot(order); snapshot != nil {
providerKey = strings.TrimSpace(snapshot.ProviderKey)
}
}
if providerKey == "" {
providerKey = strings.TrimSpace(psStringValue(order.ProviderKey))
}
if providerKey == "" {
providerKey = strings.TrimSpace(order.PaymentType)
}
switch payment.GetBasePaymentType(providerKey) {
case payment.TypeAlipay, payment.TypeEasyPay, payment.TypeWxpay:
return strings.TrimSpace(order.OutTradeNo)
default:
if tradeNo := strings.TrimSpace(order.PaymentTradeNo); tradeNo != "" {
return tradeNo
}
return strings.TrimSpace(order.OutTradeNo)
}
}
func paymentOrderShouldPersistUpstreamTradeNo(queryRef, upstreamTradeNo, currentTradeNo string) bool {
upstreamTradeNo = strings.TrimSpace(upstreamTradeNo)
if upstreamTradeNo == "" {
return false
}
if strings.EqualFold(upstreamTradeNo, strings.TrimSpace(currentTradeNo)) {
return false
}
if strings.EqualFold(upstreamTradeNo, strings.TrimSpace(queryRef)) {
return false
}
return true
}
// VerifyOrderByOutTradeNo actively queries the upstream provider to check
// if a payment was made, and processes it if so. This handles the case where
// the provider's notify callback was missed (e.g. EasyPay popup mode).