diff --git a/ecommerce/baskets/models.py b/ecommerce/baskets/models.py index 4f109d5..107fe17 100644 --- a/ecommerce/baskets/models.py +++ b/ecommerce/baskets/models.py @@ -28,7 +28,7 @@ class BasketItem(BaseAbstractModel): """ Basket item model """ - basket = models.ForeignKey(Basket, verbose_name=_("Basket"), on_delete=models.PROTECT) + basket = models.ForeignKey(Basket, verbose_name=_("Basket"), on_delete=models.PROTECT, blank=True) product = models.ForeignKey(Product, verbose_name=_("Product"), on_delete=models.PROTECT) quantity = models.PositiveIntegerField(verbose_name=_("Quantity")) price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name=_("Price")) diff --git a/ecommerce/baskets/views.py b/ecommerce/baskets/views.py index ee32571..8789a2b 100644 --- a/ecommerce/baskets/views.py +++ b/ecommerce/baskets/views.py @@ -1,12 +1,19 @@ from rest_framework import viewsets +from rest_framework.response import Response from baskets.filters import BasketItemFilter, BasketFilter from baskets.models import BasketItem, Basket -from baskets.serializers import BasketItemSerializer, BasketSerializer, BasketItemDetailedSerializer, BasketDetailedSerializer +from baskets.serializers import BasketItemSerializer, BasketSerializer, BasketItemDetailedSerializer, \ + BasketDetailedSerializer from core.mixins import DetailedViewSetMixin +from rest_framework.decorators import action + +from customers.models import Customer class BasketItemViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + permission_classes = () + http_method_names = ["get"] queryset = BasketItem.objects.all() serializer_class = BasketItemSerializer filterset_class = BasketItemFilter @@ -15,12 +22,58 @@ class BasketItemViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): "detailed": BasketItemDetailedSerializer, } + def get_queryset(self): + queryset = super().get_queryset() + user = self.request.user.id + return queryset.filter(basket__customer__id=user) + class BasketViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + permission_classes = () + http_method_names = ["get", "post", "options"] queryset = Basket.objects.all() serializer_class = BasketSerializer filterset_class = BasketFilter serializer_action_classes = { "detailed_list": BasketDetailedSerializer, "detailed": BasketDetailedSerializer, + "add_product": BasketItemSerializer, } + + def get_queryset(self): + queryset = super().get_queryset() + user = self.request.user.id + return queryset.filter(basket__customer__id=user) + + @action(detail=False, methods=["post", "options"]) + def add_product(self, request, pk=None, *args, **kwargs): + """ + Create a new endpoint for adding product to basket item + Check if Basket is exist otherwise create a new one + :param request: request + :param pk: None + :param args: + :param kwargs: + :return: Dictionary + """ + serializer = BasketItemSerializer(data=request.data) + if serializer.is_valid(): + user = self.request.user.id + customer_obj = Customer.objects.filter(id=user).first() + product = serializer.validated_data.get("product") + quantity = serializer.validated_data.get("quantity") + price = serializer.validated_data.get("price") + basket = Basket.objects.filter(customer=customer_obj, status="open").first() + if not basket: + basket = Basket.objects.create(customer=customer_obj, status="open") + basket_item = BasketItem.objects.filter(basket__customer=user, product=product, price=float(str(price))) + if not basket_item: + basket_item = BasketItem.objects.create(basket=basket, product=product, quantity=quantity, price=float(str(price))) + else: + old_qty = basket_item[0].quantity + new_qty = old_qty + float(quantity) + basket_item[0].quantity = new_qty + basket_item[0].save() + serializer_detailed_data = BasketItemDetailedSerializer(basket_item[0]).data + return Response(serializer_detailed_data) + diff --git a/ecommerce/customers/serializers.py b/ecommerce/customers/serializers.py index ffad735..a623745 100644 --- a/ecommerce/customers/serializers.py +++ b/ecommerce/customers/serializers.py @@ -1,3 +1,4 @@ +from django.contrib.auth.password_validation import validate_password from django.utils.translation import gettext_lazy as _ from django.db.transaction import atomic from rest_framework import serializers @@ -7,19 +8,49 @@ class CustomerSerializer(serializers.ModelSerializer): - class Meta: model = Customer fields = ("id", "first_name", "last_name", "email", "is_staff", "is_active", "date_joined") class ProfileSerializer(serializers.ModelSerializer): - class Meta: model = Customer fields = ("first_name", "last_name", "email") +class RegisterSerializer(serializers.ModelSerializer): + """ + Register Serializer for create new user + """ + password = serializers.CharField( + write_only=True, required=True, style={'input_type': 'password', 'placeholder': 'Password'}, + validators=[validate_password]) + password2 = serializers.CharField(write_only=True, required=True) + + def create(self, validated_data): + customer = Customer.objects.create( + first_name=validated_data.get('first_name'), + last_name=validated_data.get('last_name'), + email=validated_data['email'], + ) + customer.set_password(validated_data['password']) + customer.save() + + return customer + + def update(self, instance, validated_data): + instance.first_name = validated_data.get('first_name', instance.first_name) + instance.last_name = validated_data.get('last_name', instance.last_name) + instance.email = validated_data.get('email', instance.email) + instance.save() + return instance + + class Meta: + model = Customer + fields = ("first_name", "last_name", "email", "password", "password2") + + class CountrySerializer(serializers.ModelSerializer): class Meta: model = Country @@ -27,7 +58,6 @@ class Meta: class CitySerializer(serializers.ModelSerializer): - class Meta: model = City fields = ("id", "name", "country") @@ -55,7 +85,8 @@ def validate(self, attrs): return validated_data - def validate_full_name(self, value): + @staticmethod + def validate_full_name(value): if len(value) < 10: raise ValidationError(detail=_("Full name length must be bigger than 10")) return value diff --git a/ecommerce/customers/views.py b/ecommerce/customers/views.py index e2d05b6..c0eb649 100644 --- a/ecommerce/customers/views.py +++ b/ecommerce/customers/views.py @@ -1,3 +1,4 @@ +from django.contrib.auth import logout from django.shortcuts import get_object_or_404 from rest_framework import viewsets, permissions, mixins from rest_framework.viewsets import GenericViewSet @@ -8,7 +9,7 @@ from customers.models import Customer, Address, City, Country from customers.serializers import CustomerSerializer, AddressSerializer, CitySerializer, \ CountrySerializer, \ - AddressDetailedSerializer, CityDetailedSerializer, ProfileSerializer + AddressDetailedSerializer, CityDetailedSerializer, ProfileSerializer, RegisterSerializer class AdminCustomerViewSet(viewsets.ModelViewSet): @@ -51,6 +52,7 @@ class CityViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): class AddressViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + permission_classes = (permissions.IsAuthenticated,) queryset = Address.objects.all() serializer_class = AddressSerializer filterset_class = AddressFilter @@ -65,4 +67,22 @@ def get_queryset(self): return queryset.filter(customer=user) +class RegisterViewSet(mixins.CreateModelMixin, mixins.RetrieveModelMixin, GenericViewSet): + """ + Register new customer endpoint + """ + queryset = Customer.objects.all() + serializer_class = RegisterSerializer + permission_classes = () + http_method_names = ["get", "put", "patch", "options"] + + def get_object(self): + """ + Each customer must see own profile + :return: Customer Object + """ + queryset = self.get_queryset() + filter_kwargs = {"id": self.request.user.id} + obj = get_object_or_404(queryset, **filter_kwargs) + return obj diff --git a/ecommerce/ecommerce/urls.py b/ecommerce/ecommerce/urls.py index 28278ef..3d269aa 100644 --- a/ecommerce/ecommerce/urls.py +++ b/ecommerce/ecommerce/urls.py @@ -21,7 +21,7 @@ from baskets.views import BasketItemViewSet, BasketViewSet from core.views import APITokenObtainPairView from customers.views import AddressViewSet, CityViewSet, \ - CountryViewSet, AdminCustomerViewSet, MyProfileViewSet + CountryViewSet, AdminCustomerViewSet, MyProfileViewSet, RegisterViewSet from ecommerce.router import router from orders.views import OrderItemViewSet, OrderViewSet, BillingAddressViewSet, ShippingAddressViewSet, \ OrderBankAccountViewSet @@ -55,6 +55,7 @@ path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), path('api/profile/', MyProfileViewSet.as_view( {"get": "retrieve", "put": "update", "patch": "partial_update"}), name='profile'), + path('api/register/', RegisterViewSet.as_view({"put": "create", "get": "retrieve"}), name='register') ] if settings.DEBUG: