from decimal import Decimal from django.db.models.deletion import ProtectedError from django.utils.text import gettext_lazy as _ from django.shortcuts import get_object_or_404 from django.db import transaction from rest_framework.viewsets import ModelViewSet from rest_framework.exceptions import ValidationError from rest_framework.permissions import IsAdminUser from shop.api.v1.filters import ProductFilter from shop.api.v1.serializers import ( ProductSerializer, ProductPriceSerializer, CustomerSerializer, TaxSerializer, OrderSerializer, OrderLineSerializer, ProviderSerializer, ProductBatchSerializer, CreateProductSerializer, CreateProductPriceSerializer, TagSerializer, ListProductSerializer, UpdateProductSerializer, BrandSerializer, ) from shop.models import ( Product, ProductPrice, Customer, Tax, Order, OrderLine, Provider, ProductBatch, Tag, Brand, ) from shop.api.v1.permissions import ProductPermissions, ProductPricePermissions 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",)