svthalia/concrexit

View on GitHub
website/payments/api/v2/admin/views.py

Summary

Maintainability
A
0 mins
Test Coverage
from django.apps import apps
from django.http import Http404
from django.utils.translation import gettext_lazy as _

import rest_framework.filters as framework_filters
from oauth2_provider.contrib.rest_framework import IsAuthenticatedOrTokenHasScope
from rest_framework import serializers, status
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.generics import get_object_or_404
from rest_framework.permissions import IsAdminUser
from rest_framework.response import Response
from rest_framework.settings import api_settings
from rest_framework.views import APIView

from payments import services
from payments.api.v2 import filters
from payments.api.v2.admin.serializers.payable_create import (
    PayableCreateAdminSerializer,
)
from payments.api.v2.admin.serializers.payable_detail import PayableAdminSerializer
from payments.api.v2.admin.serializers.payment import (
    PaymentAdminSerializer,
    PaymentCreateSerializer,
)
from payments.exceptions import PaymentError
from payments.models import Payment, PaymentUser
from payments.payables import NotRegistered, payables
from thaliawebsite.api.v2.admin import (
    AdminCreateAPIView,
    AdminDestroyAPIView,
    AdminListAPIView,
    AdminRetrieveAPIView,
)


class PaymentListCreateView(AdminListAPIView, AdminCreateAPIView):
    """View that allows you to create and list payments as admin."""

    queryset = Payment.objects.prefetch_related(
        "paid_by__profile",
        "paid_by__membership_set",
        "processed_by__profile",
        "processed_by__membership_set",
    )

    required_scopes = ["payments:admin"]
    filter_backends = (
        framework_filters.OrderingFilter,
        filters.CreatedAtFilter,
        filters.PaymentTypeFilter,
    )
    ordering_fields = ("created_at",)

    def get_serializer_class(self):
        if self.request.method.lower() == "post":
            return PaymentCreateSerializer
        return PaymentAdminSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        return Response(
            PaymentAdminSerializer(
                serializer.instance, context=self.get_serializer_context()
            ).data,
            status=status.HTTP_201_CREATED,
        )


class PaymentDetailView(AdminRetrieveAPIView, AdminDestroyAPIView):
    """View that allows you to manage a single payment as admin."""

    queryset = Payment.objects.all()
    serializer_class = PaymentAdminSerializer
    permission_classes = [IsAuthenticatedOrTokenHasScope]
    required_scopes = ["payments:admin"]

    def delete(self, request, *args, **kwargs):
        if self.get_object().batch and self.get_object().batch.processed:
            raise PermissionDenied("This payment cannot be deleted.")
        return super().delete(request, *args, **kwargs)


class PayableDetailView(APIView):
    """View that allows you to manipulate the payment for the payable.

    Permissions of this view are based on the payable.
    """

    required_scopes = ["payments:admin"]
    permission_classes = [IsAuthenticatedOrTokenHasScope, IsAdminUser]

    def get_serializer_context(self):
        return {"request": self.request, "format": self.format_kwarg, "view": self}

    def get_payable(self):
        app_label = self.kwargs["app_label"]
        model_name = self.kwargs["model_name"]
        payable_pk = self.kwargs["payable_pk"]

        try:
            payable_model = apps.get_model(app_label=app_label, model_name=model_name)
            payable = payables.get_payable(
                get_object_or_404(payable_model, pk=payable_pk)
            )
        except (LookupError, NotRegistered) as e:
            raise serializers.ValidationError(
                {api_settings.NON_FIELD_ERRORS_KEY: [_("Payable model not found")]}
            ) from e

        if not payable.can_manage_payment(self.request.member):
            raise PermissionDenied(
                detail=_("You do not have permission to perform this action.")
            )

        return payable

    def get(self, request, *args, **kwargs):
        """Get information about a payable."""
        serializer = PayableAdminSerializer(
            self.get_payable(), context=self.get_serializer_context()
        )
        return Response(serializer.data, status=status.HTTP_200_OK)

    def delete(self, request, *args, **kwargs):
        """Remove the current payment for a payable."""
        payable = self.get_payable()

        if not payable.model.payment:
            raise Http404

        try:
            services.delete_payment(
                payable.model,
                request.member,
            )
            payable.model.save()
        except PaymentError as e:
            raise PermissionDenied(detail=str(e)) from e

        return Response(status=status.HTTP_204_NO_CONTENT)

    def patch(self, request, *args, **kwargs):
        """Mark the payable as paid by creating a payment for it."""
        serializer = PayableCreateAdminSerializer(
            data=request.data, context=self.get_serializer_context()
        )
        serializer.is_valid(raise_exception=True)

        payable = self.get_payable()

        try:
            services.create_payment(
                payable,
                PaymentUser.objects.get(pk=request.user.pk),
                serializer.data["payment_type"],
            )
        except PaymentError as e:
            raise ValidationError(
                detail={api_settings.NON_FIELD_ERRORS_KEY: [str(e)]}
            ) from e

        payable.model.refresh_from_db()
        return Response(
            PayableAdminSerializer(payable, context=self.get_serializer_context()).data,
            status=status.HTTP_201_CREATED,
        )