import json from django.utils.translation import ugettext_lazy as _ from django.core.urlresolvers import reverse from .base import BackendBase class StripeBackend(BackendBase): backend_id = 'stripe' backend_verbose_name = _("Stripe") backend_display_name = _("Credit Card") backend_has_recurring = True def get_plan_id(self, period): return 'ccvpn_' + period def __init__(self, settings): if 'API_KEY' not in settings or 'PUBLIC_KEY' not in settings: return import stripe self.stripe = stripe stripe.api_key = settings['API_KEY'] self.pubkey = settings['PUBLIC_KEY'] self.header_image = settings.get('HEADER_IMAGE', '') self.currency = settings.get('CURRENCY', 'EUR') self.name = settings.get('NAME', 'VPN Payment') self.backend_enabled = True def new_payment(self, payment): desc = str(payment.time) + ' for ' + payment.user.username form = '''
''' return form.format( post=reverse('payments:cb_stripe', args=(payment.id,)), pubkey=self.pubkey, img=self.header_image, email=payment.user.email or '', name=self.name, desc=desc, amount=payment.amount, curr=self.currency, ) def new_subscription(self, subscr): desc = 'Subscription (' + str(subscr.period) + ') for ' + subscr.user.username form = '''
''' return form.format( post=reverse('payments:cb_stripe_subscr', args=(subscr.id,)), pubkey=self.pubkey, img=self.header_image, email=subscr.user.email or '', name=self.name, desc=desc, amount=subscr.period_amount, curr=self.currency, ) def cancel_subscription(self, subscr): if subscr.status not in ('new', 'unconfirmed', 'active'): return try: cust = self.stripe.Customer.retrieve(subscr.backend_extid) except self.stripe.error.InvalidRequestError: return try: # Delete customer and cancel any active subscription cust.delete() except self.stripe.error.InvalidRequestError: pass subscr.status = 'cancelled' subscr.save() def callback(self, payment, request): post_data = request.POST token = post_data.get('stripeToken') if not token: payment.status = 'cancelled' payment.status_message = _("No payment information was received.") return months = int(payment.time.days / 30) username = payment.user.username try: charge = self.stripe.Charge.create( amount=payment.amount, currency=self.currency, card=token, description="%d months for %s" % (months, username), ) payment.backend_extid = charge['id'] if charge['refunded'] or not charge['paid']: payment.status = 'rejected' payment.status_message = _("The payment has been refunded or rejected.") payment.save() return payment.paid_amount = int(charge['amount']) if payment.paid_amount < payment.amount: payment.status = 'error' payment.status_message = _("The paid amount is under the required amount.") payment.save() return payment.status = 'confirmed' payment.status_message = None payment.save() payment.user.vpnuser.add_paid_time(payment.time) payment.user.vpnuser.on_payment_confirmed(payment) payment.user.vpnuser.save() except self.stripe.error.CardError as e: payment.status = 'rejected' payment.status_message = e.json_body['error']['message'] payment.save() def callback_subscr(self, subscr, request): post_data = request.POST token = post_data.get('stripeToken') if not token: subscr.status = 'cancelled' subscr.save() return try: cust = self.stripe.Customer.create( source=token, plan=self.get_plan_id(subscr.period), ) except self.stripe.error.InvalidRequestError: return except self.stripe.CardError as e: subscr.status = 'error' subscr.backend_data['stripe_error'] = e.json_body['error']['message'] return # We don't know much about the new Payment, but we know it # succeeded. Wekhooks aren't very reliable, so let's mark it as active # anyway. subscr.status = 'active' subscr.backend_extid = cust['id'] subscr.save() def webhook_payment_succeeded(self, event): from payments.models import Subscription, Payment invoice = event['data']['object'] customer_id = invoice['customer'] # Prevent making duplicate Payments if event is received twice pc = Payment.objects.filter(backend_extid=invoice['id']).count() if pc > 0: return subscr = Subscription.objects.get(backend_extid=customer_id) payment = subscr.create_payment() payment.status = 'confirmed' payment.paid_amount = invoice['total'] payment.backend_extid = invoice['id'] payment.backend_data = {'event_id': event['id']} payment.save() payment.user.vpnuser.add_paid_time(payment.time) payment.user.vpnuser.on_payment_confirmed(payment) payment.user.vpnuser.save() payment.save() subscr.status = 'active' subscr.save() def webhook(self, request): try: event_json = json.loads(request.body.decode('utf-8')) event = self.stripe.Event.retrieve(event_json["id"]) except (ValueError, self.stripe.error.InvalidRequestError): return False if event['type'] == 'invoice.payment_succeeded': self.webhook_payment_succeeded(event) return True def get_ext_url(self, payment): if not payment.backend_extid: return None return 'https://dashboard.stripe.com/payments/%s' % payment.backend_extid def get_subscr_ext_url(self, subscr): if not subscr.backend_extid: return None return 'https://dashboard.stripe.com/customers/%s' % subscr.backend_extid