This commit is contained in:
Mamalizz
2025-03-18 16:30:25 +03:30
13 changed files with 201 additions and 38 deletions
+1
View File
@@ -14,4 +14,5 @@ urlpatterns = [
path('address/<int:pk>', views.GetIDUserAddressView.as_view(), name='get-ID-address'),
path('subscribe', views.SubscribeView.as_view(), name='subscibe'),
path('attack/view/<int:pk>', views.ChangeViewAttack.as_view(), name='attack-view'),
path('logout', views.LogoutView.as_view(), name='logout'),
]
+24 -1
View File
@@ -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')
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)
+1 -2
View File
@@ -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))
@@ -0,0 +1,33 @@
# Generated by Django 5.1.2 on 2025-03-17 13:04
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='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',
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='وضعیت سفارش'),
),
]
@@ -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='قیمت'),
),
]
+15 -15
View File
@@ -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
@@ -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 = 'ایتم سبد خرید'
+12 -1
View File
@@ -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
+50 -8
View File
@@ -46,13 +46,30 @@ 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 = ('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
def get_discount_amount(self, obj):
discount_amount = int(obj.price * (obj.product.discount / 100))
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'{(final_price * obj.quantity):,.0f} تومان'
def get_price(self, obj):
return f'{(obj.price * obj.quantity):,.0f} تومان'
def get_discount(self, obj):
return obj.product.discount
@@ -78,21 +95,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 +113,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()
+2 -1
View File
@@ -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/<int:pk>', CartItemViews.as_view(), name='change-item-cart'),
path('payment', PaymentView.as_view(), name='payment'),
path('callback', callback_view, name='callback-gateway'),
path('<int:pk>', OrderGetView.as_view(), name='order-get'),
]
+25 -3
View File
@@ -8,11 +8,12 @@ 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
from utils.pagination import StructurePagination
from order.models import OrderModel
try:
pass
except DiscountNotAvailableError:
@@ -45,7 +46,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]
@@ -108,7 +116,7 @@ class CartView(APIView):
class OrderlistView(APIView):
permission_classes = [IsAuthenticated]
serializer_class = OrderSerializer
serializer_class = OrderListSerializer
pagination_class = StructurePagination
@extend_schema(
parameters=[
@@ -162,6 +170,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]
+6 -1
View File
@@ -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
+11 -3
View File
@@ -10,8 +10,8 @@ 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
from order.models import OrderModel
# class APIView(APIView):
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
@@ -54,7 +54,15 @@ 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'})
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)
+3 -3
View File
@@ -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', )