payment-poc/domain/providers/stripe/service.go

160 lines
4.9 KiB
Go
Raw Permalink Normal View History

2023-07-26 07:51:29 +00:00
package stripe
import (
2023-07-27 20:46:37 +00:00
"github.com/gin-gonic/gin"
2023-07-26 07:51:29 +00:00
"github.com/google/uuid"
2023-07-27 20:46:37 +00:00
"github.com/stripe/stripe-go/v72"
"github.com/stripe/stripe-go/v72/checkout/session"
"github.com/stripe/stripe-go/v72/paymentintent"
2024-04-01 18:29:24 +00:00
"log/slog"
database2 "payment-poc/domain/database"
"payment-poc/domain/state"
2023-07-26 07:51:29 +00:00
)
type Service struct {
2023-07-27 20:46:37 +00:00
ApiKey string
BackendUrl string
2023-07-26 07:51:29 +00:00
}
2024-04-01 18:29:24 +00:00
func (s *Service) UpdatePayment(entry database2.PaymentEntry) (updatedEntry database2.PaymentEntry, err error) {
client := paymentintent.Client{
B: stripe.GetBackend(stripe.APIBackend),
Key: s.ApiKey,
}
pi, err := client.Get(*entry.PaymentIntentId, nil)
2023-07-27 20:46:37 +00:00
if err != nil {
2023-07-31 07:21:54 +00:00
return entry, err
2023-07-27 20:46:37 +00:00
}
2023-07-31 07:21:54 +00:00
newState := determineState(pi.Status)
if entry.State != newState && newState != "" {
2024-04-01 18:29:24 +00:00
slog.Info("updated state", "entry_id", entry.Id.String(), "state", entry.State, "new_state", newState)
2023-07-31 07:21:54 +00:00
if pi.AmountReceived > 0 {
entry.Amount = &pi.AmountReceived
}
entry.State = newState
2023-07-27 20:46:37 +00:00
}
2023-07-31 07:21:54 +00:00
return entry, nil
}
func determineState(status stripe.PaymentIntentStatus) state.PaymentState {
switch status {
case stripe.PaymentIntentStatusCanceled:
return state.StateCanceled
case stripe.PaymentIntentStatusProcessing:
return state.StatePending
case stripe.PaymentIntentStatusRequiresAction:
return state.StatePending
case stripe.PaymentIntentStatusRequiresCapture:
return state.StateAccepted
case stripe.PaymentIntentStatusRequiresConfirmation:
return state.StatePending
case stripe.PaymentIntentStatusRequiresPaymentMethod:
return state.StateVoided
case stripe.PaymentIntentStatusSucceeded:
return state.StateCompleted
}
return ""
}
2024-04-01 18:29:24 +00:00
func (s *Service) CreatePaymentUrl(entry database2.PaymentEntry) (database2.PaymentEntry, string, error) {
2023-07-31 07:21:54 +00:00
entry, url, err := s.InitializePayment(entry)
2023-07-27 20:46:37 +00:00
if err != nil {
2023-07-31 07:21:54 +00:00
return entry, "", err
2023-07-27 20:46:37 +00:00
}
2023-07-31 07:21:54 +00:00
return entry, url, nil
2023-07-27 20:46:37 +00:00
}
2024-04-01 18:29:24 +00:00
func (s *Service) InitializePayment(entry database2.PaymentEntry) (database2.PaymentEntry, string, error) {
2023-07-27 20:46:37 +00:00
currency := string(stripe.CurrencyEUR)
productName := "Example product"
productDescription := "Simple example product"
params := &stripe.CheckoutSessionParams{
LineItems: []*stripe.CheckoutSessionLineItemParams{
{
PriceData: &stripe.CheckoutSessionLineItemPriceDataParams{
Currency: &currency,
ProductData: &stripe.CheckoutSessionLineItemPriceDataProductDataParams{
Name: &productName,
Description: &productDescription,
},
UnitAmount: &entry.TotalAmount,
},
Quantity: stripe.Int64(1),
},
},
Mode: stripe.String(string(stripe.CheckoutSessionModePayment)),
PaymentIntentData: &stripe.CheckoutSessionPaymentIntentDataParams{
CaptureMethod: stripe.String("manual"),
},
SuccessURL: stripe.String(s.BackendUrl + "/stripe/success?token=" + entry.Id.String()),
CancelURL: stripe.String(s.BackendUrl + "/stripe/cancel?token=" + entry.Id.String()),
2023-07-26 07:51:29 +00:00
}
2024-04-01 18:29:24 +00:00
client := session.Client{
B: stripe.GetBackend(stripe.APIBackend),
Key: s.ApiKey,
}
result, err := client.New(params)
2023-07-26 07:51:29 +00:00
if err != nil {
2024-04-01 18:29:24 +00:00
return database2.PaymentEntry{}, "", err
2023-07-26 07:51:29 +00:00
}
2023-07-31 07:21:54 +00:00
entry.State = state.StateInitialized
2023-07-27 20:46:37 +00:00
entry.PaymentIntentId = &result.PaymentIntent.ID
return entry, result.URL, nil
2023-07-26 07:51:29 +00:00
}
2024-04-01 18:29:24 +00:00
func (s *Service) CompleteTransaction(entry database2.PaymentEntry, amount int64) (database2.PaymentEntry, error) {
2023-07-27 20:46:37 +00:00
params := &stripe.PaymentIntentCaptureParams{
AmountToCapture: stripe.Int64(amount),
}
2024-04-01 18:29:24 +00:00
client := paymentintent.Client{
B: stripe.GetBackend(stripe.APIBackend),
Key: s.ApiKey,
}
pi, err := client.Capture(*entry.PaymentIntentId, params)
2023-07-27 20:46:37 +00:00
if err != nil {
2024-04-01 18:29:24 +00:00
return database2.PaymentEntry{}, err
2023-07-27 20:46:37 +00:00
}
2024-04-01 18:29:24 +00:00
slog.Info("received state on completion", "entry_id", entry.Id.String(), "state", entry.State, "new_state", pi.Status)
2023-07-31 07:21:54 +00:00
newState := determineState(pi.Status)
entry.State = newState
if newState == state.StateCompleted || newState == state.StatePending {
2023-07-30 10:14:05 +00:00
entry.Amount = &pi.AmountReceived
2023-07-27 20:46:37 +00:00
}
return entry, nil
2023-07-26 07:51:29 +00:00
}
2024-04-01 18:29:24 +00:00
func (s *Service) CancelTransaction(entry database2.PaymentEntry) (database2.PaymentEntry, error) {
2023-07-27 20:46:37 +00:00
params := &stripe.PaymentIntentCancelParams{}
2024-04-01 18:29:24 +00:00
client := paymentintent.Client{
B: stripe.GetBackend(stripe.APIBackend),
Key: s.ApiKey,
}
pi, err := client.Cancel(*entry.PaymentIntentId, params)
2023-07-27 20:46:37 +00:00
if err != nil {
2024-04-01 18:29:24 +00:00
return database2.PaymentEntry{}, err
2023-07-27 20:46:37 +00:00
}
2024-04-01 18:29:24 +00:00
slog.Info("received state on completion", "entry_id", entry.Id.String(), "state", entry.State, "new_state", pi.Status)
2023-07-27 20:46:37 +00:00
if pi.Status == stripe.PaymentIntentStatusCanceled {
entry.State = state.StateCanceled
}
return entry, nil
2023-07-26 07:51:29 +00:00
}
2024-04-01 18:29:24 +00:00
func (s *Service) HandleResponse(c *gin.Context, provider *database2.PaymentEntryProvider, paymentState state.PaymentState) (string, error) {
2023-07-27 20:46:37 +00:00
id := uuid.MustParse(c.Query("token"))
2023-07-31 07:21:54 +00:00
entry, err := provider.FetchById(id)
2023-07-27 20:46:37 +00:00
if err != nil {
return "", err
}
entry.State = paymentState
2023-07-31 08:01:37 +00:00
if _, err := provider.UpdateEntry(entry); err != nil {
return "", err
}
2024-04-01 18:29:24 +00:00
slog.Info("received authorization response", "entry_id", entry.Id.String(), "state", entry.State)
2023-07-27 20:46:37 +00:00
return "/entries/" + entry.Id.String(), nil
2023-07-26 07:51:29 +00:00
}