stripe.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package billing
  2. import (
  3. "fmt"
  4. "github.com/porter-dev/porter/api/types"
  5. "github.com/porter-dev/porter/internal/models"
  6. "github.com/stripe/stripe-go/v76"
  7. "github.com/stripe/stripe-go/v76/customer"
  8. "github.com/stripe/stripe-go/v76/paymentmethod"
  9. "github.com/stripe/stripe-go/v76/setupintent"
  10. )
  11. // StripeBillingManager interacts with the Stripe API to manage payment methods
  12. // and customers
  13. type StripeBillingManager struct {
  14. StripeSecretKey string
  15. StripePublishableKey string
  16. }
  17. // CreateCustomer will create a customer in Stripe only if the project doesn't have a BillingID
  18. func (s *StripeBillingManager) CreateCustomer(userEmail string, proj *models.Project) (customerID string, err error) {
  19. stripe.Key = s.StripeSecretKey
  20. if proj.BillingID == "" {
  21. // Create customer if not exists
  22. customerName := fmt.Sprintf("project_%s", proj.Name)
  23. params := &stripe.CustomerParams{
  24. Name: stripe.String(customerName),
  25. Email: stripe.String(userEmail),
  26. }
  27. // Create in Stripe
  28. customer, err := customer.New(params)
  29. if err != nil {
  30. return "", err
  31. }
  32. customerID = customer.ID
  33. }
  34. return customerID, nil
  35. }
  36. // DeleteCustomer will delete the customer from the billing provider
  37. func (s *StripeBillingManager) DeleteCustomer(proj *models.Project) (err error) {
  38. stripe.Key = s.StripeSecretKey
  39. if proj.BillingID != "" {
  40. params := &stripe.CustomerParams{}
  41. _, err := customer.Del(proj.BillingID, params)
  42. if err != nil {
  43. return err
  44. }
  45. }
  46. return nil
  47. }
  48. // CheckPaymentEnabled will return true if the project has a payment method added, false otherwise
  49. func (s *StripeBillingManager) CheckPaymentEnabled(proj *models.Project) (paymentEnabled bool, err error) {
  50. stripe.Key = s.StripeSecretKey
  51. params := &stripe.PaymentMethodListParams{
  52. Customer: stripe.String(proj.BillingID),
  53. Type: stripe.String(string(stripe.PaymentMethodTypeCard)),
  54. }
  55. result := paymentmethod.List(params)
  56. return result.Next(), nil
  57. }
  58. // ListPaymentMethod will return all payment methods for the project
  59. func (s *StripeBillingManager) ListPaymentMethod(proj *models.Project) (paymentMethods []types.PaymentMethod, err error) {
  60. stripe.Key = s.StripeSecretKey
  61. // Get configured payment methods
  62. params := &stripe.PaymentMethodListParams{
  63. Customer: stripe.String(proj.BillingID),
  64. Type: stripe.String(string(stripe.PaymentMethodTypeCard)),
  65. }
  66. result := paymentmethod.List(params)
  67. defaultPaymentExists, defaultPaymentID, err := s.checkDefaultPaymentMethod(proj.BillingID)
  68. if err != nil {
  69. return paymentMethods, err
  70. }
  71. for result.Next() {
  72. stripePaymentMethod := result.PaymentMethod()
  73. var isDefaultPaymentMethod bool
  74. if stripePaymentMethod.ID == defaultPaymentID {
  75. isDefaultPaymentMethod = true
  76. }
  77. paymentMethods = append(paymentMethods, types.PaymentMethod{
  78. ID: stripePaymentMethod.ID,
  79. DisplayBrand: stripePaymentMethod.Card.DisplayBrand,
  80. Last4: stripePaymentMethod.Card.Last4,
  81. ExpMonth: stripePaymentMethod.Card.ExpMonth,
  82. ExpYear: stripePaymentMethod.Card.ExpYear,
  83. Default: isDefaultPaymentMethod,
  84. })
  85. }
  86. // Set default payment method when project has payment methods enabled but
  87. // no default setup
  88. if len(paymentMethods) > 0 && !defaultPaymentExists {
  89. err = s.SetDefaultPaymentMethod(paymentMethods[len(paymentMethods)-1].ID, proj)
  90. if err != nil {
  91. return paymentMethods, err
  92. }
  93. }
  94. return paymentMethods, nil
  95. }
  96. // CreatePaymentMethod will add a new payment method to the project in Stripe
  97. func (s *StripeBillingManager) CreatePaymentMethod(proj *models.Project) (clientSecret string, err error) {
  98. stripe.Key = s.StripeSecretKey
  99. params := &stripe.SetupIntentParams{
  100. Customer: stripe.String(proj.BillingID),
  101. AutomaticPaymentMethods: &stripe.SetupIntentAutomaticPaymentMethodsParams{
  102. Enabled: stripe.Bool(false),
  103. },
  104. PaymentMethodTypes: []*string{stripe.String("card")},
  105. }
  106. intent, err := setupintent.New(params)
  107. if err != nil {
  108. return "", err
  109. }
  110. return intent.ClientSecret, nil
  111. }
  112. // SetDefaultPaymentMethod will add a new payment method to the project in Stripe
  113. func (s *StripeBillingManager) SetDefaultPaymentMethod(paymentMethodID string, proj *models.Project) (err error) {
  114. stripe.Key = s.StripeSecretKey
  115. params := &stripe.CustomerParams{
  116. InvoiceSettings: &stripe.CustomerInvoiceSettingsParams{
  117. DefaultPaymentMethod: stripe.String(paymentMethodID),
  118. },
  119. }
  120. _, err = customer.Update(proj.BillingID, params)
  121. if err != nil {
  122. return err
  123. }
  124. return nil
  125. }
  126. // DeletePaymentMethod will remove a payment method for the project in Stripe
  127. func (s *StripeBillingManager) DeletePaymentMethod(paymentMethodID string) (err error) {
  128. stripe.Key = s.StripeSecretKey
  129. _, err = paymentmethod.Detach(paymentMethodID, nil)
  130. if err != nil {
  131. return err
  132. }
  133. return nil
  134. }
  135. // GetPublishableKey is a no-op
  136. func (s *StripeBillingManager) GetPublishableKey() (key string) {
  137. return s.StripePublishableKey
  138. }
  139. func (s *StripeBillingManager) checkDefaultPaymentMethod(customerID string) (defaultPaymentExists bool, defaultPaymentID string, err error) {
  140. // Get customer to check default payment method
  141. customer, err := customer.Get(customerID, nil)
  142. if err != nil {
  143. return defaultPaymentExists, defaultPaymentID, err
  144. }
  145. if customer.InvoiceSettings != nil && customer.InvoiceSettings.DefaultPaymentMethod != nil {
  146. defaultPaymentExists = true
  147. defaultPaymentID = customer.InvoiceSettings.DefaultPaymentMethod.ID
  148. }
  149. return defaultPaymentExists, defaultPaymentID, err
  150. }