Compare commits
10 Commits
f9f7e63a07
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd67401574 | ||
|
|
5f32e8e8a7 | ||
|
|
b3d8a696e7 | ||
|
|
11f0402c4c | ||
|
|
29b1b3c86e | ||
|
|
51697bcbad | ||
|
|
23d79ea85a | ||
|
|
421f585721 | ||
|
|
23fdc55d0e | ||
|
|
2bdd10f388 |
@@ -3,7 +3,9 @@ CORS_ALLOWED_ORIGINS = [
|
||||
"http://localhost:3000",
|
||||
"http://127.0.0.1:5173",
|
||||
'https://agro365.vercel.app',
|
||||
'https://agro365.felixits.uz',
|
||||
'https://agro365-admin.vercel.app',
|
||||
'https://agro365-admin.felixits.uz',
|
||||
]
|
||||
|
||||
CSRF_TRUSTED_ORIGINS = [
|
||||
|
||||
@@ -7,4 +7,3 @@ from core.apps.shared.models.base import BaseModel
|
||||
class User(AbstractUser, BaseModel):
|
||||
tg_id = models.CharField(max_length=20, null=True, blank=True)
|
||||
|
||||
|
||||
|
||||
@@ -16,4 +16,12 @@ class CustomUserLoginSerializer(serializers.Serializer):
|
||||
user.tg_id = data.get('tg_id')
|
||||
user.save()
|
||||
data['user'] = user
|
||||
return data
|
||||
return data
|
||||
|
||||
|
||||
class UserListSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
'id', 'tg_id'
|
||||
]
|
||||
@@ -9,4 +9,5 @@ urlpatterns = [
|
||||
path('login/', user.UserLoginApiView.as_view()),
|
||||
path('<uuid:product_id>/like/', like_views.LikeApiView.as_view()),
|
||||
path('liked_products/', like_views.LikeProductListApiView.as_view()),
|
||||
path('user/list/', user.UserListApiView.as_view()),
|
||||
]
|
||||
@@ -31,4 +31,4 @@ class LikeProductListApiView(generics.GenericAPIView):
|
||||
serializer = self.serializer_class(page, many=True, context={'user': request.user})
|
||||
return self.get_paginated_response(serializer.data)
|
||||
serializer = self.serializer_class(products, many=True, context={'user': request.user})
|
||||
return Response(serializer.data, status=200)
|
||||
return Response(serializer.data, status=200)
|
||||
@@ -1,9 +1,9 @@
|
||||
from rest_framework import generics
|
||||
from rest_framework import generics, views
|
||||
from rest_framework.response import Response
|
||||
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
|
||||
from ..serializers.user import CustomUserLoginSerializer
|
||||
from ..serializers.user import CustomUserLoginSerializer, UserListSerializer
|
||||
from core.apps.accounts.models import User
|
||||
|
||||
|
||||
@@ -17,4 +17,12 @@ class UserLoginApiView(generics.GenericAPIView):
|
||||
user = serializer.validated_data.get('user')
|
||||
token = RefreshToken.for_user(user)
|
||||
return Response({'access': str(token.access_token), 'refresh': str(token)})
|
||||
return Response(data=serializer.errors)
|
||||
return Response(data=serializer.errors)
|
||||
|
||||
|
||||
class UserListApiView(views.APIView):
|
||||
def get(self, request):
|
||||
users = User.objects.exclude(tg_id__isnull=True)
|
||||
serializer = UserListSerializer(users, many=True)
|
||||
return Response(serializer.data, status=200)
|
||||
|
||||
@@ -19,6 +19,7 @@ class OrderItemSerializer(serializers.ModelSerializer):
|
||||
'name_ru': obj.product.name_ru,
|
||||
'price': obj.product.price,
|
||||
'code': obj.product.code,
|
||||
'unity': obj.product.unity.name,
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +30,7 @@ class OrderSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Order
|
||||
fields = [
|
||||
'id', 'order_number', 'total_price', 'user', 'payment_type', 'delivery_type',
|
||||
'id', 'order_number', 'status', 'total_price', 'user', 'payment_type', 'delivery_type',
|
||||
'delivery_price', 'contact_number', 'comment', 'name', 'items', 'created_at'
|
||||
]
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ class AdminProductListSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = [
|
||||
'id', 'name_uz', 'name_ru', 'image', 'category', 'price', 'description_uz', 'description_ru', 'unity', 'tg_id', 'code', 'article', 'quantity_left', 'min_quantity', 'code',
|
||||
'id', 'name_uz', 'name_ru', 'is_active', 'image', 'category', 'price', 'description_uz', 'description_ru', 'unity', 'tg_id', 'code', 'article', 'quantity_left', 'min_quantity', 'code',
|
||||
]
|
||||
|
||||
def get_category(self, obj):
|
||||
@@ -21,7 +21,7 @@ class ProductSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = [
|
||||
'name_uz', 'name_ru', 'image', 'category', 'price', 'description_uz', 'description_ru', 'unity', 'tg_id', 'code', 'article', 'quantity_left', 'min_quantity'
|
||||
'name_uz', 'name_ru', 'is_active', 'image', 'category', 'price', 'description_uz', 'description_ru', 'unity', 'tg_id', 'code', 'article', 'quantity_left', 'min_quantity'
|
||||
]
|
||||
extra_kwargs = {
|
||||
'image': {'required':False},
|
||||
|
||||
@@ -59,6 +59,7 @@ urlpatterns = [
|
||||
[
|
||||
path('list/', order_views.OrderListApiView.as_view()),
|
||||
path('<uuid:id>/delete/', order_views.OrderDeleteApiView.as_view()),
|
||||
path('<uuid:id>/status_update/', order_views.OrderStatusUpdateApiView.as_view()),
|
||||
]
|
||||
)),
|
||||
path('dashboard/', include(
|
||||
|
||||
@@ -10,7 +10,7 @@ from core.apps.orders.models import Order
|
||||
|
||||
class OrderListApiView(generics.GenericAPIView):
|
||||
serializer_class = OrderSerializer
|
||||
queryset = Order.objects.select_related('user').prefetch_related('items', 'items__product').order_by('order_number')
|
||||
queryset = Order.objects.select_related('user').prefetch_related('items', 'items__product').order_by('-status')
|
||||
permission_classes = [IsAdminUser]
|
||||
|
||||
def get(self, request):
|
||||
@@ -32,4 +32,17 @@ class OrderDeleteApiView(views.APIView, ResponseMixin):
|
||||
def delete(self, request, id):
|
||||
order = get_object_or_404(Order, id=id)
|
||||
order.delete()
|
||||
return self.success_response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
return self.success_response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
class OrderStatusUpdateApiView(views.APIView, ResponseMixin):
|
||||
permission_classes = [IsAdminUser]
|
||||
|
||||
def post(self, request, id):
|
||||
status = request.data.get('status')
|
||||
if not status:
|
||||
return self.failure_response(message='status is required, please send NEW or DONE as a statuc')
|
||||
order = get_object_or_404(Order, id=id)
|
||||
order.status = status
|
||||
order.save()
|
||||
return self.success_response(message='Saqlandi')
|
||||
@@ -13,7 +13,7 @@ class ProductListApiView(generics.GenericAPIView):
|
||||
queryset = Product.objects.select_related('category', 'unity').order_by('name')
|
||||
permission_classes = [IsAdminUser]
|
||||
filter_backends = [filters.SearchFilter]
|
||||
search_fields = ['name',]
|
||||
search_fields = ['name', 'tg_id']
|
||||
|
||||
def get(self, request):
|
||||
category_id = request.query_params.get('category')
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
from rest_framework import generics, permissions, status, views
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
|
||||
from core.apps.admin_panel.serializers.user import UserSerializer, UserLoginSerializer
|
||||
from core.apps.accounts.models import User
|
||||
from core.apps.admin_panel.serializers.user import UserLoginSerializer, UserSerializer
|
||||
from core.apps.shared.mixins.response import ResponseMixin
|
||||
|
||||
|
||||
@@ -18,14 +17,16 @@ class UserCreateApiView(generics.GenericAPIView, ResponseMixin):
|
||||
if serializer.is_valid(raise_exception=True):
|
||||
serializer.save()
|
||||
return self.success_response(
|
||||
message='User qoshildi', status_code=status.HTTP_201_CREATED
|
||||
message="User qoshildi", status_code=status.HTTP_201_CREATED
|
||||
)
|
||||
return self.error_response(data=serializer.errors, message='User qoshishda xatolik')
|
||||
|
||||
return self.error_response(
|
||||
data=serializer.errors, message="User qoshishda xatolik"
|
||||
)
|
||||
|
||||
|
||||
class UserListApiView(generics.GenericAPIView, ResponseMixin):
|
||||
serializer_class = UserSerializer
|
||||
queryset = User.objects.all()
|
||||
queryset = User.objects.filter(is_superuser=False)
|
||||
permission_classes = [permissions.IsAdminUser]
|
||||
|
||||
def get(self, request):
|
||||
@@ -35,8 +36,8 @@ class UserListApiView(generics.GenericAPIView, ResponseMixin):
|
||||
serializer = self.serializer_class(page, many=True)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
serializer = self.serializer_class(users, many=True)
|
||||
return self.success_response(data=serializer.data, message='userlar royxati')
|
||||
|
||||
return self.success_response(data=serializer.data, message="userlar royxati")
|
||||
|
||||
|
||||
class UserUpdateApiView(generics.GenericAPIView, ResponseMixin):
|
||||
serializer_class = UserSerializer
|
||||
@@ -45,11 +46,15 @@ class UserUpdateApiView(generics.GenericAPIView, ResponseMixin):
|
||||
|
||||
def patch(self, request, id):
|
||||
user = get_object_or_404(User, id=id)
|
||||
serializer = self.serializer_class(instance=user, data=request.data, partial=True)
|
||||
serializer = self.serializer_class(
|
||||
instance=user, data=request.data, partial=True
|
||||
)
|
||||
if serializer.is_valid(raise_exception=True):
|
||||
serializer.save()
|
||||
return self.success_response(message='user tahrirlandi')
|
||||
return self.failure_response(data=serializer.errors, message='user tahrirlashda xatolik')
|
||||
return self.success_response(message="user tahrirlandi")
|
||||
return self.failure_response(
|
||||
data=serializer.errors, message="user tahrirlashda xatolik"
|
||||
)
|
||||
|
||||
|
||||
class UserDeleteApiView(generics.GenericAPIView, ResponseMixin):
|
||||
@@ -60,7 +65,9 @@ class UserDeleteApiView(generics.GenericAPIView, ResponseMixin):
|
||||
def delete(self, request, id):
|
||||
user = get_object_or_404(User, id=id)
|
||||
user.delete()
|
||||
return self.success_response(message='user ochirildi', status_code=status.HTTP_204_NO_CONTENT)
|
||||
return self.success_response(
|
||||
message="user ochirildi", status_code=status.HTTP_204_NO_CONTENT
|
||||
)
|
||||
|
||||
|
||||
class UserDetailApiView(generics.GenericAPIView, ResponseMixin):
|
||||
@@ -71,7 +78,7 @@ class UserDetailApiView(generics.GenericAPIView, ResponseMixin):
|
||||
def get(self, request, id):
|
||||
user = get_object_or_404(User, id=id)
|
||||
serializer = self.serializer_class(user)
|
||||
return self.success_response(data=serializer.data, message='user malumotlari')
|
||||
return self.success_response(data=serializer.data, message="user malumotlari")
|
||||
|
||||
|
||||
class UserDashboardApiView(views.APIView, ResponseMixin):
|
||||
@@ -81,10 +88,10 @@ class UserDashboardApiView(views.APIView, ResponseMixin):
|
||||
admin_users = User.objects.filter(is_superuser=True).count()
|
||||
users = User.objects.filter(is_superuser=False).count()
|
||||
return self.success_response(
|
||||
data={'admin_users': admin_users, 'users': users},
|
||||
message='userlar soni',
|
||||
data={"admin_users": admin_users, "users": users},
|
||||
message="userlar soni",
|
||||
)
|
||||
|
||||
|
||||
|
||||
class UserLoginApiView(generics.GenericAPIView, ResponseMixin):
|
||||
serializer_class = UserLoginSerializer
|
||||
@@ -93,13 +100,12 @@ class UserLoginApiView(generics.GenericAPIView, ResponseMixin):
|
||||
def post(self, request):
|
||||
serializer = self.serializer_class(data=request.data)
|
||||
if serializer.is_valid():
|
||||
user = serializer.validated_data.get('user')
|
||||
user = serializer.validated_data.get("user")
|
||||
token = RefreshToken.for_user(user)
|
||||
return self.success_response(
|
||||
data={
|
||||
'access': str(token.access_token),
|
||||
'refresh': str(token)
|
||||
},
|
||||
message='user tizimga kirish muvaffaqiyatli yakunlandi'
|
||||
data={"access": str(token.access_token), "refresh": str(token)},
|
||||
message="user tizimga kirish muvaffaqiyatli yakunlandi",
|
||||
)
|
||||
return self.failure_response(message='user tizimga kirishda xatolik', data=serializer.errors)
|
||||
return self.failure_response(
|
||||
message="user tizimga kirishda xatolik", data=serializer.errors
|
||||
)
|
||||
|
||||
@@ -10,5 +10,5 @@ class OrderItemInline(admin.TabularInline):
|
||||
|
||||
@admin.register(Order)
|
||||
class OrderAdmin(admin.ModelAdmin):
|
||||
list_display = ['id', 'user', 'total_price']
|
||||
list_display = ['id', 'user', 'total_price', 'status']
|
||||
inlines = [OrderItemInline]
|
||||
18
core/apps/orders/migrations/0011_order_status.py
Normal file
18
core/apps/orders/migrations/0011_order_status.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2 on 2025-11-21 16:35
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('orders', '0010_remove_order_address'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='order',
|
||||
name='status',
|
||||
field=models.CharField(choices=[('NEW', 'yangi'), ('DONE', 'tayyor')], default='NEW', max_length=20),
|
||||
),
|
||||
]
|
||||
@@ -15,6 +15,10 @@ class Order(BaseModel):
|
||||
('DELIVERY_COURIES', 'kuryer orqali yetkazib berish'),
|
||||
('PICKUP', 'olib ketish'),
|
||||
)
|
||||
STATUS = (
|
||||
('NEW', 'yangi'),
|
||||
('DONE', 'tayyor'),
|
||||
)
|
||||
|
||||
total_price = models.PositiveBigIntegerField(default=0)
|
||||
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='orders')
|
||||
@@ -25,6 +29,7 @@ class Order(BaseModel):
|
||||
contact_number = models.CharField(max_length=15, null=True, blank=True)
|
||||
comment = models.CharField(max_length=500, null=True, blank=True)
|
||||
name = models.CharField(max_length=200, null=True, blank=True)
|
||||
status = models.CharField(max_length=20, choices=STATUS, default='NEW')
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.user} order'
|
||||
|
||||
@@ -88,6 +88,6 @@ class OrderListSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Order
|
||||
fields = [
|
||||
'id', 'order_number', 'total_price', 'payment_type', 'delivery_type', 'delivery_price',
|
||||
'id', 'order_number', 'status', 'total_price', 'payment_type', 'delivery_type', 'delivery_price',
|
||||
'contact_number', 'comment', 'name', 'items', 'created_at'
|
||||
]
|
||||
@@ -7,7 +7,7 @@ from core.apps.orders.serializers import order as serializers
|
||||
|
||||
class OrderCreateApiView(generics.GenericAPIView):
|
||||
serializer_class = serializers.OrderCreateSerializer
|
||||
queryset = Order.objects.all()
|
||||
queryset = Order.objects.order_by('status')
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
def post(self, request):
|
||||
|
||||
18
core/apps/products/migrations/0011_product_is_active.py
Normal file
18
core/apps/products/migrations/0011_product_is_active.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2 on 2025-11-21 16:41
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('products', '0010_product_min_quantity'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='is_active',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
]
|
||||
@@ -27,6 +27,7 @@ class Product(BaseModel):
|
||||
code = models.CharField(max_length=200, null=True, blank=True)
|
||||
quantity_left = models.PositiveBigIntegerField(default=0)
|
||||
min_quantity = models.FloatField(null=True)
|
||||
is_active = models.BooleanField(default=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@@ -11,7 +11,7 @@ class ProductListSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = [
|
||||
'id', 'name', 'image', 'price', 'description', 'liked', 'unity', 'min_quantity'
|
||||
'id', 'name', 'image', 'price', 'description', 'liked', 'unity', 'min_quantity', 'is_active'
|
||||
]
|
||||
|
||||
def get_liked(self, obj):
|
||||
|
||||
@@ -9,14 +9,14 @@ from core.apps.products.serializers import product as serializers
|
||||
|
||||
class ProductListApiView(generics.GenericAPIView):
|
||||
serializer_class = serializers.ProductListSerializer
|
||||
queryset = Product.objects.select_related('unity').order_by('name')
|
||||
queryset = Product.objects.filter(is_active=True).select_related('unity').order_by('name')
|
||||
permission_classes = []
|
||||
filter_backends = [filters.SearchFilter]
|
||||
search_fields = ['name']
|
||||
|
||||
def get(self, request, category_id):
|
||||
category = get_object_or_404(Category, id=category_id)
|
||||
products = Product.objects.filter(category=category).select_related('unity').distinct()\
|
||||
products = Product.objects.filter(category=category, is_active=True).select_related('unity').distinct()\
|
||||
.order_by('name')
|
||||
page = self.paginate_queryset(self.filter_queryset(products))
|
||||
if page is not None:
|
||||
@@ -28,7 +28,7 @@ class ProductListApiView(generics.GenericAPIView):
|
||||
|
||||
class ProductsApiView(generics.GenericAPIView):
|
||||
serializer_class = serializers.ProductListSerializer
|
||||
queryset = Product.objects.select_related('unity')
|
||||
queryset = Product.objects.select_related('unity').filter(is_active=True)
|
||||
permission_classes = []
|
||||
|
||||
def get(self, request):
|
||||
|
||||
Reference in New Issue
Block a user