payment_handler_test.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package admin
  2. import (
  3. "encoding/json"
  4. "strings"
  5. "testing"
  6. "time"
  7. dbent "github.com/Wei-Shaw/sub2api/ent"
  8. "github.com/Wei-Shaw/sub2api/internal/service"
  9. )
  10. func TestSanitizeAdminPaymentOrderForResponseAddsCurrency(t *testing.T) {
  11. now := time.Now()
  12. order := &dbent.PaymentOrder{
  13. ID: 1,
  14. UserID: 2,
  15. Amount: 100,
  16. PayAmount: 108,
  17. FeeRate: 8,
  18. OutTradeNo: "sub2_202606250001",
  19. PaymentType: "stripe",
  20. OrderType: "subscription",
  21. Status: "COMPLETED",
  22. ExpiresAt: now,
  23. CreatedAt: now,
  24. UpdatedAt: now,
  25. ProviderSnapshot: map[string]any{
  26. "schema_version": 2,
  27. "currency": "USD",
  28. },
  29. }
  30. got := sanitizeAdminPaymentOrderForResponse(order)
  31. if got == nil {
  32. t.Fatal("expected sanitized order")
  33. }
  34. if got.Currency != "USD" {
  35. t.Fatalf("expected currency USD, got %q", got.Currency)
  36. }
  37. body, err := json.Marshal(got)
  38. if err != nil {
  39. t.Fatalf("marshal sanitized order: %v", err)
  40. }
  41. if strings.Contains(string(body), "provider_snapshot") {
  42. t.Fatalf("expected provider_snapshot to be omitted, got %s", string(body))
  43. }
  44. }
  45. func TestAdminSubscriptionPlansForResponseIncludesCompositeGroupInfo(t *testing.T) {
  46. weekly := 25.0
  47. now := time.Now()
  48. plans := []*dbent.SubscriptionPlan{
  49. {
  50. ID: 11,
  51. GroupID: 7,
  52. Name: "All models",
  53. Description: "Composite access",
  54. Price: 19.99,
  55. Currency: "CNY",
  56. ValidityDays: 30,
  57. ValidityUnit: "days",
  58. Features: "OpenAI\nClaude\nGemini\nGrok",
  59. ProductName: "Sub2API",
  60. ForSale: true,
  61. SortOrder: 1,
  62. CreatedAt: now,
  63. UpdatedAt: now,
  64. },
  65. }
  66. groupInfo := map[int64]service.PlanGroupInfo{
  67. 7: {
  68. Platform: service.PlatformComposite,
  69. Name: "Bucket 2 composite",
  70. RateMultiplier: 1.5,
  71. WeeklyLimitUSD: &weekly,
  72. ModelScopes: []string{"openai", "claude", "gemini", "grok"},
  73. },
  74. }
  75. got := adminSubscriptionPlansForResponse(plans, groupInfo)
  76. if len(got) != 1 {
  77. t.Fatalf("expected one plan, got %d", len(got))
  78. }
  79. if got[0].GroupPlatform != service.PlatformComposite {
  80. t.Fatalf("expected composite group platform, got %q", got[0].GroupPlatform)
  81. }
  82. if got[0].GroupName != "Bucket 2 composite" {
  83. t.Fatalf("expected group name to be included, got %q", got[0].GroupName)
  84. }
  85. if got[0].WeeklyLimitUSD == nil || *got[0].WeeklyLimitUSD != weekly {
  86. t.Fatalf("expected weekly limit to be included, got %#v", got[0].WeeklyLimitUSD)
  87. }
  88. if strings.Join(got[0].ModelScopes, ",") != "openai,claude,gemini,grok" {
  89. t.Fatalf("expected model scopes to be preserved, got %#v", got[0].ModelScopes)
  90. }
  91. // 投影必须保留 ent 原始响应的全部套餐字段:currency 丢失曾导致编辑保存时
  92. // 静默清空套餐货币(PlanEditDialog 回传空串 → SetCurrency(""))。
  93. if got[0].Currency != "CNY" {
  94. t.Fatalf("expected currency to be preserved, got %q", got[0].Currency)
  95. }
  96. if !got[0].CreatedAt.Equal(now) || !got[0].UpdatedAt.Equal(now) {
  97. t.Fatalf("expected created_at/updated_at to be preserved, got %v / %v", got[0].CreatedAt, got[0].UpdatedAt)
  98. }
  99. }