From daadf986ca7d41116edcf39f623449ceb7468d03 Mon Sep 17 00:00:00 2001 From: Awoyalejohn Date: Fri, 5 Aug 2022 22:36:30 +0100 Subject: [PATCH] Complete webhook handler --- .vscode/settings.json | 2 +- checkout/admin.py | 6 +- ...04_order_original_cart_order_stripe_pid.py | 23 ++++++ checkout/models.py | 4 +- checkout/templates/checkout/checkout.html | 3 +- checkout/views.py | 7 +- checkout/webhook_handler.py | 82 ++++++++++++++++++- 7 files changed, 119 insertions(+), 8 deletions(-) create mode 100644 checkout/migrations/0004_order_original_cart_order_stripe_pid.py diff --git a/.vscode/settings.json b/.vscode/settings.json index deff430..5a7bc00 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -27,5 +27,5 @@ "[python]": { "editor.defaultFormatter": "ms-python.python" }, - "python.formatting.provider": "yapf" + "python.formatting.provider": "black" } diff --git a/checkout/admin.py b/checkout/admin.py index 72fa1b3..9331315 100644 --- a/checkout/admin.py +++ b/checkout/admin.py @@ -12,13 +12,15 @@ class OrderAdmin(admin.ModelAdmin): readonly_fields = ('order_number', 'date', 'discount', 'order_subtotal', - 'total',) + 'total','original_cart', + 'stripe_pid') fields = ('order_number', 'date', 'full_name', 'email', 'phone_number', 'country', 'postcode', 'town_or_city', 'street_address1', 'street_address2', 'county', 'discount', - 'order_subtotal', 'total',) + 'order_subtotal', 'total', 'original_cart', + 'stripe_pid') list_display = ('order_number', 'date', 'full_name', 'order_subtotal', 'discount', diff --git a/checkout/migrations/0004_order_original_cart_order_stripe_pid.py b/checkout/migrations/0004_order_original_cart_order_stripe_pid.py new file mode 100644 index 0000000..803aa1d --- /dev/null +++ b/checkout/migrations/0004_order_original_cart_order_stripe_pid.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.6 on 2022-08-05 19:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('checkout', '0003_orderlineitem_quantity'), + ] + + operations = [ + migrations.AddField( + model_name='order', + name='original_cart', + field=models.TextField(default=''), + ), + migrations.AddField( + model_name='order', + name='stripe_pid', + field=models.CharField(default='', max_length=254), + ), + ] diff --git a/checkout/models.py b/checkout/models.py index 5ad57fe..9e93c70 100644 --- a/checkout/models.py +++ b/checkout/models.py @@ -28,8 +28,8 @@ class Order(models.Model): discount = models.DecimalField(max_digits=6, decimal_places=2, null=False, default=0) order_subtotal = models.DecimalField(max_digits=10, decimal_places=2, null=False, default=0) total = models.DecimalField(max_digits=10, decimal_places=2, null=False, default=0) - # original_cart = models.TextField(null=False, blank=False, default='') - # stripe_pid = models.CharField(max_length=254, null=False, blank=False, default='') + original_cart = models.TextField(null=False, blank=False, default='') + stripe_pid = models.CharField(max_length=254, null=False, blank=False, default='') def _generate_order_number(self): diff --git a/checkout/templates/checkout/checkout.html b/checkout/templates/checkout/checkout.html index 536544e..7275ec2 100644 --- a/checkout/templates/checkout/checkout.html +++ b/checkout/templates/checkout/checkout.html @@ -108,7 +108,8 @@

Checkout

- + +
diff --git a/checkout/views.py b/checkout/views.py index a89788a..7c0b04e 100644 --- a/checkout/views.py +++ b/checkout/views.py @@ -96,7 +96,12 @@ def post(self, request): } order_form = OrderForm(form_data) if order_form.is_valid(): - order = order_form.save() + order = order_form.save(commit=False) + pid = request.POST.get('client_secret').split('_secret')[0] + print(pid) + order.stripe_pid = pid + order.original_cart = json.dumps(cart) + order.save() for slug, item_data in cart.items(): print(cart.items()) try: diff --git a/checkout/webhook_handler.py b/checkout/webhook_handler.py index 2733b60..a5df186 100644 --- a/checkout/webhook_handler.py +++ b/checkout/webhook_handler.py @@ -1,5 +1,11 @@ from django.http import HttpResponse +from .models import Order, OrderLineItem +from products.models import Product + +import json +import time + class StripeWH_Handler: """Handle Stripe webhooks""" @@ -21,8 +27,82 @@ def handle_payment_intent_succeeded(self, event): """ intent = event.data.object print(intent) + pid = intent.id + cart = intent.metadata.cart + save_info = intent.metadata.save_info + + billing_details = intent.charges.data[0].billing_details + shipping_details = intent.shipping + total = round(intent.charges.data[0].amount / 100, 2) + + #Clean data in the shipping details + for field, value in shipping_details.address.items(): + if value == "": + shipping_details.address[field] = None + + order_exists = False + attempt = 1 + while attempt <= 5: + try: + order = Order.objects.get( + full_name__iexact=shipping_details.name, + email__iexact=billing_details.email, + phone_number__iexact=shipping_details.phone, + country__iexact=shipping_details.address.country, + postcode__iexact=shipping_details.address.postal_code, + town_or_city__iexact=shipping_details.address.city, + street_address1__iexact=shipping_details.address.line1, + street_address2__iexact=shipping_details.address.line2, + county__iexact=shipping_details.address.state, + total=total, + original_cart=cart, + stripe_pid=pid, + ) + order_exists = True + break + + + except Order.DoesNotExist: + attempt += 1 + time.sleep(1) + if order_exists: + return HttpResponse( + content=f'Webhook received: {event["type"]} | SUCCESS: Verified order already in database', + status=200) + else: + order = None + try: + order = Order.objects.create( + full_name=shipping_details.name, + email=billing_details.email, + phone_number=shipping_details.phone, + country=shipping_details.address.country, + postcode=shipping_details.address.postal_code, + town_or_city=shipping_details.address.city, + street_address1=shipping_details.address.line1, + street_address2=shipping_details.address.line2, + county=shipping_details.address.state, + original_cart=cart, + stripe_pid=pid, + ) + for slug, item_data in json.loads(cart).items(): + product = Product.objects.get(slug=slug) + print(product) + order_line_item = OrderLineItem( + order=order, + product=product, + quantity=item_data + ) + order_line_item.save() + except Exception as e: + if order: + order.delete() + return HttpResponse( + content=f'Webhook received: {event["type"]} | ERROR: {e}', + status=500) + return HttpResponse( - content=f'Webhook received: {event["type"]}', + content=f'Webhook received: {event["type"]} | SUCCESS: Created order in webhook', status=200) def handle_payment_intent_payment_failed(self, event):