Skip to content

Commit

Permalink
fix: set email when creating new session for trial days
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelbrm committed Nov 12, 2024
1 parent b2a2a8f commit 440b911
Show file tree
Hide file tree
Showing 11 changed files with 444 additions and 131 deletions.
13 changes: 6 additions & 7 deletions services/skus/controllers.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"net/http"
"os"
"strconv"
"time"

"github.com/asaskevich/govalidator"
"github.com/go-chi/chi"
Expand Down Expand Up @@ -311,10 +312,10 @@ func VoteRouter(service *Service, instrumentHandler middleware.InstrumentHandler
}

type setTrialDaysRequest struct {
TrialDays int64 `json:"trialDays"`
Email string `json:"email"` // TODO: Make it required.
TrialDays int64 `json:"trialDays"`
}

// TODO: refactor this to avoid multiple fetches of an order.
func handleSetOrderTrialDays(svc *Service) handlers.AppHandler {
return handlers.AppHandler(func(w http.ResponseWriter, r *http.Request) *handlers.AppError {
ctx := r.Context()
Expand All @@ -324,10 +325,6 @@ func handleSetOrderTrialDays(svc *Service) handlers.AppHandler {
return handlers.ValidationError("request", map[string]interface{}{"orderID": err.Error()})
}

if err := svc.validateOrderMerchantAndCaveats(ctx, orderID); err != nil {
return handlers.ValidationError("merchant and caveats", map[string]interface{}{"orderMerchantAndCaveats": err.Error()})
}

data, err := io.ReadAll(io.LimitReader(r.Body, reqBodyLimit10MB))
if err != nil {
return handlers.WrapError(err, "failed to read request body", http.StatusBadRequest)
Expand All @@ -338,7 +335,9 @@ func handleSetOrderTrialDays(svc *Service) handlers.AppHandler {
return handlers.WrapError(err, "failed to parse request", http.StatusBadRequest)
}

if err := svc.SetOrderTrialDays(ctx, &orderID, req.TrialDays); err != nil {
now := time.Now().UTC()

if err := svc.setOrderTrialDays(ctx, orderID, req, now); err != nil {
return handlers.WrapError(err, "Error setting the trial days on the order", http.StatusInternalServerError)
}

Expand Down
29 changes: 1 addition & 28 deletions services/skus/datastore.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ type Datastore interface {
datastore.Datastore

CreateOrder(ctx context.Context, dbi sqlx.ExtContext, oreq *model.OrderNew, items []model.OrderItem) (*model.Order, error)
// SetOrderTrialDays - set the number of days of free trial for this order
SetOrderTrialDays(ctx context.Context, orderID *uuid.UUID, days int64) (*Order, error)

// GetOrder by ID
GetOrder(orderID uuid.UUID) (*Order, error)
// GetOrderByExternalID by the external id from the purchase vendor
Expand Down Expand Up @@ -99,7 +98,6 @@ type orderStore interface {
GetByExternalID(ctx context.Context, dbi sqlx.QueryerContext, extID string) (*model.Order, error)
Create(ctx context.Context, dbi sqlx.QueryerContext, oreq *model.OrderNew) (*model.Order, error)
SetLastPaidAt(ctx context.Context, dbi sqlx.ExecerContext, id uuid.UUID, when time.Time) error
SetTrialDays(ctx context.Context, dbi sqlx.QueryerContext, id uuid.UUID, ndays int64) (*model.Order, error)
SetStatus(ctx context.Context, dbi sqlx.ExecerContext, id uuid.UUID, status string) error
GetExpiresAtAfterISOPeriod(ctx context.Context, dbi sqlx.QueryerContext, id uuid.UUID) (time.Time, error)
SetExpiresAt(ctx context.Context, dbi sqlx.ExecerContext, id uuid.UUID, when time.Time) error
Expand Down Expand Up @@ -265,31 +263,6 @@ func (pg *Postgres) GetKey(id uuid.UUID, showExpired bool) (*Key, error) {
return &key, nil
}

// SetOrderTrialDays sets the number of days of free trial for this order and returns the updated result.
func (pg *Postgres) SetOrderTrialDays(ctx context.Context, orderID *uuid.UUID, days int64) (*Order, error) {
tx, err := pg.RawDB().BeginTxx(ctx, nil)
if err != nil {
return nil, fmt.Errorf("failed to create db tx: %w", err)
}
defer pg.RollbackTx(tx)

result, err := pg.orderRepo.SetTrialDays(ctx, tx, *orderID, days)
if err != nil {
return nil, fmt.Errorf("failed to execute tx: %w", err)
}

result.Items, err = pg.orderItemRepo.FindByOrderID(ctx, tx, *orderID)
if err != nil {
return nil, err
}

if err := tx.Commit(); err != nil {
return nil, err
}

return result, nil
}

// CreateOrder creates orders for Auto Contribute and Search Captcha.
//
// Deprecated: This method MUST NOT be used for Premium orders.
Expand Down
14 changes: 0 additions & 14 deletions services/skus/instrumented_datastore.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 0 additions & 30 deletions services/skus/mockdatastore.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 12 additions & 3 deletions services/skus/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,21 @@ func (o *Order) IsRadomPayable() bool {
return Slice[string](o.AllowedPaymentMethods).Contains(RadomPaymentMethod)
}

func (o *Order) ShouldSetTrialDays() bool {
return !o.IsPaid() && o.IsStripePayable()
func (o *Order) ShouldCreateTrialSessionStripe(now time.Time) bool {
return !o.IsPaidAt(now) && o.IsStripePayable()
}

// IsPaid returns true if the order is paid.
//
// TODO: Update all callers of the method to pass time explicitly.
func (o *Order) IsPaid() bool {
return o.IsPaidAt(time.Now())
}

// IsPaidAt returns true if the order is paid.
//
// If canceled, it checks if expires_at is in the future.
func (o *Order) IsPaidAt(now time.Time) bool {
switch o.Status {
case OrderStatusPaid:
// The order is paid if the status is paid.
Expand All @@ -134,7 +143,7 @@ func (o *Order) IsPaid() bool {
return false
}

return o.ExpiresAt.After(time.Now())
return o.ExpiresAt.After(now)
default:
return false
}
Expand Down
3 changes: 2 additions & 1 deletion services/skus/model/model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
"testing"
"time"

"github.com/lib/pq"
uuid "github.com/satori/go.uuid"
Expand Down Expand Up @@ -1213,7 +1214,7 @@ func TestOrder_ShouldSetTrialDays(t *testing.T) {
tc := tests[i]

t.Run(tc.name, func(t *testing.T) {
actual := tc.given.ShouldSetTrialDays()
actual := tc.given.ShouldCreateTrialSessionStripe(time.Now())
should.Equal(t, tc.exp, actual)
})
}
Expand Down
39 changes: 31 additions & 8 deletions services/skus/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ type orderStoreSvc interface {
SetStatus(ctx context.Context, dbi sqlx.ExecerContext, id uuid.UUID, status string) error
SetExpiresAt(ctx context.Context, dbi sqlx.ExecerContext, id uuid.UUID, when time.Time) error
SetLastPaidAt(ctx context.Context, dbi sqlx.ExecerContext, id uuid.UUID, when time.Time) error
SetTrialDays(ctx context.Context, dbi sqlx.ExecerContext, id uuid.UUID, ndays int64) error
AppendMetadata(ctx context.Context, dbi sqlx.ExecerContext, id uuid.UUID, key, val string) error
AppendMetadataInt(ctx context.Context, dbi sqlx.ExecerContext, id uuid.UUID, key string, val int) error
AppendMetadataInt64(ctx context.Context, dbi sqlx.ExecerContext, id uuid.UUID, key string, val int64) error
Expand Down Expand Up @@ -634,7 +635,7 @@ func (s *Service) updateOrderStripeSession(ctx context.Context, dbi sqlx.ExtCont
var newSessID string

if expSessID != "" {
nsessID, err := s.recreateStripeSession(ctx, dbi, ord, expSessID)
nsessID, err := s.recreateStripeSession(ctx, dbi, ord, expSessID, "")
if err != nil {
return fmt.Errorf("failed to create checkout session: %w", err)
}
Expand Down Expand Up @@ -755,13 +756,31 @@ func (s *Service) CancelOrderLegacy(orderID uuid.UUID) error {
return s.Datastore.UpdateOrder(orderID, OrderStatusCanceled)
}

func (s *Service) SetOrderTrialDays(ctx context.Context, orderID *uuid.UUID, days int64) error {
ord, err := s.Datastore.SetOrderTrialDays(ctx, orderID, days)
func (s *Service) setOrderTrialDays(ctx context.Context, orderID uuid.UUID, req *setTrialDaysRequest, now time.Time) error {
tx, err := s.Datastore.RawDB().BeginTxx(ctx, nil)
if err != nil {
return fmt.Errorf("failed to set the order's trial days: %w", err)
return err
}
defer func() { _ = tx.Rollback() }()

if err := s.setOrderTrialDaysTx(ctx, tx, orderID, req, now); err != nil {
return err
}

if !ord.ShouldSetTrialDays() {
return tx.Commit()
}

func (s *Service) setOrderTrialDaysTx(ctx context.Context, dbi sqlx.ExtContext, orderID uuid.UUID, req *setTrialDaysRequest, now time.Time) error {
if err := s.orderRepo.SetTrialDays(ctx, dbi, orderID, req.TrialDays); err != nil {
return err
}

ord, err := s.getOrderFullTx(ctx, dbi, orderID)
if err != nil {
return err
}

if !ord.ShouldCreateTrialSessionStripe(now) {
return nil
}

Expand All @@ -770,7 +789,7 @@ func (s *Service) SetOrderTrialDays(ctx context.Context, orderID *uuid.UUID, day
return model.ErrNoStripeCheckoutSessID
}

_, err = s.recreateStripeSession(ctx, s.Datastore.RawDB(), ord, oldSessID)
_, err = s.recreateStripeSession(ctx, dbi, ord, oldSessID, req.Email)

return err
}
Expand Down Expand Up @@ -2554,21 +2573,25 @@ func (s *Service) renewOrderStripe(ctx context.Context, dbi sqlx.ExecerContext,
return s.orderRepo.AppendMetadata(ctx, dbi, ord.ID, "paymentProcessor", model.StripePaymentMethod)
}

func (s *Service) recreateStripeSession(ctx context.Context, dbi sqlx.ExecerContext, ord *model.Order, oldSessID string) (string, error) {
func (s *Service) recreateStripeSession(ctx context.Context, dbi sqlx.ExecerContext, ord *model.Order, oldSessID, email string) (string, error) {
oldSess, err := s.stripeCl.Session(ctx, oldSessID, nil)
if err != nil {
return "", err
}

req := createStripeSessionRequest{
orderID: ord.ID.String(),
email: xstripe.CustomerEmailFromSession(oldSess),
email: email,
successURL: oldSess.SuccessURL,
cancelURL: oldSess.CancelURL,
trialDays: ord.GetTrialDays(),
items: buildStripeLineItems(ord.Items),
}

if req.email == "" {
req.email = xstripe.CustomerEmailFromSession(oldSess)
}

sessID, err := createStripeSession(ctx, s.stripeCl, req)
if err != nil {
return "", err
Expand Down
Loading

0 comments on commit 440b911

Please sign in to comment.