Coverage for website/payments/api/v2/admin/views.py: 45.65%
84 statements
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2025-08-14 10:31 +0000
1from django.apps import apps
2from django.http import Http404
3from django.utils.translation import gettext_lazy as _
5import rest_framework.filters as framework_filters
6from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope
7from rest_framework import serializers, status
8from rest_framework.exceptions import PermissionDenied, ValidationError
9from rest_framework.generics import get_object_or_404
10from rest_framework.permissions import IsAdminUser
11from rest_framework.response import Response
12from rest_framework.settings import api_settings
13from rest_framework.views import APIView
15from payments import services
16from payments.api.v2 import filters
17from payments.api.v2.admin.serializers.payable_create import (
18 PayableCreateAdminSerializer,
19)
20from payments.api.v2.admin.serializers.payable_detail import PayableAdminSerializer
21from payments.api.v2.admin.serializers.payment import (
22 PaymentAdminSerializer,
23 PaymentCreateSerializer,
24)
25from payments.exceptions import PaymentError
26from payments.models import Payment, PaymentUser
27from payments.payables import NotRegistered, payables
28from thaliawebsite.api.v2.admin import (
29 AdminCreateAPIView,
30 AdminDestroyAPIView,
31 AdminListAPIView,
32 AdminRetrieveAPIView,
33)
36class PaymentListCreateView(AdminListAPIView, AdminCreateAPIView):
37 """View that allows you to create and list payments as admin."""
39 queryset = Payment.objects.prefetch_related(
40 "paid_by__profile",
41 "paid_by__membership_set",
42 "processed_by__profile",
43 "processed_by__membership_set",
44 )
46 required_scopes = ["payments:admin"]
47 filter_backends = (
48 framework_filters.OrderingFilter,
49 filters.CreatedAtFilter,
50 filters.PaymentTypeFilter,
51 )
52 ordering_fields = ("created_at",)
54 def get_serializer_class(self):
55 if self.request.method.lower() == "post":
56 return PaymentCreateSerializer
57 return PaymentAdminSerializer
59 def create(self, request, *args, **kwargs):
60 serializer = self.get_serializer(data=request.data)
61 serializer.is_valid(raise_exception=True)
62 self.perform_create(serializer)
63 return Response(
64 PaymentAdminSerializer(
65 serializer.instance, context=self.get_serializer_context()
66 ).data,
67 status=status.HTTP_201_CREATED,
68 )
71class PaymentDetailView(AdminRetrieveAPIView, AdminDestroyAPIView):
72 """View that allows you to manage a single payment as admin."""
74 queryset = Payment.objects.all()
75 serializer_class = PaymentAdminSerializer
76 permission_classes = [IsAuthenticatedOrTokenHasScope]
77 required_scopes = ["payments:admin"]
79 def delete(self, request, *args, **kwargs):
80 if self.get_object().batch and self.get_object().batch.processed:
81 raise PermissionDenied("This payment cannot be deleted.")
82 return super().delete(request, *args, **kwargs)
85class PayableDetailView(APIView):
86 """View that allows you to manipulate the payment for the payable.
88 Permissions of this view are based on the payable.
89 """
91 required_scopes = ["payments:admin"]
92 permission_classes = [IsAuthenticatedOrTokenHasScope, IsAdminUser]
94 def get_serializer_context(self):
95 return {"request": self.request, "format": self.format_kwarg, "view": self}
97 def get_payable(self):
98 app_label = self.kwargs["app_label"]
99 model_name = self.kwargs["model_name"]
100 payable_pk = self.kwargs["payable_pk"]
102 try:
103 payable_model = apps.get_model(app_label=app_label, model_name=model_name)
104 payable = payables.get_payable(
105 get_object_or_404(payable_model, pk=payable_pk)
106 )
107 except (LookupError, NotRegistered) as e:
108 raise serializers.ValidationError(
109 {api_settings.NON_FIELD_ERRORS_KEY: [_("Payable model not found")]}
110 ) from e
112 if not payable.can_manage_payment(self.request.member):
113 raise PermissionDenied(
114 detail=_("You do not have permission to perform this action.")
115 )
117 return payable
119 def get(self, request, *args, **kwargs):
120 """Get information about a payable."""
121 serializer = PayableAdminSerializer(
122 self.get_payable(), context=self.get_serializer_context()
123 )
124 return Response(serializer.data, status=status.HTTP_200_OK)
126 def delete(self, request, *args, **kwargs):
127 """Remove the current payment for a payable."""
128 payable = self.get_payable()
130 if not payable.model.payment:
131 raise Http404
133 try:
134 services.delete_payment(
135 payable.model,
136 request.member,
137 )
138 payable.model.save()
139 except PaymentError as e:
140 raise PermissionDenied(detail=str(e)) from e
142 return Response(status=status.HTTP_204_NO_CONTENT)
144 def patch(self, request, *args, **kwargs):
145 """Mark the payable as paid by creating a payment for it."""
146 serializer = PayableCreateAdminSerializer(
147 data=request.data, context=self.get_serializer_context()
148 )
149 serializer.is_valid(raise_exception=True)
151 payable = self.get_payable()
153 try:
154 services.create_payment(
155 payable,
156 PaymentUser.objects.get(pk=request.user.pk),
157 serializer.data["payment_type"],
158 )
159 except PaymentError as e:
160 raise ValidationError(
161 detail={api_settings.NON_FIELD_ERRORS_KEY: [str(e)]}
162 ) from e
164 payable.model.refresh_from_db()
165 return Response(
166 PayableAdminSerializer(payable, context=self.get_serializer_context()).data,
167 status=status.HTTP_201_CREATED,
168 )