diff --git a/ecommerce/baskets/filters.py b/ecommerce/baskets/filters.py new file mode 100644 index 0000000..c112498 --- /dev/null +++ b/ecommerce/baskets/filters.py @@ -0,0 +1,22 @@ +from django_filters import rest_framework as filters + +from baskets.models import Basket, BasketItem +from customers.filters import CustomerFilter +from products.filters import ProductFilter + + +class BasketFilter(filters.FilterSet): + customer = CustomerFilter + + class Meta: + model = Basket + fields = ("customer",) + + +class BasketItemFilter(filters.FilterSet): + product = ProductFilter + basket = BasketFilter + + class Meta: + model = BasketItem + fields = ("basket", "product") diff --git a/ecommerce/baskets/serializers.py b/ecommerce/baskets/serializers.py new file mode 100644 index 0000000..f56891d --- /dev/null +++ b/ecommerce/baskets/serializers.py @@ -0,0 +1,25 @@ +from rest_framework import serializers +from baskets.models import Basket, BasketItem +from customers.serializers import CustomerSerializer +from products.serializers import ProductSerializer, ProductDetailedSerializer + + +class BasketSerializer(serializers.ModelSerializer): + class Meta: + model = Basket + fields = ("id", "customer", "status") + + +class BasketItemSerializer(serializers.ModelSerializer): + class Meta: + model = BasketItem + fields = ("id", "basket", "product", "quantity", "price") + + +class BasketDetailedSerializer(BasketSerializer): + customer = CustomerSerializer() + + +class BasketItemDetailedSerializer(BasketItemSerializer): + basket = BasketSerializer() + product = ProductSerializer() diff --git a/ecommerce/baskets/views.py b/ecommerce/baskets/views.py index 91ea44a..1fa0f42 100644 --- a/ecommerce/baskets/views.py +++ b/ecommerce/baskets/views.py @@ -1,3 +1,27 @@ -from django.shortcuts import render +from rest_framework import viewsets -# Create your views here. +from baskets.filters import BasketFilter, BasketItemFilter +from baskets.models import Basket, BasketItem +from baskets.serializers import BasketSerializer, BasketDetailedSerializer, BasketItemSerializer, \ + BasketItemDetailedSerializer +from core.mixins import DetailedViewSetMixin + + +class BasketViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = Basket.objects.all() + serializer_class = BasketSerializer + filterset_class = BasketFilter + serializer_action_classes = { + "detailed_list": BasketDetailedSerializer, + "detailed": BasketDetailedSerializer, + } + + +class BasketItemViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = BasketItem.objects.all() + serializer_class = BasketItemSerializer + filterset_class = BasketItemFilter + serializer_action_classes = { + "detailed_list": BasketItemDetailedSerializer, + "detailed": BasketItemDetailedSerializer, + } \ No newline at end of file diff --git a/ecommerce/customers/filters.py b/ecommerce/customers/filters.py new file mode 100644 index 0000000..414388a --- /dev/null +++ b/ecommerce/customers/filters.py @@ -0,0 +1,41 @@ +from django.utils.translation import gettext_lazy as _ +from django_filters import rest_framework as filters + +from customers.models import City, Country, Customer, Address + + +class CustomerFilter(filters.FilterSet): + first_name = filters.CharFilter(label=_("First Name"), lookup_expr="icontains") + last_name = filters.CharFilter(label=_("Last Name"), lookup_expr="icontains") + email = filters.CharFilter(label=_("Email"), lookup_expr="icontains") + + class Meta: + model = Customer + fields = ("first_name", "last_name", "email") + + +class CountryFilter(filters.FilterSet): + name = filters.CharFilter(label=_("Country Name"), lookup_expr="icontains") + + class Meta: + model = Country + fields = ("name",) + + +class CityFilter(filters.FilterSet): + country = CountryFilter + name = filters.CharFilter(label=_("City Name"), lookup_expr="icontains") + + class Meta: + model = City + fields = ("name", "country") + + +class AddressFilter(filters.FilterSet): + customer = CustomerFilter + name = filters.CharFilter(label=_("Address Name"), lookup_expr="icontains") + city = CityFilter + + class Meta: + model = Address + fields = ("customer", "name", "city") diff --git a/ecommerce/customers/serializers.py b/ecommerce/customers/serializers.py new file mode 100644 index 0000000..21d1416 --- /dev/null +++ b/ecommerce/customers/serializers.py @@ -0,0 +1,53 @@ +from rest_framework import serializers +from django.db.transaction import atomic + +from customers.models import Customer, Address, City, Country + + +class CitySerializer(serializers.ModelSerializer): + class Meta: + model = City + fields = ("id", "name", "country") + + +class CountrySerializer(serializers.ModelSerializer): + class Meta: + model = Country + fields = ("id", "name") + + +class CustomerSerializer(serializers.ModelSerializer): + class Meta: + model = Customer + fields = ("id", "first_name", "last_name", "email") + + +class AddressSerializer(serializers.ModelSerializer): + class Meta: + model = Address + fields = ("id", "customer", "name", "full_name", "line_1", "line_2", + "phone", "district", "zipcode", "city") + + +class AddressDetailedSerializer(AddressSerializer): + customer = CustomerSerializer() + city = CitySerializer() + + +class CityDetailedSerializer(CitySerializer): + country = CountrySerializer() + + class Meta: + model = City + fields = ("id", "name", "country") + + @atomic() + def create(self, validated_data): + country = validated_data.pop("country", None) + city = super().create(validated_data) + if country: + serializer = CountrySerializer(data=country, many=True) + serializer.is_valid(raise_exception=True) + serializer.save() + city.categories.add(*serializer.instance) + return city diff --git a/ecommerce/customers/views.py b/ecommerce/customers/views.py index 91ea44a..99d1310 100644 --- a/ecommerce/customers/views.py +++ b/ecommerce/customers/views.py @@ -1,3 +1,39 @@ -from django.shortcuts import render +from rest_framework import viewsets -# Create your views here. +from core.mixins import DetailedViewSetMixin +from customers.filters import CityFilter, CountryFilter, CustomerFilter, AddressFilter +from customers.models import City, Country, Customer, Address +from customers.serializers import CustomerSerializer, CitySerializer, CountrySerializer, AddressSerializer, \ + CityDetailedSerializer, AddressDetailedSerializer + + +class CityViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = City.objects.all() + serializer_class = CitySerializer + filterset_class = CityFilter + serializer_action_classes = { + "detailed_list": CityDetailedSerializer, + "detailed": CityDetailedSerializer, + } + + +class CountryViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = Country.objects.all() + serializer_class = CountrySerializer + filterset_class = CountryFilter + + +class CustomerViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = Customer.objects.all() + serializer_class = CustomerSerializer + filterset_class = CustomerFilter + + +class AddressViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = Address.objects.all() + serializer_class = AddressSerializer + filterset_class = AddressFilter + serializer_action_classes = { + "detailed_list": AddressDetailedSerializer, + "detailed": AddressDetailedSerializer, + } \ No newline at end of file diff --git a/ecommerce/ecommerce/settings.py b/ecommerce/ecommerce/settings.py index 898a8ee..8d1f879 100644 --- a/ecommerce/ecommerce/settings.py +++ b/ecommerce/ecommerce/settings.py @@ -32,7 +32,6 @@ ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[]) - # Application definition INSTALLED_APPS = [ @@ -54,7 +53,9 @@ ] REST_FRAMEWORK = { - 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'] + 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'], + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', + 'PAGE_SIZE': 100 } MIDDLEWARE = [ @@ -88,13 +89,11 @@ WSGI_APPLICATION = 'ecommerce.wsgi.application' - # Database # https://docs.djangoproject.com/en/3.2/ref/settings/#databases DATABASES = {'default': env.db('DATABASE_URL')} - # Password validation # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators @@ -113,7 +112,6 @@ }, ] - # Internationalization # https://docs.djangoproject.com/en/3.2/topics/i18n/ @@ -138,7 +136,6 @@ def gettext_noop(s): USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/3.2/howto/static-files/ @@ -151,4 +148,4 @@ def gettext_noop(s): DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' AUTH_USER_MODEL = "customers.Customer" -LOCALE_PATHS = (str(BASE_DIR / "locale/"), ) +LOCALE_PATHS = (str(BASE_DIR / "locale/"),) diff --git a/ecommerce/ecommerce/urls.py b/ecommerce/ecommerce/urls.py index 3d9479a..b85c090 100644 --- a/ecommerce/ecommerce/urls.py +++ b/ecommerce/ecommerce/urls.py @@ -18,10 +18,32 @@ from ecommerce.router import router from products.views import ProductViewSet, CategoryViewSet +from payments.views import BankViewSet, BankAccountViewSet +from customers.views import CityViewSet, CountryViewSet, CustomerViewSet, AddressViewSet +from baskets.views import BasketViewSet, BasketItemViewSet +from orders.views import OrderViewSet, BillingAddressViewSet, ShippingAddressViewSet, OrderBankAccountViewSet, \ + OrderItemViewSet router.register("products", ProductViewSet) router.register("categories", CategoryViewSet) +router.register("banks", BankViewSet) +router.register("bank-accounts", BankAccountViewSet) + +router.register("cities", CityViewSet) +router.register("countries", CountryViewSet) +router.register("customers", CustomerViewSet) +router.register("addresses", AddressViewSet) + +router.register("baskets", BasketViewSet) +router.register("basket-items", BasketItemViewSet) + +router.register("orders", OrderViewSet) +router.register("billing-addresses", BillingAddressViewSet) +router.register("shipping-addresses", ShippingAddressViewSet) +router.register("order-bank-accounts", OrderBankAccountViewSet) +router.register("order-items", OrderItemViewSet) + urlpatterns = [ path("api/", include(router.urls)), path('admin/', admin.site.urls), diff --git a/ecommerce/orders/filters.py b/ecommerce/orders/filters.py new file mode 100644 index 0000000..352413a --- /dev/null +++ b/ecommerce/orders/filters.py @@ -0,0 +1,54 @@ +from django_filters import rest_framework as filters +from django.utils.translation import gettext_lazy as _ + +from customers.filters import CityFilter, CustomerFilter +from orders.models import BillingAddress, ShippingAddress, OrderBankAccount, Order, OrderItem +from products.filters import ProductFilter +from baskets.filters import BasketFilter + + +class BillingAddressFilter(filters.FilterSet): + full_name = filters.CharFilter(label=_("Full Name"), lookup_expr="icontains") + city = CityFilter + + class Meta: + model = BillingAddress + fields = ("full_name", "city") + + +class ShippingAddressFilter(filters.FilterSet): + full_name = filters.CharFilter(label=_("Full Name"), lookup_expr="icontains") + city = CityFilter + + class Meta: + model = ShippingAddress + fields = ("full_name", "city") + + +class OrderFilter(filters.FilterSet): + customer = CustomerFilter + basket = BasketFilter + + class Meta: + model = Order + fields = ("customer", "basket") + + +class OrderBankAccountFilter(filters.FilterSet): + name = filters.CharFilter(label=_("Name"), lookup_expr="icontains") + iban = iban = filters.CharFilter(label=_("IBAN"), lookup_expr="icontains") + bank_name = filters.CharFilter(label=_("Bank Name"), lookup_expr="icontains") + order = OrderFilter + + class Meta: + model = OrderBankAccount + fields = ("name", "iban", "bank_name", "order") + + +class OrderItemFilter(filters.FilterSet): + product = ProductFilter + order = OrderFilter + + class Meta: + model = OrderItem + fields = ("order", "product") diff --git a/ecommerce/orders/serializers.py b/ecommerce/orders/serializers.py new file mode 100644 index 0000000..b20f13c --- /dev/null +++ b/ecommerce/orders/serializers.py @@ -0,0 +1,62 @@ +from rest_framework import serializers +from baskets.serializers import BasketSerializer +from customers.serializers import CustomerSerializer, CitySerializer +from orders.models import Order, OrderItem, BillingAddress, ShippingAddress, OrderBankAccount + + +class BillingAddressSerializer(serializers.ModelSerializer): + + class Meta: + model = BillingAddress + fields = ("id", "full_name", "line_1", "line_2", + "phone", "district", "zipcode", "city") + + +class ShippingAddressSerializer(serializers.ModelSerializer): + + class Meta: + model = ShippingAddress + fields = ("id", "full_name", "line_1", "line_2", + "phone", "district", "zipcode", "city") + + +class OrderBankAccountSerializer(serializers.ModelSerializer): + + class Meta: + model = OrderBankAccount + fields = ("id", "name", "iban", "bank_name", "order") + + +class OrderSerializer(serializers.ModelSerializer): + + class Meta: + model = Order + fields = ("id", "customer", "basket", "status", "total_price") + + +class OrderItemSerializer(serializers.ModelSerializer): + + class Meta: + model = OrderItem + fields = ("id", "product", "price", "order") + + +class BillingAddressDetailedSerializer(BillingAddressSerializer): + city = CitySerializer() + + +class ShippingAddressDetailedSerializer(ShippingAddressSerializer): + city = CitySerializer() + + +class OrderBankAccountDetailedSerializer(OrderBankAccountSerializer): + order = OrderSerializer() + + +class OrderDetailedSerializer(OrderSerializer): + basket = BasketSerializer() + customer = CustomerSerializer() + + +class OrderItemDetailedSerializer(OrderItemSerializer): + order = OrderSerializer() diff --git a/ecommerce/orders/views.py b/ecommerce/orders/views.py index 91ea44a..ec95474 100644 --- a/ecommerce/orders/views.py +++ b/ecommerce/orders/views.py @@ -1,3 +1,59 @@ -from django.shortcuts import render +from rest_framework import viewsets -# Create your views here. +from core.mixins import DetailedViewSetMixin +from orders.filters import BillingAddressFilter, ShippingAddressFilter, OrderBankAccountFilter, OrderFilter, \ + OrderItemFilter +from orders.models import BillingAddress, ShippingAddress, OrderBankAccount, Order, OrderItem +from orders.serializers import BillingAddressSerializer, BillingAddressDetailedSerializer, ShippingAddressSerializer, \ + ShippingAddressDetailedSerializer, OrderBankAccountSerializer, OrderBankAccountDetailedSerializer, OrderSerializer, \ + OrderItemSerializer, OrderItemDetailedSerializer, OrderDetailedSerializer + + +class BillingAddressViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = BillingAddress.objects.all() + serializer_class = BillingAddressSerializer + filterset_class = BillingAddressFilter + serializer_action_classes = { + "detailed_list": BillingAddressDetailedSerializer, + "detailed": BillingAddressDetailedSerializer, + } + + +class ShippingAddressViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = ShippingAddress.objects.all() + serializer_class = ShippingAddressSerializer + filterset_class = ShippingAddressFilter + serializer_action_classes = { + "detailed_list": ShippingAddressDetailedSerializer, + "detailed": ShippingAddressDetailedSerializer, + } + + +class OrderBankAccountViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = OrderBankAccount.objects.all() + serializer_class = OrderBankAccountSerializer + filterset_class = OrderBankAccountFilter + serializer_action_classes = { + "detailed_list": OrderBankAccountDetailedSerializer, + "detailed": OrderBankAccountDetailedSerializer, + } + + +class OrderViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = Order.objects.all() + serializer_class = OrderSerializer + filterset_class = OrderFilter + serializer_action_classes = { + "detailed_list": OrderDetailedSerializer, + "detailed": OrderDetailedSerializer, + } + + +class OrderItemViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = OrderItem.objects.all() + serializer_class = OrderItemSerializer + filterset_class = OrderItemFilter + serializer_action_classes = { + "detailed_list": OrderItemDetailedSerializer, + "detailed": OrderItemDetailedSerializer, + } \ No newline at end of file diff --git a/ecommerce/payments/filters.py b/ecommerce/payments/filters.py new file mode 100644 index 0000000..2a11176 --- /dev/null +++ b/ecommerce/payments/filters.py @@ -0,0 +1,22 @@ +from django_filters import rest_framework as filters +from django.utils.translation import gettext_lazy as _ + +from payments.models import Bank, BankAccount + + +class BankFilter(filters.FilterSet): + name = filters.CharFilter(label=_("Bank Name"), lookup_expr="icontains") + + class Meta: + model = Bank + fields = ("name", ) + + +class BankAccountFilter(filters.FilterSet): + name = filters.CharFilter(label=_("Bank Account Name"), lookup_expr="icontains") + iban = filters.CharFilter(label=_("Phone"), lookup_expr="iexact") + bank = BankFilter + + class Meta: + model = BankAccount + fields = ("bank", "name", "iban") diff --git a/ecommerce/payments/serializers.py b/ecommerce/payments/serializers.py new file mode 100644 index 0000000..9d846d0 --- /dev/null +++ b/ecommerce/payments/serializers.py @@ -0,0 +1,31 @@ +from rest_framework import serializers +from django.db.transaction import atomic + +from payments.models import Bank, BankAccount + + +class BankSerializer(serializers.ModelSerializer): + class Meta: + model = Bank + fields = ("id", "name") + + +class BankAccountSerializer(serializers.ModelSerializer): + class Meta: + model = BankAccount + fields = ("id", "bank", "name", "iban") + + +class BankAccountDetailedSerializer(BankAccountSerializer): + bank = BankSerializer() + + @atomic() + def create(self, validated_data): + bank = validated_data.pop("bank", None) + bank_account = super().create(validated_data) + if bank: + serializer = BankSerializer(data=bank, many=True) + serializer.is_valid(raise_exception=True) + serializer.save() + bank_account.categories.add(*serializer.instance) + return bank_account diff --git a/ecommerce/payments/views.py b/ecommerce/payments/views.py index 91ea44a..bf6f9bf 100644 --- a/ecommerce/payments/views.py +++ b/ecommerce/payments/views.py @@ -1,3 +1,21 @@ -from django.shortcuts import render +from rest_framework import viewsets -# Create your views here. +from core.mixins import DetailedViewSetMixin +from payments.filters import BankFilter, BankAccountFilter +from payments.models import Bank, BankAccount +from payments.serializers import BankSerializer, BankAccountSerializer, BankAccountDetailedSerializer + + +class BankViewSet(viewsets.ModelViewSet): + queryset = Bank.objects.all() + serializer_class = BankSerializer + filterset_class = BankFilter + + +class BankAccountViewSet(DetailedViewSetMixin, viewsets.ModelViewSet): + queryset = BankAccount.objects.all() + serializer_class = BankAccountSerializer + filterset_class = BankAccountFilter + serializer_action_classes = { + "detailed_list": BankAccountDetailedSerializer, + "detailed": BankAccountDetailedSerializer, }