Repository: DjangoGirls/djangogirls

Issue:
MultiValueDictKeyError: 'stripeToken'
Sentry Issue: [DJANGO-GIRLS-WEBSITE-5W](https://django-girls.sentry.io/issues/4632152543/?referrer=github_integration)

```
KeyError: 'stripeToken'
  File "django/utils/datastructures.py", line 76, in __getitem__
    list_ = super().__getitem__(key)

MultiValueDictKeyError: 'stripeToken'
  File "donations/views.py", line 33, in charge
    email=request.POST["email"], name=request.POST["name"], source=request.POST["stripeToken"]
```


Discussion:
Hello! I am working on this issue
This error is an internal server error (500).  When I was testing, it worked fine for me but this error can occur because of stripe.js not getting loaded in test mode. Ways of handling this are provided in the stripe documentation. Here are the links:
[Connection errors](https://stripe.com/docs/error-handling#connection-errors)
[Idempotent requests](https://stripe.com/docs/api/idempotent_requests)
Can I get to know more specifically the steps of producing this error, so that it could be handled in the correct way?

Resolving patch:
diff --git a/donations/views.py b/donations/views.py
--- a/donations/views.py
+++ b/donations/views.py
@@ -1,9 +1,11 @@
+import uuid
+
 import stripe
 from django.conf import settings
 from django.http import HttpResponseForbidden
 from django.shortcuts import redirect, render
 from django.urls import reverse
-from stripe.error import CardError, StripeError
+from stripe.error import APIConnectionError, CardError, StripeError
 
 from patreonmanager.models import FundraisingStatus
 
@@ -27,11 +29,17 @@ def charge(request):
         if form.is_valid():
             amount = int(request.POST["amount"])
             currency = request.POST["currency"]
-
+            key = uuid.uuid4().hex
             try:
                 customer = stripe.Customer.create(
-                    email=request.POST["email"], name=request.POST["name"], source=request.POST["stripeToken"]
+                    email=request.POST["email"],
+                    name=request.POST["name"],
+                    source=request.POST.get("stripeToken"),
+                    idempotency_key=key,
                 )
+            except APIConnectionError as err:
+                request.session["stripe_message"] = err.user_message
+                return redirect(reverse("donations:error"))
             except CardError as err:
                 request.session["stripe_message"] = err.user_message
                 return redirect(reverse("donations:error"))


Test patch:
diff --git a/tests/donations/test_views.py b/tests/donations/test_views.py
--- a/tests/donations/test_views.py
+++ b/tests/donations/test_views.py
@@ -1,10 +1,11 @@
 import os
+from unittest.mock import patch
 
 import pytest
 from django.test import override_settings
 from django.urls import reverse
 from pytest_django.asserts import assertContains
-from stripe.error import StripeError
+from stripe.error import APIConnectionError, StripeError
 
 STRIPE_PUBLIC_KEY = os.environ.get("STRIPE_PUBLIC_KEY", "test_public")
 STRIPE_SECRET_KEY = os.environ.get("STRIPE_SECRET_KEY", "test_public")
@@ -62,3 +63,26 @@ def test_sponsors(client, globalpartner, globalpartner2):
     assert resp.status_code == 200
     assertContains(resp, "Django Software Foundation")
     assertContains(resp, "Caktus Group")
+
+
+@pytest.mark.django_db
+def test_charge_post_api_connection_error(client):
+    # Mock the stripe.Customer.create method to simulate an API connection error
+    with patch("stripe.Customer.create", side_effect=APIConnectionError("A Network Connection error occured.")):
+        form_data = {
+            "name": "Paul Smith",
+            "email": "paul.smith@djangogirls.org",
+            "currency": "usd",
+            "amount": "10",
+            "stripeToken": "test_code",
+        }
+
+        response = client.post(reverse("donations:charge"), data=form_data)
+
+        # Check if the response redirects to the error view
+        assert response.status_code == 302  # 302 is the status code for a redirect
+        assert response.url == reverse("donations:error")
+
+        # Check if the expected session variable is set
+        assert "stripe_message" in client.session
+        assert client.session["stripe_message"] == "A Network Connection error occured."