svthalia/concrexit

View on GitHub
website/pizzas/api/v1/viewsets.py

Summary

Maintainability
A
35 mins
Test Coverage
from django.db import IntegrityError

from rest_framework import permissions
from rest_framework.decorators import action
from rest_framework.exceptions import NotFound, PermissionDenied, ValidationError
from rest_framework.generics import get_object_or_404
from rest_framework.mixins import ListModelMixin
from rest_framework.response import Response
from rest_framework.viewsets import GenericViewSet, ModelViewSet

from payments.api.v1.fields import PaymentTypeField
from payments.services import create_payment, delete_payment
from pizzas.models import FoodEvent, FoodOrder, Product
from pizzas.services import can_change_order

from . import serializers


class PizzaViewset(GenericViewSet, ListModelMixin):
    queryset = Product.available_products.all()
    permission_classes = (permissions.IsAuthenticated,)
    serializer_class = serializers.PizzaSerializer

    def list(self, request, *args, **kwargs):
        if FoodEvent.current() or request.user.has_perm("pizzas.change_product"):
            queryset = self.get_queryset()
            if not request.user.has_perm("pizzas.order_restricted_products"):
                queryset = queryset.exclude(restricted=True)
            serializer = serializers.PizzaSerializer(queryset, many=True)
            return Response(serializer.data)
        raise PermissionDenied

    @action(detail=False)
    def event(self, request):
        event = FoodEvent.current()

        if event:
            context = {"request": request}
            serializer = serializers.PizzaEventSerializer(event, context=context)
            return Response(serializer.data)

        raise NotFound


class OrderViewset(ModelViewSet):
    permission_classes = (permissions.IsAuthenticated,)
    queryset = FoodOrder.objects.all()

    def get_queryset(self):
        event = FoodEvent.current()
        if can_change_order(self.request.member, event):
            return FoodOrder.objects.filter(food_event=event)
        if self.action in ("update", "destroy"):
            if not event or event.has_ended:
                return FoodOrder.objects.none()

            return FoodOrder.objects.filter(
                member=self.request.member,
                payment=None,
                food_event=event,
            )
        return FoodOrder.objects.filter(member=self.request.member, food_event=event)

    def get_serializer_class(self):
        event = FoodEvent.current()
        if can_change_order(self.request.member, event):
            return serializers.AdminOrderSerializer
        return serializers.OrderSerializer

    def get_object(self):
        if self.kwargs.get(self.lookup_field) == "me":
            order = get_object_or_404(
                self.get_queryset(),
                member=self.request.member,
                food_event=FoodEvent.current(),
            )
            self.check_object_permissions(self.request, order)
            return order
        return super().get_object()

    def perform_create(self, serializer):
        try:
            if serializer.validated_data.get("name"):
                serializer.save(food_event=FoodEvent.current())
            elif can_change_order(self.request.member, FoodEvent.current()):
                order = serializer.save(food_event=FoodEvent.current())
                if "payment" in serializer.validated_data:
                    payment_type = serializer.validated_data["payment"]["type"]
                else:
                    payment_type = PaymentTypeField.NO_PAYMENT

                self._update_payment(order, payment_type, self.request.user)
            else:
                serializer.save(
                    member=self.request.member, food_event=FoodEvent.current()
                )
        except IntegrityError as e:
            raise ValidationError(
                "Something went wrong when saving the order" + str(e)
            ) from e

    def perform_update(self, serializer):
        order = serializer.save()
        if "payment" in serializer.validated_data and can_change_order(
            self.request.member, FoodEvent.current()
        ):
            self._update_payment(
                order,
                serializer.validated_data["payment"]["type"],
                self.request.user,
            )

    @staticmethod
    def _update_payment(order, payment_type=None, processed_by=None):
        if order.payment and payment_type == PaymentTypeField.NO_PAYMENT:
            delete_payment(order, processed_by)
        elif payment_type != PaymentTypeField.NO_PAYMENT:
            order.payment = create_payment(order, processed_by, payment_type)
            order.save()