We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
PaymentError: This payment has already been processed and hence cannot be deleted.
Sentry Issue: [CONCREXIT-8C](https://sentry.io/organizations/thalia/issues/2568657203/?referrer=github_integration)

```
PaymentError: This payment has already been processed and hence cannot be deleted.
(1 additional frame(s) were not displayed)
...
  File "django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "django/views/decorators/http.py", line 40, in inner
    return func(request, *args, **kwargs)
  File "pizzas/views.py", line 38, in cancel_order
    order.delete()
  File "pizzas/models.py", line 256, in delete
    delete_payment(self)
  File "payments/services.py", line 98, in delete_payment
    raise PaymentError(
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `website/pizzas/api/v2/views.py`
Content:
```
1 from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope
2 from rest_framework.generics import (
3     ListAPIView,
4     RetrieveAPIView,
5     get_object_or_404,
6     CreateAPIView,
7     DestroyAPIView,
8     UpdateAPIView,
9 )
10 
11 from rest_framework import filters as framework_filters, status
12 from rest_framework.response import Response
13 
14 from payments.exceptions import PaymentError
15 from payments.services import delete_payment
16 from pizzas.api.v2 import filters
17 from pizzas.api.v2.serializers import (
18     ProductSerializer,
19     FoodOrderSerializer,
20     FoodOrderUpdateSerializer,
21     FoodOrderCreateSerializer,
22 )
23 from pizzas.api.v2.serializers.food_event import FoodEventSerializer
24 from pizzas.models import FoodEvent, Product, FoodOrder
25 from thaliawebsite.api.v2.permissions import IsAuthenticatedOrTokenHasScopeForMethod
26 
27 
28 class FoodEventListView(ListAPIView):
29     """Returns an overview of all food events."""
30 
31     serializer_class = FoodEventSerializer
32     queryset = FoodEvent.objects.all()
33     filter_backends = (
34         framework_filters.OrderingFilter,
35         filters.FoodEventDateFilterBackend,
36     )
37     ordering_fields = ("start", "end")
38     permission_classes = [
39         IsAuthenticatedOrTokenHasScope,
40     ]
41     required_scopes = ["food:read"]
42 
43 
44 class FoodEventDetailView(RetrieveAPIView):
45     """Returns one single food event."""
46 
47     serializer_class = FoodEventSerializer
48     queryset = FoodEvent.objects.all()
49     permission_classes = [
50         IsAuthenticatedOrTokenHasScope,
51     ]
52     required_scopes = ["food:read"]
53 
54 
55 class FoodEventProductsListView(ListAPIView):
56     """Returns an overview of all products."""
57 
58     serializer_class = ProductSerializer
59     queryset = Product.available_products.all()
60     filter_backends = (framework_filters.SearchFilter,)
61     search_fields = ("name",)
62     permission_classes = [
63         IsAuthenticatedOrTokenHasScope,
64     ]
65     required_scopes = ["food:read"]
66 
67 
68 class FoodEventOrderDetailView(
69     RetrieveAPIView, CreateAPIView, UpdateAPIView, DestroyAPIView
70 ):
71     """Returns details of a food order."""
72 
73     permission_classes = [
74         IsAuthenticatedOrTokenHasScopeForMethod,
75     ]
76     required_scopes_per_method = {
77         "GET": ["food:read"],
78         "POST": ["food:order"],
79         "PUT": ["food:order"],
80         "PATCH": ["food:order"],
81         "DELETE": ["food:order"],
82     }
83 
84     def get_serializer_class(self):
85         if self.request.method.lower() == "get":
86             return FoodOrderSerializer
87         if self.request.method.lower() == "post":
88             return FoodOrderCreateSerializer
89         return FoodOrderUpdateSerializer
90 
91     def get_queryset(self):
92         return FoodOrder.objects.filter(food_event=self.food_event)
93 
94     def get_object(self):
95         queryset = self.filter_queryset(self.get_queryset())
96         obj = get_object_or_404(queryset, member=self.request.member)
97 
98         # May raise a permission denied
99         self.check_object_permissions(self.request, obj)
100 
101         return obj
102 
103     def dispatch(self, request, *args, **kwargs):
104         self.food_event = get_object_or_404(FoodEvent, pk=self.kwargs.get("pk"))
105         return super().dispatch(request, *args, **kwargs)
106 
107     def update(self, request, *args, **kwargs):
108         super().update(request, *args, **kwargs)
109         instance = self.get_object()
110 
111         if instance.payment:
112             try:
113                 delete_payment(
114                     instance, member=request.member, ignore_change_window=True
115                 )
116             except PaymentError:
117                 return Response(
118                     "Your order could not be updated because it was already paid.",
119                     status=status.HTTP_403_FORBIDDEN,
120                 )
121 
122         return Response(
123             FoodOrderSerializer(instance, context=self.get_serializer_context()).data
124         )
125 
126     def create(self, request, *args, **kwargs):
127         serializer = self.get_serializer(data=request.data)
128         serializer.is_valid(raise_exception=True)
129         self.perform_create(serializer)
130         return Response(
131             FoodOrderSerializer(
132                 serializer.instance, context=self.get_serializer_context()
133             ).data,
134             status=status.HTTP_201_CREATED,
135         )
136
```

Path: `website/pizzas/views.py`
Content:
```
1 """Views provided by the pizzas package."""
2 from django.contrib import messages
3 from django.contrib.auth.decorators import login_required
4 from django.http import Http404
5 from django.shortcuts import get_object_or_404, render, redirect
6 from django.utils.translation import gettext_lazy as _
7 from django.views.decorators.http import require_http_methods
8 
9 from payments.exceptions import PaymentError
10 from payments.services import delete_payment
11 from .models import FoodOrder, FoodEvent, Product
12 
13 
14 @login_required
15 def index(request):
16     """Overview of user order for a pizza event."""
17     products = Product.available_products.order_by("name")
18     if not request.user.has_perm("pizzas.order_restricted_products"):
19         products = products.exclude(restricted=True)
20     event = FoodEvent.current()
21     try:
22         obj = FoodOrder.objects.get(food_event=event, member=request.member)
23     except FoodOrder.DoesNotExist:
24         obj = None
25     context = {"event": event, "products": products, "order": obj}
26     return render(request, "pizzas/index.html", context)
27 
28 
29 @require_http_methods(["POST"])
30 def cancel_order(request):
31     """View that cancels a user's order."""
32     if "order" in request.POST:
33         try:
34             order = get_object_or_404(FoodOrder, pk=int(request.POST["order"]))
35             if not order.can_be_changed:
36                 messages.error(request, _("You can no longer cancel."))
37             elif order.member == request.member:
38                 order.delete()
39                 messages.success(request, _("Your order has been cancelled."))
40         except Http404:
41             messages.error(request, _("Your order could not be found."))
42     return redirect("pizzas:index")
43 
44 
45 @login_required
46 def place_order(request):
47     """View that shows the detail of the current order."""
48     event = FoodEvent.current()
49     if not event:
50         return redirect("pizzas:index")
51 
52     try:
53         obj = FoodOrder.objects.get(food_event=event, member=request.member)
54         current_order_locked = not obj.can_be_changed
55     except FoodOrder.DoesNotExist:
56         obj = None
57         current_order_locked = False
58 
59     if "product" in request.POST and not current_order_locked:
60         productset = Product.available_products.all()
61         if not request.user.has_perm("pizzas.order_restricted_products"):
62             productset = productset.exclude(restricted=True)
63         try:
64             product = productset.get(pk=int(request.POST["product"]))
65         except Product.DoesNotExist as e:
66             raise Http404("Pizza does not exist") from e
67         if not obj:
68             obj = FoodOrder(food_event=event, member=request.member)
69         obj.product = product
70         if obj.payment:
71             try:
72                 delete_payment(obj, member=request.member, ignore_change_window=True)
73             except PaymentError:
74                 messages.error(
75                     request,
76                     _("Your order could not be updated because it was already paid."),
77                 )
78                 return redirect("pizzas:index")
79         obj.save()
80     return redirect("pizzas:index")
81
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/website/pizzas/api/v2/views.py b/website/pizzas/api/v2/views.py
--- a/website/pizzas/api/v2/views.py
+++ b/website/pizzas/api/v2/views.py
@@ -102,22 +102,17 @@
 
     def dispatch(self, request, *args, **kwargs):
         self.food_event = get_object_or_404(FoodEvent, pk=self.kwargs.get("pk"))
-        return super().dispatch(request, *args, **kwargs)
+        try:
+            return super().dispatch(request, *args, **kwargs)
+        except PaymentError as e:
+            return Response(str(e), status=status.HTTP_403_FORBIDDEN,)
 
     def update(self, request, *args, **kwargs):
         super().update(request, *args, **kwargs)
         instance = self.get_object()
 
         if instance.payment:
-            try:
-                delete_payment(
-                    instance, member=request.member, ignore_change_window=True
-                )
-            except PaymentError:
-                return Response(
-                    "Your order could not be updated because it was already paid.",
-                    status=status.HTTP_403_FORBIDDEN,
-                )
+            delete_payment(instance, member=request.member, ignore_change_window=True)
 
         return Response(
             FoodOrderSerializer(instance, context=self.get_serializer_context()).data
diff --git a/website/pizzas/views.py b/website/pizzas/views.py
--- a/website/pizzas/views.py
+++ b/website/pizzas/views.py
@@ -35,8 +35,11 @@
             if not order.can_be_changed:
                 messages.error(request, _("You can no longer cancel."))
             elif order.member == request.member:
-                order.delete()
-                messages.success(request, _("Your order has been cancelled."))
+                try:
+                    order.delete()
+                    messages.success(request, _("Your order has been cancelled."))
+                except PaymentError as e:
+                    messages.error(request, str(e))
         except Http404:
             messages.error(request, _("Your order could not be found."))
     return redirect("pizzas:index")

{"golden_diff": "diff --git a/website/pizzas/api/v2/views.py b/website/pizzas/api/v2/views.py\n--- a/website/pizzas/api/v2/views.py\n+++ b/website/pizzas/api/v2/views.py\n@@ -102,22 +102,17 @@\n \n     def dispatch(self, request, *args, **kwargs):\n         self.food_event = get_object_or_404(FoodEvent, pk=self.kwargs.get(\"pk\"))\n-        return super().dispatch(request, *args, **kwargs)\n+        try:\n+            return super().dispatch(request, *args, **kwargs)\n+        except PaymentError as e:\n+            return Response(str(e), status=status.HTTP_403_FORBIDDEN,)\n \n     def update(self, request, *args, **kwargs):\n         super().update(request, *args, **kwargs)\n         instance = self.get_object()\n \n         if instance.payment:\n-            try:\n-                delete_payment(\n-                    instance, member=request.member, ignore_change_window=True\n-                )\n-            except PaymentError:\n-                return Response(\n-                    \"Your order could not be updated because it was already paid.\",\n-                    status=status.HTTP_403_FORBIDDEN,\n-                )\n+            delete_payment(instance, member=request.member, ignore_change_window=True)\n \n         return Response(\n             FoodOrderSerializer(instance, context=self.get_serializer_context()).data\ndiff --git a/website/pizzas/views.py b/website/pizzas/views.py\n--- a/website/pizzas/views.py\n+++ b/website/pizzas/views.py\n@@ -35,8 +35,11 @@\n             if not order.can_be_changed:\n                 messages.error(request, _(\"You can no longer cancel.\"))\n             elif order.member == request.member:\n-                order.delete()\n-                messages.success(request, _(\"Your order has been cancelled.\"))\n+                try:\n+                    order.delete()\n+                    messages.success(request, _(\"Your order has been cancelled.\"))\n+                except PaymentError as e:\n+                    messages.error(request, str(e))\n         except Http404:\n             messages.error(request, _(\"Your order could not be found.\"))\n     return redirect(\"pizzas:index\")\n", "issue": "PaymentError: This payment has already been processed and hence cannot be deleted.\nSentry Issue: [CONCREXIT-8C](https://sentry.io/organizations/thalia/issues/2568657203/?referrer=github_integration)\n\n```\nPaymentError: This payment has already been processed and hence cannot be deleted.\n(1 additional frame(s) were not displayed)\n...\n  File \"django/core/handlers/base.py\", line 181, in _get_response\n    response = wrapped_callback(request, *callback_args, **callback_kwargs)\n  File \"django/views/decorators/http.py\", line 40, in inner\n    return func(request, *args, **kwargs)\n  File \"pizzas/views.py\", line 38, in cancel_order\n    order.delete()\n  File \"pizzas/models.py\", line 256, in delete\n    delete_payment(self)\n  File \"payments/services.py\", line 98, in delete_payment\n    raise PaymentError(\n```\n", "before_files": [{"content": "from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope\nfrom rest_framework.generics import (\n    ListAPIView,\n    RetrieveAPIView,\n    get_object_or_404,\n    CreateAPIView,\n    DestroyAPIView,\n    UpdateAPIView,\n)\n\nfrom rest_framework import filters as framework_filters, status\nfrom rest_framework.response import Response\n\nfrom payments.exceptions import PaymentError\nfrom payments.services import delete_payment\nfrom pizzas.api.v2 import filters\nfrom pizzas.api.v2.serializers import (\n    ProductSerializer,\n    FoodOrderSerializer,\n    FoodOrderUpdateSerializer,\n    FoodOrderCreateSerializer,\n)\nfrom pizzas.api.v2.serializers.food_event import FoodEventSerializer\nfrom pizzas.models import FoodEvent, Product, FoodOrder\nfrom thaliawebsite.api.v2.permissions import IsAuthenticatedOrTokenHasScopeForMethod\n\n\nclass FoodEventListView(ListAPIView):\n    \"\"\"Returns an overview of all food events.\"\"\"\n\n    serializer_class = FoodEventSerializer\n    queryset = FoodEvent.objects.all()\n    filter_backends = (\n        framework_filters.OrderingFilter,\n        filters.FoodEventDateFilterBackend,\n    )\n    ordering_fields = (\"start\", \"end\")\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScope,\n    ]\n    required_scopes = [\"food:read\"]\n\n\nclass FoodEventDetailView(RetrieveAPIView):\n    \"\"\"Returns one single food event.\"\"\"\n\n    serializer_class = FoodEventSerializer\n    queryset = FoodEvent.objects.all()\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScope,\n    ]\n    required_scopes = [\"food:read\"]\n\n\nclass FoodEventProductsListView(ListAPIView):\n    \"\"\"Returns an overview of all products.\"\"\"\n\n    serializer_class = ProductSerializer\n    queryset = Product.available_products.all()\n    filter_backends = (framework_filters.SearchFilter,)\n    search_fields = (\"name\",)\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScope,\n    ]\n    required_scopes = [\"food:read\"]\n\n\nclass FoodEventOrderDetailView(\n    RetrieveAPIView, CreateAPIView, UpdateAPIView, DestroyAPIView\n):\n    \"\"\"Returns details of a food order.\"\"\"\n\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScopeForMethod,\n    ]\n    required_scopes_per_method = {\n        \"GET\": [\"food:read\"],\n        \"POST\": [\"food:order\"],\n        \"PUT\": [\"food:order\"],\n        \"PATCH\": [\"food:order\"],\n        \"DELETE\": [\"food:order\"],\n    }\n\n    def get_serializer_class(self):\n        if self.request.method.lower() == \"get\":\n            return FoodOrderSerializer\n        if self.request.method.lower() == \"post\":\n            return FoodOrderCreateSerializer\n        return FoodOrderUpdateSerializer\n\n    def get_queryset(self):\n        return FoodOrder.objects.filter(food_event=self.food_event)\n\n    def get_object(self):\n        queryset = self.filter_queryset(self.get_queryset())\n        obj = get_object_or_404(queryset, member=self.request.member)\n\n        # May raise a permission denied\n        self.check_object_permissions(self.request, obj)\n\n        return obj\n\n    def dispatch(self, request, *args, **kwargs):\n        self.food_event = get_object_or_404(FoodEvent, pk=self.kwargs.get(\"pk\"))\n        return super().dispatch(request, *args, **kwargs)\n\n    def update(self, request, *args, **kwargs):\n        super().update(request, *args, **kwargs)\n        instance = self.get_object()\n\n        if instance.payment:\n            try:\n                delete_payment(\n                    instance, member=request.member, ignore_change_window=True\n                )\n            except PaymentError:\n                return Response(\n                    \"Your order could not be updated because it was already paid.\",\n                    status=status.HTTP_403_FORBIDDEN,\n                )\n\n        return Response(\n            FoodOrderSerializer(instance, context=self.get_serializer_context()).data\n        )\n\n    def create(self, request, *args, **kwargs):\n        serializer = self.get_serializer(data=request.data)\n        serializer.is_valid(raise_exception=True)\n        self.perform_create(serializer)\n        return Response(\n            FoodOrderSerializer(\n                serializer.instance, context=self.get_serializer_context()\n            ).data,\n            status=status.HTTP_201_CREATED,\n        )\n", "path": "website/pizzas/api/v2/views.py"}, {"content": "\"\"\"Views provided by the pizzas package.\"\"\"\nfrom django.contrib import messages\nfrom django.contrib.auth.decorators import login_required\nfrom django.http import Http404\nfrom django.shortcuts import get_object_or_404, render, redirect\nfrom django.utils.translation import gettext_lazy as _\nfrom django.views.decorators.http import require_http_methods\n\nfrom payments.exceptions import PaymentError\nfrom payments.services import delete_payment\nfrom .models import FoodOrder, FoodEvent, Product\n\n\n@login_required\ndef index(request):\n    \"\"\"Overview of user order for a pizza event.\"\"\"\n    products = Product.available_products.order_by(\"name\")\n    if not request.user.has_perm(\"pizzas.order_restricted_products\"):\n        products = products.exclude(restricted=True)\n    event = FoodEvent.current()\n    try:\n        obj = FoodOrder.objects.get(food_event=event, member=request.member)\n    except FoodOrder.DoesNotExist:\n        obj = None\n    context = {\"event\": event, \"products\": products, \"order\": obj}\n    return render(request, \"pizzas/index.html\", context)\n\n\n@require_http_methods([\"POST\"])\ndef cancel_order(request):\n    \"\"\"View that cancels a user's order.\"\"\"\n    if \"order\" in request.POST:\n        try:\n            order = get_object_or_404(FoodOrder, pk=int(request.POST[\"order\"]))\n            if not order.can_be_changed:\n                messages.error(request, _(\"You can no longer cancel.\"))\n            elif order.member == request.member:\n                order.delete()\n                messages.success(request, _(\"Your order has been cancelled.\"))\n        except Http404:\n            messages.error(request, _(\"Your order could not be found.\"))\n    return redirect(\"pizzas:index\")\n\n\n@login_required\ndef place_order(request):\n    \"\"\"View that shows the detail of the current order.\"\"\"\n    event = FoodEvent.current()\n    if not event:\n        return redirect(\"pizzas:index\")\n\n    try:\n        obj = FoodOrder.objects.get(food_event=event, member=request.member)\n        current_order_locked = not obj.can_be_changed\n    except FoodOrder.DoesNotExist:\n        obj = None\n        current_order_locked = False\n\n    if \"product\" in request.POST and not current_order_locked:\n        productset = Product.available_products.all()\n        if not request.user.has_perm(\"pizzas.order_restricted_products\"):\n            productset = productset.exclude(restricted=True)\n        try:\n            product = productset.get(pk=int(request.POST[\"product\"]))\n        except Product.DoesNotExist as e:\n            raise Http404(\"Pizza does not exist\") from e\n        if not obj:\n            obj = FoodOrder(food_event=event, member=request.member)\n        obj.product = product\n        if obj.payment:\n            try:\n                delete_payment(obj, member=request.member, ignore_change_window=True)\n            except PaymentError:\n                messages.error(\n                    request,\n                    _(\"Your order could not be updated because it was already paid.\"),\n                )\n                return redirect(\"pizzas:index\")\n        obj.save()\n    return redirect(\"pizzas:index\")\n", "path": "website/pizzas/views.py"}], "after_files": [{"content": "from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope\nfrom rest_framework.generics import (\n    ListAPIView,\n    RetrieveAPIView,\n    get_object_or_404,\n    CreateAPIView,\n    DestroyAPIView,\n    UpdateAPIView,\n)\n\nfrom rest_framework import filters as framework_filters, status\nfrom rest_framework.response import Response\n\nfrom payments.exceptions import PaymentError\nfrom payments.services import delete_payment\nfrom pizzas.api.v2 import filters\nfrom pizzas.api.v2.serializers import (\n    ProductSerializer,\n    FoodOrderSerializer,\n    FoodOrderUpdateSerializer,\n    FoodOrderCreateSerializer,\n)\nfrom pizzas.api.v2.serializers.food_event import FoodEventSerializer\nfrom pizzas.models import FoodEvent, Product, FoodOrder\nfrom thaliawebsite.api.v2.permissions import IsAuthenticatedOrTokenHasScopeForMethod\n\n\nclass FoodEventListView(ListAPIView):\n    \"\"\"Returns an overview of all food events.\"\"\"\n\n    serializer_class = FoodEventSerializer\n    queryset = FoodEvent.objects.all()\n    filter_backends = (\n        framework_filters.OrderingFilter,\n        filters.FoodEventDateFilterBackend,\n    )\n    ordering_fields = (\"start\", \"end\")\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScope,\n    ]\n    required_scopes = [\"food:read\"]\n\n\nclass FoodEventDetailView(RetrieveAPIView):\n    \"\"\"Returns one single food event.\"\"\"\n\n    serializer_class = FoodEventSerializer\n    queryset = FoodEvent.objects.all()\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScope,\n    ]\n    required_scopes = [\"food:read\"]\n\n\nclass FoodEventProductsListView(ListAPIView):\n    \"\"\"Returns an overview of all products.\"\"\"\n\n    serializer_class = ProductSerializer\n    queryset = Product.available_products.all()\n    filter_backends = (framework_filters.SearchFilter,)\n    search_fields = (\"name\",)\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScope,\n    ]\n    required_scopes = [\"food:read\"]\n\n\nclass FoodEventOrderDetailView(\n    RetrieveAPIView, CreateAPIView, UpdateAPIView, DestroyAPIView\n):\n    \"\"\"Returns details of a food order.\"\"\"\n\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScopeForMethod,\n    ]\n    required_scopes_per_method = {\n        \"GET\": [\"food:read\"],\n        \"POST\": [\"food:order\"],\n        \"PUT\": [\"food:order\"],\n        \"PATCH\": [\"food:order\"],\n        \"DELETE\": [\"food:order\"],\n    }\n\n    def get_serializer_class(self):\n        if self.request.method.lower() == \"get\":\n            return FoodOrderSerializer\n        if self.request.method.lower() == \"post\":\n            return FoodOrderCreateSerializer\n        return FoodOrderUpdateSerializer\n\n    def get_queryset(self):\n        return FoodOrder.objects.filter(food_event=self.food_event)\n\n    def get_object(self):\n        queryset = self.filter_queryset(self.get_queryset())\n        obj = get_object_or_404(queryset, member=self.request.member)\n\n        # May raise a permission denied\n        self.check_object_permissions(self.request, obj)\n\n        return obj\n\n    def dispatch(self, request, *args, **kwargs):\n        self.food_event = get_object_or_404(FoodEvent, pk=self.kwargs.get(\"pk\"))\n        try:\n            return super().dispatch(request, *args, **kwargs)\n        except PaymentError as e:\n            return Response(str(e), status=status.HTTP_403_FORBIDDEN,)\n\n    def update(self, request, *args, **kwargs):\n        super().update(request, *args, **kwargs)\n        instance = self.get_object()\n\n        if instance.payment:\n            delete_payment(instance, member=request.member, ignore_change_window=True)\n\n        return Response(\n            FoodOrderSerializer(instance, context=self.get_serializer_context()).data\n        )\n\n    def create(self, request, *args, **kwargs):\n        serializer = self.get_serializer(data=request.data)\n        serializer.is_valid(raise_exception=True)\n        self.perform_create(serializer)\n        return Response(\n            FoodOrderSerializer(\n                serializer.instance, context=self.get_serializer_context()\n            ).data,\n            status=status.HTTP_201_CREATED,\n        )\n", "path": "website/pizzas/api/v2/views.py"}, {"content": "\"\"\"Views provided by the pizzas package.\"\"\"\nfrom django.contrib import messages\nfrom django.contrib.auth.decorators import login_required\nfrom django.http import Http404\nfrom django.shortcuts import get_object_or_404, render, redirect\nfrom django.utils.translation import gettext_lazy as _\nfrom django.views.decorators.http import require_http_methods\n\nfrom payments.exceptions import PaymentError\nfrom payments.services import delete_payment\nfrom .models import FoodOrder, FoodEvent, Product\n\n\n@login_required\ndef index(request):\n    \"\"\"Overview of user order for a pizza event.\"\"\"\n    products = Product.available_products.order_by(\"name\")\n    if not request.user.has_perm(\"pizzas.order_restricted_products\"):\n        products = products.exclude(restricted=True)\n    event = FoodEvent.current()\n    try:\n        obj = FoodOrder.objects.get(food_event=event, member=request.member)\n    except FoodOrder.DoesNotExist:\n        obj = None\n    context = {\"event\": event, \"products\": products, \"order\": obj}\n    return render(request, \"pizzas/index.html\", context)\n\n\n@require_http_methods([\"POST\"])\ndef cancel_order(request):\n    \"\"\"View that cancels a user's order.\"\"\"\n    if \"order\" in request.POST:\n        try:\n            order = get_object_or_404(FoodOrder, pk=int(request.POST[\"order\"]))\n            if not order.can_be_changed:\n                messages.error(request, _(\"You can no longer cancel.\"))\n            elif order.member == request.member:\n                try:\n                    order.delete()\n                    messages.success(request, _(\"Your order has been cancelled.\"))\n                except PaymentError as e:\n                    messages.error(request, str(e))\n        except Http404:\n            messages.error(request, _(\"Your order could not be found.\"))\n    return redirect(\"pizzas:index\")\n\n\n@login_required\ndef place_order(request):\n    \"\"\"View that shows the detail of the current order.\"\"\"\n    event = FoodEvent.current()\n    if not event:\n        return redirect(\"pizzas:index\")\n\n    try:\n        obj = FoodOrder.objects.get(food_event=event, member=request.member)\n        current_order_locked = not obj.can_be_changed\n    except FoodOrder.DoesNotExist:\n        obj = None\n        current_order_locked = False\n\n    if \"product\" in request.POST and not current_order_locked:\n        productset = Product.available_products.all()\n        if not request.user.has_perm(\"pizzas.order_restricted_products\"):\n            productset = productset.exclude(restricted=True)\n        try:\n            product = productset.get(pk=int(request.POST[\"product\"]))\n        except Product.DoesNotExist as e:\n            raise Http404(\"Pizza does not exist\") from e\n        if not obj:\n            obj = FoodOrder(food_event=event, member=request.member)\n        obj.product = product\n        if obj.payment:\n            try:\n                delete_payment(obj, member=request.member, ignore_change_window=True)\n            except PaymentError:\n                messages.error(\n                    request,\n                    _(\"Your order could not be updated because it was already paid.\"),\n                )\n                return redirect(\"pizzas:index\")\n        obj.save()\n    return redirect(\"pizzas:index\")\n", "path": "website/pizzas/views.py"}]}