fix payment visible methods and resume recovery
This commit is contained in:
@@ -310,12 +310,14 @@ func buildWxpayResultURL(returnURL string, req payment.CreatePaymentRequest) (st
|
||||
return "", fmt.Errorf("return URL must be an absolute http(s) URL")
|
||||
}
|
||||
|
||||
values := url.Values{}
|
||||
values := u.Query()
|
||||
values.Set("out_trade_no", strings.TrimSpace(req.OrderID))
|
||||
if paymentType := strings.TrimSpace(req.PaymentType); paymentType != "" {
|
||||
values.Set("payment_type", paymentType)
|
||||
}
|
||||
u.Path = wxpayResultPath
|
||||
if strings.TrimSpace(u.Path) == "" {
|
||||
u.Path = wxpayResultPath
|
||||
}
|
||||
u.RawPath = ""
|
||||
u.RawQuery = values.Encode()
|
||||
u.Fragment = ""
|
||||
|
||||
@@ -4,6 +4,7 @@ package provider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -263,6 +264,36 @@ func TestNewWxpay(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildWxpayResultURLPreservesResumeToken(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
resultURL, err := buildWxpayResultURL("https://app.example.com/payment/result?order_id=42&resume_token=resume-42&status=success", payment.CreatePaymentRequest{
|
||||
OrderID: "sub2_42",
|
||||
PaymentType: payment.TypeWxpay,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("buildWxpayResultURL returned error: %v", err)
|
||||
}
|
||||
|
||||
parsed, err := url.Parse(resultURL)
|
||||
if err != nil {
|
||||
t.Fatalf("url.Parse returned error: %v", err)
|
||||
}
|
||||
query := parsed.Query()
|
||||
if parsed.Path != wxpayResultPath {
|
||||
t.Fatalf("path = %q, want %q", parsed.Path, wxpayResultPath)
|
||||
}
|
||||
if query.Get("resume_token") != "resume-42" {
|
||||
t.Fatalf("resume_token = %q, want %q", query.Get("resume_token"), "resume-42")
|
||||
}
|
||||
if query.Get("order_id") != "42" {
|
||||
t.Fatalf("order_id = %q, want %q", query.Get("order_id"), "42")
|
||||
}
|
||||
if query.Get("out_trade_no") != "sub2_42" {
|
||||
t.Fatalf("out_trade_no = %q, want %q", query.Get("out_trade_no"), "sub2_42")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveWxpayJSAPIAppID(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -20,6 +20,18 @@ func (s *PaymentConfigService) GetAvailableMethodLimits(ctx context.Context) (*M
|
||||
return nil, fmt.Errorf("query provider instances: %w", err)
|
||||
}
|
||||
typeInstances := pcGroupByPaymentType(instances)
|
||||
if s.settingRepo != nil {
|
||||
vals, err := s.settingRepo.GetMultiple(ctx, []string{
|
||||
SettingPaymentVisibleMethodAlipayEnabled,
|
||||
SettingPaymentVisibleMethodAlipaySource,
|
||||
SettingPaymentVisibleMethodWxpayEnabled,
|
||||
SettingPaymentVisibleMethodWxpaySource,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query visible method settings: %w", err)
|
||||
}
|
||||
typeInstances = pcApplyVisibleMethodRouting(typeInstances, vals, buildVisibleMethodSourceAvailability(instances))
|
||||
}
|
||||
resp := &MethodLimitsResponse{
|
||||
Methods: make(map[string]MethodLimits, len(typeInstances)),
|
||||
}
|
||||
@@ -31,6 +43,40 @@ func (s *PaymentConfigService) GetAvailableMethodLimits(ctx context.Context) (*M
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func pcApplyVisibleMethodRouting(typeInstances map[string][]*dbent.PaymentProviderInstance, vals map[string]string, available map[string]bool) map[string][]*dbent.PaymentProviderInstance {
|
||||
if len(typeInstances) == 0 {
|
||||
return typeInstances
|
||||
}
|
||||
|
||||
filtered := make(map[string][]*dbent.PaymentProviderInstance, len(typeInstances))
|
||||
for paymentType, instances := range typeInstances {
|
||||
visibleMethod := NormalizeVisibleMethod(paymentType)
|
||||
switch visibleMethod {
|
||||
case payment.TypeAlipay, payment.TypeWxpay:
|
||||
if !visibleMethodShouldBeExposed(visibleMethod, vals, available) {
|
||||
continue
|
||||
}
|
||||
targetProviderKey, ok := VisibleMethodProviderKeyForSource(visibleMethod, vals[visibleMethodSourceSettingKey(visibleMethod)])
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
matching := make([]*dbent.PaymentProviderInstance, 0, len(instances))
|
||||
for _, inst := range instances {
|
||||
if inst.ProviderKey == targetProviderKey {
|
||||
matching = append(matching, inst)
|
||||
}
|
||||
}
|
||||
if len(matching) == 0 {
|
||||
continue
|
||||
}
|
||||
filtered[paymentType] = matching
|
||||
default:
|
||||
filtered[paymentType] = instances
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
// GetMethodLimits returns per-payment-type limits from enabled provider instances.
|
||||
func (s *PaymentConfigService) GetMethodLimits(ctx context.Context, types []string) ([]MethodLimits, error) {
|
||||
instances, err := s.entClient.PaymentProviderInstance.Query().
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
dbent "github.com/Wei-Shaw/sub2api/ent"
|
||||
@@ -299,3 +300,73 @@ func TestPcInstanceTypeLimits(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetAvailableMethodLimitsRespectsVisibleMethodRouting(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
client := newPaymentConfigServiceTestClient(t)
|
||||
|
||||
_, err := client.PaymentProviderInstance.Create().
|
||||
SetProviderKey(payment.TypeAlipay).
|
||||
SetName("Official Alipay").
|
||||
SetConfig("{}").
|
||||
SetSupportedTypes("alipay").
|
||||
SetLimits(`{"alipay":{"singleMin":10,"singleMax":100}}`).
|
||||
SetEnabled(true).
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("create official alipay instance: %v", err)
|
||||
}
|
||||
_, err = client.PaymentProviderInstance.Create().
|
||||
SetProviderKey(payment.TypeEasyPay).
|
||||
SetName("EasyPay Alipay").
|
||||
SetConfig("{}").
|
||||
SetSupportedTypes("alipay").
|
||||
SetLimits(`{"alipay":{"singleMin":20,"singleMax":200}}`).
|
||||
SetEnabled(true).
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("create easypay alipay instance: %v", err)
|
||||
}
|
||||
_, err = client.PaymentProviderInstance.Create().
|
||||
SetProviderKey(payment.TypeWxpay).
|
||||
SetName("Official WeChat").
|
||||
SetConfig("{}").
|
||||
SetSupportedTypes("wxpay").
|
||||
SetLimits(`{"wxpay":{"singleMin":30,"singleMax":300}}`).
|
||||
SetEnabled(true).
|
||||
Save(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("create official wxpay instance: %v", err)
|
||||
}
|
||||
|
||||
svc := &PaymentConfigService{
|
||||
entClient: client,
|
||||
settingRepo: &paymentConfigSettingRepoStub{
|
||||
values: map[string]string{
|
||||
SettingPaymentVisibleMethodAlipayEnabled: "true",
|
||||
SettingPaymentVisibleMethodAlipaySource: VisibleMethodSourceEasyPayAlipay,
|
||||
SettingPaymentVisibleMethodWxpayEnabled: "false",
|
||||
SettingPaymentVisibleMethodWxpaySource: VisibleMethodSourceOfficialWechat,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := svc.GetAvailableMethodLimits(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("GetAvailableMethodLimits returned error: %v", err)
|
||||
}
|
||||
|
||||
alipayLimits, ok := resp.Methods[payment.TypeAlipay]
|
||||
if !ok {
|
||||
t.Fatalf("expected visible alipay limits, got %v", resp.Methods)
|
||||
}
|
||||
if alipayLimits.SingleMin != 20 || alipayLimits.SingleMax != 200 {
|
||||
t.Fatalf("alipay limits = %+v, want easypay-only min=20 max=200", alipayLimits)
|
||||
}
|
||||
if _, ok := resp.Methods[payment.TypeWxpay]; ok {
|
||||
t.Fatalf("wxpay should be hidden when visible method is disabled, got %v", resp.Methods[payment.TypeWxpay])
|
||||
}
|
||||
if resp.GlobalMin != 20 || resp.GlobalMax != 200 {
|
||||
t.Fatalf("global range = (%v, %v), want (20, 200)", resp.GlobalMin, resp.GlobalMax)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user