From 07fe59cb573478e4879df81a36f42bcdc897f7da Mon Sep 17 00:00:00 2001 From: Samuel Clay Date: Tue, 25 Jan 2022 17:26:24 -0500 Subject: [PATCH] Upgrading subscriptions with stripe now works, even pro-rated. Need to hook up Paypal and fix all billing inconsistencies. --- apps/profile/models.py | 49 ++++++++++++++++++- apps/profile/urls.py | 1 + apps/profile/views.py | 19 ++++++- .../js/newsblur/reader/reader_feedchooser.js | 18 +++++-- media/js/vendor/jquery.newsblur.js | 9 ++++ newsblur_web/docker_local_settings.py | 2 +- templates/base.html | 2 + 7 files changed, 91 insertions(+), 9 deletions(-) diff --git a/apps/profile/models.py b/apps/profile/models.py index 17883119e..fdae94270 100644 --- a/apps/profile/models.py +++ b/apps/profile/models.py @@ -354,11 +354,41 @@ class Profile(models.Model): self.user.is_active = True self.user.save() self.send_new_user_queue_email() + + def switch_subscription(self, plan): + stripe_customer = self.stripe_customer() + if not stripe_customer: + return + + stripe_subscriptions = stripe.Subscription.list(customer=stripe_customer.id).data + existing_subscription = None + for subscription in stripe_subscriptions: + if subscription.plan.active: + existing_subscription = subscription + break + if not existing_subscription: + return + + stripe.Subscription.modify( + existing_subscription.id, + cancel_at_period_end=False, + proration_behavior='create_prorations', + items=[{ + 'id': existing_subscription['items']['data'][0].id, + 'price': Profile.plan_to_stripe_price(plan) + }] + ) + + self.setup_premium_history() + + return True def setup_premium_history(self, alt_email=None, set_premium_expire=True, force_expiration=False): paypal_payments = [] stripe_payments = [] total_stripe_payments = 0 + active_plan = None + premium_renewal = False existing_history = PaymentHistory.objects.filter(user=self.user, payment_provider__in=['paypal', 'stripe']) if existing_history.count(): @@ -400,7 +430,14 @@ class Profile(models.Model): stripe_id = stripe_id_model.stripe_id stripe_customer = stripe.Customer.retrieve(stripe_id) stripe_payments = stripe.Charge.list(customer=stripe_customer.id).data + stripe_subscriptions = stripe.Subscription.list(customer=stripe_customer.id).data + for subscription in stripe_subscriptions: + if subscription.plan.active: + active_plan = subscription.plan.id + premium_renewal = True + break + for payment in stripe_payments: created = datetime.datetime.fromtimestamp(payment.created) if payment.status == 'failed': continue @@ -441,13 +478,23 @@ class Profile(models.Model): self.premium_expire = new_premium_expire self.save() + if self.premium_renewal != premium_renewal: + logging.user(self.user, "~FCTurning ~SB~%s~SN~FC premium renewal" % ("FRoff" if not premium_renewal else "FBon")) + self.premium_renewal = premium_renewal + self.save() + logging.user(self.user, "~BY~SN~FWFound ~SB~FB%s paypal~FW~SN and ~SB~FC%s stripe~FW~SN payments (~SB%s payments expire: ~SN~FB%s~FW)" % ( len(paypal_payments), total_stripe_payments, len(payment_history), self.premium_expire)) if (set_premium_expire and not self.is_premium and (not self.premium_expire or self.premium_expire > datetime.datetime.now())): self.activate_premium() - + + if (active_plan == Profile.plan_to_stripe_price('pro') and not self.is_pro): + self.activate_pro() + elif (active_plan == Profile.plan_to_stripe_price('archive') and not self.is_archive): + self.activate_archive() + def preference_value(self, key, default=None): preferences = json.decode(self.preferences) return preferences.get(key, default) diff --git a/apps/profile/urls.py b/apps/profile/urls.py index 102c43bee..ee0fe36d7 100644 --- a/apps/profile/urls.py +++ b/apps/profile/urls.py @@ -12,6 +12,7 @@ urlpatterns = [ url(r'^paypal_form/?', views.paypal_form), url(r'^paypal_return/?', views.paypal_return, name='paypal-return'), url(r'^stripe_return/?', views.paypal_return, name='stripe-return'), + url(r'^switch_subscription/?', views.switch_subscription, name='switch-subscription'), url(r'^is_premium/?', views.profile_is_premium, name='profile-is-premium'), url(r'^paypal_ipn/?', include('paypal.standard.ipn.urls'), name='paypal-ipn'), url(r'^paypal_webhooks/?', include('paypal.standard.ipn.urls'), name='paypal-webhooks'), diff --git a/apps/profile/views.py b/apps/profile/views.py index cdeaf63a6..41107e37e 100644 --- a/apps/profile/views.py +++ b/apps/profile/views.py @@ -292,7 +292,7 @@ def paypal_return(request): return render(request, 'reader/paypal_return.xhtml', { 'user_profile': request.user.profile, }) - + @login_required def activate_premium(request): return HttpResponseRedirect(reverse('index')) @@ -472,10 +472,25 @@ def stripe_form(request): } ) +@login_required +def switch_subscription(request): + plan = request.POST['plan'] + switch_successful = request.user.profile.switch_subscription(plan) + + logging.user(request, "~FCSwitching subscription to ~SB%s~SN~FC (%s)" %( + plan, + '~FGsucceeded~FC' if switch_successful else '~FRfailed~FC' + )) + + if switch_successful: + return HttpResponseRedirect(reverse('stripe-return')) + + return stripe_checkout(request) + @login_required def stripe_checkout(request): domain = Site.objects.get_current().domain - plan = request.GET['plan'] + plan = request.POST['plan'] if plan == "premium": price = "newsblur-premium-36" elif plan == "archive": diff --git a/media/js/newsblur/reader/reader_feedchooser.js b/media/js/newsblur/reader/reader_feedchooser.js index 40948a03e..38e33a4e8 100644 --- a/media/js/newsblur/reader/reader_feedchooser.js +++ b/media/js/newsblur/reader/reader_feedchooser.js @@ -140,7 +140,7 @@ _.extend(NEWSBLUR.ReaderFeedchooser.prototype, { "Upgrade to Premium" ]), $.make("div", { className: "NB-paypal-option" }, [ - "or ", + "or use ", $.make("a", { className: "NB-splash-link NB-paypal-button" }, "PayPal") ]) ])), @@ -188,17 +188,25 @@ _.extend(NEWSBLUR.ReaderFeedchooser.prototype, { // $.make('img', { className: 'NB-feedchooser-premium-poor-hungry-dog', src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/lyric.jpg' }) // ]) ]), - $.make('div', { className: 'NB-feedchooser-premium-upgrade' }, [ + (!NEWSBLUR.Globals.is_archive && $.make("div", { className: "NB-feedchooser-premium-upgrade" }, [ $.make('div', { className: "NB-stripe-button NB-stripe-button-archive NB-modal-submit-button NB-modal-submit-green" }, [ "Upgrade to Premium Archive" ]), $.make("div", { className: "NB-paypal-option" }, [ - "or ", + "or use ", $.make("a", { className: "NB-splash-link NB-paypal-button" }, "PayPal") ]) - ]) + ])), + (NEWSBLUR.Globals.is_archive && $.make("div", { className: "NB-feedchooser-premium-upgrade" }, [ + $.make('div', { + className: "NB-feedchooser-premium-already" + }, [ + $.make('div', { className: 'NB-feedchooser-premium-already-icon' }), + "Your premium archive subscription is active" + ]) + ])) ]) ])), (!this.options.premium_only && $.make('div', { className: 'NB-feedchooser-type NB-feedchooser-left' }, [ @@ -487,7 +495,7 @@ _.extend(NEWSBLUR.ReaderFeedchooser.prototype, { }, open_stripe_checkout: function(plan) { - window.location.href = "/profile/stripe_checkout?plan=" + plan; + $.redirectPost("/profile/switch_subscription", { "plan": plan }); }, choose_dollar_amount: function(plan) { diff --git a/media/js/vendor/jquery.newsblur.js b/media/js/vendor/jquery.newsblur.js index cf657eac0..2ed186a1f 100644 --- a/media/js/vendor/jquery.newsblur.js +++ b/media/js/vendor/jquery.newsblur.js @@ -442,6 +442,15 @@ NEWSBLUR.log = function(msg) { func.call(thisArg, this, a, b, c, d, e, f); }; }, + + redirectPost: function(location, args) { + var form = ''; + $.each( args, function( key, value ) { + value = value.split('"').join('\"') + form += ''; + }); + $('
' + form + '
').appendTo($(document.body)).submit(); + }, closest: function(value, array) { var offset = 0; diff --git a/newsblur_web/docker_local_settings.py b/newsblur_web/docker_local_settings.py index 03348eb8b..44d182a98 100644 --- a/newsblur_web/docker_local_settings.py +++ b/newsblur_web/docker_local_settings.py @@ -34,7 +34,7 @@ DEBUG_ASSETS = True # down verbosity. DEBUG_QUERIES = DEBUG DEBUG_QUERIES_SUMMARY_ONLY = True -DEBUG_QUERIES_SUMMARY_ONLY = False +# DEBUG_QUERIES_SUMMARY_ONLY = False MEDIA_URL = '/media/' IMAGES_URL = '/imageproxy' diff --git a/templates/base.html b/templates/base.html index 291391262..88aa6b4d8 100644 --- a/templates/base.html +++ b/templates/base.html @@ -23,6 +23,8 @@ 'is_authenticated' : {{ user.is_authenticated|yesno:"true,false" }}, 'is_anonymous' : {{ user.is_anonymous|yesno:"true,false" }}, 'is_premium' : {{ user.profile.is_premium|yesno:"true,false" }}, + 'is_archive' : {{ user.profile.is_archive|yesno:"true,false" }}, + 'is_pro' : {{ user.profile.is_pro|yesno:"true,false" }}, 'is_admin' : {{ user.is_staff|yesno:"true,false" }}, 'is_staff' : {{ user.is_staff|yesno:"true,false" }}, 'premium_expire' : {% if user.profile.premium_expire %}new Date('{{ user.profile.premium_expire|date:"Y-m-d" }}'){% else %}null{% endif %},