pythondjangostripe-payments

Django stripe expand data to webhook


I sent an order data by posting a request to stripe, creating session, and setting my order in line_items. The problem is that I want this line_items data to expand to the stripe webhook view, and by creating an order, and payment history, I tried first to set this data to:

metadata={"data": items}

But I get an error, because there is a limited count of keys, which means that my data is too big to put in metadata. After that, I found that I can put my data in expand like that:

expand=['line_items']

But nothing happened. I don't get this data in my webhook view, but I get this data on the stripe website.

enter image description here

so here is my code i hope someone helps me :p

from django.conf import settings
from django.http import HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.views.decorators.csrf import csrf_exempt
import stripe
from rest_framework.decorators import api_view
from accounts.models import AppUser

stripe.api_key = settings.STRIPE_SECRET_KEY


class StripeCheckoutView(APIView):
    def post(self, request):
        try:

            data = request.data['orderData']['orderItems']
            items = []
            for i in data.keys():
               i = data[i]
               desc = ', '.join([i.get('name') for i in i.get('extra').values()]) + i.get('extra_info')
               name = ', '.join(
                   filter(None, [
                        i.get('name'),
                        i.get('pizzaDough', ''),
                        f"{str(i.get('size', ''))} size" if i.get('size') else '',
                        f"{str(i.get('grams', ''))} grams" if i.get('grams') else '',
                   ])
               )
               items.append(
                    {   
                        "price_data": {
                            "currency": "usd",
                            "unit_amount": int(i['price']),
                            "product_data": {
                                "name": name,
                                "description": f"+ {desc}" if len(desc) > 0 else " ",
                                "images": [i['img_modify'],],
                            },
                        },
                        "quantity": i['quantity'],
                    }
                )


            checkout_session = stripe.checkout.Session.create(
                line_items=items,
                mode='payment',
                expand=['line_items'],
                success_url=settings.SITE_URL + '/?success=true&session_id={CHECKOUT_SESSION_ID}',
                cancel_url=settings.SITE_URL + '/?canceled=true',
                automatic_tax={"enabled": True},
                #discounts=[{"coupon": "promo_1PnWnuGKlfpQfnx9vj6v7cw9"}],
                allow_promotion_codes=True,
                shipping_options=[
                    {
                    "shipping_rate_data": {
                        "type": 'fixed_amount',
                        "fixed_amount": {
                            "amount": 500,
                            "currency": 'usd',
                        },
                        "display_name": 'Food Shipping',
                        "delivery_estimate": {
                        "maximum": {
                            "unit": 'hour',
                            "value": 1,
                        },
                        },
                    },
                    },
                ],
            )


            return Response({"url": checkout_session.url})
        except:
            return Response(
                {'error': 'Something went wrong when creating stripe checkout session'},
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )


@csrf_exempt
@api_view(['POST'])
def stripe_webhook_view(request):
    payload = request.body
    sig_header = request.META['HTTP_STRIPE_SIGNATURE']
    event = None

    print(request.POST)

    try:
        event = stripe.Webhook.construct_event(
            payload,
            sig_header,
            settings.STRIPE_SECRET_WEBHOOK
        )
    except ValueError as e:
        return HttpResponse({"error": 'Error parsing payload', 'payload': payload},status=400)
    except stripe.error.SignatureVerificationError as e:
        return HttpResponse({"error":'Error verifying webhook signature', 'sign_header': sig_header},status=400)

    if event['type'] == 'checkout.session.completed':
        session = event['data']['object']
        print(session, event['data'])
    if event.type == 'payment_intent.succeeded':
        payment_intent = event.data.object # contains a stripe.PaymentIntent
        print(payment_intent)
    elif event.type == 'payment_method.attached':
        payment_method = event.data.object # contains a stripe.PaymentMethod
        print(payment_method)
    # ... handle other event types
    else:
        print('Unhandled event type {}'.format(event.type))


    return HttpResponse(status=200)

Solution

  • line_items are "includable" meaning they're not included in the base view of the object. Webhooks always send the base version. You should make an API request to stripe.checkout.Session.retrieve when handling the webhook and you can pass expand=['line_items'] in that retrieve call.

    It's the same example explained at https://docs.stripe.com/expand#with-webhooks and at https://docs.stripe.com/checkout/fulfillment