diff --git a/rowers/forms.py b/rowers/forms.py index 05fc77a8..0994a61e 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -18,7 +18,11 @@ from django.forms import formset_factory from utils import landingpages from metrics import axes - +# Braintree form +class BrainTreeForm(forms.Form): + amount = forms.FloatField(required=True) + payment_method_nonce = forms.CharField(max_length=255) + # login form class LoginForm(forms.Form): diff --git a/rowers/templates/payments.html b/rowers/templates/payments.html new file mode 100644 index 00000000..4cc0b8f1 --- /dev/null +++ b/rowers/templates/payments.html @@ -0,0 +1,295 @@ + +{% extends "newbase.html" %} +{% block title %}Rowsandall Pro Membership{% endblock title %} +{% block main %} +{% load rowerfilters %} + +
Donations are welcome to keep this web site going. To help cover the hosting
+ costs, I have created several paid plans offering advanced functionality.
+ Once I process your
+ donation, I will give you access to some special
features on this
+ website.
The following table gives an overview of the different plans. As we are + constantly developing new functionality, the table might be slightly outdated. Don't + hesitate to contact us.
+ +The Pro membership is open for a free 14 day trial
++
| + | BASIC | +PRO | +SELF-COACH | +COACH | +
|---|---|---|---|---|
| Basic rowing metrics (spm, time, distance, heart rate, power) | +✔ | +✔ | +✔ | +✔ | +
| Manual Import, Export, Synchronization and download of all your data | +✔ | +✔ | +✔ | +✔ | +
| Automatic Synchronization with other fitness sites | ++ | ✔ | +✔ | +✔ | +
| Heart rate and power zones | +✔ | +✔ | +✔ | +✔ | +
| Ranking Pieces, Stroke Analysis | +✔ | +✔ | +✔ | +✔ | +
| Advanced Analysis (Critical Power, Stats, Box Chart, Trend Flex) | ++ | ✔ | +✔ | +✔ | +
| Compare Workouts | ++ | ✔ | +✔ | +✔ | +
| Empower Stroke Profile | ++ | ✔ | +✔ | +✔ | +
| Sensor Fusion, Split Workout, In-stroke metrics | ++ | ✔ | +✔ | +✔ | +
| Create Training plans, tests and challenges for yourself. Track your performance + against plan. | ++ | + | ✔ | +✔ | +
| Create Training plans, tests and challenges for your athletes. Track their performance + against plan. | ++ | + | + | ✔ | +
| Create and manage teams. | ++ | + | + | ✔ | +
| Manage your athlete's workouts | ++ | + | + | ✔ | +
The Coach plan functionality listed is available to the coach only. Individual athletes + can purchase upgrades to "Pro" and "Self-Coach" plans. +
+ +Rowsandall.com's Training Planning functionality + is part of the paid "Self-Coach" and "Coach" plans.
+ +On the "Self-Coach" plan, you can plan your own sessions.
+ +On the "Coach" plan, you can establish teams, see workouts done by + athletes on your team, and plan individual and group sessions for your + athletes. +
+ +If you would like to find a coach who helps you plan your training + through rowsandall.com, contact me throught the contact form.
+ + {% if user.rower.rowerplan == 'basic' and user.rower.protrialexpires|date_dif == 1 %} ++ You qualify for a 14 day free trial. No credit card needed. + Try out Pro or Self-Coach membership for two weeks. Click the button below to + sign up for the trial. After your trial period expires, you will be + automatically reset to the Basic plan, unless you upgrade to Pro. +
+Yes, I want to try Pro membership for 14 days for free. No strings attached.
+Yes, I want to try Self-Coach membership for 14 days for free. No strings attached.
+ {% endif %} +Click on the PayPal button to pay for your Pro membership. Before you pay, please register for the free Basic membership and add your user name to the form. + Your payment will be valid for one year. + You will be taken to the secure PayPal payment site. +
+You need a Paypal account for this. This is plan will automatically renew each year.
++
+ +Only a credit card needed. Will not automatically renew
+ ++
+ +After you do the payment, we will manually change your membership to + "Pro". Depending on our availability, this may take some time + (typically one working day). Don't hesitate to contact us + if you have any questions at this stage.
+ +If, for any reason, you are not happy with your Pro membership, please let me know through the contact form. I will contact you as soon as possible to discuss how we can make things better.
+ +If, for any reason, you are not happy with your Pro membership, please let me know through the contact form. I will contact you as soon as possible to discuss how we can make things better.
+ diff --git a/rowers/urls.py b/rowers/urls.py index 242c07b4..ee3aa1ce 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -437,6 +437,8 @@ urlpatterns = [ url(r'^analysis/$', views.analysis_view,name='analysis'), url(r'^laboratory/$', views.laboratory_view,name='laboratory'), url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'), + url(r'^checkouts',views.checkouts_view,name='checkouts'), + url(r'^payments',views.payments_view,name='payments'), 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 8a32085c..de29e3f2 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -28,6 +28,7 @@ import isodate import re import cgi from icalendar import Calendar, Event +import braintree from django.shortcuts import render from django.template.loader import render_to_string @@ -50,7 +51,7 @@ from rowers.forms import ( RaceResultFilterForm,PowerIntervalUpdateForm,FlexAxesForm, FlexOptionsForm,DataFrameColumnsForm,OteWorkoutTypeForm, MetricsForm,DisqualificationForm,disqualificationreasons, - disqualifiers,SearchForm, + disqualifiers,SearchForm,BrainTreeForm ) from django.core.urlresolvers import reverse, reverse_lazy @@ -139,6 +140,7 @@ from rowsandall_app.settings import ( UNDERARMOUR_CLIENT_SECRET,UNDERARMOUR_CLIENT_KEY, RUNKEEPER_CLIENT_ID,RUNKEEPER_REDIRECT_URI,RUNKEEPER_CLIENT_SECRET, TP_CLIENT_ID,TP_REDIRECT_URI,TP_CLIENT_KEY,TP_CLIENT_SECRET, + BRAINTREE_MERCHANT_ID,BRAINTREE_PUBLIC_KEY,BRAINTREE_PRIVATE_KEY ) from rowers.tasks_standalone import addcomment2 @@ -1027,6 +1029,87 @@ def add_defaultfavorites(r): f.save() return 1 +# Experimental - Payments +@login_required() +def payments_view(request): + + r = getrequestrower(request) + + gateway = braintree.BraintreeGateway( + braintree.Configuration( + braintree.Environment.Sandbox, + merchant_id=BRAINTREE_MERCHANT_ID, + public_key=BRAINTREE_PUBLIC_KEY, + private_key=BRAINTREE_PRIVATE_KEY, + ) + ) + + # add code to store customer_id + + client_token = gateway.client_token.generate({ + "customer_id": r.id, + }) + + return render(request, + "payments.html", + { + 'client_token':client_token, + }) + + +@login_required() +def checkouts_view(request): + + r = getrequestrower(request) + + if request.method != 'POST': + url = reverse(payments_view) + return HttpResponseRedirect(url) + + # we're still here + gateway = braintree.BraintreeGateway( + braintree.Configuration( + braintree.Environment.Sandbox, + merchant_id=BRAINTREE_MERCHANT_ID, + public_key=BRAINTREE_PUBLIC_KEY, + private_key=BRAINTREE_PRIVATE_KEY, + ) + ) + + form = BrainTreeForm(request.POST) + if form.is_valid(): + nonce_from_the_client = form.cleaned_data['payment_method_nonce'] + amount = form.cleaned_data['amount'] + amount = str(amount) + + result = gateway.transaction.sale({ + "amount": amount, + "payment_method_nonce": nonce_from_the_client, + "options": { + "submit_for_settlement": True + } + }) + if result.is_success: + transaction = result.transaction + amount = transaction.amount + messages.info(request, + "We have successfully received your payment of {amount} Euro".format( + amount=amount + ) + ) + else: + messages.error(request,"We are sorry but there was an error with the payment") + url = reverse(payments_view) + return HttpResponseRedirect(url) + + else: + messages.error(request,"There was an error in the payment form") + url = reverse(payments_view) + return HttpResponseRedirect(url) + + url = reverse(payments_view) + return HttpResponseRedirect(url) + # User registration def rower_register_view(request): diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py index 93bfb4a4..61484bbf 100644 --- a/rowsandall_app/settings.py +++ b/rowsandall_app/settings.py @@ -421,3 +421,20 @@ try: except KeyError: workoutemailbox = 'workouts@rowsandall.com' + +# payments + +try: + BRAINTREE_MERCHANT_ID = CFG['braintree_merchant_id'] +except KeyError: + BRAINTREE_MERCHANT_ID = '' + +try: + BRAINTREE_PUBLIC_KEY = CFG['braintree_public_key'] +except KeyError: + BRAINTREE_PUBLIC_KEY = '' + +try: + BRAINTREE_PRIVATE_KEY = CFG['braintree_private_key'] +except KeyError: + BRAINTREE_PRIVATE_KEY = ''