I’m working on a Django project where users can purchase subscriptions to various packages using Stripe Checkout. However, after a successful payment, I’m encountering an issue where the session_id is not being provided in the request when redirected to the payment_success view.
here are the models.py:
class Package(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
price_monthly = models.DecimalField(max_digits=10, decimal_places=2)
price_annually = models.DecimalField(max_digits=10, decimal_places=2)
tax_percentage = models.DecimalField(max_digits=5, decimal_places=2, default=0)
def __str__(self):
return self.name
class Subscription(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
stripe_customer_id = models.CharField(max_length=255)
stripe_subscription_id = models.CharField(max_length=255)
package = models.ForeignKey(Package, on_delete=models.CASCADE)
interval = models.CharField(max_length=10) # 'monthly' or 'annual'
active = models.BooleanField(default=True)
Here are the relevant views:
def package_list(request):
packages = Package.objects.all()
return render(request, 'subscriptions/package_list.html', {'packages': packages})
def create_checkout_session(request, package_id, interval):
package = get_object_or_404(Package, id=package_id)
if interval not in ['monthly', 'annually']:
return redirect('package_list')
if interval == 'monthly':
price = package.price_monthly_including_tax()
stripe_interval = 'month'
else:
price = package.price_annually_including_tax()
stripe_interval = 'year'
session = stripe.checkout.Session.create(
payment_method_types=['card'],
line_items=[{
'price_data': {
'currency': 'cad',
'product_data': {
'name': package.name,
},
'unit_amount': int(price * 100), # Stripe expects the amount in cents
'recurring': {
'interval': stripe_interval,
},
},
'quantity': 1,
}],
mode='subscription',
success_url=request.build_absolute_uri('/subscriptions/payment-success/?session_id={{CHECKOUT_SESSION_ID}}'),
cancel_url=request.build_absolute_uri('/subscriptions/packages/'),
customer_email=request.user.email if request.user.is_authenticated else None,
)
return redirect(session.url, code=303)
def payment_success(request):
session_id = request.GET.get('session_id')
if not session_id:
logger.error("No session_id provided in the request.")
return redirect('subscriptions:package_list')
try:
session = stripe.checkout.Session.retrieve(session_id)
logger.info(f"Session retrieved: {session}")
except stripe.error.StripeError as e:
logger.error(f"Stripe error: {e}")
return redirect('subscriptions:package_list')
customer_id = session.customer
subscription_id = session.subscription
try:
subscription = Subscription.objects.get(stripe_subscription_id=subscription_id)
except Subscription.DoesNotExist:
logger.error(f"No subscription found for ID: {subscription_id}")
return redirect('subscriptions:package_list')
context = {
'session_id': session_id,
'customer_id': customer_id,
'subscription_id': subscription_id,
'subscription': subscription,
}
return render(request, 'subscriptions/payment_success.html', context)
@csrf_exempt
def stripe_webhook(request):
payload = request.body
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
endpoint_secret = settings.STRIPE_WEBHOOK_SECRET
event = None
try:
event = stripe.Webhook.construct_event(
payload, sig_header, endpoint_secret
)
except ValueError as e:
# Invalid payload
logger.error(f"Invalid payload: {e}")
return JsonResponse({'status': 'invalid payload'}, status=400)
except stripe.error.SignatureVerificationError as e:
# Invalid signature
logger.error(f"Invalid signature: {e}")
return JsonResponse({'status': 'invalid signature'}, status=400)
# Handle the event
if event['type'] == 'checkout.session.completed':
session = event['data']['object']
handle_checkout_session_completed(session)
# Add more event types if needed
return JsonResponse({'status': 'success'}, status=200)
def handle_checkout_session_completed(session):
customer_id = session.get('customer')
subscription_id = session.get('subscription')
package_name = session['display_items'][0]['custom']['name']
user_email = session['customer_email']
interval = session['line_items']['data'][0]['price']['recurring']['interval']
try:
user = User.objects.get(email=user_email)
package = Package.objects.get(name=package_name)
Subscription.objects.create(
user=user,
stripe_customer_id=customer_id,
stripe_subscription_id=subscription_id,
package=package,
interval=interval,
active=True
)
except User.DoesNotExist:
logger.error(f"User with email {user_email} does not exist.")
except Package.DoesNotExist:
logger.error(f"Package with name {package_name} does not exist.")
except Exception as e:
logger.error(f"Error creating subscription: {e}")
Issue
After a successful payment, the user is redirected to the payment_success view, but the session_id is not provided in the request, resulting in No session_id provided in the request.
Expected Behavior
The user should be redirected to the payment_success view with the session_id as a query parameter, allowing the view to retrieve the session details and display the subscription information.
Actual Behavior
The user is redirected to the package page not to the success screen due to the error
question how can I fix this error