fix payment resume result consistency

This commit is contained in:
IanShaw027
2026-04-21 02:08:34 +08:00
parent e12599c1b9
commit a27a7add3d
6 changed files with 264 additions and 14 deletions

View File

@@ -30,6 +30,15 @@ func (s *PaymentService) GetPublicOrderByResumeToken(ctx context.Context, token
if claims.PaymentType != "" && strings.TrimSpace(order.PaymentType) != claims.PaymentType {
return nil, fmt.Errorf("resume token payment type mismatch")
}
if order.Status == OrderStatusPending || order.Status == OrderStatusExpired {
result := s.checkPaid(ctx, order)
if result == checkPaidResultAlreadyPaid {
order, err = s.entClient.PaymentOrder.Get(ctx, order.ID)
if err != nil {
return nil, fmt.Errorf("reload order by resume token: %w", err)
}
}
}
return order, nil
}

View File

@@ -11,6 +11,35 @@ import (
"github.com/stretchr/testify/require"
)
type paymentResumeLookupProvider struct {
queryCount int
}
func (p *paymentResumeLookupProvider) Name() string { return "resume-lookup-provider" }
func (p *paymentResumeLookupProvider) ProviderKey() string { return payment.TypeAlipay }
func (p *paymentResumeLookupProvider) SupportedTypes() []payment.PaymentType {
return []payment.PaymentType{payment.TypeAlipay}
}
func (p *paymentResumeLookupProvider) CreatePayment(context.Context, payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) {
panic("unexpected call")
}
func (p *paymentResumeLookupProvider) QueryOrder(context.Context, string) (*payment.QueryOrderResponse, error) {
p.queryCount++
return &payment.QueryOrderResponse{Status: payment.ProviderStatusPending}, nil
}
func (p *paymentResumeLookupProvider) VerifyNotification(context.Context, string, map[string]string) (*payment.PaymentNotification, error) {
panic("unexpected call")
}
func (p *paymentResumeLookupProvider) Refund(context.Context, payment.RefundRequest) (*payment.RefundResponse, error) {
panic("unexpected call")
}
func TestGetPublicOrderByResumeTokenReturnsMatchingOrder(t *testing.T) {
ctx := context.Background()
client := newPaymentConfigServiceTestClient(t)
@@ -116,3 +145,58 @@ func TestGetPublicOrderByResumeTokenRejectsSnapshotMismatch(t *testing.T) {
require.Error(t, err)
require.Contains(t, err.Error(), "resume token")
}
func TestGetPublicOrderByResumeTokenChecksUpstreamForPendingOrder(t *testing.T) {
ctx := context.Background()
client := newPaymentConfigServiceTestClient(t)
user, err := client.User.Create().
SetEmail("resume-refresh@example.com").
SetPasswordHash("hash").
SetUsername("resume-refresh-user").
Save(ctx)
require.NoError(t, err)
order, err := client.PaymentOrder.Create().
SetUserID(user.ID).
SetUserEmail(user.Email).
SetUserName(user.Username).
SetAmount(88).
SetPayAmount(88).
SetFeeRate(0).
SetRechargeCode("RESUME-PENDING").
SetOutTradeNo("sub2_resume_lookup_pending").
SetPaymentType(payment.TypeAlipay).
SetPaymentTradeNo("trade-pending").
SetOrderType(payment.OrderTypeBalance).
SetStatus(OrderStatusPending).
SetExpiresAt(time.Now().Add(time.Hour)).
SetClientIP("127.0.0.1").
SetSrcHost("api.example.com").
Save(ctx)
require.NoError(t, err)
resumeSvc := NewPaymentResumeService([]byte("0123456789abcdef0123456789abcdef"))
token, err := resumeSvc.CreateToken(ResumeTokenClaims{
OrderID: order.ID,
UserID: user.ID,
PaymentType: payment.TypeAlipay,
CanonicalReturnURL: "https://app.example.com/payment/result",
})
require.NoError(t, err)
registry := payment.NewRegistry()
provider := &paymentResumeLookupProvider{}
registry.Register(provider)
svc := &PaymentService{
entClient: client,
registry: registry,
resumeService: resumeSvc,
providersLoaded: true,
}
got, err := svc.GetPublicOrderByResumeToken(ctx, token)
require.NoError(t, err)
require.Equal(t, order.ID, got.ID)
require.Equal(t, 1, provider.queryCount)
}