Coverage for website/payments/api/v2/views.py: 58.23%
73 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.utils.translation import gettext_lazy as _
4import rest_framework.filters as framework_filters
5from rest_framework import serializers, status
6from rest_framework.exceptions import PermissionDenied, ValidationError
7from rest_framework.generics import ListAPIView, RetrieveAPIView, get_object_or_404
8from rest_framework.response import Response
9from rest_framework.settings import api_settings
11from payments import services
12from payments.api.v2 import filters
13from payments.api.v2.serializers import PaymentSerializer
14from payments.api.v2.serializers.payable_detail import PayableSerializer
15from payments.api.v2.serializers.payment_user import PaymentUserSerializer
16from payments.exceptions import PaymentError
17from payments.models import Payment, PaymentUser
18from payments.payables import NotRegistered, payables
19from thaliawebsite.api.v2.permissions import IsAuthenticatedOrTokenHasScopeForMethod
20from thaliawebsite.api.v2.serializers import EmptySerializer
23class PaymentListView(ListAPIView):
24 """Returns an overview of all an authenticated user's payments."""
26 queryset = Payment.objects.all()
27 serializer_class = PaymentSerializer
29 permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod]
30 required_scopes_per_method = {"GET": ["payments:read"]}
31 filter_backends = (
32 framework_filters.OrderingFilter,
33 filters.CreatedAtFilter,
34 filters.PaymentTypeFilter,
35 filters.PaymentSettledFilter,
36 )
37 ordering_fields = ("created_at",)
39 def get_queryset(self):
40 return (
41 super()
42 .get_queryset()
43 .filter(paid_by=PaymentUser.objects.get(pk=self.request.member.pk))
44 )
47class PaymentDetailView(RetrieveAPIView):
48 """Returns a single payment made by the authenticated user."""
50 queryset = Payment.objects.all()
51 serializer_class = PaymentSerializer
52 permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod]
53 required_scopes_per_method = {"GET": ["payments:read"]}
55 def get_queryset(self):
56 return (
57 super()
58 .get_queryset()
59 .filter(paid_by=PaymentUser.objects.get(pk=self.request.member.pk))
60 )
63class PayableDetailView(RetrieveAPIView):
64 """Allow you to get information about a payable and process it."""
66 permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod]
67 required_scopes_per_method = {
68 "GET": ["payments:read"],
69 "PATCH": ["payments:write"],
70 }
72 def get_serializer_class(self, *args, **kwargs):
73 if self.request.method.lower() == "patch":
74 return EmptySerializer
75 return PayableSerializer
77 def get(self, request, *args, **kwargs):
78 serializer = self.get_serializer(self.get_payable())
79 return Response(serializer.data, status=status.HTTP_200_OK)
81 def get_payable(self):
82 app_label = self.kwargs["app_label"]
83 model_name = self.kwargs["model_name"]
84 payable_pk = self.kwargs["payable_pk"]
86 try:
87 payable_model = apps.get_model(app_label=app_label, model_name=model_name)
88 payable = payables.get_payable(
89 get_object_or_404(payable_model, pk=payable_pk)
90 )
91 except (LookupError, NotRegistered) as e:
92 raise serializers.ValidationError(
93 {api_settings.NON_FIELD_ERRORS_KEY: [_("Payable model not found.")]}
94 ) from e
96 if (
97 not payable.payment_payer
98 or not payable.tpay_allowed
99 or payable.payment_payer != PaymentUser.objects.get(pk=self.request.user.pk)
100 ):
101 raise PermissionDenied(
102 detail=_("You do not have permission to perform this action.")
103 )
105 return payable
107 def patch(self, request, *args, **kwargs):
108 payable = self.get_payable()
110 if payable.payment:
111 return Response(
112 data={"detail": _("This object has already been paid for.")},
113 status=status.HTTP_409_CONFLICT,
114 )
116 try:
117 services.create_payment(
118 payable,
119 PaymentUser.objects.get(pk=request.user.pk),
120 Payment.TPAY,
121 )
122 except PaymentError as e:
123 raise ValidationError(
124 detail={api_settings.NON_FIELD_ERRORS_KEY: [str(e)]}
125 ) from e
127 payable.model.refresh_from_db()
128 return Response(
129 PayableSerializer(payable, context=self.get_serializer_context()).data,
130 status=status.HTTP_201_CREATED,
131 )
134class PaymentUserCurrentView(RetrieveAPIView):
135 """Returns details of the authenticated member."""
137 queryset = PaymentUser
138 serializer_class = PaymentUserSerializer
139 permission_classes = [
140 IsAuthenticatedOrTokenHasScopeForMethod,
141 ]
143 required_scopes_per_method = {"GET": ["payments:read"]}
145 def get_object(self):
146 return get_object_or_404(PaymentUser, pk=self.request.user.pk)