From ab9579a048d970487b584a78b59c0a350201adcb Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 20 Dec 2018 17:40:32 +0100 Subject: [PATCH] downgrade notifications --- rowers/braintreestuff.py | 15 ++- rowers/forms.py | 4 +- rowers/tasks.py | 16 ++- rowers/templates/downgrade.html | 52 ++++++++ rowers/templates/downgrade_completed.html | 26 ++++ rowers/templates/downgradeconfirm.html | 118 ++++++++++++++++++ .../subscription_downgrade_email.html | 62 +++++++++ .../subscription_downgrade_notification.html | 26 ++++ rowers/urls.py | 4 + rowers/views.py | 112 ++++++++++++++++- 10 files changed, 423 insertions(+), 12 deletions(-) create mode 100644 rowers/templates/downgrade.html create mode 100644 rowers/templates/downgrade_completed.html create mode 100644 rowers/templates/downgradeconfirm.html create mode 100644 rowers/templates/subscription_downgrade_email.html create mode 100644 rowers/templates/subscription_downgrade_notification.html diff --git a/rowers/braintreestuff.py b/rowers/braintreestuff.py index 4a2bc46e..30fd6adb 100644 --- a/rowers/braintreestuff.py +++ b/rowers/braintreestuff.py @@ -107,7 +107,7 @@ def make_payment(rower,data): else: return 0,'' -def update_subscription(rower,data): +def update_subscription(rower,data,method='up'): planid = data['plan'] plan = PaidPlan.objects.get(id=planid) nonce_from_the_client = data['payment_method_nonce'] @@ -148,11 +148,13 @@ def update_subscription(rower,data): l = rower.user.last_name, ) + if method == 'up': + transactions = result.subscription.transactions - transactions = result.subscription.transactions - - if transactions: - amount = transactions[0].amount + if transactions: + amount = transactions[0].amount + else: + amount = 0 else: amount = 0 @@ -164,7 +166,8 @@ def update_subscription(rower,data): plan.paymenttype == 'recurring', plan.price, amount, - result.subscription.billing_period_end_date.strftime('%Y-%m-%d')) + result.subscription.billing_period_end_date.strftime('%Y-%m-%d'), + method) return True else: diff --git a/rowers/forms.py b/rowers/forms.py index 31d292de..f0145b7d 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -721,6 +721,7 @@ class PlanSelectForm(forms.Form): def __init__(self, *args, **kwargs): paymentprocessor = kwargs.pop('paymentprocessor',None) rower = kwargs.pop('rower',None) + includeall = kwargs.pop('includeall',False) super(PlanSelectForm, self).__init__(*args, **kwargs) self.fields['plan'].empty_label = None if paymentprocessor: @@ -731,7 +732,7 @@ class PlanSelectForm(forms.Form): ).order_by( "price","clubsize","shortname" ) - if rower: + if rower and not includeall: try: amount = rower.paidplan.price except AttributeError: @@ -743,6 +744,7 @@ class PlanSelectForm(forms.Form): ).order_by( "price","clubsize","shortname" ) + class CourseSelectForm(forms.Form): course = forms.ModelChoiceField(queryset=GeoCourse.objects.all()) diff --git a/rowers/tasks.py b/rowers/tasks.py index c354b25c..a848cd37 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -797,14 +797,13 @@ def handle_send_email_failed_cancel( @app.task def handle_send_email_subscription_update( username, useremail, planname, recurring, price, amount, - end_of_billing_period, **kwargs): + end_of_billing_period, method, **kwargs): if 'debug' in kwargs: debug = kwargs['debug'] else: debug = True - subject = "Rowsandall Payment Confirmation" from_email = 'Rowsandall ' @@ -818,14 +817,23 @@ def handle_send_email_subscription_update( 'end_of_billing_period': end_of_billing_period, } + if method == 'down': + template_name = 'subscription_downgrade_email.html' + notification_template_name = 'subscription_downgrade_notification.html' + subject = "Rowsandall Change Confirmation" + else: + template_name = 'subscription_update_email.html' + notification_template_name = 'subscription_update_notification.html' + subject = "Rowsandall Payment Confirmation" + res = send_template_email(from_email,[useremail], subject, - 'subscription_update_email.html', + template_name, d, **kwargs) res = send_template_email(from_email,['info@rowsandall.com'], 'Subscription Update Notification', - 'subscription_update_notification.html', + template_name, d, **kwargs) return 1 diff --git a/rowers/templates/downgrade.html b/rowers/templates/downgrade.html new file mode 100644 index 00000000..091b0dfe --- /dev/null +++ b/rowers/templates/downgrade.html @@ -0,0 +1,52 @@ +{% extends "newbase.html" %} +{% block title %}Rowsandall Paid Membership{% endblock title %} +{% load rowerfilters %} +{% block main %} + +

Downgrade

+ +
+
    +
  • +

    Billing Details

    +

    For tax reasons, we need your country of residence. You should + update this when it is incorrect.

    + + {{ billingaddressform.as_table }} +
    +
  • +
  • +

    Choose your Plan

    + + {{ planselectform.as_table }} +
    +
  • +
  • +

    + Your downgrade will be effective immediately. + The price difference for the current billing cycle will + be credited to your next charge (prorated). For example, + when you downgrade from a 65€ plan to a 15€ plan + (50€ difference), in the 6th month of the 12 month + billing cycle, you will have a credit of 25€ which + will be used for the next billing cycles. +

    + +

    + Looking for the downgrade option? +

    +
  • +
  • + {% csrf_token %} + + You will be able to review your order before purchase. +
  • +
+
+ +{% endblock %} + +{% block sidebar %} +{% include 'menu_profile.html' %} +{% endblock %} + diff --git a/rowers/templates/downgrade_completed.html b/rowers/templates/downgrade_completed.html new file mode 100644 index 00000000..1fdde09b --- /dev/null +++ b/rowers/templates/downgrade_completed.html @@ -0,0 +1,26 @@ +{% extends "newbase.html" %} +{% block title %}Rowsandall Paid Membership{% endblock title %} +{% load rowerfilters %} +{% block main %} + +

Your Change was completed

+ +

+ Thank you for changing to {{ user.rower.paidplan.name }}. You're all settled. + membership. +

+ +

+ {% if user.rower.paymenttype == 'recurring' %} + Your next payment will be automatically processed on {{ user.rower.planexpires }} + {% else %} + Your plan will end automatically on {{ user.rower.planexpires }} + {% endif %} +

+ +{% endblock %} + +{% block sidebar %} +{% include 'menu_profile.html' %} +{% endblock %} + diff --git a/rowers/templates/downgradeconfirm.html b/rowers/templates/downgradeconfirm.html new file mode 100644 index 00000000..c5bb79b2 --- /dev/null +++ b/rowers/templates/downgradeconfirm.html @@ -0,0 +1,118 @@ +{% extends "newbase.html" %} +{% block title %}Rowsandall Paid Membership{% endblock title %} +{% load rowerfilters %} +{% block main %} + +

Confirm Your Changes

+ +

Order Overview

+ + + + + + + +{% endblock %} + +{% block sidebar %} +{% include 'menu_profile.html' %} +{% endblock %} + diff --git a/rowers/templates/subscription_downgrade_email.html b/rowers/templates/subscription_downgrade_email.html new file mode 100644 index 00000000..789b48ae --- /dev/null +++ b/rowers/templates/subscription_downgrade_email.html @@ -0,0 +1,62 @@ +{% extends "emailbase.html" %} + +{% block body %} +

Dear {{ name }},

+ +

+ Thank you. You have successfully changed your plan to "{{ planname }}". +

+ +{% if recurring %} +

+ The subscription cost is €{{ price }} per year. + Your next charge is due on {{ end_of_billing_period }}. We will charge you automatically + on that date. Because you downgraded, you have a credit on your account which will be + used before charging your payment method. +

+ +

+ The subscription will keep running until you change or stop it. At any point in time you + can change the automatically renewing subscription to a "one year only" subscription through + the upgrade page. On this page, you can also + upgrade your subscription. +

+ +{% else %} +

+ The price of the subscription is €{{ price }}. + This one year subscription will automatically end on {{ end_of_billing_period }}. You can + renew your subscription after that. Because you downgraded, you have a credit on your + account which will be used for future subscriptions or upgrades. +

+ +

+ At any point in time, you can change your subscription to an automatically renewing subscription. + You can do this on the upgrade page. + Here, you can also upgrade your subscription. +

+{% endif %} + +

+ Upgrades in the middle of a billing cycle are charged pro-rated. For the current billing + cycle, you have only been charged for the price difference for the remaining fraction of the + billing cycle. If you downgraded to a lower cost subscription, the pro-rated difference will be + used as a credit, lowering the amount charged on the next billing cycle. +

+ +

+ You can stop the subscription through + the subscription management page. The + subscription will be stopped immediately without a refund. +

+ +

+ Please contact our customer service by replying to this email if you have any further + questions regarding your subscription. +

+ +

+ Best Regards, the Rowsandall Team +

+{% endblock %} + diff --git a/rowers/templates/subscription_downgrade_notification.html b/rowers/templates/subscription_downgrade_notification.html new file mode 100644 index 00000000..dce13caf --- /dev/null +++ b/rowers/templates/subscription_downgrade_notification.html @@ -0,0 +1,26 @@ +{% extends "emailbase.html" %} + +{% block body %} +

User {{ name }} has downgraded his subscription.

+ +

+ New plan: "{{ planname }}". +

+ +{% if recurring %} +

+ The subscription cost is €{{ price }} per year. + The next charge is due on {{ end_of_billing_period }}. on that date. +

+{% else %} +

+ The subscription cost is €{{ price }}. The subscription ends on {{ end_of_billing_period }} +

+{% endif %} + + +

+ Best Regards, the Rowsandall Team +

+{% endblock %} + diff --git a/rowers/urls.py b/rowers/urls.py index 646ac0cf..474946e3 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -440,14 +440,18 @@ urlpatterns = [ url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'), url(r'^checkout/(?P\d+)$',views.payment_confirm_view), url(r'^upgradecheckout/(?P\d+)$',views.upgrade_confirm_view), + url(r'^downgradecheckout/(?P\d+)$',views.downgrade_confirm_view), url(r'^billing$',views.billing_view,name='billing'), url(r'^upgrade$',views.upgrade_view,name='upgrade'), + url(r'^downgrade$',views.downgrade_view,name='downgrade'), url(r'^paymentcompleted$',views.payment_completed_view), + url(r'^downgradecompleted$',views.downgrade_completed_view), url(r'^paidplans$',views.paidplans_view,name='paidplans'), url(r'^me/cancelsubscriptions$',views.plan_stop_view), url(r'^me/cancelsubscription/(?P[\w\ ]+.*)$',views.plan_tobasic_view), url(r'^checkouts$',views.checkouts_view,name='checkouts'), url(r'^upgradecheckouts$',views.upgrade_checkouts_view,name='upgrade_checkouts'), + url(r'^downgradecheckouts$',views.downgrade_checkouts_view,name='downgrade_checkouts'), url(r'^planrequired',views.planrequired_view), url(r'^starttrial$',views.start_trial_view), url(r'^startplantrial$',views.start_plantrial_view), diff --git a/rowers/views.py b/rowers/views.py index a4ee2992..cbd35ca3 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -1147,6 +1147,54 @@ def upgrade_view(request): 'planselectform':planselectform, }) +@login_required() +def downgrade_view(request): + r = getrequestrower(request) + + if r.subscription_id is None or r.subscription_id == '': + url = reverse(billing_view) + return HttpResponseRedirect(url) + + if request.method == 'POST': + billingaddressform = RowerBillingAddressForm(request.POST) + planselectform = PlanSelectForm(request.POST,paymentprocessor='braintree') + if billingaddressform.is_valid(): + cd = billingaddressform.cleaned_data + for attr, value in cd.items(): + setattr(r, attr, value) + r.save() + + if planselectform.is_valid(): + plan = planselectform.cleaned_data['plan'] + + if plan.price > r.paidplan.price: + nextview = upgrade_confirm_view + elif plan.price == r.paidplan.price: + messages.info(request,'You did not select a new plan') + url = reverse(downgrade_view) + return HttpResponseRedirect(url) + else: + nextview = downgrade_confirm_view + + if billingaddressform.is_valid(): + url = reverse(nextview, + kwargs={ + 'planid':plan.id + }) + return HttpResponseRedirect(url) + + else: + billingaddressform = RowerBillingAddressForm(instance=r) + planselectform = PlanSelectForm(paymentprocessor='braintree', + rower=r,includeall=True, initial={'plan':r.paidplan}) + + return render(request, + 'downgrade.html', + {'rower':r, + 'billingaddressform':billingaddressform, + 'planselectform':planselectform, + }) + @login_required() def plan_stop_view(request): r = getrequestrower(request) @@ -1207,6 +1255,28 @@ def upgrade_confirm_view(request,planid = 0): 'rower':r, }) +@login_required() +def downgrade_confirm_view(request,planid = 0): + try: + plan = PaidPlan.objects.get(id=planid) + except PaidPlan.DoesNotExist: + messages.error(request,"Something went wrong. Please try again.") + url = reverse(billing_view) + return HttpResponseRedirect(url) + + r = getrequestrower(request) + + client_token = braintreestuff.get_client_token(r) + + return render(request, + "downgradeconfirm.html", + { + 'plan':plan, + 'client_token':client_token, + 'rower':r, + }) + + @login_required() def payment_confirm_view(request,planid = 0): try: @@ -1288,7 +1358,37 @@ def upgrade_checkouts_view(request): url = reverse(paidplans_view) return HttpResponseRedirect(url) - + +@login_required() +def downgrade_checkouts_view(request): + + r = getrequestrower(request) + + if request.method != 'POST': + url = reverse(paidplans_view) + return HttpResponseRedirect(url) + + form = BillingForm(request.POST) + if form.is_valid(): + data = form.cleaned_data + success = braintreestuff.update_subscription(r,data,method='down') + if success: + messages.info(request,"Your plan has been updated") + url = reverse(downgrade_completed_view) + return HttpResponseRedirect(url) + else: + messages.error(request,"There was a problem with your transaction") + url = reverse(upgrade_view) + return HttpResponseRedirect(url) + + else: + messages.error(request,"There was an error in the payment form") + url = reverse(upgrade_view) + return HttpResponseRedirect(url) + + url = reverse(paidplans_view) + return HttpResponseRedirect(url) + @login_required() def payment_completed_view(request): @@ -1300,6 +1400,16 @@ def payment_completed_view(request): 'rower':r }) +@login_required() +def downgrade_completed_view(request): + r = getrequestrower(request) + + return render(request, + "downgrade_completed.html", + { + 'rower':r + }) + # User registration def rower_register_view(request):