6464
6565const (
6666 // TODO(pavelb): Gradually replace it everywhere.
67- //
6867 // OrderStatusCanceled - string literal used in db for canceled status
6968 OrderStatusCanceled = model .OrderStatusCanceled
7069 // OrderStatusPaid - string literal used in db for canceled status
@@ -768,7 +767,7 @@ func (s *Service) newRadomSub(ctx context.Context, dbi sqlx.ExtContext, oid uuid
768767 return err
769768 }
770769
771- if err := s .renewOrderWithExpPaidTimeTx (ctx , dbi , oid , expAt , paidAt ); err != nil {
770+ if err := s .updateOrderWithExpPaidTimeTx (ctx , dbi , oid , expAt , paidAt ); err != nil {
772771 return err
773772 }
774773
@@ -1877,7 +1876,6 @@ func (s *Service) processStripeNotificationTx(ctx context.Context, dbi sqlx.ExtC
18771876 return err
18781877 }
18791878
1880- // Reset numPaymentFailed.
18811879 if err := s .resetNumPaymentFailed (ctx , dbi , oid ); err != nil {
18821880 return err
18831881 }
@@ -1902,6 +1900,38 @@ func (s *Service) processStripeNotificationTx(ctx context.Context, dbi sqlx.ExtC
19021900
19031901 return s .recordPayFailureStripe (ctx , dbi , ord , subID )
19041902
1903+ case ntf .shouldActivatePL ():
1904+ oid , err := ntf .orderID ()
1905+ if err != nil {
1906+ return err
1907+ }
1908+
1909+ ord , err := s .getOrderFullTx (ctx , dbi , oid )
1910+ if err != nil {
1911+ return err
1912+ }
1913+
1914+ // Currently, we should only receive payment_intent.succeeded events for one-off payments
1915+ // i.e. those related to perpetual licenses. However, to safeguard we should
1916+ // check the order is definitely eligible before activating.
1917+ if ! ord .IsOneOffPayment () {
1918+ return model .ErrOrderNotOneOffPayment
1919+ }
1920+
1921+ pid , err := ntf .paymentID ()
1922+ if err != nil {
1923+ return err
1924+ }
1925+
1926+ paidt , err := ntf .paidAt ()
1927+ if err != nil {
1928+ return err
1929+ }
1930+
1931+ expt := paidt .AddDate (100 , 0 , 0 )
1932+
1933+ return s .activateStripePL (ctx , dbi , ord , pid , paidt , expt )
1934+
19051935 default :
19061936 return nil
19071937 }
@@ -1944,7 +1974,7 @@ func (s *Service) processAppStoreNotificationTx(ctx context.Context, dbi sqlx.Ex
19441974 expt := txn .expiresTime ().Add (24 * time .Hour )
19451975 paidt := time .Now ()
19461976
1947- return s .renewOrderWithExpPaidTimeTx (ctx , dbi , ord .ID , expt , paidt )
1977+ return s .updateOrderWithExpPaidTimeTx (ctx , dbi , ord .ID , expt , paidt )
19481978
19491979 case ntf .shouldCancel ():
19501980 return s .cancelOrderTx (ctx , dbi , ord .ID )
@@ -1994,7 +2024,7 @@ func (s *Service) processPlayStoreNotificationTx(ctx context.Context, dbi sqlx.E
19942024 expt := sub .expiresTime ().Add (24 * time .Hour )
19952025 paidt := time .Now ()
19962026
1997- return s .renewOrderWithExpPaidTimeTx (ctx , dbi , ord .ID , expt , paidt )
2027+ return s .updateOrderWithExpPaidTimeTx (ctx , dbi , ord .ID , expt , paidt )
19982028
19992029 // Sub cancellation.
20002030 case ntf .SubscriptionNtf != nil && ntf .SubscriptionNtf .shouldCancel ():
@@ -2293,24 +2323,22 @@ func (s *Service) createOrderTx(ctx context.Context, dbi sqlx.ExtContext, oreq *
22932323 return result , nil
22942324}
22952325
2296- func (s * Service ) renewOrderWithExpPaidTime (ctx context.Context , id uuid.UUID , expt , paidt time.Time ) error {
2326+ func (s * Service ) updateOrderWithExpPaidTime (ctx context.Context , id uuid.UUID , expt , paidt time.Time ) error {
22972327 tx , err := s .Datastore .RawDB ().BeginTxx (ctx , nil )
22982328 if err != nil {
22992329 return err
23002330 }
23012331 defer func () { _ = tx .Rollback () }()
23022332
2303- if err := s .renewOrderWithExpPaidTimeTx (ctx , tx , id , expt , paidt ); err != nil {
2333+ if err := s .updateOrderWithExpPaidTimeTx (ctx , tx , id , expt , paidt ); err != nil {
23042334 return err
23052335 }
23062336
23072337 return tx .Commit ()
23082338}
23092339
2310- // renewOrderWithExpPaidTimeTx performs updates relevant to advancing a paid order forward after renewal.
2311- //
23122340// TODO: Add a repo method to update all three fields at once.
2313- func (s * Service ) renewOrderWithExpPaidTimeTx (ctx context.Context , dbi sqlx.ExecerContext , id uuid.UUID , expt , paidt time.Time ) error {
2341+ func (s * Service ) updateOrderWithExpPaidTimeTx (ctx context.Context , dbi sqlx.ExecerContext , id uuid.UUID , expt , paidt time.Time ) error {
23142342 if err := s .orderRepo .SetStatus (ctx , dbi , id , model .OrderStatusPaid ); err != nil {
23152343 return err
23162344 }
@@ -2416,7 +2444,7 @@ func (s *Service) createOrderWithReceipt(ctx context.Context, req model.ReceiptR
24162444 // Examples:
24172445 // - annual VPN users on mobile pre-July 2024;
24182446 // - mobile Developers and QAs using the same store id repeatedly.
2419- if err := s .renewOrderWithExpPaidTime (ctx , ord .ID , rcpt .ExpiresAt , paidt ); err != nil {
2447+ if err := s .updateOrderWithExpPaidTime (ctx , ord .ID , rcpt .ExpiresAt , paidt ); err != nil {
24202448 return nil , err
24212449 }
24222450
@@ -2468,7 +2496,7 @@ func (s *Service) processSubmitReceipt(ctx context.Context, req model.ReceiptReq
24682496
24692497 paidt := time .Now ()
24702498
2471- if err := s .renewOrderWithExpPaidTimeTx (ctx , tx , oid , rcpt .ExpiresAt , paidt ); err != nil {
2499+ if err := s .updateOrderWithExpPaidTimeTx (ctx , tx , oid , rcpt .ExpiresAt , paidt ); err != nil {
24722500 return model.ReceiptData {}, err
24732501 }
24742502
@@ -2552,7 +2580,7 @@ func (s *Service) processRadomNotificationTx(ctx context.Context, dbi sqlx.ExtCo
25522580 return err
25532581 }
25542582
2555- if err := s .renewOrderWithExpPaidTimeTx (ctx , dbi , ord .ID , expAt , paidAt ); err != nil {
2583+ if err := s .updateOrderWithExpPaidTimeTx (ctx , dbi , ord .ID , expAt , paidAt ); err != nil {
25562584 return err
25572585 }
25582586
@@ -2611,7 +2639,7 @@ func checkOrderReceipt(ctx context.Context, dbi sqlx.QueryerContext, repo orderS
26112639// This interface exists because in its current form Service is hardly testable.
26122640type paidOrderCreator interface {
26132641 createOrderPremium (ctx context.Context , req * model.CreateOrderRequestNew , ordNew * model.OrderNew , items []model.OrderItem ) (* model.Order , error )
2614- renewOrderWithExpPaidTime (ctx context.Context , id uuid.UUID , expt , paidt time.Time ) error
2642+ updateOrderWithExpPaidTime (ctx context.Context , id uuid.UUID , expt , paidt time.Time ) error
26152643 appendOrderMetadata (ctx context.Context , oid uuid.UUID , mdata datastore.Metadata ) error
26162644}
26172645
@@ -2662,7 +2690,7 @@ func createOrderWithReceipt(
26622690 }
26632691
26642692 // 4. Mark order as paid with proper expiration.
2665- if err := svc .renewOrderWithExpPaidTime (ctx , order .ID , rcpt .ExpiresAt , paidt ); err != nil {
2693+ if err := svc .updateOrderWithExpPaidTime (ctx , order .ID , rcpt .ExpiresAt , paidt ); err != nil {
26662694 return nil , err
26672695 }
26682696
@@ -2708,7 +2736,7 @@ func (s *Service) renewOrderStripe(ctx context.Context, dbi sqlx.ExecerContext,
27082736 // Add 1-day leeway in case next billing cycle's webhook gets delayed.
27092737 expt = expt .Add (24 * time .Hour )
27102738
2711- if err := s .renewOrderWithExpPaidTimeTx (ctx , dbi , ord .ID , expt , paidt ); err != nil {
2739+ if err := s .updateOrderWithExpPaidTimeTx (ctx , dbi , ord .ID , expt , paidt ); err != nil {
27122740 return err
27132741 }
27142742
@@ -2725,6 +2753,18 @@ func (s *Service) renewOrderStripe(ctx context.Context, dbi sqlx.ExecerContext,
27252753 return s .orderRepo .AppendMetadata (ctx , dbi , ord .ID , "paymentProcessor" , model .StripePaymentMethod )
27262754}
27272755
2756+ func (s * Service ) activateStripePL (ctx context.Context , dbi sqlx.ExecerContext , ord * model.Order , paymentID string , paidt , expt time.Time ) error {
2757+ if err := s .updateOrderWithExpPaidTimeTx (ctx , dbi , ord .ID , expt , paidt ); err != nil {
2758+ return err
2759+ }
2760+
2761+ if err := s .orderRepo .AppendMetadata (ctx , dbi , ord .ID , "paymentProcessor" , model .StripePaymentMethod ); err != nil {
2762+ return err
2763+ }
2764+
2765+ return s .orderRepo .AppendMetadata (ctx , dbi , ord .ID , "stripePaymentId" , paymentID )
2766+ }
2767+
27282768func (s * Service ) processStripeMtoA (ctx context.Context , dbi sqlx.ExtContext , ntf * stripeNotification ) error {
27292769 umaData , err := ntf .umaData ()
27302770 if err != nil {
0 commit comments