prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Food order can be changed after paying
  ### Describe the bug
  If you order a pizza and pay it, you can still change the product. If you change the product through the api, the payment is not removed.
  
  ### How to reproduce
  Steps to reproduce the behaviour:
  1. Order a pizza
  2. Pay with Thalia Pay
  3. Change the order through the api
  4. Get an expensive pizza for little money
  
  ### Expected behaviour
  Either changing the order after paying is impossible, or it removes the payment. I think removing the payment (as the website currently seems to do) would be strange, and for event registration we've decided not to enable this.
  
  ### Screenshots
  <img width="569" alt="image" src="https://user-images.githubusercontent.com/41264528/123456318-01d59880-d5e3-11eb-86c8-9217e4720988.png">
  
  There are probably no food events any time soon, so a hotfix may not be needed, though it might be good to double-check that similar stuff is not possible with registrations.
  
  
  </issue>
  <code>
  [start of website/pizzas/api/v2/views.py]
  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.permissions import DjangoModelPermissionsOrAnonReadOnly
  13 from rest_framework.response import Response
  14 
  15 from pizzas.api.v2 import filters
  16 from pizzas.api.v2.serializers import (
  17     ProductSerializer,
  18     FoodOrderSerializer,
  19     FoodOrderUpdateSerializer,
  20     FoodOrderCreateSerializer,
  21 )
  22 from pizzas.api.v2.serializers.food_event import FoodEventSerializer
  23 from pizzas.models import FoodEvent, Product, FoodOrder
  24 from thaliawebsite.api.v2.permissions import IsAuthenticatedOrTokenHasScopeForMethod
  25 
  26 
  27 class FoodEventListView(ListAPIView):
  28     """Returns an overview of all food events."""
  29 
  30     serializer_class = FoodEventSerializer
  31     queryset = FoodEvent.objects.all()
  32     filter_backends = (
  33         framework_filters.OrderingFilter,
  34         filters.FoodEventDateFilterBackend,
  35     )
  36     ordering_fields = ("start", "end")
  37     permission_classes = [
  38         IsAuthenticatedOrTokenHasScope,
  39         DjangoModelPermissionsOrAnonReadOnly,
  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         DjangoModelPermissionsOrAnonReadOnly,
  52     ]
  53     required_scopes = ["food:read"]
  54 
  55 
  56 class FoodEventProductsListView(ListAPIView):
  57     """Returns an overview of all products."""
  58 
  59     serializer_class = ProductSerializer
  60     queryset = Product.available_products.all()
  61     filter_backends = (framework_filters.SearchFilter,)
  62     search_fields = ("name",)
  63     permission_classes = [
  64         IsAuthenticatedOrTokenHasScope,
  65         DjangoModelPermissionsOrAnonReadOnly,
  66     ]
  67     required_scopes = ["food:read"]
  68 
  69 
  70 class FoodEventOrderDetailView(
  71     RetrieveAPIView, CreateAPIView, UpdateAPIView, DestroyAPIView
  72 ):
  73     """Returns details of a food order."""
  74 
  75     permission_classes = [
  76         IsAuthenticatedOrTokenHasScopeForMethod,
  77         DjangoModelPermissionsOrAnonReadOnly,
  78     ]
  79     required_scopes_per_method = {
  80         "GET": ["food:read"],
  81         "POST": ["food:order"],
  82         "PUT": ["food:order"],
  83         "PATCH": ["food:order"],
  84         "DELETE": ["food:order"],
  85     }
  86 
  87     def get_serializer_class(self):
  88         if self.request.method.lower() == "get":
  89             return FoodOrderSerializer
  90         if self.request.method.lower() == "post":
  91             return FoodOrderCreateSerializer
  92         return FoodOrderUpdateSerializer
  93 
  94     def get_queryset(self):
  95         return FoodOrder.objects.filter(food_event=self.food_event)
  96 
  97     def get_object(self):
  98         queryset = self.filter_queryset(self.get_queryset())
  99         obj = get_object_or_404(queryset, member=self.request.member)
  100 
  101         # May raise a permission denied
  102         self.check_object_permissions(self.request, obj)
  103 
  104         return obj
  105 
  106     def dispatch(self, request, *args, **kwargs):
  107         self.food_event = get_object_or_404(FoodEvent, pk=self.kwargs.get("pk"))
  108         return super().dispatch(request, *args, **kwargs)
  109 
  110     def update(self, request, *args, **kwargs):
  111         super().update(request, *args, **kwargs)
  112         instance = self.get_object()
  113         return Response(
  114             FoodOrderSerializer(instance, context=self.get_serializer_context()).data
  115         )
  116 
  117     def create(self, request, *args, **kwargs):
  118         serializer = self.get_serializer(data=request.data)
  119         serializer.is_valid(raise_exception=True)
  120         self.perform_create(serializer)
  121         return Response(
  122             FoodOrderSerializer(
  123                 serializer.instance, context=self.get_serializer_context()
  124             ).data,
  125             status=status.HTTP_201_CREATED,
  126         )
  127
  [end of website/pizzas/api/v2/views.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: 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
  @@ -12,6 +12,8 @@
   from rest_framework.permissions import DjangoModelPermissionsOrAnonReadOnly
   from rest_framework.response import Response
   
  +from payments.exceptions import PaymentError
  +from payments.services import delete_payment
   from pizzas.api.v2 import filters
   from pizzas.api.v2.serializers import (
       ProductSerializer,
  @@ -110,6 +112,18 @@
       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,
  +                )
  +
           return Response(
               FoodOrderSerializer(instance, context=self.get_serializer_context()).data
           )
  
verification_info: {"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@@ -12,6 +12,8 @@\n from rest_framework.permissions import DjangoModelPermissionsOrAnonReadOnly\n from rest_framework.response import Response\n \n+from payments.exceptions import PaymentError\n+from payments.services import delete_payment\n from pizzas.api.v2 import filters\n from pizzas.api.v2.serializers import (\n     ProductSerializer,\n@@ -110,6 +112,18 @@\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", "issue": "Food order can be changed after paying\n### Describe the bug\r\nIf you order a pizza and pay it, you can still change the product. If you change the product through the api, the payment is not removed.\r\n\r\n### How to reproduce\r\nSteps to reproduce the behaviour:\r\n1. Order a pizza\r\n2. Pay with Thalia Pay\r\n3. Change the order through the api\r\n4. Get an expensive pizza for little money\r\n\r\n### Expected behaviour\r\nEither changing the order after paying is impossible, or it removes the payment. I think removing the payment (as the website currently seems to do) would be strange, and for event registration we've decided not to enable this.\r\n\r\n### Screenshots\r\n<img width=\"569\" alt=\"image\" src=\"https://user-images.githubusercontent.com/41264528/123456318-01d59880-d5e3-11eb-86c8-9217e4720988.png\">\r\n\r\nThere are probably no food events any time soon, so a hotfix may not be needed, though it might be good to double-check that similar stuff is not possible with registrations.\r\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.permissions import DjangoModelPermissionsOrAnonReadOnly\nfrom rest_framework.response import Response\n\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        DjangoModelPermissionsOrAnonReadOnly,\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        DjangoModelPermissionsOrAnonReadOnly,\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        DjangoModelPermissionsOrAnonReadOnly,\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        DjangoModelPermissionsOrAnonReadOnly,\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        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"}]}