buy now flow complete except email confirmation
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
import braintree
|
import braintree
|
||||||
|
from django.utils import timezone
|
||||||
|
import datetime
|
||||||
|
|
||||||
from rowsandall_app.settings import (
|
from rowsandall_app.settings import (
|
||||||
BRAINTREE_MERCHANT_ID,BRAINTREE_PUBLIC_KEY,BRAINTREE_PRIVATE_KEY
|
BRAINTREE_MERCHANT_ID,BRAINTREE_PUBLIC_KEY,BRAINTREE_PRIVATE_KEY
|
||||||
@@ -16,8 +18,8 @@ gateway = braintree.BraintreeGateway(
|
|||||||
from rowers.models import Rower,PaidPlan
|
from rowers.models import Rower,PaidPlan
|
||||||
from rowers.utils import ProcessorCustomerError
|
from rowers.utils import ProcessorCustomerError
|
||||||
|
|
||||||
def create_customer(rower):
|
def create_customer(rower,force=False):
|
||||||
if not rower.customer_id:
|
if not rower.customer_id or force:
|
||||||
result = gateway.customer.create(
|
result = gateway.customer.create(
|
||||||
{
|
{
|
||||||
'first_name':rower.user.first_name,
|
'first_name':rower.user.first_name,
|
||||||
@@ -28,14 +30,25 @@ def create_customer(rower):
|
|||||||
raise ProcessorCustomerError
|
raise ProcessorCustomerError
|
||||||
else:
|
else:
|
||||||
rower.customer_id = result.customer.id
|
rower.customer_id = result.customer.id
|
||||||
|
rower.paymentprocessor = 'braintree'
|
||||||
rower.save()
|
rower.save()
|
||||||
|
return rower.customer_id
|
||||||
else:
|
else:
|
||||||
return rower.customer_id
|
return rower.customer_id
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_client_token(rower):
|
def get_client_token(rower):
|
||||||
client_token = gateway.client_token.generate({
|
try:
|
||||||
"customer_id":rower.customer_id,
|
client_token = gateway.client_token.generate({
|
||||||
|
"customer_id":rower.customer_id,
|
||||||
})
|
})
|
||||||
|
except ValueError:
|
||||||
|
customer_id = create_customer(rower,force=True)
|
||||||
|
|
||||||
|
client_token = gateway.client_token.generate({
|
||||||
|
"customer_id": customer_id,
|
||||||
|
})
|
||||||
|
|
||||||
return client_token
|
return client_token
|
||||||
|
|
||||||
@@ -51,3 +64,125 @@ def get_plans_costs():
|
|||||||
plan.save()
|
plan.save()
|
||||||
|
|
||||||
return plans
|
return plans
|
||||||
|
|
||||||
|
def make_payment(rower,data):
|
||||||
|
nonce_from_the_client = data['payment_method_nonce']
|
||||||
|
amount = 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
|
||||||
|
|
||||||
|
return amount
|
||||||
|
else:
|
||||||
|
return 0,''
|
||||||
|
|
||||||
|
def create_subscription(rower,data):
|
||||||
|
planid = data['plan']
|
||||||
|
plan = PaidPlan.objects.get(id=planid)
|
||||||
|
nonce_from_the_client = data['payment_method_nonce']
|
||||||
|
amount = data['amount']
|
||||||
|
|
||||||
|
# create or find payment method
|
||||||
|
result = gateway.payment_method.create({
|
||||||
|
"customer_id": rower.customer_id,
|
||||||
|
"payment_method_nonce": nonce_from_the_client
|
||||||
|
})
|
||||||
|
|
||||||
|
if result.is_success:
|
||||||
|
payment_method_token = result.payment_method.token
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
result = gateway.subscription.create({
|
||||||
|
"payment_method_token": payment_method_token,
|
||||||
|
"plan_id": plan.external_id
|
||||||
|
})
|
||||||
|
|
||||||
|
if result.is_success:
|
||||||
|
rower.paidplan = plan
|
||||||
|
rower.planexpires = timezone.now()+datetime.timedelta(days=365)
|
||||||
|
rower.teamplanexpires = timezone.now()+datetime.timedelta(days=365)
|
||||||
|
rower.clubsize = plan.clubsize
|
||||||
|
rower.paymenttype = plan.paymenttype
|
||||||
|
rower.rowerplan = plan.shortname
|
||||||
|
rower.save()
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def cancel_subscription(rower,id):
|
||||||
|
themessages = []
|
||||||
|
errormessages = []
|
||||||
|
try:
|
||||||
|
result = gateway.subscription.cancel(id)
|
||||||
|
messages.append("Subscription canceled")
|
||||||
|
except:
|
||||||
|
errormessages.append("We could not find the subscription record in our customer database")
|
||||||
|
return False, themessages, errormessages
|
||||||
|
|
||||||
|
rower.paidplan = None
|
||||||
|
rower.teamplanexpires = timezone.now()
|
||||||
|
rower.planexpires = timezone.now()
|
||||||
|
rower.clubsize = 0
|
||||||
|
rower.rowerplan = 'basic'
|
||||||
|
rower.save()
|
||||||
|
themessages.append("Your plan was reset to basic")
|
||||||
|
|
||||||
|
return True, themessages,errormessages
|
||||||
|
|
||||||
|
|
||||||
|
def find_subscriptions(rower):
|
||||||
|
try:
|
||||||
|
result = gateway.customer.find(rower.customer_id)
|
||||||
|
except:
|
||||||
|
raise ProcessorCustomerError("We could not find the customer in the database")
|
||||||
|
|
||||||
|
active_subscriptions = []
|
||||||
|
|
||||||
|
cards = result.credit_cards
|
||||||
|
for card in cards:
|
||||||
|
for subscription in card.subscriptions:
|
||||||
|
if subscription.status == 'Active':
|
||||||
|
active_subscriptions.append(subscription)
|
||||||
|
|
||||||
|
try:
|
||||||
|
paypal_accounts = result.paypal_accounts
|
||||||
|
for account in accuonts:
|
||||||
|
for subscription in account.subscriptions:
|
||||||
|
if subscription.status == 'Active':
|
||||||
|
active_subscriptions.append(subscription)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
result = []
|
||||||
|
|
||||||
|
for subscription in active_subscriptions:
|
||||||
|
|
||||||
|
plan = PaidPlan.objects.filter(paymentprocessor="braintree",
|
||||||
|
external_id=subscription.plan_id)[0]
|
||||||
|
|
||||||
|
thedict = {
|
||||||
|
'end_date': subscription.billing_period_end_date,
|
||||||
|
'plan_id': subscription.plan_id,
|
||||||
|
'price': subscription.price,
|
||||||
|
'id': subscription.id,
|
||||||
|
'plan': plan.name
|
||||||
|
}
|
||||||
|
|
||||||
|
result.append(thedict)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ from metrics import axes
|
|||||||
# BillingForm form
|
# BillingForm form
|
||||||
class BillingForm(forms.Form):
|
class BillingForm(forms.Form):
|
||||||
amount = forms.FloatField(required=True)
|
amount = forms.FloatField(required=True)
|
||||||
payment_method_nonce = forms.CharField(max_length=255)
|
plan = forms.IntegerField(widget=forms.HiddenInput())
|
||||||
|
payment_method_nonce = forms.CharField(max_length=255,required=True)
|
||||||
|
|
||||||
|
|
||||||
# login form
|
# login form
|
||||||
|
|||||||
@@ -558,7 +558,7 @@ paymentprocessors = (
|
|||||||
class PaidPlan(models.Model):
|
class PaidPlan(models.Model):
|
||||||
shortname = models.CharField(max_length=50,choices=plans)
|
shortname = models.CharField(max_length=50,choices=plans)
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
external_id = models.IntegerField(blank=True,null=True,default=None)
|
external_id = models.CharField(blank=True,null=True,default=None,max_length=200)
|
||||||
price = models.FloatField(blank=True,null=True,default=None)
|
price = models.FloatField(blank=True,null=True,default=None)
|
||||||
paymentprocessor = models.CharField(
|
paymentprocessor = models.CharField(
|
||||||
max_length=50,choices=paymentprocessors,default='braintree')
|
max_length=50,choices=paymentprocessors,default='braintree')
|
||||||
@@ -633,7 +633,8 @@ class Rower(models.Model):
|
|||||||
)
|
)
|
||||||
paymentprocessor = models.CharField(max_length=50,
|
paymentprocessor = models.CharField(max_length=50,
|
||||||
choices=paymentprocessors,
|
choices=paymentprocessors,
|
||||||
default='braintree')
|
null=True,blank=True,
|
||||||
|
default=None)
|
||||||
|
|
||||||
paidplan = models.ForeignKey(PaidPlan,null=True,default=None)
|
paidplan = models.ForeignKey(PaidPlan,null=True,default=None)
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ def setrowerplans():
|
|||||||
print 'Could not set plan for ',r
|
print 'Could not set plan for ',r
|
||||||
|
|
||||||
def is_existing_customer(rower):
|
def is_existing_customer(rower):
|
||||||
if rower.country is not None and rower.customer_id is not None and r.country != '':
|
if rower.country is not None and rower.customer_id is not None and rower.country != '':
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -31,6 +31,6 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block sidebar %}
|
{% block sidebar %}
|
||||||
{% include 'menu_help.html' %}
|
{% include 'menu_profile.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
26
rowers/templates/payment_completed.html
Normal file
26
rowers/templates/payment_completed.html
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{% extends "newbase.html" %}
|
||||||
|
{% block title %}Rowsandall Paid Membership{% endblock title %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
<h1>Your Payment was completed</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Thank you for registering to {{ user.rower.paidplan.name }}. You have paid for 12 months
|
||||||
|
membership.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{% 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 %}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% include 'menu_profile.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
113
rowers/templates/paymentconfirm.html
Normal file
113
rowers/templates/paymentconfirm.html
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
{% extends "newbase.html" %}
|
||||||
|
{% block title %}Rowsandall Paid Membership{% endblock title %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
<h1>Confirm Your Payment</h1>
|
||||||
|
|
||||||
|
<h2>Order Overview</h2>
|
||||||
|
|
||||||
|
<ul class="main-content">
|
||||||
|
<li class="grid_2">
|
||||||
|
<p>
|
||||||
|
<table class="plantable shortpadded" width="80%">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>Plan</th><td>{{ plan.name }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Payment Type</th><td>{{ plan.paymenttype }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Plan Duration</th><td>1 year starting today</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Total</th><td>€ {{ plan.price|currency }}
|
||||||
|
{% if plan.paymenttype == 'recurring' %}
|
||||||
|
/year
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<table class="plantable shortpadded" width="80%">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<th>Street Address</th><td>{{ user.rower.street_address }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>City</th><td>{{ user.rower.city }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Posstal Code</th><td>{{ user.rower.postal_code }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>Country</th><td>{{ user.rower.country }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li class="grid_2">
|
||||||
|
<p>
|
||||||
|
<a href="/rowers/billing">Change Order</a>
|
||||||
|
</li>
|
||||||
|
<li class="grid_4">
|
||||||
|
<form id="payment-form" method="post" action="/rowers/checkouts"
|
||||||
|
autocomplete="off">
|
||||||
|
<section>
|
||||||
|
<label for="amount">
|
||||||
|
<div class="input-wrapper amount-wrapper">
|
||||||
|
<input id="amount" name="amount" type="hidden" min="1" placeholder="Amount"
|
||||||
|
value="{{ plan.price }}" readonly>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<div class="bt-drop-in-wrapper">
|
||||||
|
<div id="bt-dropin"></div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<input type="hidden" id="nonce" name="payment_method_nonce" />
|
||||||
|
<input type="hidden" id="plan" name="plan" value="{{ plan.id }}">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button type="submit" id="submit-button"><span>Pay € {{ plan.price|currency }}</span></button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<script src="https://js.braintreegateway.com/web/dropin/1.14.1/js/dropin.min.js"></script>
|
||||||
|
<script>
|
||||||
|
var form = document.querySelector('#payment-form');
|
||||||
|
var client_token = '{{ client_token }}';
|
||||||
|
braintree.dropin.create({
|
||||||
|
authorization: client_token,
|
||||||
|
container: '#bt-dropin',
|
||||||
|
paypal: {
|
||||||
|
flow: 'checkout'
|
||||||
|
}
|
||||||
|
}, function (createErr, instance) {
|
||||||
|
form.addEventListener('submit', function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
instance.requestPaymentMethod(function (err, payload) {
|
||||||
|
if (err) {
|
||||||
|
console.log('Error', err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Add the nonce to the form and submit
|
||||||
|
document.querySelector('#nonce').value = payload.nonce;
|
||||||
|
form.submit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% include 'menu_profile.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<h2>Account Information</h2>
|
<h2>Account Information</h2>
|
||||||
<p>
|
<p>
|
||||||
{% if rower.user == user %}
|
{% if rower.user == user %}
|
||||||
<a class="button blue small" href="/password_change/">Password Change</a>
|
<a href="/password_change/">Password Change</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -34,29 +34,49 @@
|
|||||||
{{ userform.as_table }}
|
{{ userform.as_table }}
|
||||||
{{ accountform.as_table }}
|
{{ accountform.as_table }}
|
||||||
<tr>
|
<tr>
|
||||||
<th>Plan</th><td>{{ rower.rowerplan }}</td>
|
<th> </th><td></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Plan Expiry</th><td>{{ rower.planexpires }}</td>
|
<th>Plan</th><td>{{ rower.paidplan.name }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% if rower.rowerplan != 'basic' %}
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{% if rower.paymenttype != 'recurring' %}
|
||||||
|
Plan Expiry
|
||||||
|
{% else %}
|
||||||
|
Next Payment Due
|
||||||
|
{% endif %}
|
||||||
|
</th><td>{{ rower.planexpires }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% if rower.rowerplan == 'basic' and rower.user == user %}
|
{% if rower.rowerplan != 'coach' and rower.user == user %}
|
||||||
<a class="button blue" href="/rowers/promembership">Upgrade</a>
|
<p>
|
||||||
|
<a href="/rowers/paidplans">Upgrade</a>
|
||||||
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
<p>
|
||||||
|
|
||||||
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<input class="button green" type="submit" value="Save">
|
{% if rower.rowerplan != 'basic' and rower.user == user %}
|
||||||
|
<p>
|
||||||
|
<a href="/rowers/me/cancelsubscriptions">Cancel Subscription</a>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
<input type="submit" value="Save">
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
{% if rower.user == user %}
|
{% if rower.user == user %}
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<h2>GDPR - Data Protection</h2>
|
<h2>GDPR - Data Protection</h2>
|
||||||
<p>
|
<p>
|
||||||
<a class="button blue small" href="/rowers/exportallworkouts">Download your data</a>
|
<a href="/rowers/exportallworkouts">Download your data</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a class="button blue small" href="/rowers/me/deactivate">Deactivate Account</a>
|
<a href="/rowers/me/deactivate">Deactivate Account</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<a class="button red small" href="/rowers/me/delete">Delete Account</a>
|
<a class="button red small" href="/rowers/me/delete">Delete Account</a>
|
||||||
@@ -79,7 +99,7 @@
|
|||||||
<td>{{ grant.application }}</td>
|
<td>{{ grant.application }}</td>
|
||||||
<td>{{ grant.scope }}</td>
|
<td>{{ grant.scope }}</td>
|
||||||
<td>
|
<td>
|
||||||
<a class="button red small" href="/rowers/me/revokeapp/{{ grant.application.id }}">Revoke</a>
|
<a href="/rowers/me/revokeapp/{{ grant.application.id }}">Revoke</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
64
rowers/templates/subscriptions_cancel.html
Normal file
64
rowers/templates/subscriptions_cancel.html
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{% extends "newbase.html" %}
|
||||||
|
{% block title %}Rowsandall Paid Membership{% endblock title %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
<h1>Cancel Subscriptions</h1>
|
||||||
|
|
||||||
|
<ul class="main-content">
|
||||||
|
<li class="grid_4">
|
||||||
|
{% if subscriptions %}
|
||||||
|
<p>
|
||||||
|
<table class="plantable shortpadded" width="80%">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Subscription</th><th>Next Billing Date</th><th>Price</th><th> </th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for subscription in subscriptions %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{ subscription|lookup:"plan" }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ subscription|lookup:"end_date" }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ subscription|lookup:"price" }} €
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/me/cancelsubscription/{{ subscription|lookup:'id' }}">Stop this plan</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p>
|
||||||
|
<p>
|
||||||
|
By clicking on the link to stop the plan, you will downgrade to the Basic plan.
|
||||||
|
Future payments will be stopped.
|
||||||
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p>
|
||||||
|
You don't have any subscriptions or your subscriptions cannot be automatically stopped
|
||||||
|
from the site.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you have paid through PayPal, log in to your PayPal account and cancel the recurring payment
|
||||||
|
there. We will manually downgrade your subscription.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you have questions, don't hesitate to contact us.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% include 'menu_profile.html' %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
@@ -125,7 +125,16 @@ def c2userid(user):
|
|||||||
c2userid = c2stuff.get_userid(thetoken)
|
c2userid = c2stuff.get_userid(thetoken)
|
||||||
|
|
||||||
return c2userid
|
return c2userid
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def currency(word):
|
||||||
|
try:
|
||||||
|
amount = float(word)
|
||||||
|
except ValueError:
|
||||||
|
return word
|
||||||
|
|
||||||
|
return '{amount:.2f}'.format(amount=amount)
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def rkuserid(user):
|
def rkuserid(user):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -438,10 +438,13 @@ urlpatterns = [
|
|||||||
url(r'^analysis/$', views.analysis_view,name='analysis'),
|
url(r'^analysis/$', views.analysis_view,name='analysis'),
|
||||||
url(r'^laboratory/$', views.laboratory_view,name='laboratory'),
|
url(r'^laboratory/$', views.laboratory_view,name='laboratory'),
|
||||||
url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'),
|
url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'),
|
||||||
|
url(r'^checkout/(?P<planid>\d+)$',views.payment_confirm_view),
|
||||||
url(r'^billing',views.billing_view,name='billing'),
|
url(r'^billing',views.billing_view,name='billing'),
|
||||||
|
url(r'^paymentcompleted',views.payment_completed_view),
|
||||||
url(r'^paidplans',views.paidplans_view,name='paidplans'),
|
url(r'^paidplans',views.paidplans_view,name='paidplans'),
|
||||||
|
url(r'^me/cancelsubscriptions',views.plan_stop_view),
|
||||||
|
url(r'^me/cancelsubscription/(?P<id>[\w\ ]+.*)$',views.plan_tobasic_view),
|
||||||
url(r'^checkouts',views.checkouts_view,name='checkouts'),
|
url(r'^checkouts',views.checkouts_view,name='checkouts'),
|
||||||
url(r'^payments',views.payments_view,name='payments'),
|
|
||||||
url(r'^planrequired',views.planrequired_view),
|
url(r'^planrequired',views.planrequired_view),
|
||||||
url(r'^starttrial$',views.start_trial_view),
|
url(r'^starttrial$',views.start_trial_view),
|
||||||
url(r'^startplantrial$',views.start_plantrial_view),
|
url(r'^startplantrial$',views.start_plantrial_view),
|
||||||
|
|||||||
211
rowers/views.py
211
rowers/views.py
@@ -84,7 +84,7 @@ from rowers.models import (
|
|||||||
createmicrofillers, createmesofillers,
|
createmicrofillers, createmesofillers,
|
||||||
microcyclecheckdates,mesocyclecheckdates,macrocyclecheckdates,
|
microcyclecheckdates,mesocyclecheckdates,macrocyclecheckdates,
|
||||||
TrainingMesoCycleForm, TrainingMicroCycleForm,
|
TrainingMesoCycleForm, TrainingMicroCycleForm,
|
||||||
RaceLogo,RowerBillingAddressForm,
|
RaceLogo,RowerBillingAddressForm,PaidPlan,
|
||||||
)
|
)
|
||||||
from rowers.models import (
|
from rowers.models import (
|
||||||
RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm,
|
RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm,
|
||||||
@@ -738,8 +738,27 @@ def deactivate_user(request):
|
|||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
user_form = DeactivateUserForm(request.POST, instance=user)
|
user_form = DeactivateUserForm(request.POST, instance=user)
|
||||||
if user_form.is_valid():
|
if user_form.is_valid():
|
||||||
|
r = Rower.objects.get(user=user)
|
||||||
|
if r.paidplan is not None and r.paidplan.paymentprocessor == 'braintree':
|
||||||
|
try:
|
||||||
|
subscriptions = braintreestuff.find_subscriptions(r)
|
||||||
|
for subscription in subscriptions:
|
||||||
|
success, themessages,errormessages = braintreestuff.cancel_subscription(r,id)
|
||||||
|
for message in themessages:
|
||||||
|
messages.info(request,message)
|
||||||
|
except ProcessorCustomerError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
r.paidplan = None
|
||||||
|
r.teamplanexpires = timezone.now()
|
||||||
|
r.planexpires = timezone.now()
|
||||||
|
r.clubsize = 0
|
||||||
|
r.rowerplan = 'basic'
|
||||||
|
r.save()
|
||||||
|
|
||||||
deactivate_user = user_form.save(commit=False)
|
deactivate_user = user_form.save(commit=False)
|
||||||
user.is_active = False
|
user.is_active = False
|
||||||
|
user.save()
|
||||||
deactivate_user.save()
|
deactivate_user.save()
|
||||||
# url = reverse(auth_views.logout_then_login)
|
# url = reverse(auth_views.logout_then_login)
|
||||||
url = '/logout/?next=/login'
|
url = '/logout/?next=/login'
|
||||||
@@ -790,7 +809,17 @@ def remove_user(request):
|
|||||||
name = user.first_name+' '+user.last_name
|
name = user.first_name+' '+user.last_name
|
||||||
email = user.email
|
email = user.email
|
||||||
|
|
||||||
|
r = Rower.objects.get(user=user)
|
||||||
|
if r.paidplan is not None and r.paidplan.paymentprocessor == 'braintree':
|
||||||
|
try:
|
||||||
|
subscriptions = braintreestuff.find_subscriptions(r)
|
||||||
|
for subscription in subscriptions:
|
||||||
|
success, themessages,errormessages = braintreestuff.cancel_subscription(r,id)
|
||||||
|
for message in themessages:
|
||||||
|
messages.info(request,message)
|
||||||
|
except ProcessorCustomerError:
|
||||||
|
pass
|
||||||
|
|
||||||
if cd['delete_user']:
|
if cd['delete_user']:
|
||||||
user.delete()
|
user.delete()
|
||||||
res = myqueue(queuehigh,
|
res = myqueue(queuehigh,
|
||||||
@@ -998,7 +1027,7 @@ def hasplannedsessions(user):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
from rowers.utils import isprorower
|
from rowers.utils import isprorower,ProcessorCustomerError
|
||||||
|
|
||||||
# Check if a user is a Pro member
|
# Check if a user is a Pro member
|
||||||
def ispromember(user):
|
def ispromember(user):
|
||||||
@@ -1056,6 +1085,19 @@ def billing_view(request):
|
|||||||
|
|
||||||
if planselectform.is_valid():
|
if planselectform.is_valid():
|
||||||
plan = planselectform.cleaned_data['plan']
|
plan = planselectform.cleaned_data['plan']
|
||||||
|
if billingaddressform.is_valid():
|
||||||
|
try:
|
||||||
|
customer_id = braintreestuff.create_customer(r)
|
||||||
|
except ProcessorCustomerError:
|
||||||
|
messages.error(request,"Something went wrong registering you as a customer.")
|
||||||
|
url = reverse(billing_view)
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
url = reverse(payment_confirm_view,
|
||||||
|
kwargs={
|
||||||
|
'planid':plan.id
|
||||||
|
})
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
billingaddressform = RowerBillingAddressForm(instance=r)
|
billingaddressform = RowerBillingAddressForm(instance=r)
|
||||||
planselectform = PlanSelectForm(paymentprocessor='braintree')
|
planselectform = PlanSelectForm(paymentprocessor='braintree')
|
||||||
@@ -1067,50 +1109,66 @@ def billing_view(request):
|
|||||||
'planselectform':planselectform,
|
'planselectform':planselectform,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Experimental - Payments
|
|
||||||
@login_required()
|
@login_required()
|
||||||
def payments_view(request):
|
def plan_stop_view(request):
|
||||||
|
r = getrequestrower(request)
|
||||||
|
|
||||||
|
subscriptions = []
|
||||||
|
|
||||||
|
if r.paidplan is not None and r.paidplan.paymentprocessor == 'braintree':
|
||||||
|
try:
|
||||||
|
subscriptions = braintreestuff.find_subscriptions(r)
|
||||||
|
except ProcessorCustomerError:
|
||||||
|
r.paymentprocessor = None
|
||||||
|
r.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return render(request,
|
||||||
|
'subscriptions_cancel.html',
|
||||||
|
{'rower':r,
|
||||||
|
'subscriptions':subscriptions
|
||||||
|
})
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def plan_tobasic_view(request,id=0):
|
||||||
|
r = getrequestrower(request)
|
||||||
|
|
||||||
|
if r.paidplan.paymentprocessor == 'braintree':
|
||||||
|
success, themessages,errormessages = braintreestuff.cancel_subscription(r,id)
|
||||||
|
for message in themessages:
|
||||||
|
messages.info(request,message)
|
||||||
|
|
||||||
|
for message in errormessages:
|
||||||
|
messages.error(request,message)
|
||||||
|
|
||||||
|
url = reverse(plan_stop_view)
|
||||||
|
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def payment_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)
|
r = getrequestrower(request)
|
||||||
|
|
||||||
gateway = braintree.BraintreeGateway(
|
client_token = braintreestuff.get_client_token(r)
|
||||||
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
|
|
||||||
if not r.customer_id:
|
|
||||||
result = gateway.customer.create(
|
|
||||||
{
|
|
||||||
'first_name':r.user.first_name,
|
|
||||||
'last_name':r.user.last_name,
|
|
||||||
'email':r.user.email,
|
|
||||||
})
|
|
||||||
|
|
||||||
if not result.is_success:
|
|
||||||
messages.error(request,'Failed to create customer. Please try again later')
|
|
||||||
return render(request,
|
|
||||||
"payments.html")
|
|
||||||
else:
|
|
||||||
r.customer_id = result.customer.id
|
|
||||||
r.save()
|
|
||||||
|
|
||||||
client_token = gateway.client_token.generate({
|
|
||||||
"customer_id": r.customer_id,
|
|
||||||
})
|
|
||||||
|
|
||||||
return render(request,
|
return render(request,
|
||||||
"payments.html",
|
"paymentconfirm.html",
|
||||||
{
|
{
|
||||||
|
'plan':plan,
|
||||||
'client_token':client_token,
|
'client_token':client_token,
|
||||||
|
'rower':r,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required()
|
@login_required()
|
||||||
def checkouts_view(request):
|
def checkouts_view(request):
|
||||||
@@ -1118,72 +1176,41 @@ def checkouts_view(request):
|
|||||||
r = getrequestrower(request)
|
r = getrequestrower(request)
|
||||||
|
|
||||||
if request.method != 'POST':
|
if request.method != 'POST':
|
||||||
url = reverse(payments_view)
|
url = reverse(paidplans_view)
|
||||||
return HttpResponseRedirect(url)
|
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 = BillingForm(request.POST)
|
form = BillingForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
nonce_from_the_client = form.cleaned_data['payment_method_nonce']
|
data = form.cleaned_data
|
||||||
amount = form.cleaned_data['amount']
|
success = braintreestuff.create_subscription(r,data)
|
||||||
amount = str(amount)
|
if success:
|
||||||
|
messages.info(request,"Your payment has succeeded and your plan has been updated")
|
||||||
#for testing
|
url = reverse(payment_completed_view)
|
||||||
#nonce_from_the_client = 'fake-processor-declined-visa-none'
|
|
||||||
|
|
||||||
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
|
|
||||||
if transaction.payment_instrument_type == "credit_card":
|
|
||||||
country = transaction.credit_card_details.country_of_issuance
|
|
||||||
if country == 'Unknown':
|
|
||||||
bin = transaction.credit_card_details.bin
|
|
||||||
url = "https://lookup.binlist.net/"+str(bin)
|
|
||||||
headers = {
|
|
||||||
'Accept-Version':'3',
|
|
||||||
}
|
|
||||||
binresult = requests.get(url,headers=headers)
|
|
||||||
print binresult.status_code
|
|
||||||
if binresult.status_code == 200:
|
|
||||||
js = binresult.json()
|
|
||||||
country = js['country']['name']
|
|
||||||
|
|
||||||
print country
|
|
||||||
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)
|
return HttpResponseRedirect(url)
|
||||||
|
else:
|
||||||
|
messages.error(request,"There was a problem with your payment")
|
||||||
|
url = reverse(billing_view)
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
messages.error(request,"There was an error in the payment form")
|
messages.error(request,"There was an error in the payment form")
|
||||||
url = reverse(payments_view)
|
url = reverse(billing_view)
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
url = reverse(payments_view)
|
url = reverse(payments_view)
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def payment_completed_view(request):
|
||||||
|
r = getrequestrower(request)
|
||||||
|
|
||||||
|
return render(request,
|
||||||
|
"payment_completed.html",
|
||||||
|
{
|
||||||
|
'rower':r
|
||||||
|
})
|
||||||
|
|
||||||
# User registration
|
# User registration
|
||||||
def rower_register_view(request):
|
def rower_register_view(request):
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user