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

1from django.apps import apps 

2from django.utils.translation import gettext_lazy as _ 

3 

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 

10 

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 

21 

22 

23class PaymentListView(ListAPIView): 

24 """Returns an overview of all an authenticated user's payments.""" 

25 

26 queryset = Payment.objects.all() 

27 serializer_class = PaymentSerializer 

28 

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",) 

38 

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 ) 

45 

46 

47class PaymentDetailView(RetrieveAPIView): 

48 """Returns a single payment made by the authenticated user.""" 

49 

50 queryset = Payment.objects.all() 

51 serializer_class = PaymentSerializer 

52 permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] 

53 required_scopes_per_method = {"GET": ["payments:read"]} 

54 

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 ) 

61 

62 

63class PayableDetailView(RetrieveAPIView): 

64 """Allow you to get information about a payable and process it.""" 

65 

66 permission_classes = [IsAuthenticatedOrTokenHasScopeForMethod] 

67 required_scopes_per_method = { 

68 "GET": ["payments:read"], 

69 "PATCH": ["payments:write"], 

70 } 

71 

72 def get_serializer_class(self, *args, **kwargs): 

73 if self.request.method.lower() == "patch": 

74 return EmptySerializer 

75 return PayableSerializer 

76 

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) 

80 

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"] 

85 

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 

95 

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 ) 

104 

105 return payable 

106 

107 def patch(self, request, *args, **kwargs): 

108 payable = self.get_payable() 

109 

110 if payable.payment: 

111 return Response( 

112 data={"detail": _("This object has already been paid for.")}, 

113 status=status.HTTP_409_CONFLICT, 

114 ) 

115 

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 

126 

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 ) 

132 

133 

134class PaymentUserCurrentView(RetrieveAPIView): 

135 """Returns details of the authenticated member.""" 

136 

137 queryset = PaymentUser 

138 serializer_class = PaymentUserSerializer 

139 permission_classes = [ 

140 IsAuthenticatedOrTokenHasScopeForMethod, 

141 ] 

142 

143 required_scopes_per_method = {"GET": ["payments:read"]} 

144 

145 def get_object(self): 

146 return get_object_or_404(PaymentUser, pk=self.request.user.pk)