diff --git a/microservices/payment/app/data/session.go b/microservices/payment/app/data/session.go new file mode 100644 index 00000000..98209bd2 --- /dev/null +++ b/microservices/payment/app/data/session.go @@ -0,0 +1,9 @@ +package data + +// Session of a user to pay +type Session struct { + SuccessURL string `json:"success_url"` + CancelURL string `json:"cancel_url"` + PriceID string `json:"price_id"` + CustomerID string `json:"customer_id"` +} diff --git a/microservices/payment/app/go.sum b/microservices/payment/app/go.sum index 434c041f..b9819bd5 100644 --- a/microservices/payment/app/go.sum +++ b/microservices/payment/app/go.sum @@ -1,9 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/alexandr-io/backend v1.14.7 h1:MXfFCjPQ9cI2zQTZ1Fp0tegqzIlzzOSTkmurXzWZvrE= -github.com/alexandr-io/backend/common v0.0.0-20210913201527-0adcfe9625ce h1:MMvxuttBdMhau2AXPdbLuLRC4miZnxtZhzUKkfyMn2k= -github.com/alexandr-io/backend/common v0.0.0-20210913201527-0adcfe9625ce/go.mod h1:MBKlKzS+NO8TPhDbBpazCcTn0eH0Kvc3a3NogZtxEA4= github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= @@ -74,7 +71,6 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -86,8 +82,8 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= @@ -266,7 +262,6 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= diff --git a/microservices/payment/app/handlers/customer.go b/microservices/payment/app/handlers/customer.go new file mode 100644 index 00000000..b243cdd9 --- /dev/null +++ b/microservices/payment/app/handlers/customer.go @@ -0,0 +1,32 @@ +package handlers + +import ( + "strconv" + + "github.com/gofiber/fiber/v2" + + "github.com/alexandr-io/backend/payment/data" + "github.com/alexandr-io/backend/payment/database/customer" + stripeCustomer "github.com/alexandr-io/backend/payment/stripe/customer" +) + +// GetCustomerSubscription get the current subscription price of an user +func GetCustomerSubscription(ctx *fiber.Ctx) error { + userID, err := userIDFromHeader(ctx) + if err != nil { + return err + } + + var localCustomer *data.Customer + localCustomer, err = customer.GetByUserID(userID) + if err != nil { + return err + } + + price := stripeCustomer.GetCustomerSubscription(localCustomer.StripeID) + + if err = ctx.Status(fiber.StatusOK).Send([]byte(strconv.Itoa(int(price)))); err != nil { + return data.NewHTTPErrorInfo(fiber.StatusInternalServerError, err.Error()) + } + return nil +} diff --git a/microservices/payment/app/handlers/subscribe.go b/microservices/payment/app/handlers/subscribe.go index 21dc723d..8f956525 100644 --- a/microservices/payment/app/handlers/subscribe.go +++ b/microservices/payment/app/handlers/subscribe.go @@ -1,11 +1,10 @@ package handlers import ( - "log" - "github.com/alexandr-io/backend/payment/data" "github.com/alexandr-io/backend/payment/database/customer" "github.com/alexandr-io/backend/payment/internal" + "github.com/alexandr-io/backend/payment/stripe/session" "github.com/gofiber/fiber/v2" ) @@ -18,12 +17,18 @@ func Subscribe(ctx *fiber.Ctx) error { return err } - var Customer data.Customer - err = ParseBodyJSON(ctx, &Customer) + var sessionData data.Session + err = ParseBodyJSON(ctx, &sessionData) if err != nil { return err } + var customerData = data.Customer{ + UserID: userID, + Email: user.Email, + Username: user.Username, + } + var localCustomer *data.Customer localCustomer, err = customer.GetByUserID(userID) if err != nil { @@ -31,7 +36,7 @@ func Subscribe(ctx *fiber.Ctx) error { // Override status code if fiber.Error type if e.Code == fiber.StatusNotFound { - localCustomer, err = internal.CreateStripeCustomerForUser(user, Customer) + localCustomer, err = internal.CreateStripeCustomerForUser(user, customerData) if err != nil { return err } @@ -43,9 +48,14 @@ func Subscribe(ctx *fiber.Ctx) error { } } - log.Println(localCustomer) - // TODO: CREATE LINK TO PAY ON STRIPE - // - // Should use localCustomer + sessionData.CustomerID = localCustomer.StripeID + newSession, err := session.Create(sessionData) + if err != nil { + return err + } + + if err = ctx.Status(fiber.StatusOK).Send([]byte(newSession.URL)); err != nil { + return data.NewHTTPErrorInfo(fiber.StatusInternalServerError, err.Error()) + } return nil } diff --git a/microservices/payment/app/handlers/subscriptionList.go b/microservices/payment/app/handlers/subscriptionList.go index 1db41bce..785156f7 100644 --- a/microservices/payment/app/handlers/subscriptionList.go +++ b/microservices/payment/app/handlers/subscriptionList.go @@ -3,7 +3,6 @@ package handlers import ( "github.com/alexandr-io/backend/payment/data" "github.com/alexandr-io/backend/payment/internal" - "github.com/gofiber/fiber/v2" ) diff --git a/microservices/payment/app/rooting.go b/microservices/payment/app/rooting.go index f58c5a1f..ab9b83ee 100644 --- a/microservices/payment/app/rooting.go +++ b/microservices/payment/app/rooting.go @@ -27,6 +27,7 @@ func createRoute(app *fiber.App) { app.Get("/subscriptions", handlers.ListSubscriptions) app.Post("/subscribe", middleware.Protected(), handlers.Subscribe) + app.Get("/subscription/price", middleware.Protected(), handlers.GetCustomerSubscription) // Ping route used for testing that the service is up and running app.Get("/ping", func(c *fiber.Ctx) error { diff --git a/microservices/payment/app/stripe/customer/read.go b/microservices/payment/app/stripe/customer/read.go new file mode 100644 index 00000000..79c90cc0 --- /dev/null +++ b/microservices/payment/app/stripe/customer/read.go @@ -0,0 +1,17 @@ +package customer + +import ( + "github.com/stripe/stripe-go/v72" + "github.com/stripe/stripe-go/v72/customer" +) + +// GetCustomerSubscription get a customer subscription +func GetCustomerSubscription(stripeID string) int64 { + params := &stripe.CustomerParams{} + params.AddExpand("subscriptions") + c, _ := customer.Get(stripeID, params) + if len(c.Subscriptions.Data) != 0 { + return c.Subscriptions.Data[0].Items.Data[0].Price.UnitAmount + } + return 0 +} diff --git a/microservices/payment/app/stripe/session/create.go b/microservices/payment/app/stripe/session/create.go new file mode 100644 index 00000000..11bef0aa --- /dev/null +++ b/microservices/payment/app/stripe/session/create.go @@ -0,0 +1,33 @@ +package session + +import ( + "github.com/alexandr-io/backend/payment/data" + "github.com/gofiber/fiber/v2" + "github.com/stripe/stripe-go/v72" + "github.com/stripe/stripe-go/v72/checkout/session" +) + +// Create a stripe customer session +func Create(sessionData data.Session) (*stripe.CheckoutSession, error) { + params := &stripe.CheckoutSessionParams{ + SuccessURL: stripe.String(sessionData.SuccessURL), + CancelURL: stripe.String(sessionData.CancelURL), + PaymentMethodTypes: stripe.StringSlice([]string{ + "card", + }), + LineItems: []*stripe.CheckoutSessionLineItemParams{ + { + Price: stripe.String(sessionData.PriceID), + Quantity: stripe.Int64(1), + }, + }, + Mode: stripe.String(string(stripe.CheckoutSessionModeSubscription)), + Customer: stripe.String(sessionData.CustomerID), + } + + result, err := session.New(params) + if err != nil { + return nil, data.NewHTTPErrorInfo(fiber.StatusInternalServerError, err.Error()) + } + return result, nil +}