From d62bef84ec9f3ed296a064127b7bb13a7380aeee Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 14:29:56 +0330 Subject: [PATCH 01/15] delete discount code --- backend/order/views.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/order/views.py b/backend/order/views.py index a4a9309..bb15291 100644 --- a/backend/order/views.py +++ b/backend/order/views.py @@ -45,7 +45,14 @@ class ApplyDiscountView(APIView): cart_order.save() return Response({'detail': 'کد تخفیف با موفقیت اعمال شد'}, status=status.HTTP_200_OK) - + def delete(self, request): + cart_order, created = OrderModel.objects.get_or_create( + user=request.user, + status='CART' + ) + cart_order.discount_code = None + cart_order.save() + return Response({'detail': 'کد تخفیف با موفقیت حذف شد'}, status=status.HTTP_204_NO_CONTENT) class CartItemClear(APIView): permission_classes = [IsAuthenticated] From f9a339b039d5b22779ef3bc0f44558ffa120394e Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 16:15:38 +0330 Subject: [PATCH 02/15] update order list serializer add get order view and its permission --- ..._ordermodel_tax_alter_ordermodel_status.py | 23 ++++++++++++ ...ermodel_discount_ordermodel_final_price.py | 23 ++++++++++++ backend/order/models.py | 28 +++++++------- backend/order/permissons.py | 13 ++++++- backend/order/serializers.py | 37 ++++++++++++++++--- backend/order/urls.py | 3 +- backend/order/views.py | 18 ++++++++- backend/ticket/serializers.py | 6 +-- 8 files changed, 124 insertions(+), 27 deletions(-) create mode 100644 backend/order/migrations/0021_ordermodel_tax_alter_ordermodel_status.py create mode 100644 backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py diff --git a/backend/order/migrations/0021_ordermodel_tax_alter_ordermodel_status.py b/backend/order/migrations/0021_ordermodel_tax_alter_ordermodel_status.py new file mode 100644 index 0000000..888434b --- /dev/null +++ b/backend/order/migrations/0021_ordermodel_tax_alter_ordermodel_status.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.2 on 2025-03-17 12:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0020_rename_bank_record_ordermodel_bank_records'), + ] + + operations = [ + migrations.AddField( + model_name='ordermodel', + name='tax', + field=models.BigIntegerField(blank=True, null=True, verbose_name='مالیات'), + ), + migrations.AlterField( + model_name='ordermodel', + name='status', + field=models.CharField(choices=[('CART', 'در سبد خرید'), ('ADMIN_PENDING', 'در انتظار تایید'), ('PENDING', 'درحال پردازش'), ('POSTED', 'ارسال شده'), ('RECEIVED', 'تحویل شده'), ('CANCELED', 'لغو شده'), ('REFUNDED', 'مرجوع شده')], max_length=20, verbose_name='وضعیت سفارش'), + ), + ] diff --git a/backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py b/backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py new file mode 100644 index 0000000..7ace70e --- /dev/null +++ b/backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py @@ -0,0 +1,23 @@ +# Generated by Django 5.1.2 on 2025-03-17 12:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0021_ordermodel_tax_alter_ordermodel_status'), + ] + + operations = [ + migrations.AddField( + model_name='ordermodel', + name='discount', + field=models.BigIntegerField(blank=True, null=True, verbose_name='کل تخقیف'), + ), + migrations.AddField( + model_name='ordermodel', + name='final_price', + field=models.BigIntegerField(blank=True, null=True, verbose_name='قیمت نهایی'), + ), + ] diff --git a/backend/order/models.py b/backend/order/models.py index aabb946..d79b3b0 100644 --- a/backend/order/models.py +++ b/backend/order/models.py @@ -59,7 +59,7 @@ class OrderModel(models.Model): bank_records = models.ManyToManyField(Bank, max_length=100, verbose_name='رکورد بانکی', null=True, blank=True) def __str__(self): - return f'سفارش: {self.id}' + return f'سفارش: {self.id + 1000}' class Meta: verbose_name = 'سفارش' @@ -80,27 +80,27 @@ class OrderModel(models.Model): - def discount(self): - # total_with_item_discount = sum(item.total_with_discount() for item in self.items.all()) - # discount_percent = self.discount_code.percent - # return total_with_item_discount * ((100 - discount_percent) / 100) - pass + # def discount(self): + # # total_with_item_discount = sum(item.total_with_discount() for item in self.items.all()) + # # discount_percent = self.discount_code.percent + # # return total_with_item_discount * ((100 - discount_percent) / 100) + # pass - def tax(self): - return self.total_without_tax() * 0.2 + # def tax(self): + # return self.total_without_tax() * 0.2 - def total(self): - pass + # def total(self): + # pass # return self.total_with_discount() + self.tax() - def final_price(self): - pass + # def final_price(self): + # pass - def submit_cart(self): - pass + # def submit_cart(self): + # pass diff --git a/backend/order/permissons.py b/backend/order/permissons.py index 7b0ef86..af60575 100644 --- a/backend/order/permissons.py +++ b/backend/order/permissons.py @@ -1,7 +1,7 @@ from rest_framework.permissions import BasePermission class CanDeleteCartItemPermissions(BasePermission): - message = "شما دسترسی حذف این ایتم رو ندارید" + message = "شما دسترسی حذف این ایتم را ندارید" def has_object_permission(self, request, view, obj): if obj.order.user != request.user: @@ -12,4 +12,15 @@ class CanDeleteCartItemPermissions(BasePermission): self.message = "وضعیت سفارش سبد خرید نیست و آیتمی را نمی‌توانید حذف کنید." return False + return True + + +class GetOrderPermission(BasePermission): + message = "شما دسترسی به این سفارش را ندارید" + def has_object_permission(self, request, view, obj): + if obj.user != request.user: + return False + if obj.status != 'CART': + self.message = "سفارش در وضعیت سبد خرید است" + return False return True \ No newline at end of file diff --git a/backend/order/serializers.py b/backend/order/serializers.py index ce2edc3..2aa58b4 100644 --- a/backend/order/serializers.py +++ b/backend/order/serializers.py @@ -78,21 +78,17 @@ class CartSerializer(serializers.ModelSerializer): return None - - - def get_tax(self, obj): return f'{1000:,.0f} تومان' def get_cart_total(self, obj): - return f'{10000:,.0f} تومان' - def get_final_price(self, obj): + def get_final_price(self, obj): return f'{8000:,.0f} تومان' -class OrderSerializer(serializers.ModelSerializer): +class OrderListSerializer(serializers.ModelSerializer): count = serializers.SerializerMethodField() images = serializers.SerializerMethodField() order_id = serializers.SerializerMethodField() @@ -100,6 +96,35 @@ class OrderSerializer(serializers.ModelSerializer): class Meta: model = OrderModel fields = ['created_at', 'status', "images", "count", "id", 'final_price', 'order_id', 'verbose_status'] + read_only_fields = ['count', 'images', 'order_id', 'verbose_status'] + def get_verbose_status(self, obj): + return obj.get_status_display() + + def get_count(self, obj): + return obj.items.all().count() + + def get_images(self, obj): + image_list = [ + self.context.get('request').build_absolute_uri(image.image.url) + if (image := item.product.images.all().first()) else None + for item in obj.items.all()[:3] + ] + return filter(lambda x: x is not None, image_list) + def get_order_id(self, obj): + return obj.id + 1000 + + +class OrderGetSerializer(serializers.ModelSerializer): + count = serializers.SerializerMethodField() + images = serializers.SerializerMethodField() + order_id = serializers.SerializerMethodField() + verbose_status = serializers.SerializerMethodField() + items = OrderItemSerailzier(many=True) + address = UserAddressSerializer() + discount_code = DiscountCodeSerializer() + class Meta: + model = OrderModel + fields = ['created_at', 'status', "images", "count", "id", 'final_price', 'order_id', 'verbose_status', 'address', 'items', 'tax' , 'cart_total', 'discount_code', 'discount'] def get_verbose_status(self, obj): return obj.get_status_display() diff --git a/backend/order/urls.py b/backend/order/urls.py index c439005..969c612 100644 --- a/backend/order/urls.py +++ b/backend/order/urls.py @@ -1,7 +1,7 @@ from django.conf.urls.static import static from django.contrib import admin from django.urls import path, include -from .views import CartItemViews, CartView, OrderlistView, CartItemClear, ApplyDiscountView +from .views import CartItemViews, CartView, OrderlistView, CartItemClear, ApplyDiscountView, OrderGetView from .views import PaymentView, callback_view urlpatterns = [ @@ -12,4 +12,5 @@ urlpatterns = [ path('cart/item/', CartItemViews.as_view(), name='change-item-cart'), path('payment', PaymentView.as_view(), name='payment'), path('callback', callback_view, name='callback-gateway'), + path('', OrderGetView.as_view(), name='order-get'), ] diff --git a/backend/order/views.py b/backend/order/views.py index bb15291..5055e6b 100644 --- a/backend/order/views.py +++ b/backend/order/views.py @@ -8,7 +8,7 @@ from .serializers import * # from cart.models import from rest_framework import status from .models import OrderItemModel, OrderModel, DiscountCode -from .permissons import CanDeleteCartItemPermissions +from .permissons import CanDeleteCartItemPermissions, GetOrderPermission from azbankgateways import bankfactories, models as bank_models from azbankgateways.exceptions import AZBankGatewaysException from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes @@ -115,7 +115,7 @@ class CartView(APIView): class OrderlistView(APIView): permission_classes = [IsAuthenticated] - serializer_class = OrderSerializer + serializer_class = OrderListSerializer pagination_class = StructurePagination @extend_schema( parameters=[ @@ -169,6 +169,20 @@ class OrderlistView(APIView): +class OrderGetView(APIView): + permission_classes = [IsAuthenticated, GetOrderPermission] + serializer_class = OrderGetSerializer + def get(self, request, pk): + order_object = get_object_or_404(OrderModel, pk=pk) + + + permission = GetOrderPermission() + if not permission.has_object_permission(request, self, order_object): + return Response({"detail": permission.message}, status=status.HTTP_403_FORBIDDEN) + + + order_ser = self.serializer_class(order_object, context={'request': request}) + return Response(order_ser.data, status=status.HTTP_200_OK) class PaymentView(APIView): permission_classes = [IsAuthenticated] diff --git a/backend/ticket/serializers.py b/backend/ticket/serializers.py index 6be7138..d99a8d2 100644 --- a/backend/ticket/serializers.py +++ b/backend/ticket/serializers.py @@ -1,7 +1,7 @@ from rest_framework import serializers from .models import Ticket, Message, Attachment from django.utils.timezone import localtime -from order.serializers import OrderSerializer +from order.serializers import OrderListSerializer from order.serializers import OrderModel class AttachmentSerializer(serializers.ModelSerializer): @@ -50,7 +50,7 @@ class TicketSerializer(serializers.ModelSerializer): messages = MessageAttachmentSerializer(many=True, read_only=True) message = MessageForTicketSerializer(write_only=True) order_id = serializers.PrimaryKeyRelatedField(queryset=OrderModel.objects.all(), write_only=True, source='order') - order = OrderSerializer(read_only=True) + order = OrderListSerializer(read_only=True) class Meta: model = Ticket exclude = ('customer', 'admin') @@ -79,7 +79,7 @@ class TicketSerializer(serializers.ModelSerializer): class TicketListSerializer(serializers.ModelSerializer): status = serializers.SerializerMethodField() ticket_category = serializers.SerializerMethodField() - order = OrderSerializer() + order = OrderListSerializer() class Meta: model = Ticket exclude = ('customer', 'admin', ) From 35b81ea6ac598a087f3560d3e9698e9e4a271e04 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 16:31:37 +0330 Subject: [PATCH 03/15] test --- .../migrations/0021_ordermodel_tax_alter_ordermodel_status.py | 1 + .../0022_ordermodel_discount_ordermodel_final_price.py | 1 + 2 files changed, 2 insertions(+) diff --git a/backend/order/migrations/0021_ordermodel_tax_alter_ordermodel_status.py b/backend/order/migrations/0021_ordermodel_tax_alter_ordermodel_status.py index 888434b..4115b50 100644 --- a/backend/order/migrations/0021_ordermodel_tax_alter_ordermodel_status.py +++ b/backend/order/migrations/0021_ordermodel_tax_alter_ordermodel_status.py @@ -21,3 +21,4 @@ class Migration(migrations.Migration): field=models.CharField(choices=[('CART', 'در سبد خرید'), ('ADMIN_PENDING', 'در انتظار تایید'), ('PENDING', 'درحال پردازش'), ('POSTED', 'ارسال شده'), ('RECEIVED', 'تحویل شده'), ('CANCELED', 'لغو شده'), ('REFUNDED', 'مرجوع شده')], max_length=20, verbose_name='وضعیت سفارش'), ), ] + diff --git a/backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py b/backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py index 7ace70e..ec48cb9 100644 --- a/backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py +++ b/backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py @@ -21,3 +21,4 @@ class Migration(migrations.Migration): field=models.BigIntegerField(blank=True, null=True, verbose_name='قیمت نهایی'), ), ] + From ef776192b8fe00c3d2261f0f4c08da213a5f2f01 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 16:35:47 +0330 Subject: [PATCH 04/15] fix migrations problem --- ...scount_ordermodel_final_price_and_more.py} | 13 ++++++++-- ...ermodel_discount_ordermodel_final_price.py | 24 ------------------- 2 files changed, 11 insertions(+), 26 deletions(-) rename backend/order/migrations/{0021_ordermodel_tax_alter_ordermodel_status.py => 0021_ordermodel_discount_ordermodel_final_price_and_more.py} (65%) delete mode 100644 backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py diff --git a/backend/order/migrations/0021_ordermodel_tax_alter_ordermodel_status.py b/backend/order/migrations/0021_ordermodel_discount_ordermodel_final_price_and_more.py similarity index 65% rename from backend/order/migrations/0021_ordermodel_tax_alter_ordermodel_status.py rename to backend/order/migrations/0021_ordermodel_discount_ordermodel_final_price_and_more.py index 4115b50..c466457 100644 --- a/backend/order/migrations/0021_ordermodel_tax_alter_ordermodel_status.py +++ b/backend/order/migrations/0021_ordermodel_discount_ordermodel_final_price_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.2 on 2025-03-17 12:15 +# Generated by Django 5.1.2 on 2025-03-17 13:04 from django.db import migrations, models @@ -10,6 +10,16 @@ class Migration(migrations.Migration): ] operations = [ + migrations.AddField( + model_name='ordermodel', + name='discount', + field=models.BigIntegerField(blank=True, null=True, verbose_name='کل تخقیف'), + ), + migrations.AddField( + model_name='ordermodel', + name='final_price', + field=models.BigIntegerField(blank=True, null=True, verbose_name='قیمت نهایی'), + ), migrations.AddField( model_name='ordermodel', name='tax', @@ -21,4 +31,3 @@ class Migration(migrations.Migration): field=models.CharField(choices=[('CART', 'در سبد خرید'), ('ADMIN_PENDING', 'در انتظار تایید'), ('PENDING', 'درحال پردازش'), ('POSTED', 'ارسال شده'), ('RECEIVED', 'تحویل شده'), ('CANCELED', 'لغو شده'), ('REFUNDED', 'مرجوع شده')], max_length=20, verbose_name='وضعیت سفارش'), ), ] - diff --git a/backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py b/backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py deleted file mode 100644 index ec48cb9..0000000 --- a/backend/order/migrations/0022_ordermodel_discount_ordermodel_final_price.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 5.1.2 on 2025-03-17 12:15 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('order', '0021_ordermodel_tax_alter_ordermodel_status'), - ] - - operations = [ - migrations.AddField( - model_name='ordermodel', - name='discount', - field=models.BigIntegerField(blank=True, null=True, verbose_name='کل تخقیف'), - ), - migrations.AddField( - model_name='ordermodel', - name='final_price', - field=models.BigIntegerField(blank=True, null=True, verbose_name='قیمت نهایی'), - ), - ] - From 6f3354920040db252d55c38fe156c75111fbfad4 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 16:48:38 +0330 Subject: [PATCH 05/15] send price in serializer --- backend/order/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/order/serializers.py b/backend/order/serializers.py index 2aa58b4..a4a9f63 100644 --- a/backend/order/serializers.py +++ b/backend/order/serializers.py @@ -48,8 +48,8 @@ class OrderItemSerailzier(serializers.ModelSerializer): product = serializers.SerializerMethodField() class Meta: model = OrderItemModel - exclude = ('price', 'order') - read_only_fields = ('order', 'product', ) + exclude = ('order',) + read_only_fields = ('order', 'product',) def get_product(self, obj): return ProductVariantSerialzier(instance=obj.product, context={'request': self.context.get('request')}).data From dc449c834733a390fbc2fa7fb3ecfb37cc1f206d Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 17:09:01 +0330 Subject: [PATCH 06/15] update order item serilizer --- backend/order/serializers.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/backend/order/serializers.py b/backend/order/serializers.py index a4a9f63..c02a393 100644 --- a/backend/order/serializers.py +++ b/backend/order/serializers.py @@ -46,6 +46,10 @@ class DiscountCodeSerializer(serializers.ModelSerializer): class OrderItemSerailzier(serializers.ModelSerializer): product = serializers.SerializerMethodField() + discount_amount = serializers.SerializerMethodField() + price = serializers.SerializerMethodField() + final_price = serializers.SerializerMethodField() + discount = serializers.SerializerMethodField() class Meta: model = OrderItemModel exclude = ('order',) @@ -53,6 +57,19 @@ class OrderItemSerailzier(serializers.ModelSerializer): def get_product(self, obj): return ProductVariantSerialzier(instance=obj.product, context={'request': self.context.get('request')}).data + def get_discount_amount(self, obj): + discount_amount = int(obj.price * (obj.product.discount / 100)) + return f'{():,.0f} تومان' + + def get_final_price(self, obj): + final_price = obj.price - int(obj.price * (obj.product.discount / 100)) + return f'{():,.0f} تومان' + + def get_price(self, obj): + return f'{(obj.price * obj.quantity):,.0f} تومان' + + def get_discount(self, obj): + return obj.product.discount From 966b6bf538ff6996351e440bea3a315842925a0c Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 17:28:05 +0330 Subject: [PATCH 07/15] debug cart serializer --- backend/order/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/order/serializers.py b/backend/order/serializers.py index c02a393..f25a84f 100644 --- a/backend/order/serializers.py +++ b/backend/order/serializers.py @@ -59,11 +59,11 @@ class OrderItemSerailzier(serializers.ModelSerializer): def get_discount_amount(self, obj): discount_amount = int(obj.price * (obj.product.discount / 100)) - return f'{():,.0f} تومان' + return f'{(discount_amount * obj.quantity):,.0f} تومان' def get_final_price(self, obj): final_price = obj.price - int(obj.price * (obj.product.discount / 100)) - return f'{():,.0f} تومان' + return f'{(final_price * obj.quantity):,.0f} تومان' def get_price(self, obj): return f'{(obj.price * obj.quantity):,.0f} تومان' From 57e19c5abb4fe7d3637d0fa3668949b1d38eb0f5 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 17:38:00 +0330 Subject: [PATCH 08/15] test of in cart quantity --- backend/product/serializers.py | 7 ++++++- backend/product/views.py | 7 +++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/backend/product/serializers.py b/backend/product/serializers.py index cd65826..135e7da 100644 --- a/backend/product/serializers.py +++ b/backend/product/serializers.py @@ -65,7 +65,12 @@ class ProductVariantSerialzier(serializers.ModelSerializer): request = self.context.get('request') if not request or not request.user.is_authenticated: return 0 - return 1 + cart_items = self.context.get('cart_items', []) + if cart_items: + for item in cart_items: + if item['product']['id'] == obj.id: + return item['quantity'] + return 0 diff --git a/backend/product/views.py b/backend/product/views.py index 79b1c60..41aa520 100644 --- a/backend/product/views.py +++ b/backend/product/views.py @@ -10,7 +10,7 @@ from rest_framework.permissions import IsAuthenticatedOrReadOnly from utils.pagination import StructurePagination from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes from rest_framework.permissions import AllowAny - +from order.serializers import OrderItemSerailzier # class APIView(APIView): # def __init__(self, *args, **kwargs): @@ -54,7 +54,10 @@ class ProductView(APIView): # authentication_classes = [] def get(self, request, pk): product = get_object_or_404(ProductModel, id=pk) - product_ser = self.serializer_class(instance=product, many=False, context={'request': request, 'view_type': 'instance'}) + cart_obj, _ = OrderModel.objects.get_or_create(user=request.user, status='CART') + cart_items = cart_obj.items.all() + cart_items_ser = OrderItemSerailzier(cart_items, many=True) + product_ser = self.serializer_class(instance=product, many=False, context={'request': request, 'view_type': 'instance', 'cart_items': cart_items_ser.data}) return Response(product_ser.data, status=status.HTTP_200_OK) From a5f881171c15fbff3fa9c97d93a0fe77a23437d7 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 17:41:16 +0330 Subject: [PATCH 09/15] import ordermodel --- backend/order/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/order/views.py b/backend/order/views.py index 5055e6b..d797810 100644 --- a/backend/order/views.py +++ b/backend/order/views.py @@ -13,6 +13,7 @@ from azbankgateways import bankfactories, models as bank_models from azbankgateways.exceptions import AZBankGatewaysException from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes from utils.pagination import StructurePagination +from order.models import OrderModel try: pass except DiscountNotAvailableError: From fb3da6bcaa54d5dd526689762253eb9c1e0b724a Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 17:44:16 +0330 Subject: [PATCH 10/15] import OrderModel --- backend/product/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/product/views.py b/backend/product/views.py index 41aa520..414c5df 100644 --- a/backend/product/views.py +++ b/backend/product/views.py @@ -11,7 +11,7 @@ from utils.pagination import StructurePagination from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes from rest_framework.permissions import AllowAny from order.serializers import OrderItemSerailzier - +from order.models import OrderModel # class APIView(APIView): # def __init__(self, *args, **kwargs): # super().__init__(*args, **kwargs) From 0496e23680e45ef39342d34df34d174d41a52633 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 17:50:09 +0330 Subject: [PATCH 11/15] context for item serializer --- backend/product/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/product/views.py b/backend/product/views.py index 414c5df..545fc4e 100644 --- a/backend/product/views.py +++ b/backend/product/views.py @@ -56,7 +56,7 @@ class ProductView(APIView): product = get_object_or_404(ProductModel, id=pk) cart_obj, _ = OrderModel.objects.get_or_create(user=request.user, status='CART') cart_items = cart_obj.items.all() - cart_items_ser = OrderItemSerailzier(cart_items, many=True) + cart_items_ser = OrderItemSerailzier(cart_items, many=True, context={'request': request}) product_ser = self.serializer_class(instance=product, many=False, context={'request': request, 'view_type': 'instance', 'cart_items': cart_items_ser.data}) return Response(product_ser.data, status=status.HTTP_200_OK) From 58cb417ef91065ecb6ee7400667a5b385ba50dfd Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 17:56:22 +0330 Subject: [PATCH 12/15] defualy price --- .../0022_alter_orderitemmodel_price.py | 18 ++++++++++++++++++ backend/order/models.py | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 backend/order/migrations/0022_alter_orderitemmodel_price.py diff --git a/backend/order/migrations/0022_alter_orderitemmodel_price.py b/backend/order/migrations/0022_alter_orderitemmodel_price.py new file mode 100644 index 0000000..7471b3c --- /dev/null +++ b/backend/order/migrations/0022_alter_orderitemmodel_price.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1.2 on 2025-03-17 14:26 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0021_ordermodel_discount_ordermodel_final_price_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='orderitemmodel', + name='price', + field=models.PositiveIntegerField(default=0, verbose_name='قیمت'), + ), + ] diff --git a/backend/order/models.py b/backend/order/models.py index d79b3b0..0e5f02f 100644 --- a/backend/order/models.py +++ b/backend/order/models.py @@ -108,7 +108,7 @@ class OrderModel(models.Model): class OrderItemModel(models.Model): order = models.ForeignKey(OrderModel, on_delete=models.CASCADE, related_name='items', verbose_name='سفارش') quantity = models.PositiveSmallIntegerField(verbose_name="تعداد") - price = models.PositiveIntegerField(verbose_name='قیمت', blank=True, null=True) + price = models.PositiveIntegerField(verbose_name='قیمت', default=0) product = models.ForeignKey(ProductVariant, on_delete=models.PROTECT, verbose_name="محصول") class Meta: verbose_name = 'ایتم سبد خرید' From b15aaa52711a9792a85de19a54ff2b3407a39d31 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 18:05:24 +0330 Subject: [PATCH 13/15] fix in cart quantity 12323233 --- backend/product/views.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/backend/product/views.py b/backend/product/views.py index 545fc4e..ccc51ee 100644 --- a/backend/product/views.py +++ b/backend/product/views.py @@ -54,10 +54,15 @@ class ProductView(APIView): # authentication_classes = [] def get(self, request, pk): product = get_object_or_404(ProductModel, id=pk) - cart_obj, _ = OrderModel.objects.get_or_create(user=request.user, status='CART') - cart_items = cart_obj.items.all() - cart_items_ser = OrderItemSerailzier(cart_items, many=True, context={'request': request}) - product_ser = self.serializer_class(instance=product, many=False, context={'request': request, 'view_type': 'instance', 'cart_items': cart_items_ser.data}) + if request.user.is_authenticated: + cart_obj, _ = OrderModel.objects.get_or_create(user=request.user, status='CART') + cart_items = cart_obj.items.all() + cart_items_ser = OrderItemSerailzier(cart_items, many=True, context={'request': request}) + product_ser_context = {'request': request, 'view_type': 'instance', 'cart_items': cart_items_ser.data} + else: + product_ser_context = {'request': request, 'view_type': 'instance'} + + product_ser = self.serializer_class(instance=product, many=False, context=product_ser_context) return Response(product_ser.data, status=status.HTTP_200_OK) From 75dd8abbc1e9c3b08bfef4c21e262cec895041c6 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 18:27:43 +0330 Subject: [PATCH 14/15] logout view --- backend/account/urls.py | 1 + backend/account/views.py | 25 ++++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/backend/account/urls.py b/backend/account/urls.py index efdc99e..f3cb639 100644 --- a/backend/account/urls.py +++ b/backend/account/urls.py @@ -14,4 +14,5 @@ urlpatterns = [ path('address/', views.GetIDUserAddressView.as_view(), name='get-ID-address'), path('subscribe', views.SubscribeView.as_view(), name='subscibe'), path('attack/view/', views.ChangeViewAttack.as_view(), name='attack-view'), + path('logout', views.LogoutView.as_view(), name='logout'), ] \ No newline at end of file diff --git a/backend/account/views.py b/backend/account/views.py index 64d6fac..2b52687 100644 --- a/backend/account/views.py +++ b/backend/account/views.py @@ -195,4 +195,27 @@ class ChangeViewAttack(View): attack = get_object_or_404(SecurityBreachAttemptModel, pk=pk) attack.viewd = not attack.viewd attack.save() - return redirect('admin:account_securitybreachattemptmodel_changelist') \ No newline at end of file + return redirect('admin:account_securitybreachattemptmodel_changelist') + + +from rest_framework import serializers +from rest_framework_simplejwt.tokens import RefreshToken + +class LogoutSerializer(serializers.Serializer): + refresh_token = serializers.CharField(help_text="Refresh token to be blacklisted") + +class LogoutView(APIView): + permission_classes = (IsAuthenticated,) + + @extend_schema( + request=LogoutSerializer, + responses={205: None, 400: "Bad request (invalid token or missing data)"}, + ) + def post(self, request): + try: + refresh_token = request.data["refresh_token"] + token = RefreshToken(refresh_token) + token.blacklist() + return Response(status=status.HTTP_205_RESET_CONTENT) + except Exception as e: + return Response(status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file From 062001ef0e8abfefc6cb80dd2a17f55f42391a87 Mon Sep 17 00:00:00 2001 From: Parsa Nazer Date: Mon, 17 Mar 2025 21:12:51 +0330 Subject: [PATCH 15/15] correct error message scurtiy breach --- backend/core/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/core/views.py b/backend/core/views.py index 6dbeb76..d57f36a 100644 --- a/backend/core/views.py +++ b/backend/core/views.py @@ -288,6 +288,5 @@ class FakeAdminLoginView(View): hacker, created = SecurityBreachAttemptModel.objects.get_or_create(ip_address=ip) hacker.trys += 1 hacker.save() - messages.error(request, "Please correct the error below.") - messages.error(request, "Please enter the correct شماره تماس and password for a staff account. Note that both fields may be case-sensitive.") + messages.error(request, "لطفا شماره تماس و گذرواژه را برای یک حساب کارمند وارد کنید. توجه داشته باشید که ممکن است هر دو به کوچکی و بزرگی حروف حساس باشند.") return render(request, 'admin/fake_login.html', self.get_context(request)) \ No newline at end of file