payment_config_limits_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. package service
  2. import (
  3. "context"
  4. "testing"
  5. dbent "github.com/Wei-Shaw/sub2api/ent"
  6. "github.com/Wei-Shaw/sub2api/internal/payment"
  7. infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors"
  8. "github.com/stretchr/testify/require"
  9. )
  10. func TestUnionFloat(t *testing.T) {
  11. t.Parallel()
  12. tests := []struct {
  13. name string
  14. agg float64
  15. limited bool
  16. val float64
  17. wantMin bool
  18. wantAgg float64
  19. wantLimited bool
  20. }{
  21. {"first non-zero value", 0, true, 5, true, 5, true},
  22. {"lower min replaces", 10, true, 3, true, 3, true},
  23. {"higher min does not replace", 3, true, 10, true, 3, true},
  24. {"higher max replaces", 10, true, 20, false, 20, true},
  25. {"lower max does not replace", 20, true, 10, false, 20, true},
  26. {"zero value makes unlimited", 5, true, 0, true, 5, false},
  27. {"already unlimited stays unlimited", 5, false, 10, true, 5, false},
  28. {"zero on first call", 0, true, 0, true, 0, false},
  29. }
  30. for _, tt := range tests {
  31. t.Run(tt.name, func(t *testing.T) {
  32. t.Parallel()
  33. gotAgg, gotLimited := unionFloat(tt.agg, tt.limited, tt.val, tt.wantMin)
  34. if gotAgg != tt.wantAgg || gotLimited != tt.wantLimited {
  35. t.Fatalf("unionFloat(%v, %v, %v, %v) = (%v, %v), want (%v, %v)",
  36. tt.agg, tt.limited, tt.val, tt.wantMin,
  37. gotAgg, gotLimited, tt.wantAgg, tt.wantLimited)
  38. }
  39. })
  40. }
  41. }
  42. func makeInstance(id int64, providerKey, supportedTypes, limits string) *dbent.PaymentProviderInstance {
  43. return &dbent.PaymentProviderInstance{
  44. ID: id,
  45. ProviderKey: providerKey,
  46. SupportedTypes: supportedTypes,
  47. Limits: limits,
  48. Enabled: true,
  49. }
  50. }
  51. func TestPcAggregateMethodLimits(t *testing.T) {
  52. t.Parallel()
  53. t.Run("single instance with limits", func(t *testing.T) {
  54. t.Parallel()
  55. inst := makeInstance(1, "easypay", "alipay,wxpay",
  56. `{"alipay":{"singleMin":2,"singleMax":14},"wxpay":{"singleMin":1,"singleMax":12}}`)
  57. ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst})
  58. if ml.SingleMin != 2 || ml.SingleMax != 14 {
  59. t.Fatalf("alipay limits = min:%v max:%v, want min:2 max:14", ml.SingleMin, ml.SingleMax)
  60. }
  61. })
  62. t.Run("two instances union takes widest range", func(t *testing.T) {
  63. t.Parallel()
  64. inst1 := makeInstance(1, "easypay", "alipay,wxpay",
  65. `{"alipay":{"singleMin":5,"singleMax":100}}`)
  66. inst2 := makeInstance(2, "easypay", "alipay,wxpay",
  67. `{"alipay":{"singleMin":2,"singleMax":200}}`)
  68. ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst1, inst2})
  69. if ml.SingleMin != 2 {
  70. t.Fatalf("SingleMin = %v, want 2 (lowest floor)", ml.SingleMin)
  71. }
  72. if ml.SingleMax != 200 {
  73. t.Fatalf("SingleMax = %v, want 200 (highest ceiling)", ml.SingleMax)
  74. }
  75. })
  76. t.Run("one instance unlimited makes aggregate unlimited", func(t *testing.T) {
  77. t.Parallel()
  78. inst1 := makeInstance(1, "easypay", "wxpay",
  79. `{"wxpay":{"singleMin":3,"singleMax":10}}`)
  80. inst2 := makeInstance(2, "easypay", "wxpay", "") // no limits = unlimited
  81. ml := pcAggregateMethodLimits("wxpay", []*dbent.PaymentProviderInstance{inst1, inst2})
  82. if ml.SingleMin != 0 || ml.SingleMax != 0 {
  83. t.Fatalf("limits = min:%v max:%v, want min:0 max:0 (unlimited)", ml.SingleMin, ml.SingleMax)
  84. }
  85. })
  86. t.Run("one field unlimited others limited", func(t *testing.T) {
  87. t.Parallel()
  88. inst1 := makeInstance(1, "easypay", "alipay",
  89. `{"alipay":{"singleMin":5,"singleMax":100}}`)
  90. inst2 := makeInstance(2, "easypay", "alipay",
  91. `{"alipay":{"singleMin":3,"singleMax":0}}`) // singleMax=0 = unlimited
  92. ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst1, inst2})
  93. if ml.SingleMin != 3 {
  94. t.Fatalf("SingleMin = %v, want 3 (lowest floor)", ml.SingleMin)
  95. }
  96. if ml.SingleMax != 0 {
  97. t.Fatalf("SingleMax = %v, want 0 (unlimited)", ml.SingleMax)
  98. }
  99. })
  100. t.Run("empty instances returns zeros", func(t *testing.T) {
  101. t.Parallel()
  102. ml := pcAggregateMethodLimits("alipay", nil)
  103. if ml.SingleMin != 0 || ml.SingleMax != 0 || ml.DailyLimit != 0 {
  104. t.Fatalf("empty instances should return all zeros, got %+v", ml)
  105. }
  106. })
  107. t.Run("invalid JSON treated as unlimited", func(t *testing.T) {
  108. t.Parallel()
  109. inst := makeInstance(1, "easypay", "alipay", `{invalid json}`)
  110. ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst})
  111. if ml.SingleMin != 0 || ml.SingleMax != 0 {
  112. t.Fatalf("invalid JSON should be treated as unlimited, got %+v", ml)
  113. }
  114. })
  115. t.Run("type not in limits JSON treated as unlimited", func(t *testing.T) {
  116. t.Parallel()
  117. inst := makeInstance(1, "easypay", "alipay,wxpay",
  118. `{"wxpay":{"singleMin":1,"singleMax":10}}`) // only wxpay, no alipay
  119. ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst})
  120. if ml.SingleMin != 0 || ml.SingleMax != 0 {
  121. t.Fatalf("missing type should be treated as unlimited, got %+v", ml)
  122. }
  123. })
  124. t.Run("daily limit aggregation", func(t *testing.T) {
  125. t.Parallel()
  126. inst1 := makeInstance(1, "easypay", "alipay",
  127. `{"alipay":{"singleMin":1,"singleMax":100,"dailyLimit":500}}`)
  128. inst2 := makeInstance(2, "easypay", "alipay",
  129. `{"alipay":{"singleMin":2,"singleMax":200,"dailyLimit":1000}}`)
  130. ml := pcAggregateMethodLimits("alipay", []*dbent.PaymentProviderInstance{inst1, inst2})
  131. if ml.DailyLimit != 1000 {
  132. t.Fatalf("DailyLimit = %v, want 1000 (highest cap)", ml.DailyLimit)
  133. }
  134. })
  135. }
  136. func TestPcGroupByPaymentType(t *testing.T) {
  137. t.Parallel()
  138. t.Run("stripe instance maps all types to stripe group", func(t *testing.T) {
  139. t.Parallel()
  140. stripe := makeInstance(1, payment.TypeStripe, "card,alipay,link,wxpay", "")
  141. easypay := makeInstance(2, payment.TypeEasyPay, "alipay,wxpay", "")
  142. groups := pcGroupByPaymentType([]*dbent.PaymentProviderInstance{stripe, easypay})
  143. // Stripe instance should only be in "stripe" group
  144. if len(groups[payment.TypeStripe]) != 1 || groups[payment.TypeStripe][0].ID != 1 {
  145. t.Fatalf("stripe group should contain only stripe instance, got %v", groups[payment.TypeStripe])
  146. }
  147. // alipay group should only contain easypay, NOT stripe
  148. if len(groups[payment.TypeAlipay]) != 1 || groups[payment.TypeAlipay][0].ID != 2 {
  149. t.Fatalf("alipay group should contain only easypay instance, got %v", groups[payment.TypeAlipay])
  150. }
  151. // wxpay group should only contain easypay, NOT stripe
  152. if len(groups[payment.TypeWxpay]) != 1 || groups[payment.TypeWxpay][0].ID != 2 {
  153. t.Fatalf("wxpay group should contain only easypay instance, got %v", groups[payment.TypeWxpay])
  154. }
  155. })
  156. t.Run("multiple easypay instances in same groups", func(t *testing.T) {
  157. t.Parallel()
  158. ep1 := makeInstance(1, payment.TypeEasyPay, "alipay,wxpay", "")
  159. ep2 := makeInstance(2, payment.TypeEasyPay, "alipay,wxpay", "")
  160. groups := pcGroupByPaymentType([]*dbent.PaymentProviderInstance{ep1, ep2})
  161. if len(groups[payment.TypeAlipay]) != 2 {
  162. t.Fatalf("alipay group should have 2 instances, got %d", len(groups[payment.TypeAlipay]))
  163. }
  164. if len(groups[payment.TypeWxpay]) != 2 {
  165. t.Fatalf("wxpay group should have 2 instances, got %d", len(groups[payment.TypeWxpay]))
  166. }
  167. })
  168. t.Run("stripe with no supported types still in stripe group", func(t *testing.T) {
  169. t.Parallel()
  170. stripe := makeInstance(1, payment.TypeStripe, "", "")
  171. groups := pcGroupByPaymentType([]*dbent.PaymentProviderInstance{stripe})
  172. if len(groups[payment.TypeStripe]) != 1 {
  173. t.Fatalf("stripe with empty types should still be in stripe group, got %v", groups)
  174. }
  175. })
  176. }
  177. func TestPcAggregateMethodCurrency(t *testing.T) {
  178. t.Parallel()
  179. svc := &PaymentConfigService{}
  180. stripe := makeInstance(1, payment.TypeStripe, payment.TypeStripe, "")
  181. stripe.Config = `{"currency":"hkd"}`
  182. currency, ok := svc.pcAggregateMethodCurrency([]*dbent.PaymentProviderInstance{stripe})
  183. require.True(t, ok)
  184. require.Equal(t, "HKD", currency)
  185. airwallex := makeInstance(2, payment.TypeAirwallex, payment.TypeAirwallex, "")
  186. airwallex.Config = `{"currency":"usd"}`
  187. currency, ok = svc.pcAggregateMethodCurrency([]*dbent.PaymentProviderInstance{stripe, airwallex})
  188. require.False(t, ok)
  189. require.Empty(t, currency)
  190. easypay := makeInstance(3, payment.TypeEasyPay, payment.TypeAlipay, "")
  191. currency, ok = svc.pcAggregateMethodCurrency([]*dbent.PaymentProviderInstance{easypay})
  192. require.True(t, ok)
  193. require.Equal(t, payment.DefaultPaymentCurrency, currency)
  194. }
  195. func TestGetAvailableMethodLimitsOmitsMixedCurrencyMethod(t *testing.T) {
  196. ctx := context.Background()
  197. client := newPaymentConfigServiceTestClient(t)
  198. _, err := client.PaymentProviderInstance.Create().
  199. SetProviderKey(payment.TypeStripe).
  200. SetName("Stripe HKD").
  201. SetConfig(`{"currency":"HKD"}`).
  202. SetSupportedTypes("card,link").
  203. SetEnabled(true).
  204. Save(ctx)
  205. require.NoError(t, err)
  206. _, err = client.PaymentProviderInstance.Create().
  207. SetProviderKey(payment.TypeStripe).
  208. SetName("Stripe USD").
  209. SetConfig(`{"currency":"USD"}`).
  210. SetSupportedTypes("card,link").
  211. SetEnabled(true).
  212. Save(ctx)
  213. require.NoError(t, err)
  214. svc := &PaymentConfigService{entClient: client}
  215. resp, err := svc.GetAvailableMethodLimits(ctx)
  216. require.NoError(t, err)
  217. require.NotContains(t, resp.Methods, payment.TypeStripe)
  218. _, err = svc.ValidateMethodCurrencyConsistency(ctx, payment.TypeStripe)
  219. require.Error(t, err)
  220. appErr := infraerrors.FromError(err)
  221. require.Equal(t, "PAYMENT_METHOD_CURRENCY_CONFLICT", appErr.Reason)
  222. }
  223. func TestGetAvailableMethodLimitsIncludesEasyPayCustomMethodDisplayName(t *testing.T) {
  224. ctx := context.Background()
  225. client := newPaymentConfigServiceTestClient(t)
  226. _, err := client.PaymentProviderInstance.Create().
  227. SetProviderKey(payment.TypeEasyPay).
  228. SetName("EasyPay Custom").
  229. SetConfig(`{"customMethods":"[{\"type\":\"ldc\",\"upstreamType\":\"ldc\",\"displayName\":\"LDC Pay\"}]"}`).
  230. SetSupportedTypes("alipay,wxpay,ldc").
  231. SetEnabled(true).
  232. Save(ctx)
  233. require.NoError(t, err)
  234. svc := &PaymentConfigService{entClient: client}
  235. resp, err := svc.GetAvailableMethodLimits(ctx)
  236. require.NoError(t, err)
  237. limits, ok := resp.Methods["ldc"]
  238. require.True(t, ok, "expected custom EasyPay method limits to be visible")
  239. require.Equal(t, "LDC Pay", limits.DisplayName)
  240. }
  241. func TestPcComputeGlobalRange(t *testing.T) {
  242. t.Parallel()
  243. t.Run("all methods have limits", func(t *testing.T) {
  244. t.Parallel()
  245. methods := map[string]MethodLimits{
  246. "alipay": {SingleMin: 2, SingleMax: 14},
  247. "wxpay": {SingleMin: 1, SingleMax: 12},
  248. "stripe": {SingleMin: 5, SingleMax: 100},
  249. }
  250. gMin, gMax := pcComputeGlobalRange(methods)
  251. if gMin != 1 {
  252. t.Fatalf("global min = %v, want 1 (lowest floor)", gMin)
  253. }
  254. if gMax != 100 {
  255. t.Fatalf("global max = %v, want 100 (highest ceiling)", gMax)
  256. }
  257. })
  258. t.Run("one method unlimited makes global unlimited", func(t *testing.T) {
  259. t.Parallel()
  260. methods := map[string]MethodLimits{
  261. "alipay": {SingleMin: 2, SingleMax: 14},
  262. "stripe": {SingleMin: 0, SingleMax: 0}, // unlimited
  263. }
  264. gMin, gMax := pcComputeGlobalRange(methods)
  265. if gMin != 0 {
  266. t.Fatalf("global min = %v, want 0 (unlimited)", gMin)
  267. }
  268. if gMax != 0 {
  269. t.Fatalf("global max = %v, want 0 (unlimited)", gMax)
  270. }
  271. })
  272. t.Run("empty methods returns zeros", func(t *testing.T) {
  273. t.Parallel()
  274. gMin, gMax := pcComputeGlobalRange(map[string]MethodLimits{})
  275. if gMin != 0 || gMax != 0 {
  276. t.Fatalf("empty methods should return (0, 0), got (%v, %v)", gMin, gMax)
  277. }
  278. })
  279. t.Run("only min unlimited", func(t *testing.T) {
  280. t.Parallel()
  281. methods := map[string]MethodLimits{
  282. "alipay": {SingleMin: 0, SingleMax: 100},
  283. "wxpay": {SingleMin: 5, SingleMax: 50},
  284. }
  285. gMin, gMax := pcComputeGlobalRange(methods)
  286. if gMin != 0 {
  287. t.Fatalf("global min = %v, want 0 (unlimited)", gMin)
  288. }
  289. if gMax != 100 {
  290. t.Fatalf("global max = %v, want 100", gMax)
  291. }
  292. })
  293. }
  294. func TestPcInstanceTypeLimits(t *testing.T) {
  295. t.Parallel()
  296. t.Run("empty limits string returns false", func(t *testing.T) {
  297. t.Parallel()
  298. inst := makeInstance(1, "easypay", "alipay", "")
  299. _, ok := pcInstanceTypeLimits(inst, "alipay")
  300. if ok {
  301. t.Fatal("expected ok=false for empty limits")
  302. }
  303. })
  304. t.Run("type found returns correct values", func(t *testing.T) {
  305. t.Parallel()
  306. inst := makeInstance(1, "easypay", "alipay",
  307. `{"alipay":{"singleMin":2,"singleMax":14,"dailyLimit":500}}`)
  308. cl, ok := pcInstanceTypeLimits(inst, "alipay")
  309. if !ok {
  310. t.Fatal("expected ok=true")
  311. }
  312. if cl.SingleMin != 2 || cl.SingleMax != 14 || cl.DailyLimit != 500 {
  313. t.Fatalf("limits = %+v, want min:2 max:14 daily:500", cl)
  314. }
  315. })
  316. t.Run("type not found returns false", func(t *testing.T) {
  317. t.Parallel()
  318. inst := makeInstance(1, "easypay", "alipay",
  319. `{"wxpay":{"singleMin":1}}`)
  320. _, ok := pcInstanceTypeLimits(inst, "alipay")
  321. if ok {
  322. t.Fatal("expected ok=false for missing type")
  323. }
  324. })
  325. t.Run("invalid JSON returns false", func(t *testing.T) {
  326. t.Parallel()
  327. inst := makeInstance(1, "easypay", "alipay", `{bad json}`)
  328. _, ok := pcInstanceTypeLimits(inst, "alipay")
  329. if ok {
  330. t.Fatal("expected ok=false for invalid JSON")
  331. }
  332. })
  333. }
  334. func TestGetAvailableMethodLimitsUsesConfiguredVisibleMethodSource(t *testing.T) {
  335. tests := []struct {
  336. name string
  337. sourceSetting string
  338. wantAlipaySingleMin float64
  339. wantAlipaySingleMax float64
  340. wantGlobalMin float64
  341. wantGlobalMax float64
  342. }{
  343. {
  344. name: "official source",
  345. sourceSetting: VisibleMethodSourceOfficialAlipay,
  346. wantAlipaySingleMin: 10,
  347. wantAlipaySingleMax: 100,
  348. wantGlobalMin: 10,
  349. wantGlobalMax: 300,
  350. },
  351. {
  352. name: "easypay source",
  353. sourceSetting: VisibleMethodSourceEasyPayAlipay,
  354. wantAlipaySingleMin: 20,
  355. wantAlipaySingleMax: 200,
  356. wantGlobalMin: 20,
  357. wantGlobalMax: 300,
  358. },
  359. }
  360. for _, tt := range tests {
  361. t.Run(tt.name, func(t *testing.T) {
  362. ctx := context.Background()
  363. client := newPaymentConfigServiceTestClient(t)
  364. _, err := client.PaymentProviderInstance.Create().
  365. SetProviderKey(payment.TypeAlipay).
  366. SetName("Official Alipay").
  367. SetConfig("{}").
  368. SetSupportedTypes("alipay").
  369. SetLimits(`{"alipay":{"singleMin":10,"singleMax":100}}`).
  370. SetEnabled(true).
  371. Save(ctx)
  372. if err != nil {
  373. t.Fatalf("create official alipay instance: %v", err)
  374. }
  375. _, err = client.PaymentProviderInstance.Create().
  376. SetProviderKey(payment.TypeEasyPay).
  377. SetName("EasyPay Alipay").
  378. SetConfig("{}").
  379. SetSupportedTypes("alipay").
  380. SetLimits(`{"alipay":{"singleMin":20,"singleMax":200}}`).
  381. SetEnabled(true).
  382. Save(ctx)
  383. if err != nil {
  384. t.Fatalf("create easypay alipay instance: %v", err)
  385. }
  386. _, err = client.PaymentProviderInstance.Create().
  387. SetProviderKey(payment.TypeWxpay).
  388. SetName("Official WeChat").
  389. SetConfig("{}").
  390. SetSupportedTypes("wxpay").
  391. SetLimits(`{"wxpay":{"singleMin":30,"singleMax":300}}`).
  392. SetEnabled(true).
  393. Save(ctx)
  394. if err != nil {
  395. t.Fatalf("create official wxpay instance: %v", err)
  396. }
  397. svc := &PaymentConfigService{
  398. entClient: client,
  399. settingRepo: &paymentConfigSettingRepoStub{
  400. values: map[string]string{
  401. SettingPaymentVisibleMethodAlipaySource: tt.sourceSetting,
  402. },
  403. },
  404. }
  405. resp, err := svc.GetAvailableMethodLimits(ctx)
  406. if err != nil {
  407. t.Fatalf("GetAvailableMethodLimits returned error: %v", err)
  408. }
  409. alipayLimits, ok := resp.Methods[payment.TypeAlipay]
  410. if !ok {
  411. t.Fatalf("expected alipay limits to remain visible, got %v", resp.Methods)
  412. }
  413. if alipayLimits.SingleMin != tt.wantAlipaySingleMin || alipayLimits.SingleMax != tt.wantAlipaySingleMax {
  414. t.Fatalf("alipay limits = %+v, want min=%v max=%v", alipayLimits, tt.wantAlipaySingleMin, tt.wantAlipaySingleMax)
  415. }
  416. wxpayLimits, ok := resp.Methods[payment.TypeWxpay]
  417. if !ok {
  418. t.Fatalf("expected wxpay limits to remain visible, got %v", resp.Methods)
  419. }
  420. if wxpayLimits.SingleMin != 30 || wxpayLimits.SingleMax != 300 {
  421. t.Fatalf("wxpay limits = %+v, want official-only min=30 max=300", wxpayLimits)
  422. }
  423. if resp.GlobalMin != tt.wantGlobalMin || resp.GlobalMax != tt.wantGlobalMax {
  424. t.Fatalf("global range = (%v, %v), want (%v, %v)", resp.GlobalMin, resp.GlobalMax, tt.wantGlobalMin, tt.wantGlobalMax)
  425. }
  426. })
  427. }
  428. }
  429. func TestGetAvailableMethodLimitsPreservesLegacyCrossProviderBehaviorWhenVisibleMethodSourceMissing(t *testing.T) {
  430. ctx := context.Background()
  431. client := newPaymentConfigServiceTestClient(t)
  432. _, err := client.PaymentProviderInstance.Create().
  433. SetProviderKey(payment.TypeAlipay).
  434. SetName("Official Alipay").
  435. SetConfig("{}").
  436. SetSupportedTypes("alipay").
  437. SetLimits(`{"alipay":{"singleMin":10,"singleMax":100}}`).
  438. SetEnabled(true).
  439. Save(ctx)
  440. require.NoError(t, err)
  441. _, err = client.PaymentProviderInstance.Create().
  442. SetProviderKey(payment.TypeEasyPay).
  443. SetName("EasyPay Mixed").
  444. SetConfig("{}").
  445. SetSupportedTypes("alipay,wxpay").
  446. SetLimits(`{"alipay":{"singleMin":20,"singleMax":200},"wxpay":{"singleMin":40,"singleMax":400}}`).
  447. SetEnabled(true).
  448. Save(ctx)
  449. require.NoError(t, err)
  450. _, err = client.PaymentProviderInstance.Create().
  451. SetProviderKey(payment.TypeWxpay).
  452. SetName("Official WeChat").
  453. SetConfig("{}").
  454. SetSupportedTypes("wxpay").
  455. SetLimits(`{"wxpay":{"singleMin":30,"singleMax":300}}`).
  456. SetEnabled(true).
  457. Save(ctx)
  458. require.NoError(t, err)
  459. svc := &PaymentConfigService{
  460. entClient: client,
  461. settingRepo: &paymentConfigSettingRepoStub{values: map[string]string{}},
  462. }
  463. resp, err := svc.GetAvailableMethodLimits(ctx)
  464. require.NoError(t, err)
  465. alipayLimits, ok := resp.Methods[payment.TypeAlipay]
  466. require.True(t, ok, "expected alipay limits to remain visible")
  467. require.Equal(t, 10.0, alipayLimits.SingleMin)
  468. require.Equal(t, 200.0, alipayLimits.SingleMax)
  469. wxpayLimits, ok := resp.Methods[payment.TypeWxpay]
  470. require.True(t, ok, "expected wxpay limits to remain visible")
  471. require.Equal(t, 30.0, wxpayLimits.SingleMin)
  472. require.Equal(t, 400.0, wxpayLimits.SingleMax)
  473. require.Equal(t, 10.0, resp.GlobalMin)
  474. require.Equal(t, 400.0, resp.GlobalMax)
  475. }