Skip to content

Commit

Permalink
Merge branch 'paydebt'
Browse files Browse the repository at this point in the history
  • Loading branch information
ppannuto committed Aug 28, 2015
2 parents 951d64d + 985678d commit bf53b58
Show file tree
Hide file tree
Showing 9 changed files with 244 additions and 65 deletions.
2 changes: 2 additions & 0 deletions chezbetty/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ def debug(request):
config.add_route('item_request', '/item/request')
config.add_route('item_request_new', '/item/request/new')

config.add_route('paydebt', '/paydebt/{uniqname}')
config.add_route('paydebt_submit', '/paydebt/{uniqname}/submit')

# TERMINAL VIEWS
config.add_route('user', '/terminal/profile/{umid}')
Expand Down
4 changes: 2 additions & 2 deletions chezbetty/templates/admin/email_deadbeats.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
Betty {{ user.balance|format_currency|safe }}. Please pay at your earliest
convenience.</p>

<p>To pay with a credit card, please visit
<a href="https://chezbetty.eecs.umich.edu/user">your user page</a>.
<p><a href="https://chezbetty.eecs.umich.edu/paydebt/{{ user.uniqname }}">
Click here to pay online.</a></p>

<p>Thank you,</p>
<p>Chez Betty</p>
4 changes: 2 additions & 2 deletions chezbetty/templates/admin/email_endofsemester.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ by graduate students with limited resources. You currently owe Betty
{{ user.balance|format_currency|safe }}. We would greatly appreciate if you
could settle your debts with Betty.</p>

<p>To pay with a credit card, please visit
<a href="https://chezbetty.eecs.umich.edu/user">your user page</a>.
<p><a href="https://chezbetty.eecs.umich.edu/paydebt/{{ user.uniqname }}">
Click here to pay online.</a></p>

<p>Thank you,</p>
<p>Chez Betty</p>
Expand Down
4 changes: 2 additions & 2 deletions chezbetty/templates/admin/users_email.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
$<input name="threshold" value="20.00"> in debt to Chez Betty encouraging
them to settle up.</p>
<div class="well">
{% set user = {'name': '<< name >>', 'balance': '<< balance >>'} %}
{% set user = {'name': '<< name >>', 'balance': '<< balance >>', 'uniqname': '<< uniqname >> '} %}
{% include "email_deadbeats.jinja2" %}
</div>
<button type="submit" class="btn btn-success">Email Deadbeat Users</button>
Expand All @@ -29,7 +29,7 @@
$<input name="threshold" value="2.00"> in debt to Chez Betty encouraging
them to settle up.</p>
<div class="well">
{% set user = {'name': '<< name >>', 'balance': '<< balance >>'} %}
{% set user = {'name': '<< name >>', 'balance': '<< balance >>', 'uniqname': '<< uniqname >> '} %}
{% include "email_endofsemester.jinja2" %}
</div>
<button type="submit" class="btn btn-success">Send End of Semester Email</button>
Expand Down
2 changes: 2 additions & 0 deletions chezbetty/templates/base.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,11 @@
{% endblock %}

{% set timeout = timeout|default(60*1000*5) -%}
{% if timeout %}
<script>
setTimeout(function(){window.location.replace("/");}, {{ timeout }});
</script>
{% endif %}

<!-- Google Analytics tracker -->
<script>
Expand Down
118 changes: 118 additions & 0 deletions chezbetty/templates/paydebt.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
{% set timeout = 0 %}
{% extends "base.jinja2" %}
{% block title %}Pay Debt{% endblock %}

{% set amount = -(user.balance|float) %}

{% set charge = (amount + 0.3) / 0.971 %}
{% set fee = charge - amount %}
{% set total_cents = (charge*100)|round|int %}

{% block content %}

<h1>Pay Debt</h1>
<hr />

{% if user.balance < 0 %}

<h3>
{{ _('We use stripe to process credit card transactions.') }}
</h3>
<p>
{{ _('Stripe charges 2.9% + $0.30 for each transaction.') }}
{{ _('We pass this charge directly onto you.') }}
</p>

<h3>
{{ _('Your current balance is %(balance)s and your card will be charged %(charge)s.')|format(balance=user.balance|format_currency,charge=charge|format_currency)|safe }}
</h3>

<hr />

<button id="pay_btn" class="btn btn-success btn-huge">Pay Debt</button>

<script src="https://checkout.stripe.com/checkout.js"></script>
<script>
var handler = StripeCheckout.configure({
key: '{{ stripe_pk }}',
image: '{{"chezbetty:static/chezbetty_1000px.jpg"|static_url}}',
token: function(token) {
console.log(token);
// Callback w/ token.id to create a charge and token.email
$.ajax({
type: "POST",
url: "/paydebt/{{ user.uniqname }}/submit",
data: {
stripeToken: token.id,
betty_amount: '{{ amount }}',
betty_total_cents: '{{ total_cents }}'
},
success: function () {
window.location.reload();
},
error: function (e) {
console.log(e);
alert("Error posting data to server");
},
dataType: "json"
});
},
name: 'Chez Betty',
description: '${{ "%0.2f"|format(amount) }} Deposit (${{ "%0.2f"|format(total_cents/100) }} Charge)',
amount: {{ total_cents }},
email: '{{ user.uniqname }}@umich.edu',
});
$('#pay_btn').on('click', function(e) {
handler.open();
e.preventDefault();
});
$(window).on('popstate', function() {
handler.close();
});
</script>

<hr />

<a href="/user">{{ _('For more options and transaction history, log in to your user account') }}</a>

{#
<form action="/user/deposit_cc/submit" method="POST">
<input type="hidden" name="betty_amount" value="{{ amount }}">
<input type="hidden" name="betty_total_cents" value="{{ total_cents }}">
<input type="hidden" name="betty_to_account" value="{{ account }}" class="cc-betty-to-account">
<script
id="cc-script-{{ amount }}"
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="{{ stripe_pk }}"
data-amount="{{ total_cents }}"
data-name="Chez Betty"
data-description="${{ '%0.2f'|format(amount) }} Deposit (${{ '%0.2f'|format(total_cents/100) }} Charge)"
data-image="{{'chezbetty:static/chezbetty_1000px.jpg'|static_url}}">
</script>
</form>
#}


{% else %} {# user.balance >= 0 #}

<h3>
{{ _('You currently do not owe Chez Betty any money.') }}
</h3>
<h3>
{{ _('Thank you for paying your debts.') }}
</h3>
<hr />

<a href="/user" class="btn btn-success btn-huge">
{{ _('Log into your user account') }}
</a>
<a href="/" class="btn btn-default btn-huge pull-right">
{{ _('Chez Betty Home') }}
</a>

{% endif %}

{% endblock %}

67 changes: 67 additions & 0 deletions chezbetty/utility.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import datetime
from decimal import Decimal
import itertools
import qrcode
import qrcode.image.svg
import stripe
import traceback

from pyramid.renderers import render
from pyramid.threadlocal import get_current_registry
Expand Down Expand Up @@ -255,3 +258,67 @@ def timeseries_balance_total_daily(rows):

return out

def post_stripe_payment(
datalayer, # Need to pass as argument to avoid circular import, ugh
request,
token,
amount,
total_cents,
account_making_payment,
account_depositing_into,
):
# See http://stripe.com/docs/tutorials/charges
stripe.api_key = request.registry.settings['stripe.secret_key']

charge = (amount + 0.3) / 0.971
fee = charge - amount
if total_cents != int(round((amount + fee)*100)):
print("Stripe total mismatch. total_cents {} != {}".format(
total_cents, int(round((amount + fee)*100))))
request.session.flash('Unexpected error processing transaction. Card NOT charged.', 'error')
return False
amount = Decimal(amount)

if amount <= 0.0:
request.session.flash(
_('Deposit amount must be greater than $0.00. Card NOT charged.'),
'error'
)
return False

try:
charge = stripe.Charge.create(
amount = total_cents,
currency="usd",
source=token,
description=account_making_payment.uniqname+'@umich.edu'
)

except stripe.CardError as e:
traceback.print_exc()
request.session.flash('Card error processing transaction. Card NOT charged.', 'error')
return False
except stripe.StripeError as e:
traceback.print_exc()
request.session.flash('Unexpected error processing transaction. Card NOT charged.', 'error')
request.session.flash('Please e-mail [email protected] so we can correct this error', 'error')
return False

try:
deposit = datalayer.cc_deposit(
account_making_payment,
account_depositing_into,
amount,
charge['id'],
charge['source']['last4'])

request.session.flash('Deposit added successfully.', 'success')

except Exception as e:
traceback.print_exc()
request.session.flash('A unknown error has occured.', 'error')
request.session.flash('Your card HAS been charged, but your account HAS NOT been credited.', 'error')
request.session.flash('Please e-mail [email protected] so we can correct this error', 'error')

return True

38 changes: 38 additions & 0 deletions chezbetty/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

from .utility import user_password_reset
from .utility import send_email
from .utility import post_stripe_payment

from pyramid.security import Allow, Everyone, remember, forget

Expand Down Expand Up @@ -116,3 +117,40 @@ def users(request):
.filter(User.balance < -5)\
.order_by(User.balance).all()
return {'users': users}


@view_config(route_name='paydebt', renderer='templates/paydebt.jinja2')
def paydebt(request):
uniqname = request.matchdict['uniqname']
user = User.from_uniqname(uniqname, local_only=True)
return {
'user': user,
'stripe_pk': request.registry.settings['stripe.publishable_key'],
}

@view_config(route_name='paydebt_submit',
request_method='POST',
renderer='json',
)
def paydebt_submit(request):
uniqname = request.matchdict['uniqname']
user = User.from_uniqname(uniqname, local_only=True)

print(request.POST)

token = request.POST['stripeToken']
amount = float(request.POST['betty_amount'])
total_cents = int(request.POST['betty_total_cents'])

post_stripe_payment(
datalayer,
request,
token,
amount,
total_cents,
user,
user,
)

return {}

Loading

0 comments on commit bf53b58

Please sign in to comment.