Private
Public Access
1
0

Merge branch 'feature/eurocredits' into develop

This commit is contained in:
Sander Roosendaal
2021-11-11 14:12:39 +01:00
13 changed files with 129 additions and 11 deletions

View File

@@ -27,6 +27,9 @@ from rowers.tasks import (
#handle_send_email_transaction_notification,
)
from rowers import credits
from rowers.utils import dologging
import pandas as pd
from rowsandall_app.settings import (
@@ -68,6 +71,19 @@ def process_webhook(notification):
except TypeError:
f.write(timestamp+'\n')
if notification.kind == 'subscription_charged_successfully':
subscription = notification.subscription
rs = Rower.objects.filter(subscription_id=subscription.id)
if rs.count() == 0:
dologging('braintreewebhooks.log','Could not find rowers with subscription ID {id}'.format(
id=subscription.id
))
else:
r = rs[0]
transactions = subscription.transactions
if transactions:
amount = int(transactions[0].amount)
eurocredits = credits.upgrade(amount,r)
eurocredits = credits.upgrade(amount,r)
return send_invoice(notification.subscription)
if notification.kind == 'subscription_canceled':
subscription = notification.subscription
@@ -268,6 +284,8 @@ def update_subscription(rower,data,method='up'):
if result.is_success:
yesterday = (timezone.now()-datetime.timedelta(days=1)).date()
rower.paidplan = plan
amount_int = int(float(amount))
eurocredits = credits.upgrade(amount_int,rower)
rower.planexpires = result.subscription.billing_period_end_date
rower.teamplanexpires = result.subscription.billing_period_end_date
rower.clubsize = plan.clubsize

41
rowers/credits.py Normal file
View File

@@ -0,0 +1,41 @@
class InsufficientCreditError(Exception):
"""Raised when trying to subtract more than available"""
pass
def upgrade(amount, rower):
if rower.eurocredits > amount:
return rower.eurocredits
else:
rower.eurocredits = amount
rower.save()
return rower.eurocredits
return rower.eurocredits
def withdraw(amount, rower):
if rower.eurocredits < amount:
rower.eurocredits = 0
rower.save()
raise InsufficientCreditError
else:
rower.eurocredits = rower.eurocredits - amount
rower.save()
return rower.eurocredits
return rower.eurocredits
def discount(amount,rower):
if amount < rower.eurocredits:
return amount
else:
return rower.eurocredits
return 0
def discounted(amount,rower):
if amount > rower.eurocredits:
return amount-rower.eurocredits
else:
return 0
return 0

View File

@@ -878,6 +878,8 @@ class Rower(models.Model):
null=True,blank=True,
default='braintree')
eurocredits = models.IntegerField(default=0)
paidplan = models.ForeignKey(PaidPlan,null=True,default=None,on_delete=models.SET_NULL)
planexpires = models.DateField(default=current_day)

View File

@@ -21,6 +21,10 @@
<p>Plan: {{ plan.name }}</p>
<p>Price: {{ plan.price }}&euro;</p>
{% if rower.eurocredits > 0 %}
<p>Your Discount: {{ plan.price|discount:rower }}</p>
<p>You will pay: {{ plan.price|discounted:rower }}</p>
{% endif %}
</li>
<li>
<p>

View File

@@ -37,7 +37,7 @@
<th>Plan</th><td>{{ plan.name }}</td>
</tr>
<tr>
<th>Total</th><td>&euro; {{ plan.price|currency }}
<th>Total</th><td>&euro; {{ plan.price|discounted:rower|currency }}
</td>
</tr>
</tbody>
@@ -70,7 +70,7 @@
<label for="amount">
<div class="input-wrapper amount-wrapper">
<input id="amount" name="amount" type="hidden" min="1" placeholder="Amount"
value="{{ plan.price }}" readonly>
value="{{ plan.price|discounted:rower }}" readonly>
</div>
</label>
<div class="bt-drop-in-wrapper">
@@ -91,7 +91,7 @@
Policy and agree with the <a href="/rowers/legal/" target="_blank">Terms of Service</a>.
</p>
{% csrf_token %}
<button type="submit" id="submit-button"><span>Purchase for &euro; {{ plan.price|currency }}</span></button>
<button type="submit" id="submit-button"><span>Purchase for &euro; {{ plan.price|discounted:rower|currency }}</span></button>
</form>
</li>
<li class="grid_4">

View File

@@ -32,6 +32,10 @@
{% else %}
<p>Price: {{ plan.price }}&euro;</p>
{% endif %}
{% if rower.eurocredits and plan.price > 0 %}
<p>Your discount: {{ plan.price|discount:rower }}&euro;</p>
<p>You pay: {{ plan.price|discounted:rower }}&euro;</p>
{% endif %}
</li>
{% if form %}
<li class="grid_2">
@@ -47,7 +51,7 @@
If you have <a href="/rowers/createplan/">set a training target</a>, you can also ask to plan by that target. Select the
target from the targets list, and select "plan by target".
</p>
{% if plan.price == 0 %}
{% if plan.price|discounted:rower == 0 %}
<form enctype="multipart/form-data" action="" method="post">
{% else %}
<form enctype="multipart/form-data" action="/rowers/buyplan/{{ plan.id }}/" method="post">
@@ -56,7 +60,7 @@
{{ form.as_table }}
</table>
{% csrf_token %}
{% if plan.price == 0 %}
{% if plan.price|discounted:rower == 0 %}
<p><input class="button" type="submit" value="Create Plan and Add Sessions"></p>
{% else %}
<p><input class="button" type="submit" action="/rowers/buyplan/{{ plan.id }}/" value="BUY NOW and Add Sessions"></p>

View File

@@ -10,11 +10,19 @@
<ul class="main-content">
<li class="grid_4">
<p>
On this page, you find trusted training plans that work. If you are looking for a plan, this page is for you.
This ever growing list of plans contains a plan for everyone, whether you are a beginning rower or experienced,
irrespective of your current fitness level. Click on a plan to read more and see the sessions. If you're
on a Self-Coach plan or higher, you can get the plan including even more detailed workout instructions
copied straight to your training calendar on this site, with the simple click of a button.
</p>
{% if rower.eurocredits %}
<p>
<em>Your have discount vouchers for an mount of {{ rower.eurocredits }}&euro;</em>. You
will get discount for up to this amount on any paid plan.
</p>
{% endif %}
</li>
{% for plan in plans %}
<li class="rounder">
@@ -34,6 +42,10 @@
{% else %}
<p>Price: {{ plan.price }}&euro;</p>
{% endif %}
{% if rower.eurocredits and plan.price > 0 %}
<p>Your discount: {{ plan.price|discount:rower }}&euro;</p>
<p>You pay: {{ plan.price|discounted:rower }}&euro;</p>
{% endif %}
</li>
{% endfor %}

View File

@@ -52,6 +52,12 @@
{% endif %}
</th><td>{{ rower.planexpires }}</td>
</tr>
{% if rower.eurocredits %}
<tr>
<th>Discount voucher for training plans</th>
<td>{{ rower.eurocredits }}&euro;</td>
</tr>
{% endif %}
{% endif %}
</table>
{% csrf_token %}

View File

@@ -19,6 +19,7 @@ from rowers.plannedsessions import (
race_can_register, race_can_submit,race_rower_status
)
from rowers import credits
from rowers import c2stuff
from rowers.c2stuff import c2_open
from rowers.rower_rules import is_coach_user, is_workout_user, isplanmember,ispromember
@@ -153,6 +154,15 @@ def weekbegin(nr):
return True
return False
@register.filter
def discount(amount,rower):
return credits.discount(amount,rower)
@register.filter
def discounted(amount,rower):
return credits.discounted(amount,rower)
@register.filter
def weekend(nr):
week, day = divmod(nr,7)

View File

@@ -406,8 +406,8 @@ description: ""
@patch('rowers.views.braintreestuff.gateway', side_effect=MockBraintreeGateway)
@patch('rowers.fakturoid.create_invoice',side_effect=mocked_invoiceid)
@patch('rowers.braintreestuff.myqueue')
def test_purchase_trainingplan_view(self, mocked_gateway,mocked_invoiceid,mocked_myqueue):
@patch('rowers.utils.myqueue')
def test_purchase_trainingplan_view(self, mocked_gateway,mocked_invoiceid, mocked_myqueue):
u = UserFactory()
r = Rower.objects.create(user=u,
birthdate=faker.profile()['birthdate'],

Binary file not shown.

View File

@@ -6,6 +6,8 @@ from __future__ import unicode_literals
from rowers.views.statements import *
from django.core.mail import EmailMessage
from rowers import credits
@csrf_exempt
def braintree_webhook_view(request):
with open('braintreewebhooks.log','a') as f:
@@ -212,6 +214,11 @@ def purchase_checkouts_view(request):
return HttpResponseRedirect(reverse('rower_select_instantplan'))
amount, success = braintreestuff.make_payment(r,data)
diff = plan.price - int(amount)
eurocredits = credits.withdraw(diff,r)
if success:
messages.info(request,"Your payment was completed and the sessions are copied to your calendar")
@@ -243,7 +250,7 @@ def purchase_checkouts_view(request):
p.rowers.add(r)
create_sessions_from_json(plansteps,r,startdate,r.user)
job = myqueue(queuehigh,handle_send_email_instantplan_notification,
r.user.username,
r.user.email,
@@ -251,7 +258,6 @@ def purchase_checkouts_view(request):
plan.name,
startdate,
enddate)
print(job,'noot')
url = reverse('plannedsessions_view')
timeperiod = startdate.strftime('%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')

View File

@@ -9,6 +9,7 @@ import json
from taggit.models import Tag
import rowers.garmin_stuff as gs
from rowers import credits
@login_required
@permission_required('plannedsession.view_session',fn=get_session_by_pk,raise_exception=True)
@@ -1653,7 +1654,7 @@ def plannedsessions_manage_view(request,userid=0,
user=r,date__gte=startdate,
date__lte=enddate
).order_by(
"date","startdatetime","id"
"-date","-startdatetime","-id"
)
@@ -2575,7 +2576,7 @@ def rower_view_instantplan(request,id='',userid=0):
raise Http404("Plan does not exist")
plan = InstantPlan.objects.get(uuid=id)
discountedprice = credits.discounted(plan.price,r)
authorizationstring = 'Bearer '+settings.WORKOUTS_FIT_TOKEN
url = settings.WORKOUTS_FIT_URL+"/trainingplan/"+id
@@ -2621,10 +2622,24 @@ def rower_view_instantplan(request,id='',userid=0):
'id':id,
})
return HttpResponseRedirect(url)
# check if plan is free or credits are sufficient
if plan.price > 0:
if plan.price > r.eurocredits:
messages.error(request,'You did not have enough credit to purchase this plan')
url = reverse('rower_view_instantplan',kwargs={
'id':id,
})
return HttpResponseRedirect(url)
form = InstantPlanSelectForm(request.POST,targets=targets)
if form.is_valid():
if plan.price > 0:
eurocredits = credits.withdraw(plan.price,r)
plansteps = response.json()
name = form.cleaned_data['name']
try: