from django.core.mail import EmailMessage, EmailMultiAlternatives from django.shortcuts import render from django.template.loader import render_to_string from rest_framework import viewsets, permissions, status from rest_framework.decorators import action from rest_framework.response import Response from bernini import settings from order.models import SaleOrder, SaleOrderLine, Product from order.serializers import ( SaleOrderSerializer, SaleOrderLineSerializer, ProductSerializer, ) class SaleOrderViewSet(viewsets.ModelViewSet): """ API endpoint that allows orders to be viewed or edited. A `SaleOrder` object will render the general sale document that wraps n products a client can buy, using an intermediate model called `SaleOrderLine`, this means: a `SaleOrder` object does not interact directly with a product, a `SaleOrderLine` is just a wrap of a product, which holds its price-per-unit value, and a quantity for that product; lastly, on the other hand, a `SaleOrder` object will hold the total information by doing a sum() operation with all the lines """ queryset = SaleOrder.objects.all().order_by("name") serializer_class = SaleOrderSerializer permission_classes = [permissions.IsAuthenticated] def update(self, request, pk=None, *args, **kwargs): order: SaleOrder = self.get_object() for field in SaleOrder.ReadonlyMeta.readonly: if request.data.get(field) != SaleOrderSerializer(order).data[field]: return Response( data=f"You can't manually set the field {field}", status=status.HTTP_400_BAD_REQUEST, ) return super(SaleOrderViewSet, self).update(request, *args, **kwargs) def partial_update(self, request, pk=None, *args, **kwargs): order: SaleOrder = self.get_object() for field in SaleOrder.ReadonlyMeta.readonly: if request.data.get(field) != SaleOrderSerializer(order).data[field]: return Response( data=f"You can't manually set the field {field}", status=status.HTTP_400_BAD_REQUEST, ) return super(SaleOrderViewSet, self).partial_update(request, *args, **kwargs) @action(detail=True, name="Get the total amount") def total(self, request, pk=None): order: SaleOrder = self.get_object() return Response({"amount_total": order.amount_total}) @action(detail=True) def sold(self, request, pk=None): """ Try to sell a `SaleOrder` object, this is, the sale will have assigned the user which is doing this operation, the persistent total attribute will be set -`total`- and the `sold_at` :param request: :param pk: :return: the object with -possibly- updated values """ return Response( SaleOrderSerializer( self.get_object().sell(request.user), context={"request": request} ).data ) @action(detail=True) def sent(self, request, pk=None): order: SaleOrder = self.get_object() if order.sold_at and order.sold_to.email and settings.EMAIL_HOST_USER: mail = EmailMultiAlternatives( subject=f"Order {order.name} from Zapatos Bernini", from_email=settings.EMAIL_HOST_USER, to=[order.sold_to.email], reply_to=[settings.EMAIL_HOST_USER], ) mail.attach_alternative( render_to_string( template_name="order_sold.html", context={"order": order}, ), mimetype="text/html", ) mail.attach( filename=f"Bernini order {order.name}.csv", content=order.as_csv(), mimetype="text/csv", ) for line in order.saleorderline_set.all(): mail.attach( filename=f"Bernini order {order.name}/{line.name}.csv", content=line.as_csv(), mimetype="text/csv", ) mail.send() return Response( status=status.HTTP_200_OK, data=f"Email sent! You should receive it at {order.sold_to.email}", ) return Response( status=status.HTTP_500_INTERNAL_SERVER_ERROR, data="Something went wrong on our end", ) class SaleOrderLineViewSet(viewsets.ModelViewSet): """ API endpoint that allows orders to be viewed or edited. """ queryset = SaleOrderLine.objects.all().order_by("name") serializer_class = SaleOrderLineSerializer permission_classes = [permissions.IsAuthenticated] class ProductViewSet(viewsets.ReadOnlyModelViewSet): """ API endpoint that allows orders to be viewed or edited """ queryset = Product.objects.all().order_by("name") serializer_class = ProductSerializer permission_classes = [permissions.IsAuthenticatedOrReadOnly]