diff --git a/ecommerce/baskets/models.py b/ecommerce/baskets/models.py index 4f109d5..5751276 100644 --- a/ecommerce/baskets/models.py +++ b/ecommerce/baskets/models.py @@ -38,4 +38,4 @@ class Meta: verbose_name_plural = _("Basket items") def __str__(self): - return f"{self.basket} - {self.product} - {self.quantity} - {self.price}" \ No newline at end of file + return f"{self.basket} - {self.product} - {self.quantity} - {self.price}" diff --git a/ecommerce/baskets/serializers.py b/ecommerce/baskets/serializers.py new file mode 100644 index 0000000..cb3c8b8 --- /dev/null +++ b/ecommerce/baskets/serializers.py @@ -0,0 +1,40 @@ +from rest_framework import serializers +from rest_framework.fields import SerializerMethodField + +from baskets.models import Basket, BasketItem +from products.serializers import NestedProductSerializer + + +class BasketItemSerializer(serializers.ModelSerializer): + class Meta: + model = BasketItem + fields = ("id", "basket", "product", "quantity", "price", "created_at", "modified_at") + + +class NestedBasketItemDetailed(serializers.ModelSerializer): + + product = NestedProductSerializer() + + class Meta: + model = BasketItem + fields = ("id", "basket", "product", "quantity", "price") + + +class BasketSerializer(serializers.ModelSerializer): + class Meta: + model = Basket + fields = ("id", "customer", "status", "created_at", "modified_at") + + +class BasketDetailedSerializer(serializers.ModelSerializer): + items = SerializerMethodField() + + def get_items(self, obj): + basket_item_qset = BasketItem.objects.filter(basket__id=obj.id) + + items = NestedBasketItemDetailed(basket_item_qset, many=True).data + return items + + class Meta: + model = Basket + fields = ("id", "customer", "status", "items", "created_at", "modified_at") diff --git a/ecommerce/baskets/views.py b/ecommerce/baskets/views.py index 91ea44a..e896db0 100644 --- a/ecommerce/baskets/views.py +++ b/ecommerce/baskets/views.py @@ -1,3 +1,19 @@ -from django.shortcuts import render +from rest_framework import viewsets + +from baskets.models import BasketItem, Basket +from baskets.serializers import BasketItemSerializer, BasketSerializer, BasketDetailedSerializer +from core.mixins import DetailedViewSetMixin + + +class BasketItemViewSet(viewsets.ModelViewSet): + queryset = BasketItem.objects.all() + serializer_class = BasketItemSerializer + + +class BasketViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = Basket.objects.all() + serializer_class = BasketSerializer + serializer_action_classes = { + "detailed": BasketDetailedSerializer, + } -# Create your views here. diff --git a/ecommerce/customers/managers.py b/ecommerce/customers/managers.py index c3a7d36..48156f4 100644 --- a/ecommerce/customers/managers.py +++ b/ecommerce/customers/managers.py @@ -6,6 +6,9 @@ class CustomerManager(BaseUserManager): use_in_migrations = True + def non_staff_users(self): + return self.filter(is_staff=False) + def _create_user(self, email, password, **extra_fields): """ Create and save a user with the given username, email, and password. diff --git a/ecommerce/customers/models.py b/ecommerce/customers/models.py index 71f79a6..a851c76 100644 --- a/ecommerce/customers/models.py +++ b/ecommerce/customers/models.py @@ -117,7 +117,8 @@ class Address(BaseAbstractModel): line_1 = models.CharField(max_length=255, verbose_name=_("Address Line 1")) line_2 = models.CharField(max_length=255, verbose_name=_("Address Line 2"), null=True, blank=True) phone = models.CharField( - max_length=20, verbose_name=_("Phone Number"), validators=[phonenumber_validator], help_text=_("Phone number must be entered in the format: +901234567890. ")) + max_length=20, verbose_name=_("Phone Number"), validators=[phonenumber_validator], + help_text=_("Phone number must be entered in the format: +901234567890. ")) district = models.CharField(max_length=255, verbose_name=_("District")) zipcode = models.CharField(max_length=20, verbose_name=_("Zip Code")) city = models.ForeignKey(City, verbose_name=_("City"), on_delete=models.PROTECT) diff --git a/ecommerce/customers/serializers.py b/ecommerce/customers/serializers.py new file mode 100644 index 0000000..0cdc2b5 --- /dev/null +++ b/ecommerce/customers/serializers.py @@ -0,0 +1,63 @@ +from rest_framework import serializers + +from customers.models import Country, City, Customer, Address + + +class NestedCountrySerializer(serializers.ModelSerializer): + class Meta: + model = Country + fields = ("id", "name",) + + +class CountrySerializer(serializers.ModelSerializer): + class Meta: + model = Country + fields = ("id", "name", "created_at", "modified_at") + + +class CitySerializer(serializers.ModelSerializer): + class Meta: + model = City + fields = ("id", "name", "country", "created_at", "modified_at") + + +class CityDetailedSerializer(serializers.ModelSerializer): + + country = NestedCountrySerializer() + + class Meta: + model = City + fields = ("id", "name", "country", "created_at", "modified_at") + + +class NestedCitySerializer(serializers.ModelSerializer): + country = NestedCountrySerializer() + + class Meta: + model = City + fields = ("id", "name", "country") + + +class AddressSerializer(serializers.ModelSerializer): + class Meta: + model = Address + fields = ( + "id", "customer", "name", "full_name", "line_1", "line_2", "phone", "district", "zipcode", "city", + "is_default", "created_at", "modified_at") + + +class AddressDetailedSerializer(serializers.ModelSerializer): + + city = NestedCitySerializer() + + class Meta: + model = Address + fields = ( + "id", "customer", "name", "full_name", "line_1", "line_2", "phone", "district", "zipcode", "city", + "is_default", "created_at", "modified_at") + + +class CustomerSerializer(serializers.ModelSerializer): + class Meta: + model = Customer + fields = ("first_name", "last_name", "email", "date_joined") diff --git a/ecommerce/customers/views.py b/ecommerce/customers/views.py index 91ea44a..b5a009a 100644 --- a/ecommerce/customers/views.py +++ b/ecommerce/customers/views.py @@ -1,3 +1,35 @@ -from django.shortcuts import render +from rest_framework import viewsets -# Create your views here. +from core.mixins import DetailedViewSetMixin +from customers.models import Country, City, Address, Customer +from customers.serializers import CountrySerializer, CitySerializer, AddressSerializer, CustomerSerializer, \ + CityDetailedSerializer, AddressDetailedSerializer + + +class CountryViewSet(viewsets.ModelViewSet): + queryset = Country.objects.all() + serializer_class = CountrySerializer + + +class CityViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = City.objects.all() + serializer_class = CitySerializer + serializer_action_classes = { + "detailed_list": CityDetailedSerializer, + "detailed": CityDetailedSerializer, + } + + +class AddressViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = Address.objects.all() + serializer_class = AddressSerializer + + serializer_action_classes = { + "detailed_list": AddressDetailedSerializer, + "detailed": AddressDetailedSerializer, + } + + +class CustomerViewSet(viewsets.ModelViewSet): + queryset = Customer.objects.non_staff_users() + serializer_class = CustomerSerializer diff --git a/ecommerce/ecommerce/settings.py b/ecommerce/ecommerce/settings.py index 898a8ee..4a7b6cf 100644 --- a/ecommerce/ecommerce/settings.py +++ b/ecommerce/ecommerce/settings.py @@ -152,3 +152,8 @@ def gettext_noop(s): AUTH_USER_MODEL = "customers.Customer" LOCALE_PATHS = (str(BASE_DIR / "locale/"), ) + +REST_FRAMEWORK = { + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', + 'PAGE_SIZE': 2 +} diff --git a/ecommerce/ecommerce/urls.py b/ecommerce/ecommerce/urls.py index 3d9479a..77c52f7 100644 --- a/ecommerce/ecommerce/urls.py +++ b/ecommerce/ecommerce/urls.py @@ -16,11 +16,40 @@ from django.contrib import admin from django.urls import path, include +from baskets.views import BasketItemViewSet, BasketViewSet +from customers.views import CountryViewSet, CityViewSet, AddressViewSet, CustomerViewSet from ecommerce.router import router -from products.views import ProductViewSet, CategoryViewSet +from products.views import ProductViewSet, CategoryViewSet, StockViewSet, PriceViewSet +from payments.views import BankViewSet, BankAccountViewSet +from orders.views import ShippingAddressViewSet, BillingAddressViewSet, OrderBankAccountViewSet, OrderViewSet, \ + OrderItemViewSet +# API endpoints of products app router.register("products", ProductViewSet) router.register("categories", CategoryViewSet) +router.register("stocks", StockViewSet) +router.register("prices", PriceViewSet) + +# API endpoints of customers app +router.register("countries", CountryViewSet) +router.register("cities", CityViewSet) +router.register("addresses", AddressViewSet) +router.register("customers", CustomerViewSet) + +# API endpoints of baskets app +router.register("basket-items", BasketItemViewSet) +router.register("baskets", BasketViewSet) + +# API endpoints of orders app +router.register("billing-addresses", BillingAddressViewSet) +router.register("shipping-addresses", ShippingAddressViewSet) +router.register("order-bank-accounts", OrderBankAccountViewSet) +router.register("orders", OrderViewSet) +router.register("order-items", OrderItemViewSet) + +# API endpoints of payments app +router.register("banks", BankViewSet) +router.register("bank-accounts", BankAccountViewSet) urlpatterns = [ path("api/", include(router.urls)), diff --git a/ecommerce/orders/models.py b/ecommerce/orders/models.py index 238a0aa..7240896 100644 --- a/ecommerce/orders/models.py +++ b/ecommerce/orders/models.py @@ -100,4 +100,4 @@ class Meta: verbose_name_plural = _("Order Items") def __str__(self): - return f"{self.order} - {self.product} - {self.price}" \ No newline at end of file + return f"{self.order} - {self.product} - {self.price}" diff --git a/ecommerce/orders/serializers.py b/ecommerce/orders/serializers.py new file mode 100644 index 0000000..7fe2ae7 --- /dev/null +++ b/ecommerce/orders/serializers.py @@ -0,0 +1,37 @@ +from rest_framework import serializers + +from orders.models import Order, ShippingAddress, BillingAddress, OrderBankAccount, OrderItem + + +class BillingAddressSerializer(serializers.ModelSerializer): + class Meta: + model = BillingAddress + fields = ( + "id", "full_name", "line_1", "line_2", "phone", "district", "zipcode", "city", "created_at", "modified_at") + + +class ShippingAddressSerializer(serializers.ModelSerializer): + class Meta: + model = ShippingAddress + fields = ( + "id", "full_name", "line_1", "line_2", "phone", "district", "zipcode", "city", "created_at", "modified_at") + + +class OrderBankAccountSerializer(serializers.ModelSerializer): + class Meta: + model = OrderBankAccount + fields = ("id", "name", "iban", "bank_name", "order", "created_at", "modified_at") + + +class OrderSerializer(serializers.ModelSerializer): + class Meta: + model = Order + fields = ( + "id", "customer", "basket", "status", "billing_address", "shipping_address", "total_price", "created_at", + "modified_at") + + +class OrderItemSerializer(serializers.ModelSerializer): + class Meta: + model = OrderItem + fields = ("id", "order", "product", "price", "created_at", "modified_at") diff --git a/ecommerce/orders/views.py b/ecommerce/orders/views.py index 91ea44a..9849642 100644 --- a/ecommerce/orders/views.py +++ b/ecommerce/orders/views.py @@ -1,3 +1,30 @@ -from django.shortcuts import render +from rest_framework import viewsets -# Create your views here. +from orders.models import Order, ShippingAddress, BillingAddress, OrderBankAccount, OrderItem +from orders.serializers import BillingAddressSerializer, ShippingAddressSerializer, OrderBankAccountSerializer, \ + OrderSerializer, OrderItemSerializer + + +class BillingAddressViewSet(viewsets.ModelViewSet): + queryset = BillingAddress.objects.all() + serializer_class = BillingAddressSerializer + + +class ShippingAddressViewSet(viewsets.ModelViewSet): + queryset = ShippingAddress.objects.all() + serializer_class = ShippingAddressSerializer + + +class OrderViewSet(viewsets.ModelViewSet): + queryset = Order.objects.all() + serializer_class = OrderSerializer + + +class OrderBankAccountViewSet(viewsets.ModelViewSet): + queryset = OrderBankAccount.objects.all() + serializer_class = OrderBankAccountSerializer + + +class OrderItemViewSet(viewsets.ModelViewSet): + queryset = OrderItem.objects.all() + serializer_class = OrderItemSerializer diff --git a/ecommerce/payments/serializers.py b/ecommerce/payments/serializers.py new file mode 100644 index 0000000..ecf36ec --- /dev/null +++ b/ecommerce/payments/serializers.py @@ -0,0 +1,15 @@ +from rest_framework import serializers + +from payments.models import Bank, BankAccount + + +class BankSerializer(serializers.ModelSerializer): + class Meta: + model = Bank + fields = ("id", "name", "created_at", "modified_at") + + +class BankAccountSerializer(serializers.ModelSerializer): + class Meta: + model = BankAccount + fields = ("id", "name", "bank", "iban", "created_at", "modified_at") diff --git a/ecommerce/payments/views.py b/ecommerce/payments/views.py index 91ea44a..bcf2a93 100644 --- a/ecommerce/payments/views.py +++ b/ecommerce/payments/views.py @@ -1,3 +1,14 @@ -from django.shortcuts import render +from rest_framework import viewsets -# Create your views here. +from payments.models import Bank, BankAccount +from payments.serializers import BankAccountSerializer, BankSerializer + + +class BankViewSet(viewsets.ModelViewSet): + queryset = Bank.objects.all() + serializer_class = BankSerializer + + +class BankAccountViewSet(viewsets.ModelViewSet): + queryset = BankAccount.objects.all() + serializer_class = BankAccountSerializer diff --git a/ecommerce/products/serializers.py b/ecommerce/products/serializers.py index a7eb006..e85f080 100644 --- a/ecommerce/products/serializers.py +++ b/ecommerce/products/serializers.py @@ -1,29 +1,62 @@ from django.db.transaction import atomic from rest_framework import serializers -from products.models import Product, Category +from products.models import Product, Category, Stock, Price -class ProductSerializer(serializers.ModelSerializer): +class CategorySerializer(serializers.ModelSerializer): + class Meta: + model = Category + fields = ("id", "name",) + +class StockSerializer(serializers.ModelSerializer): class Meta: - model = Product - fields = ("id", "sku", "name", "description", "color", "size", "categories", "created_at", "modified_at") + model = Stock + fields = ("id", "product", "quantity", "created_at", "modified_at") -class CategorySerializer(serializers.ModelSerializer): +class NestedStockSerializer(serializers.ModelSerializer): + class Meta: + model = Stock + fields = ("id", "quantity") + +class PriceSerializer(serializers.ModelSerializer): class Meta: - model = Category - fields = ("id", "name", ) + model = Price + fields = ("id", "product", "amount", "created_at", "modified_at") + + +class NestedPriceSerializer(serializers.ModelSerializer): + class Meta: + model = Price + fields = ("id", "amount") + + +class ProductSerializer(serializers.ModelSerializer): + class Meta: + model = Product + fields = ("id", "sku", "name", "description", "color", "size", "categories", "stock", "price", "created_at", + "modified_at") + + +class NestedProductSerializer(serializers.ModelSerializer): + class Meta: + model = Product + fields = ("id", "sku", "name", "color", "size", "categories", "price") class ProductDetailedSerializer(serializers.ModelSerializer): categories = CategorySerializer(many=True) + stock = NestedStockSerializer() + price = NestedPriceSerializer() class Meta: model = Product - fields = ("id", "sku", "name", "description", "color", "size", "categories", "created_at", "modified_at") + fields = ( + "id", "sku", "name", "description", "color", "size", "categories", "stock", "price", "created_at", + "modified_at") @atomic() def create(self, validated_data): @@ -37,4 +70,3 @@ def create(self, validated_data): return product - diff --git a/ecommerce/products/views.py b/ecommerce/products/views.py index fdd33fd..46db87e 100644 --- a/ecommerce/products/views.py +++ b/ecommerce/products/views.py @@ -2,9 +2,9 @@ from core.mixins import DetailedViewSetMixin from products.filters import ProductFilter -from products.models import Product, Category +from products.models import Product, Category, Stock, Price from products.serializers import ProductSerializer, CategorySerializer, \ - ProductDetailedSerializer + ProductDetailedSerializer, StockSerializer, PriceSerializer class ProductViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): @@ -20,3 +20,13 @@ class ProductViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): class CategoryViewSet(viewsets.ModelViewSet): queryset = Category.objects.all() serializer_class = CategorySerializer + + +class StockViewSet(viewsets.ModelViewSet): + queryset = Stock.objects.all() + serializer_class = StockSerializer + + +class PriceViewSet(viewsets.ModelViewSet): + queryset = Price.objects.all() + serializer_class = PriceSerializer