'''.format(pk=self.public_key, sess=session['id'])
def new_payment(self, payment):
root_url = project_settings.ROOT_URL
assert root_url
months = payment.time.days // 30
if months > 1:
desc = '{} months for {}'.format(months, payment.user.username)
else:
desc = 'One month for {}'.format(payment.user.username)
session = self.stripe.checkout.Session.create(
success_url=root_url + reverse('payments:view', args=(payment.id,)),
cancel_url=root_url + reverse('payments:cancel', args=(payment.id,)),
payment_method_types=['card'],
line_items=[
{
'amount': payment.amount,
'currency': self.currency.lower(),
'name': self.title,
'description': desc,
'quantity': 1,
}
],
)
payment.backend_extid = session['id']
payment.backend_data = {'session_id': session['id']}
payment.save()
return self.make_redirect(session)
def new_subscription(self, subscr):
root_url = project_settings.ROOT_URL
assert root_url
session = self.stripe.checkout.Session.create(
success_url=root_url + reverse('payments:return_subscr', args=(subscr.id,)),
cancel_url=root_url + reverse('payments:cancel_subscr', args=(subscr.id,)),
client_reference_id='sub_%d'%subscr.id,
payment_method_types=['card'],
subscription_data={
'items': [{
'plan': self.get_plan_id(subscr.period),
'quantity': 1,
}],
},
)
subscr.backend_data = {'session_id': session['id']}
subscr.save()
return self.make_redirect(session)
def cancel_subscription(self, subscr):
if subscr.status not in ('new', 'unconfirmed', 'active'):
return
if subscr.backend_extid.startswith('pi'):
# a session that didn't create a subscription yet (intent)
pass
elif subscr.backend_extid.startswith('sub_'):
# Subscription object
try:
self.stripe.Subscription.delete(subscr.backend_extid)
except self.stripe.error.InvalidRequestError:
pass
elif subscr.backend_extid.startswith('cus_'):
# Legacy Customer object
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
else:
raise Exception("Failed to cancel subscription %r" % subscr.backend_extid)
subscr.status = 'cancelled'
subscr.save()
return True
def webhook_session_completed(self, event):
session = event['data']['object']
if session['subscription']:
# Subscription creation
from payments.models import Payment, Subscription
sub_id = session['subscription']
assert sub_id
parts = session['client_reference_id'].split('_')
if len(parts) != 2 or parts[0] != 'sub':
raise Exception("invalid reference id")
sub_internal_id = int(parts[1])
# Fetch sub by ID and confirm it
subscr = Subscription.objects.get(id=sub_internal_id)
subscr.status = 'active'
subscr.backend_extid = sub_id
subscr.backend_data['subscription_id'] = sub_id
subscr.save()
else:
from payments.models import Payment
payment = Payment.objects.filter(backend_extid=session['id']).get()
# the amount is provided server-side, we do not have to check
payment.paid_amount = payment.amount
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()
def get_subscription_from_invoice(self, invoice):
from payments.models import Subscription
subscription_id = invoice['subscription']
customer_id = invoice['customer']
# once it's confirmed, the id to the subscription is stored as extid
subscr = Subscription.objects.filter(backend_extid=subscription_id).first()
if subscr:
return subscr
# older subscriptions will have a customer id instead
subscr = Subscription.objects.filter(backend_extid=customer_id).first()
if subscr:
return subscr
return None
def webhook_payment_succeeded(self, event):
""" webhook event for a subscription's succeeded payment """
from payments.models import Payment
invoice = event['data']['object']
subscr = self.get_subscription_from_invoice(invoice)
if not subscr:
# the subscription does not exist
# checkout.confirmed event will create it and handle the initial payment
# return True
raise Exception("Unknown subscription for invoice %r" % invoice['id'])
# Prevent making duplicate Payments if event is received twice
pc = Payment.objects.filter(backend_extid=invoice['id']).count()
if pc > 0:
return
payment = subscr.create_payment()
payment.status = 'confirmed'
payment.paid_amount = payment.amount
payment.backend_extid = invoice['id']
if invoice['subscription']:
if isinstance(invoice['subscription'], str):
payment.backend_sub_id = invoice['subscription']
else:
payment.backend_sub_id = invoice['subscription']['id']
payment.backend_data = {'event_id': event['id'], 'sub_id': payment.backend_sub_id}
payment.save()
payment.user.vpnuser.add_paid_time(payment.time)
payment.user.vpnuser.on_payment_confirmed(payment)
payment.user.vpnuser.save()
payment.save()
def webhook(self, request):
payload = request.body
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
try:
event = self.stripe.Webhook.construct_event(
payload, sig_header, self.wh_key,
)
except (ValueError, self.stripe.error.InvalidRequestError, self.stripe.error.SignatureVerificationError):
return False
if event['type'] == 'invoice.payment_succeeded':
self.webhook_payment_succeeded(event)
if event['type'] == 'checkout.session.completed':
self.webhook_session_completed(event)
return True
def get_ext_url(self, payment):
extid = payment.backend_extid
if not extid:
return None
if extid.startswith('in_'):
return 'https://dashboard.stripe.com/invoices/%s' % extid
if extid.startswith('ch_'):
return 'https://dashboard.stripe.com/payments/%s' % extid
def get_subscr_ext_url(self, subscr):
extid = subscr.backend_extid
if not extid:
return None
if extid.startswith('sub_') and self.stripe:
livemode = False
try:
sub = self.stripe.Subscription.retrieve(extid)
livemode = sub['livemode']
except Exception:
pass
if livemode:
return 'https://dashboard.stripe.com/subscriptions/' + extid
else:
return 'https://dashboard.stripe.com/test/subscriptions/' + extid
if extid.startswith('cus_'):
return 'https://dashboard.stripe.com/customers/%s' % subscr.backend_extid