from decimal import Decimal from django.db import transaction from django.db.models.deletion import ProtectedError from django.shortcuts import get_object_or_404 from django.utils.text import gettext_lazy as _ from rest_framework.exceptions import ValidationError from rest_framework.permissions import IsAdminUser from rest_framework.viewsets import ModelViewSet from shop.api.v1.permissions import ProductPermissions, ProductPricePermissions from shop.api.v1.serializers import (BrandSerializer, CreateProductPriceSerializer, CreateProductSerializer, CustomerSerializer, ListProductSerializer, OrderLineSerializer, OrderSerializer, ProductBatchSerializer, ProductPriceSerializer, ProductSerializer, ProviderSerializer, TagSerializer, TaxSerializer, UpdateProductSerializer) from shop.filters import ProductFilter from shop.models import (Brand, Customer, Order, OrderLine, Product, ProductBatch, ProductPrice, Provider, Tag, Tax) from shop.utils import delete_product_batch class ProductViewSet(ModelViewSet): serializer_class = ProductSerializer queryset = ( Product.objects.prefetch_related("prices") .prefetch_related("tags") .prefetch_related("images") .all() ) permission_classes = ( IsAdminUser, ProductPermissions, ) search_fields = ("name",) filterset_class = ProductFilter def get_serializer_class(self): if self.action == "create": return CreateProductSerializer elif self.action == "list": return ListProductSerializer elif self.action in ("update", "partial_update"): return UpdateProductSerializer return self.serializer_class def perform_destroy(self, instance): try: super().perform_destroy(instance) except ProtectedError: raise ValidationError(_("No se puede borrar el producto")) class ProductPriceViewSet(ModelViewSet): serializer_class = ProductPriceSerializer queryset = ProductPrice.objects.all() permission_classes = ( IsAdminUser, ProductPricePermissions, ) def get_queryset(self): return super().get_queryset().filter(product_id=self.kwargs.get("product_id")) def get_serializer_class(self): if self.action == "create": return CreateProductPriceSerializer return self.serializer_class def perform_create(self, serializer): product = get_object_or_404(Product, pk=self.kwargs.get("product_id")) product.prices.all().update(current=False) serializer.save(product=product, current=True) class ProductBatchViewSet(ModelViewSet): serializer_class = ProductBatchSerializer queryset = ProductBatch.objects.all() permission_classes = (IsAdminUser,) def perform_create(self, serializer): instance = serializer.save() product = instance.product product.stock += instance.quantity product.save() def perform_destroy(self, instance): delete_product_batch(instance) def perform_update(self, serializer): instance = self.get_object() product = instance.product product.stock -= instance.quantity updated_batch = serializer.save() product.stock += updated_batch.quantity product.save() class CustomerViewSet(ModelViewSet): serializer_class = CustomerSerializer queryset = Customer.objects.all() permission_classes = (IsAdminUser,) class ProviderViewSet(ModelViewSet): serializer_class = ProviderSerializer queryset = Provider.objects.all() permission_classes = (IsAdminUser,) class TaxViewSet(ModelViewSet): serializer_class = TaxSerializer queryset = Tax.objects.all() permission_classes = (IsAdminUser,) search_fields = ("code",) class OrderViewSet(ModelViewSet): serializer_class = OrderSerializer queryset = Order.objects.all() lookup_field = "uuid" class OrderLineViewSet(ModelViewSet): serializer_class = OrderLineSerializer queryset = OrderLine.objects.all() def perform_create(self, serializer): with transaction.atomic(): order = get_object_or_404(Order, uuid=self.kwargs.get("order_id")) product = serializer.validated_data.get("product") price = product.prices.last() tax = price.tax.value quantity = serializer.validated_data.get("quantity") base_total = quantity * price.price taxes = base_total * (tax / Decimal("100")) total = base_total + taxes instance = serializer.save( order=order, price=price.price, base_total=base_total, tax_value=tax, taxes=taxes, total=total, ) order.base_total += instance.base_total order.total += instance.total order.save() def perform_destroy(self, instance): order = instance.order with transaction.atomic(): order.base_total -= instance.base_total order.total -= instance.total instance.delete() order.save() def get_queryset(self): return ( super() .get_queryset() .select_related("order") .filter(order__uuid=self.kwargs.get("order_id")) ) class TagViewSet(ModelViewSet): serializer_class = TagSerializer queryset = Tag.objects.all() permission_classes = (IsAdminUser,) class BrandViewSet(ModelViewSet): serializer_class = BrandSerializer queryset = Brand.objects.all() permission_classes = (IsAdminUser,) search_fields = ("name",)