Stripe subscription cancel: KeyError 'HTTP_STRIPE_SIGNATURE' - python

I'm trying to configure Django Stripe Subscriptions for WebApp.
I want to let Subscribed users cancel the subscription themselves.
The code below is to delete user's information from StripeAPI and Django StripeCustomer model.
Here is view.py
import stripe
from django.conf import settings
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.http.response import JsonResponse, HttpResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth import get_user_model
from subscriptions.models import StripeCustomer
#login_required
#csrf_exempt
def cancel_subscription(request):
if request.user.is_authenticated:
endpoint_secret = settings.STRIPE_ENDPOINT_SECRET
payload = request.body
event = None
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
session = event['data']['object']
stripe_customer = StripeCustomer.objects.get(user=request.user)
stripe.api_key = settings.STRIPE_SECRET_KEY
sub_id = stripe.Subscription.retrieve(stripe_customer.stripeSubscriptionId)
client_reference_id = session.get('client_reference_id')
user = get_user_model().objects.get(id=client_reference_id)
try:
#delete from stripeapi
stripe.Subscription.delete(sub_id)
#delete from StripeCustomer model
StripeCustomer.objects.delete(
user=user,
stripeCustomerId=stripe_customer_id,
stripeSubscriptionId=stripe_subscription_id,
)
print(user.username + ' unsubscribed.')
except Exception as e:
import traceback
traceback.print_exc()
return JsonResponse({'error': (e.args[0])}, status =403)
return render(request, 'home.html')
When I excecute the code error occuerd at
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
The error message is below
Exception Type: keyError
Exception Value: 'HTTP_STRIPE_SIGNATURE'
I don't understand why the error occurs at request.META['HTTP_STRIPE_SIGNATURE'],because other part of this view can execute this code.
I just mentioned the above settings in this question but still if more code is required then tell me I'll update my question with that information. Thank you

I think you're mixing up a webhook handler and a regular POST request route as part of your application here. You either need one or the other, and I suspect you don't need the webhook stuff at all given what you're trying to to.

Related

Integrate Stripe payment flow into django

I’m trying to integrate stripe custom payments flow into my Django ecom website as PayPal isn’t as good but the docs (https://stripe.com/docs/payments/quickstart?lang=python) for python are in the flask framework. Does anyone have boilerplate code for handling a simple transaction for this in Django (views, template etc.)
In theory, the only thing that needs to change is the flask part of that code and change it into Django view(s).
The rest, html+js+css, should be able to be copied + pasted (especially cause the html is dynamically created by the Stripe JS)
views.py
from django.shortcuts import render
from django.http import HttpResponse
# The GET checkout form
#
# urlpattern:
# path('checkout', views.checkout, name='checkout'),
def checkout(request):
return render(request, 'checkout.html')
# The POST checkout form
#
# urlpattern:
# path('create-payment-intent', views.create_payment, name='create_payment'),
def create_payment(request):
if request.method == 'POST':
import json
try:
data = json.loads(request.POST)
def calculate_order_amount(items):
# Replace this constant with a calculation of the order's amount
# Calculate the order total on the server to prevent
# people from directly manipulating the amount on the client
return 1400
# this api_key could possibly go into settings.py like:
# STRIPE_API_KEY = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
#
# and fetched out with:
# from django.conf import settings
# stripe.api_key = settings.STRIPE_API_KEY
import stripe
stripe.api_key = 'sk_test_4eC39HqLyjWDarjtT1zdp7dc'
# Create a PaymentIntent with the order amount and currency
intent = stripe.PaymentIntent.create(
amount=calculate_order_amount(data['items']),
currency='usd',
automatic_payment_methods={
'enabled': True,
},
)
return HttpResponse(
json.dumps({'clientSecret': intent['client_secret']}),
content_type='application/json'
)
except Exception as e:
# Just return the 403 and NO error msg
# Not sure how to raise a 403 AND return the error msg
from django.http import HttpResponseForbidden
return HttpResponseForbidden()
# OR you could return just the error msg
# but the js would need to be changed to handle this
return HttpResponse(
json.dumps({'error': str(e)}),
content_type='application/json'
)
# POST only View, Raise Error
from django.http import Http404
raise Http404
Note: You might also have to change the two urls in the .js to match your django URLS. What they have "/create-payment-intent" + "http://localhost:4242/checkout.html" (not sure why that 2nd one is full url, but remember to get the port correct)
This would just be the barebones that your URL you included shows, you still have to figure out how to get the items into checkout.html, dynamically pass them to the page + eventually to the POST and then redo calculate_order_amount(items)
To understand working with Stripepayement I am sharing my GIT URL in which stripe payment is integrated you may refer
https://github.com/KBherwani/BookManagement/

'None Type' object has no attribute 'id' Hot to resolve Type Error

This is a medical inventory system.
Can't seem to get around this Type error. I am new to python and django.
I have looked at other similar errors but have not found a solution. here is my views.py file inside the home directory.
Kindly assist...thank you.
from django.shortcuts import render, redirect, Http404, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect, JsonResponse
from accounts.models import Registration, YearEnding
from home.backup import BackupDatabase
#login_required(login_url='/account/login/')
def HomePage(request):
if not request.user.is_authenticated():
raise Http404
try:
** current_session_id = request.session['session'] **
except:
** currentSession = YearEnding.objects.order_by("-id").first() **
** request.session['session'] = currentSession.id **
current_session_id = currentSession.id
current_session = get_object_or_404(YearEnding, id = current_session_id)
return render(request, 'home/index.html', {"current_session":current_session})
#login_required(login_url='/account/login/')
def takeBackup(request):
if request.method == "GET" and request.is_ajax():
forcefully = request.GET.get("forcefully")
backup = BackupDatabase()
response = backup.run(forcefully = int(forcefully))
if response["code"] == 200:
return JsonResponse(response, status=200)
else:
return JsonResponse(response, status=400)
else:
return JsonResponse({}, status=400)
As per documentation:
Returns the first object matched by the queryset, or None if there is no matching object.
Means if there is not YearEnding instance has been created, then YearEnding.objects.order_by("-id").first() will return None. So you need create one. You can do that from admin site, or shell. For example:
>> python manage.py shell
>> [python] from my_app.models import YearEnding
>> [python] YearEnding.objects.create(field1=value1,field2=value2)
One more suggestion, you can remove this code:
if not request.user.is_authenticated():
raise Http404
Because you are using #login_required decorator, it will automatically prevent non-logged in users from entering this view.

View UrlGatewayLogin didn't return an HttpResponse object. It returned None instead

It's a bit repetitive this error is everywhere to find, but I'm a bit confused about what is happening.
I'm trying to pass a token in the url for the user to login like so http://localhost:8000/auth/login/?token=token. After the user is authenticated it should be redirected to dashboard. But I'm getting this error. Can you help me understand what is happening?
View:
import logging
from django.contrib.auth import authenticate, login
from django.core.urlresolvers import reverse, reverse_lazy
from django.shortcuts import render
from django.views.generic import View
from django.http import HttpResponseRedirect, Http404, HttpResponse
from django.contrib.auth.backends import ModelBackend
from rest_framework_jwt.settings import api_settings
from business_accounts.models.my_user import MyUser
logger = logging.getLogger(__name__)
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
class UrlGatewayLogin(View):
def get(self, request, **kwargs):
page_group = kwargs.get('page_group')
token = request.GET.get('token')
try:
payload = jwt_decode_handler(token)
user = MyUser.objects.get(pk=payload.get('id'))
user.backend = 'django.contrib.auth.backends.ModelBackend'
except MyUser.DoesNotExist:
return None
authenticate(token=token)
logger.warning("User is=%s", user)
print(user)
login(request, user)
return HttpResponseRedirect('dashboard', {'page_group': page_group})
URL:
url(r'^auth/login/$', UrlGatewayLogin.as_view(), name='auth-login')
As the error suggests, your view should always return an HttpResponse object. At the moment, you have return None in your except block.
You could prevent the error by doing something like:
from django.http import HttpResponseBadRequest
try:
...
except MyUser.DoesNotExist:
return HttpResponseBadRequest("Invalid token")

How import and use csrf token in django 1.11?

Pease help use csrf token in django 1.11
in view.py i use follow code:
from django.shortcuts import render_to_response, redirect
from django.contrib import auth
from django.views.decorators.csrf import csrf
def login(request):
args = {}
args.update(csrf(request))
if request.POST:
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
return redirect('/')
else:
args['login_error'] = 'Пользователь не найден';
return render_to_response('login.html', args)
else:
return render_to_response('login.html', args)
but console display follow error message:
File "/home/kalinin/django/login/views.py", line 3, in from
django.views.decorators.csrf import csrf ImportError: cannot import
name 'csrf'
in django 1.8 i use similar code, but import csrf:
from django.core.context_processors import csrf
and applications is running without problems
Please help run my application for django 1.11
In Django 1.8 the template context processor was moved to django.template.context_processors.csrf, so the import would be:
from django.template.context_processors import csrf
However, you don't need to import it at all. Stop using render_to_response, it's obsolete. Use the render shortcut instead.
from django.shortcuts import render
return render(request, 'login.html', args)
When you use the render shortcut, then you don't need to worry about the csrf token in the view, and you can remove this line.
args.update(csrf(request))

Django serves zero byte response

This just happened to one of my sites and I have no idea what caused it.
This happens for any URL that is served by mod_wsgi for a particular application, which used to work fine.
Syntax errors in settings.py cause HTTP 500.
Syntax errors in urls.py don't influence anything—seems like this file is never loaded.
What is there to check?
The culprit was this line:
from django.contrib.auth.forms import AuthenticationForm
in middleware.py.
Moving the import into the function that uses AuthenticationForm solved the problem:
from django.http import HttpResponseRedirect
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import login
#from django.contrib.auth.forms import AuthenticationForm <-- THE LINE WAS HERE
class LoginFormMiddleware(object):
def process_request(self, request):
if request.method == 'POST' and 'is_top_login_form' in request.POST:
from django.contrib.auth.forms import AuthenticationForm # <-- MOVED HERE
form = AuthenticationForm(data=request.POST)
is_valid = form.is_valid()
if is_valid:
login(request, form.get_user())
program = request.user.get_profile().first_intern.program
NavigationMiddleware.set_program(request, program)
return HttpResponseRedirect('%s?quick' % program.get_absolute_url())
else:
messages.error(request, request.POST['username'], extra_tags='login')
return HttpResponseRedirect(request.get_full_path())
I still have no idea why the code used to work, why it suddenly broke and why doing this solved the problem.
There has to be some magick in Python, after all.

Categories