Compare commits

..

10 Commits

Author SHA1 Message Date
behruz-dev
fd67401574 fix 2025-11-22 14:27:03 +05:00
behruz-dev
5f32e8e8a7 fix 2025-11-21 18:46:09 +05:00
behruz-dev
b3d8a696e7 fix 2025-11-21 18:45:15 +05:00
behruz-dev
11f0402c4c fix 2025-11-21 17:57:32 +05:00
behruz-dev
29b1b3c86e fix 2025-11-21 17:56:54 +05:00
behruz-dev
51697bcbad search by tg_id added for product list api view 2025-11-21 16:45:15 +05:00
behruz-dev
23d79ea85a added new fields 2025-11-21 16:41:35 +05:00
behruz-dev
421f585721 add: add new domain for cors 2025-09-30 14:39:23 +05:00
behruz-dev
23fdc55d0e add: add new field for order list serializer 2025-09-27 20:46:30 +05:00
behruz-dev
2bdd10f388 add: add new api for bot 2025-09-27 18:19:17 +05:00
21 changed files with 123 additions and 42 deletions

View File

@@ -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 = [

View File

@@ -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)

View File

@@ -17,3 +17,11 @@ class CustomUserLoginSerializer(serializers.Serializer):
user.save()
data['user'] = user
return data
class UserListSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = [
'id', 'tg_id'
]

View File

@@ -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()),
]

View File

@@ -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
@@ -18,3 +18,11 @@ class UserLoginApiView(generics.GenericAPIView):
token = RefreshToken.for_user(user)
return Response({'access': str(token.access_token), 'refresh': str(token)})
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)

View File

@@ -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'
]

View File

@@ -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},

View File

@@ -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(

View File

@@ -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):
@@ -33,3 +33,16 @@ class OrderDeleteApiView(views.APIView, ResponseMixin):
order = get_object_or_404(Order, id=id)
order.delete()
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')

View File

@@ -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')

View File

@@ -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,7 +36,7 @@ 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):
@@ -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,8 +88,8 @@ 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",
)
@@ -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)

View File

@@ -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]

View 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),
),
]

View File

@@ -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'

View File

@@ -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'
]

View File

@@ -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):

View 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),
),
]

View File

@@ -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

View File

@@ -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):

View File

@@ -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):