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
+
+
+
+{% 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
+
+
+ -
+
+
+
+
+ | Plan | {{ plan.name }} |
+
+
+ | Payment Type | {{ plan.paymenttype }} |
+
+
+ | Billing Cycle | 1 year |
+
+
+ | Total | € {{ plan.price|currency }}
+ {% if plan.paymenttype == 'recurring' %}
+ /year
+ {% endif %}
+ |
+
+
+
+
+
+
+
+
+ | Street Address | {{ user.rower.street_address }} |
+
+
+ | City | {{ user.rower.city }} |
+
+
+ | Postal Code | {{ user.rower.postal_code }} |
+
+
+ | Country | {{ user.rower.country }}
+ |
+
+
+
+
+
+
+
+ Change Downgrade
+
+
+
+
+
+
+ Your downgrade will be effective immediately. You will not be charged.
+
+
+
+
+
+
+
+
+{% 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):