diff --git a/rowers/admin.py b/rowers/admin.py index e7a22b76..5e77e04f 100644 --- a/rowers/admin.py +++ b/rowers/admin.py @@ -7,10 +7,12 @@ from .models import ( Team,TeamInvite,TeamRequest, WorkoutComment,C2WorldClassAgePerformance,PlannedSession, GeoCourse,GeoPolygon,GeoPoint,VirtualRace,VirtualRaceResult, + PaidPlan ) # Register your models here so you can use them in the Admin module + # Rower details directly under the User class RowerInline(admin.StackedInline): model = Rower @@ -120,6 +122,9 @@ class VirtualRaceAdmin(admin.ModelAdmin): class VirtualRaceResultAdmin(admin.ModelAdmin): list_display = ('race','userid','username','boattype','age','weightcategory') search_fields = ['race__name','username'] + +class PaidPlanAdmin(admin.ModelAdmin): + list_display = ('name','shortname','price','paymenttype') admin.site.unregister(User) admin.site.register(User,UserAdmin) @@ -137,3 +142,4 @@ admin.site.register(PlannedSession,PlannedSessionAdmin) admin.site.register(GeoCourse, GeoCourseAdmin) admin.site.register(VirtualRace, VirtualRaceAdmin) admin.site.register(VirtualRaceResult, VirtualRaceResultAdmin) +admin.site.register(PaidPlan,PaidPlanAdmin) diff --git a/rowers/braintreestuff.py b/rowers/braintreestuff.py new file mode 100644 index 00000000..863b512d --- /dev/null +++ b/rowers/braintreestuff.py @@ -0,0 +1,53 @@ +import braintree + +from rowsandall_app.settings import ( + BRAINTREE_MERCHANT_ID,BRAINTREE_PUBLIC_KEY,BRAINTREE_PRIVATE_KEY + ) + +gateway = braintree.BraintreeGateway( + braintree.Configuration( + braintree.Environment.Sandbox, + merchant_id=BRAINTREE_MERCHANT_ID, + public_key=BRAINTREE_PUBLIC_KEY, + private_key=BRAINTREE_PRIVATE_KEY, + ) +) + +from rowers.models import Rower,PaidPlan +from rowers.utils import ProcessorCustomerError + +def create_customer(rower): + if not rower.customer_id: + result = gateway.customer.create( + { + 'first_name':rower.user.first_name, + 'last_name':rower.user.last_name, + 'email':rower.user.email, + }) + if not result.is_success: + raise ProcessorCustomerError + else: + rower.customer_id = result.customer.id + rower.save() + else: + return rower.customer_id + +def get_client_token(rower): + client_token = gateway.client_token.generate({ + "customer_id":rower.customer_id, + }) + + return client_token + +def get_plans_costs(): + plans = gateway.plan.all() + + localplans = PaidPlan.object.all() + + for plan in localplans: + for btplan in btplans: + if int(btplan.id) == plan.braintree_id: + plan.price = float(x) + plan.save() + + return plans diff --git a/rowers/forms.py b/rowers/forms.py index c86e6cb8..effeadf1 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -18,8 +18,8 @@ from django.forms import formset_factory from utils import landingpages from metrics import axes -# Braintree form -class BrainTreeForm(forms.Form): +# BillingForm form +class BillingForm(forms.Form): amount = forms.FloatField(required=True) payment_method_nonce = forms.CharField(max_length=255) diff --git a/rowers/models.py b/rowers/models.py index ad3d68b5..04de22f5 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -537,6 +537,27 @@ weightcategories = ( ) +# Plan +plans = ( + ('basic','basic'), + ('pro','pro'), + ('plan','plan'), + ('coach','coach') +) + +paymenttypes = ( + ('single','single'), + ('recurring','recurring') +) + +class PaidPlan(models.Model): + shortname = models.CharField(max_length=50,choices=plans) + name = models.CharField(max_length=200) + braintree_id = models.IntegerField(blank=True,null=True,default=None) + price = models.FloatField(blank=True,null=True,default=None) + paymenttype = models.CharField(max_length=50,choices=paymenttypes) + clubsize = models.IntegerField(default=0) + # Extension of User with rowing specific data class Rower(models.Model): adaptivetypes = mytypes.adaptivetypes @@ -694,13 +715,6 @@ class Rower(models.Model): blank=True,null=True) runkeeper_auto_export = models.BooleanField(default=False) - # Plan - plans = ( - ('basic','basic'), - ('pro','pro'), - ('plan','plan'), - ('coach','coach') - ) privacychoices = ( ('visible','Visible'), @@ -720,10 +734,7 @@ class Rower(models.Model): paymenttype = models.CharField( default='single',max_length=30, verbose_name='Payment Type', - choices=( - ('single','single'), - ('recurring','recurring') - ) + choices=paymenttypes, ) planexpires = models.DateField(default=timezone.now) diff --git a/rowers/templates/paidplans.html b/rowers/templates/paidplans.html new file mode 100644 index 00000000..0cd4a34f --- /dev/null +++ b/rowers/templates/paidplans.html @@ -0,0 +1,269 @@ +{% extends "newbase.html" %} +{% block title %}Rowsandall Paid Membership{% endblock title %} +{% load rowerfilters %} +{% block main %} + +
Rowsandall.com offers free data and analysis for rowers, by rowers. + Of course, offering this service is not free. To help cover the + hosting costs, we have created paid plans offering extended + functionality. +
+ ++
| + | 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 | ++ | + | + | ✔ | +||||||||||||
| Pricing | +FREE | +From 15€/year | +From 65€/year | +From 90€/year | +||||||||||||
| Your current plan | +
+ {% if rower.rowerplan == 'basic' %}
+ BASIC+ {% else %} + + {% endif %} + |
+ + {% if rower.rowerplan == 'pro' %} + PRO + {% else %} + + {% endif %} + | ++ {% if rower.rowerplan == 'plan' %} + SELF-COACH + {% else %} + + {% endif %} + | ++ {% if rower.rowerplan == 'coach' %} + COACH + {% else %} + + {% endif %} + | +||||||||||||
| + Available trials + | ++ + | ++ {% if user.is_anonymous %} + + {% elif rower and rower.rowerplan == 'basic' and rower.protrialexpires|date_dif == 1 %} + + {% else %} + + {% endif %} + | ++ {% if user.is_anonymous %} + + {% elif rower and rower.rowerplan == 'basic' and rower.plantrialexpires|date_dif == 1 %} + + {% else %} + + {% endif %} + | ++ + | +||||||||||||
| + Available upgrades + | ++ + | + {% if user.is_anonymous %} ++ + | + {% elif rower and rower.rowerplan == 'basic' %} ++ + | + {% elif rower and rower.rowerplan == 'pro' %} ++ | + + | + {% elif rower and rower.rowerplan == 'plan' %} ++ | + | + + | + {% else %} ++ + | + {% endif %} +|||||||
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.
+ +