Upgrading subscriptions with stripe now works, even pro-rated. Need to hook up Paypal and fix all billing inconsistencies.

This commit is contained in:
Samuel Clay 2022-01-25 17:26:24 -05:00
parent 813f5dec9f
commit 07fe59cb57
7 changed files with 91 additions and 9 deletions

View file

@ -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)

View file

@ -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'),

View file

@ -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":

View file

@ -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) {

View file

@ -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 += '<input type="hidden" name="'+key+'" value="'+value+'">';
});
$('<form action="' + location + '" method="POST">' + form + '</form>').appendTo($(document.body)).submit();
},
closest: function(value, array) {
var offset = 0;

View file

@ -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'

View file

@ -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 %},