prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Add sales order API
  ### Describe the solution you'd like
  - An api endpoint `api/v2/sales/order/<uuid>/` that returns the order information that is shown on the website when you pay for the url from a qr code.
  - It should be possible to pay the order through `api/v2/payments/sales/order/<uuid>`. This might already be possible, I haven't checked.
  
  ### Motivation
  This way people will be able to pay from the app, instead of through the website where they may even need to log in. I think this is an obvious case where the ease of use of an app is very welcome.
  
  
  
  </issue>
  <code>
  [start of website/sales/api/v2/views.py]
  1 from django.db.models import Q
  2 from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope
  3 from rest_framework.exceptions import PermissionDenied
  4 from rest_framework.generics import (
  5     ListAPIView,
  6     RetrieveAPIView,
  7     CreateAPIView,
  8     UpdateAPIView,
  9     DestroyAPIView,
  10 )
  11 from rest_framework.permissions import DjangoModelPermissionsOrAnonReadOnly
  12 
  13 from sales.api.v2.admin.serializers.order import OrderSerializer, OrderListSerializer
  14 from sales.api.v2.admin.views import (
  15     OrderListView,
  16     OrderDetailView,
  17     ShiftDetailView,
  18     ShiftListView,
  19 )
  20 from sales.api.v2.serializers.user_order import UserOrderSerializer
  21 from sales.api.v2.serializers.user_shift import UserShiftSerializer
  22 from sales.models.shift import SelfOrderPeriod, Shift
  23 from thaliawebsite.api.v2.permissions import IsAuthenticatedOrTokenHasScopeForMethod
  24 
  25 
  26 class UserShiftListView(ShiftListView):
  27     serializer_class = UserShiftSerializer
  28     # queryset = SelfOrderPeriod.objects.all()
  29     permission_classes = [
  30         IsAuthenticatedOrTokenHasScope,
  31         DjangoModelPermissionsOrAnonReadOnly,
  32     ]
  33     required_scopes = ["sales:read"]
  34 
  35 
  36 class UserShiftDetailView(ShiftDetailView):
  37     serializer_class = UserShiftSerializer
  38     # queryset = SelfOrderPeriod.objects.all()
  39     permission_classes = [
  40         IsAuthenticatedOrTokenHasScope,
  41         DjangoModelPermissionsOrAnonReadOnly,
  42     ]
  43     required_scopes = ["sales:read"]
  44 
  45 
  46 class UserOrderListView(OrderListView):
  47     permission_classes = [
  48         IsAuthenticatedOrTokenHasScopeForMethod,
  49     ]
  50     required_scopes_per_method = {
  51         "GET": ["sales:read"],
  52         "POST": ["sales:order"],
  53     }
  54     method_serializer_classes = {
  55         ("GET",): OrderListSerializer,
  56         ("POST",): UserOrderSerializer,
  57     }
  58 
  59     def create(self, request, *args, **kwargs):
  60         shift = Shift.objects.get(pk=kwargs["pk"])
  61         if not shift.user_orders_allowed:
  62             raise PermissionDenied
  63         return super(UserOrderListView, self).create(request, *args, **kwargs)
  64 
  65     def perform_create(self, serializer):
  66         serializer.save(
  67             payer_id=self.request.member.pk, created_by_id=self.request.member.pk
  68         )
  69 
  70     def get_queryset(self):
  71         queryset = super(UserOrderListView, self).get_queryset()
  72         return queryset.filter(
  73             Q(payer=self.request.member) | Q(created_by=self.request.member)
  74         )
  75 
  76 
  77 class UserOrderDetailView(OrderDetailView):
  78     serializer_class = UserOrderSerializer
  79     permission_classes = [
  80         IsAuthenticatedOrTokenHasScopeForMethod,
  81     ]
  82     required_scopes_per_method = {
  83         "GET": ["sales:read"],
  84         "PATCH": ["sales:order"],
  85         "PUT": ["sales:order"],
  86         "DELETE": ["sales:order"],
  87     }
  88 
  89     def get_queryset(self):
  90         queryset = super(UserOrderDetailView, self).get_queryset()
  91         return queryset.filter(
  92             Q(payer=self.request.member) | Q(created_by=self.request.member)
  93         )
  94 
  95     def update(self, request, *args, **kwargs):
  96         if not self.get_object().shift.user_orders_allowed:
  97             raise PermissionDenied
  98         if self.get_object().payment:
  99             raise PermissionDenied
  100         return super(UserOrderDetailView, self).update(request, *args, **kwargs)
  101 
  102     def partial_update(self, request, *args, **kwargs):
  103         if not self.get_object().shift.user_orders_allowed:
  104             raise PermissionDenied
  105         if self.get_object().payment:
  106             raise PermissionDenied
  107         return super(UserOrderDetailView, self).partial_update(request, *args, **kwargs)
  108 
  109     def destroy(self, request, *args, **kwargs):
  110         if not self.get_object().shift.user_orders_allowed:
  111             raise PermissionDenied
  112         if self.get_object().payment:
  113             raise PermissionDenied
  114         return super(UserOrderDetailView, self).destroy(request, *args, **kwargs)
  115
  [end of website/sales/api/v2/views.py]
  [start of website/sales/api/v2/urls.py]
  1 from django.urls import path
  2 
  3 from sales.api.v2.views import (
  4     UserShiftListView,
  5     UserShiftDetailView,
  6     UserOrderListView,
  7     UserOrderDetailView,
  8 )
  9 
  10 app_name = "sales"
  11 
  12 urlpatterns = [
  13     path("sales/shifts/", UserShiftListView.as_view(), name="user-shift-list"),
  14     path(
  15         "sales/shifts/<int:pk>/",
  16         UserShiftDetailView.as_view(),
  17         name="user-shift-detail",
  18     ),
  19     path(
  20         "sales/shifts/<int:pk>/orders/",
  21         UserOrderListView.as_view(),
  22         name="user-order-list",
  23     ),
  24     path(
  25         "sales/orders/<uuid:pk>/",
  26         UserOrderDetailView.as_view(),
  27         name="user-order-detail",
  28     ),
  29 ]
  30
  [end of website/sales/api/v2/urls.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/sales/api/v2/urls.py b/website/sales/api/v2/urls.py
  --- a/website/sales/api/v2/urls.py
  +++ b/website/sales/api/v2/urls.py
  @@ -1,6 +1,7 @@
   from django.urls import path
   
   from sales.api.v2.views import (
  +    OrderClaimView,
       UserShiftListView,
       UserShiftDetailView,
       UserOrderListView,
  @@ -10,6 +11,7 @@
   app_name = "sales"
   
   urlpatterns = [
  +    path("sales/order/<uuid:pk>/claim/", OrderClaimView.as_view(), name="order-claim"),
       path("sales/shifts/", UserShiftListView.as_view(), name="user-shift-list"),
       path(
           "sales/shifts/<int:pk>/",
  diff --git a/website/sales/api/v2/views.py b/website/sales/api/v2/views.py
  --- a/website/sales/api/v2/views.py
  +++ b/website/sales/api/v2/views.py
  @@ -1,25 +1,23 @@
   from django.db.models import Q
   from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope
   from rest_framework.exceptions import PermissionDenied
  -from rest_framework.generics import (
  -    ListAPIView,
  -    RetrieveAPIView,
  -    CreateAPIView,
  -    UpdateAPIView,
  -    DestroyAPIView,
  -)
  +from rest_framework.generics import GenericAPIView
   from rest_framework.permissions import DjangoModelPermissionsOrAnonReadOnly
  +from rest_framework.response import Response
  +from rest_framework.schemas.openapi import AutoSchema
   
  -from sales.api.v2.admin.serializers.order import OrderSerializer, OrderListSerializer
  +from sales.api.v2.admin.serializers.order import OrderListSerializer
   from sales.api.v2.admin.views import (
  -    OrderListView,
       OrderDetailView,
  +    OrderListView,
       ShiftDetailView,
       ShiftListView,
   )
  +from sales import services
   from sales.api.v2.serializers.user_order import UserOrderSerializer
   from sales.api.v2.serializers.user_shift import UserShiftSerializer
  -from sales.models.shift import SelfOrderPeriod, Shift
  +from sales.models.shift import Shift
  +from sales.models.order import Order
   from thaliawebsite.api.v2.permissions import IsAuthenticatedOrTokenHasScopeForMethod
   
   
  @@ -111,4 +109,40 @@
               raise PermissionDenied
           if self.get_object().payment:
               raise PermissionDenied
  -        return super(UserOrderDetailView, self).destroy(request, *args, **kwargs)
  +
  +
  +class OrderClaimView(GenericAPIView):
  +    """Claims an order to be paid by the current user."""
  +
  +    class OrderClaimViewSchema(AutoSchema):
  +        def get_request_serializer(self, path, method):
  +            # This endpoint does not expect any content in the request body.
  +            return None
  +
  +    queryset = Order.objects.all()
  +    serializer_class = UserOrderSerializer
  +    schema = OrderClaimViewSchema(operation_id_base="claimOrder")
  +    permission_classes = [IsAuthenticatedOrTokenHasScope]
  +    required_scopes = ["sales:order"]
  +
  +    def patch(self, request, *args, **kwargs):
  +        if request.member is None:
  +            raise PermissionDenied("You need to be a member to pay for an order.")
  +
  +        order = self.get_object()
  +        if order.payment:
  +            raise PermissionDenied(detail="This order was already paid for.")
  +
  +        if order.payer is not None and order.payer != request.member:
  +            raise PermissionDenied(detail="This order is not yours.")
  +
  +        order.payer = request.member
  +        order.save()
  +
  +        if order.age_restricted and not services.is_adult(request.member):
  +            raise PermissionDenied(
  +                "The age restrictions on this order do not allow you to pay for this order."
  +            )
  +
  +        serializer = self.get_serializer(order)
  +        return Response(serializer.data)
  
verification_info: {"golden_diff": "diff --git a/website/sales/api/v2/urls.py b/website/sales/api/v2/urls.py\n--- a/website/sales/api/v2/urls.py\n+++ b/website/sales/api/v2/urls.py\n@@ -1,6 +1,7 @@\n from django.urls import path\n \n from sales.api.v2.views import (\n+    OrderClaimView,\n     UserShiftListView,\n     UserShiftDetailView,\n     UserOrderListView,\n@@ -10,6 +11,7 @@\n app_name = \"sales\"\n \n urlpatterns = [\n+    path(\"sales/order/<uuid:pk>/claim/\", OrderClaimView.as_view(), name=\"order-claim\"),\n     path(\"sales/shifts/\", UserShiftListView.as_view(), name=\"user-shift-list\"),\n     path(\n         \"sales/shifts/<int:pk>/\",\ndiff --git a/website/sales/api/v2/views.py b/website/sales/api/v2/views.py\n--- a/website/sales/api/v2/views.py\n+++ b/website/sales/api/v2/views.py\n@@ -1,25 +1,23 @@\n from django.db.models import Q\n from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope\n from rest_framework.exceptions import PermissionDenied\n-from rest_framework.generics import (\n-    ListAPIView,\n-    RetrieveAPIView,\n-    CreateAPIView,\n-    UpdateAPIView,\n-    DestroyAPIView,\n-)\n+from rest_framework.generics import GenericAPIView\n from rest_framework.permissions import DjangoModelPermissionsOrAnonReadOnly\n+from rest_framework.response import Response\n+from rest_framework.schemas.openapi import AutoSchema\n \n-from sales.api.v2.admin.serializers.order import OrderSerializer, OrderListSerializer\n+from sales.api.v2.admin.serializers.order import OrderListSerializer\n from sales.api.v2.admin.views import (\n-    OrderListView,\n     OrderDetailView,\n+    OrderListView,\n     ShiftDetailView,\n     ShiftListView,\n )\n+from sales import services\n from sales.api.v2.serializers.user_order import UserOrderSerializer\n from sales.api.v2.serializers.user_shift import UserShiftSerializer\n-from sales.models.shift import SelfOrderPeriod, Shift\n+from sales.models.shift import Shift\n+from sales.models.order import Order\n from thaliawebsite.api.v2.permissions import IsAuthenticatedOrTokenHasScopeForMethod\n \n \n@@ -111,4 +109,40 @@\n             raise PermissionDenied\n         if self.get_object().payment:\n             raise PermissionDenied\n-        return super(UserOrderDetailView, self).destroy(request, *args, **kwargs)\n+\n+\n+class OrderClaimView(GenericAPIView):\n+    \"\"\"Claims an order to be paid by the current user.\"\"\"\n+\n+    class OrderClaimViewSchema(AutoSchema):\n+        def get_request_serializer(self, path, method):\n+            # This endpoint does not expect any content in the request body.\n+            return None\n+\n+    queryset = Order.objects.all()\n+    serializer_class = UserOrderSerializer\n+    schema = OrderClaimViewSchema(operation_id_base=\"claimOrder\")\n+    permission_classes = [IsAuthenticatedOrTokenHasScope]\n+    required_scopes = [\"sales:order\"]\n+\n+    def patch(self, request, *args, **kwargs):\n+        if request.member is None:\n+            raise PermissionDenied(\"You need to be a member to pay for an order.\")\n+\n+        order = self.get_object()\n+        if order.payment:\n+            raise PermissionDenied(detail=\"This order was already paid for.\")\n+\n+        if order.payer is not None and order.payer != request.member:\n+            raise PermissionDenied(detail=\"This order is not yours.\")\n+\n+        order.payer = request.member\n+        order.save()\n+\n+        if order.age_restricted and not services.is_adult(request.member):\n+            raise PermissionDenied(\n+                \"The age restrictions on this order do not allow you to pay for this order.\"\n+            )\n+\n+        serializer = self.get_serializer(order)\n+        return Response(serializer.data)\n", "issue": "Add sales order API\n### Describe the solution you'd like\r\n- An api endpoint `api/v2/sales/order/<uuid>/` that returns the order information that is shown on the website when you pay for the url from a qr code.\r\n- It should be possible to pay the order through `api/v2/payments/sales/order/<uuid>`. This might already be possible, I haven't checked.\r\n\r\n### Motivation\r\nThis way people will be able to pay from the app, instead of through the website where they may even need to log in. I think this is an obvious case where the ease of use of an app is very welcome.\r\n\r\n\n", "before_files": [{"content": "from django.db.models import Q\nfrom oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope\nfrom rest_framework.exceptions import PermissionDenied\nfrom rest_framework.generics import (\n    ListAPIView,\n    RetrieveAPIView,\n    CreateAPIView,\n    UpdateAPIView,\n    DestroyAPIView,\n)\nfrom rest_framework.permissions import DjangoModelPermissionsOrAnonReadOnly\n\nfrom sales.api.v2.admin.serializers.order import OrderSerializer, OrderListSerializer\nfrom sales.api.v2.admin.views import (\n    OrderListView,\n    OrderDetailView,\n    ShiftDetailView,\n    ShiftListView,\n)\nfrom sales.api.v2.serializers.user_order import UserOrderSerializer\nfrom sales.api.v2.serializers.user_shift import UserShiftSerializer\nfrom sales.models.shift import SelfOrderPeriod, Shift\nfrom thaliawebsite.api.v2.permissions import IsAuthenticatedOrTokenHasScopeForMethod\n\n\nclass UserShiftListView(ShiftListView):\n    serializer_class = UserShiftSerializer\n    # queryset = SelfOrderPeriod.objects.all()\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScope,\n        DjangoModelPermissionsOrAnonReadOnly,\n    ]\n    required_scopes = [\"sales:read\"]\n\n\nclass UserShiftDetailView(ShiftDetailView):\n    serializer_class = UserShiftSerializer\n    # queryset = SelfOrderPeriod.objects.all()\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScope,\n        DjangoModelPermissionsOrAnonReadOnly,\n    ]\n    required_scopes = [\"sales:read\"]\n\n\nclass UserOrderListView(OrderListView):\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScopeForMethod,\n    ]\n    required_scopes_per_method = {\n        \"GET\": [\"sales:read\"],\n        \"POST\": [\"sales:order\"],\n    }\n    method_serializer_classes = {\n        (\"GET\",): OrderListSerializer,\n        (\"POST\",): UserOrderSerializer,\n    }\n\n    def create(self, request, *args, **kwargs):\n        shift = Shift.objects.get(pk=kwargs[\"pk\"])\n        if not shift.user_orders_allowed:\n            raise PermissionDenied\n        return super(UserOrderListView, self).create(request, *args, **kwargs)\n\n    def perform_create(self, serializer):\n        serializer.save(\n            payer_id=self.request.member.pk, created_by_id=self.request.member.pk\n        )\n\n    def get_queryset(self):\n        queryset = super(UserOrderListView, self).get_queryset()\n        return queryset.filter(\n            Q(payer=self.request.member) | Q(created_by=self.request.member)\n        )\n\n\nclass UserOrderDetailView(OrderDetailView):\n    serializer_class = UserOrderSerializer\n    permission_classes = [\n        IsAuthenticatedOrTokenHasScopeForMethod,\n    ]\n    required_scopes_per_method = {\n        \"GET\": [\"sales:read\"],\n        \"PATCH\": [\"sales:order\"],\n        \"PUT\": [\"sales:order\"],\n        \"DELETE\": [\"sales:order\"],\n    }\n\n    def get_queryset(self):\n        queryset = super(UserOrderDetailView, self).get_queryset()\n        return queryset.filter(\n            Q(payer=self.request.member) | Q(created_by=self.request.member)\n        )\n\n    def update(self, request, *args, **kwargs):\n        if not self.get_object().shift.user_orders_allowed:\n            raise PermissionDenied\n        if self.get_object().payment:\n            raise PermissionDenied\n        return super(UserOrderDetailView, self).update(request, *args, **kwargs)\n\n    def partial_update(self, request, *args, **kwargs):\n        if not self.get_object().shift.user_orders_allowed:\n            raise PermissionDenied\n        if self.get_object().payment:\n            raise PermissionDenied\n        return super(UserOrderDetailView, self).partial_update(request, *args, **kwargs)\n\n    def destroy(self, request, *args, **kwargs):\n        if not self.get_object().shift.user_orders_allowed:\n            raise PermissionDenied\n        if self.get_object().payment:\n            raise PermissionDenied\n        return super(UserOrderDetailView, self).destroy(request, *args, **kwargs)\n", "path": "website/sales/api/v2/views.py"}, {"content": "from django.urls import path\n\nfrom sales.api.v2.views import (\n    UserShiftListView,\n    UserShiftDetailView,\n    UserOrderListView,\n    UserOrderDetailView,\n)\n\napp_name = \"sales\"\n\nurlpatterns = [\n    path(\"sales/shifts/\", UserShiftListView.as_view(), name=\"user-shift-list\"),\n    path(\n        \"sales/shifts/<int:pk>/\",\n        UserShiftDetailView.as_view(),\n        name=\"user-shift-detail\",\n    ),\n    path(\n        \"sales/shifts/<int:pk>/orders/\",\n        UserOrderListView.as_view(),\n        name=\"user-order-list\",\n    ),\n    path(\n        \"sales/orders/<uuid:pk>/\",\n        UserOrderDetailView.as_view(),\n        name=\"user-order-detail\",\n    ),\n]\n", "path": "website/sales/api/v2/urls.py"}]}