NOT NULL constraint failed: payments_orderdetail.stripe_payment_intent

I am trying to integrate stripe into my django application, i have followed the documentation and some articles, but when i hit the checkout button i get this error that says NOT NULL constraint failed: payments_orderdetail.stripe_payment_intent, what could be the issue here because everything seems to be working fine, this is the github repo.

views.py

@csrf_exempt
def create_checkout_session(request, id):

    request_data = json.loads(request.body)
    product = get_object_or_404(Product, pk=id)

    stripe.api_key = settings.STRIPE_SECRET_KEY
    checkout_session = stripe.checkout.Session.create(
        # Customer Email is optional,
        # It is not safe to accept email directly from the client side
        customer_email = request_data['email'],
        payment_method_types=['card'],
        line_items=[
            {
                'price_data': {
                    'currency': 'inr',
                    'product_data': {
                    'name': product.name,
                    },
                    'unit_amount': int(product.price * 100),
                },
                'quantity': 1,
            }
        ],
        mode='payment',
        success_url=request.build_absolute_uri(
            reverse('success')
        ) + "?session_id={CHECKOUT_SESSION_ID}",
        cancel_url=request.build_absolute_uri(reverse('failed')),
    )

    # OrderDetail.objects.create(
    #     customer_email=email,
    #     product=product, ......
    # )

    order = OrderDetail()
    order.customer_email = request_data['email']
    order.product = product
    order.stripe_payment_intent = checkout_session['payment_intent']
    order.amount = int(product.price * 100)
    order.save()

    # return JsonResponse({'data': checkout_session})
    return JsonResponse({'sessionId': checkout_session.id})

models.py

class OrderDetail(models.Model):

    id = models.BigAutoField(
        primary_key=True
    )

    # You can change as a Foreign Key to the user model
    customer_email = models.EmailField(
        verbose_name='Customer Email'
    )

    product = models.ForeignKey(
        to=Product,
        verbose_name='Product',
        on_delete=models.PROTECT
    )

    amount = models.IntegerField(
        verbose_name='Amount'
    )

    stripe_payment_intent = models.CharField(
        max_length=200,
        null=True, blank=True
    )

if i add null=True, blank=True to stripe_payment_intent field, it loads up the checkout page, but then no payment intent get saved in the field and i cannot return the Order Detail since, because i need to filter the order detail by the payment intent

Have you looked at what you’re getting back in checkout_session? Are you getting back a dict that includes payment_intent as a key?

This is what the checkout_session is returning

checkout_session ============== {
  "after_expiration": null,
  "allow_promotion_codes": null,
  "amount_subtotal": 5000,
  "amount_total": 5000,
  "automatic_tax": {
    "enabled": false,
    "status": null
  },
  "billing_address_collection": null,
  "cancel_url": "http://127.0.0.1:8000/failed/",
  "client_reference_id": null,
  "consent": null,
  "consent_collection": null,
  "created": 1678047294,
  "currency": "usd",
  "custom_fields": [],
  "custom_text": {
    "shipping_address": null,
    "submit": null
  },
  "customer": null,
  "customer_creation": "if_required",
  "customer_details": {
    "address": null,
    "email": "desphixs@gmail.com",
    "name": null,
    "phone": null,
    "tax_exempt": "none",
    "tax_ids": null
  },
  "customer_email": "desphixs@gmail.com",
  "expires_at": 1678133694,
  "id": "cs_test_a11oJg3j7zVAYGtfrUE7ir4RIMimptOyKxe8R45JPyc02XJvT6QO6TTe8Q",
  "invoice": null,
  "invoice_creation": {
    "enabled": false,
    "invoice_data": {
      "account_tax_ids": null,
      "custom_fields": null,
      "description": null,
      "footer": null,
      "metadata": {},
      "rendering_options": null
    }
  },
  "livemode": false,
  "locale": null,
  "metadata": {},
  "mode": "payment",
  "object": "checkout.session",
  "payment_intent": null,
  "payment_link": null,
  "payment_method_collection": "always",
  "payment_method_options": {},
  "payment_method_types": [
    "card"
  ],
  "payment_status": "unpaid",
  "phone_number_collection": {
    "enabled": false
  },
  "recovered_from": null,
  "setup_intent": null,
  "shipping_address_collection": null,
  "shipping_cost": null,
  "shipping_details": null,
  "shipping_options": [],
  "status": "open",
  "submit_type": null,
  "subscription": null,
  "success_url": "http://127.0.0.1:8000/success/?session_id={CHECKOUT_SESSION_ID}",
  "total_details": {
    "amount_discount": 0,
    "amount_shipping": 0,
    "amount_tax": 0
  },
  "url": "https://checkout.stripe.com/c/pay/cs_test_a11oJg3j7zVAYGtfrUE7ir4RIMimptOyKxe8R45JPyc02XJvT6QO6TTe8Q#fidkdWxOYHwnPyd1blpxYHZxWjA0SF9AYzNGdX9nPX1kdH9yM31sdW1HSl8ybGNWMX8xQkRtSmNNNHdGSjddfF9WdEhEZG92c11QYXZ8STFIXzVRSkp3cDZzVUFoX3V8dlJvaEhNfVdhbGpCNTV1b3NxaXw2aycpJ2N3amhWYHdzYHcnP3F3cGApJ2lkfGpwcVF8dWAnPyd2bGtiaWBabHFgaCcpJ2BrZGdpYFVpZGZgbWppYWB3dic%2FcXdwYHgl"
}

the payment_intent is returning null

  "payment_intent": null,

Update

I noticed that the SESSION ID that is supposed to be stored in the payment_intent is stored in the id instead

  "id": "cs_test_a11oJg3j7zVAYGtfrUE7ir4RIMimptOyKxe8R45JPyc02XJvT6QO6TTe8Q",

Update 2

I have changed this line to actually save the payment intent in the model

    order.stripe_payment_intent = checkout_session['id']
    order.save()

It’s now saving the payment_intent in the model, in the success page, i am filtering the Order Model by the payment_intent, but after it redirect to the success page, it displays this error

Page not found (404)
No OrderDetail matches the given query.

But the order actually exists in my model.

This is my PaymentSuccessView


class PaymentSuccessView(TemplateView):
    template_name = "payments/payment_success.html"

    def get(self, request, *args, **kwargs):
        session_id = request.GET.get('session_id')
        if session_id is None:
            return HttpResponseNotFound()
        
        stripe.api_key = settings.STRIPE_SECRET_KEY
        session = stripe.checkout.Session.retrieve(session_id)

        order = get_object_or_404(OrderDetail, stripe_payment_intent=session.payment_intent)
        order.has_paid = True
        order.save()
        print("order ====", order)
        return render(request, self.template_name)
1 Like

Is the url being generated correctly for this view? (Does it have the session_id as part of the url that you’re expecting?)

You’re using that session_id to make another call to stripe?

Is that returning the data you’re expecting from stripe?
(Have you verified what that session object is after this call has returned?)

1 Like

This helped me to fix it, thanks alot.

Destiny can you please tell me the workaround ?

facing same issue here.

payment intent is null during creating checkout session.

what was your solution ?

I believe you have the line above, instead of checkout_session['payment_intent'] let it be checkout_session[‘id’] use the id key instead.

Here is a full code:

checkout_session = stripe.checkout.Session.create(
  customer_email=order.email,
  payment_method_types=['card'],
  line_items=[
      {
          'price_data': {
              'currency': 'usd',
              'product_data': {
                  'name': order.full_name,
              },
              'unit_amount': int(order.total * 100),
          },
          'quantity': 1,
      }
  ],
  mode='payment',
  success_url=settings.SITE_URL+'/payment-success/'+ order.oid +'?session_id={CHECKOUT_SESSION_ID}',
  cancel_url=settings.SITE_URL+'/?session_id={CHECKOUT_SESSION_ID}',
)
# change the checkout_session[payment_intent"] let it be checkout_session['id'] 
order.stripe_session_id = checkout_session['id']
order.save()