This commit is contained in:
Shaxobff
2026-05-06 17:05:35 +05:00
parent a17c2a52ce
commit 89a5411e3c
16 changed files with 226 additions and 11 deletions

View File

@@ -9,7 +9,9 @@ class IsAdminRole(BasePermission):
if not request.user.is_authenticated: if not request.user.is_authenticated:
return False return False
if request.user.role != RoleChoice.ADMIN: if request.user.role != RoleChoice.ADMIN or request.user.role != RoleChoice.SUPERUSER:
raise PermissionDenied("Only admin can access this") raise PermissionDenied("Only admin can access this")
return True return True

View File

@@ -9,7 +9,7 @@ from .views import RegisterView, ResetPasswordView, MeView, ChangePasswordView,
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from .views.permission import PermissionToActionViewSet, PermissionToTabViewSet, PermissionViewSet, RoleViewSet from .views.permission import PermissionToActionViewSet, PermissionToTabViewSet, PermissionViewSet, RoleViewSet
from core.apps.accounts.views.user import DeleteAdminUserApiView, UserDetailAPIView from core.apps.accounts.views.user import DeleteAdminUserApiView, UserDetailAPIView, AdminPermissionsAPIView
router = DefaultRouter() router = DefaultRouter()
router.register("auth", RegisterView, basename="auth") router.register("auth", RegisterView, basename="auth")
@@ -34,4 +34,5 @@ urlpatterns = [
path("admin/update/<int:pk>/", AdminUpdateAPIView.as_view(), name="user-update"), path("admin/update/<int:pk>/", AdminUpdateAPIView.as_view(), name="user-update"),
path('user/admin/<int:pk>/delete/', DeleteAdminUserApiView.as_view(), name='user-delete'), path('user/admin/<int:pk>/delete/', DeleteAdminUserApiView.as_view(), name='user-delete'),
path('user/<int:pk>/', UserDetailAPIView.as_view(), name='user-detail'), path('user/<int:pk>/', UserDetailAPIView.as_view(), name='user-detail'),
path('admin-permission/',AdminPermissionsAPIView.as_view(),name='admin-permissions'),
] ]

View File

@@ -1,6 +1,6 @@
from django_core.mixins import BaseViewSetMixin from django_core.mixins import BaseViewSetMixin
from drf_spectacular.utils import extend_schema from drf_spectacular.utils import extend_schema
from rest_framework.permissions import AllowAny, IsAdminUser from rest_framework.permissions import IsAdminUser
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from core.apps.accounts.models.permission import PermissionToAction, PermissionToTab, Permission, Role from core.apps.accounts.models.permission import PermissionToAction, PermissionToTab, Permission, Role
@@ -19,7 +19,7 @@ class PermissionToActionViewSet(BaseViewSetMixin, ModelViewSet):
} }
action_permission_classes = { action_permission_classes = {
'create': [AllowAny], 'create': [IsAdminUser],
'destroy': [IsAdminUser], 'destroy': [IsAdminUser],
} }

View File

@@ -97,7 +97,7 @@ class UserDetailAPIView(generics.RetrieveAPIView):
serializer_class = UserSerializer serializer_class = UserSerializer
lookup_field = 'id' lookup_field = 'id'
@extend_schema(tags=['User'])
class AdminPermissionsAPIView(generics.GenericAPIView): class AdminPermissionsAPIView(generics.GenericAPIView):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
queryset = User.objects.all() queryset = User.objects.all()

View File

@@ -5,6 +5,7 @@ from django.utils.translation import gettext_lazy as _
class RoomType(models.TextChoices): class RoomType(models.TextChoices):
AUTO_EVALUATION = "auto_evaluation", _("AutoEvaluation xonasi") AUTO_EVALUATION = "auto_evaluation", _("AutoEvaluation xonasi")
DIRECT = "direct", _("To'g'ridan-to'g'ri") DIRECT = "direct", _("To'g'ridan-to'g'ri")
MECHANIC_AUTO_EVALUATION = 'mechanic_evaluation', _("Mechanic Auto-Evaluation xonasi")
class MessageType(models.TextChoices): class MessageType(models.TextChoices):

View File

@@ -3,6 +3,7 @@ from django.utils.translation import gettext_lazy as _
from django_core.models import AbstractBaseModel from django_core.models import AbstractBaseModel
from model_bakery import baker from model_bakery import baker
from core.apps import evaluation
from core.apps.chat.choices.chat import MessageType, RoomType from core.apps.chat.choices.chat import MessageType, RoomType

View File

@@ -16,6 +16,7 @@ class AutoEvaluationStatus(models.TextChoices):
EVALUATED = "baxolandi", _("Baholandi") EVALUATED = "baxolandi", _("Baholandi")
REJECTED = "rad_etildi", _("Rad etildi") REJECTED = "rad_etildi", _("Rad etildi")
APPROVED = "tasdiqlandi", _("Tasdiqlandi") APPROVED = "tasdiqlandi", _("Tasdiqlandi")
PENDING = "pending", _("Pending")
class ObjectOwnerType(models.IntegerChoices): class ObjectOwnerType(models.IntegerChoices):

View File

@@ -0,0 +1,109 @@
# Generated by Django 5.2.7 on 2026-05-06 12:03
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("evaluation", "0046_mechanicauto_fields_and_multi_tex_passport"),
]
operations = [
migrations.AddField(
model_name="autoevaluationmodel",
name="tender_contract_date",
field=models.DateField(blank=True, null=True),
),
migrations.AddField(
model_name="autoevaluationmodel",
name="tender_contract_file",
field=models.FileField(blank=True, null=True, upload_to="tender_contracts/%Y/%m/"),
),
migrations.AddField(
model_name="autoevaluationmodel",
name="tender_contract_number",
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.AddField(
model_name="autoevaluationmodel",
name="with_tender_field",
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name="mechanicautoevaluationmodel",
name="tender_contract_date",
field=models.DateField(blank=True, null=True),
),
migrations.AddField(
model_name="mechanicautoevaluationmodel",
name="tender_contract_file",
field=models.FileField(blank=True, null=True, upload_to="tender_contracts/%Y/%m/"),
),
migrations.AddField(
model_name="mechanicautoevaluationmodel",
name="tender_contract_number",
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.AddField(
model_name="mechanicautoevaluationmodel",
name="with_tender_field",
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name="mechanicautoevaluationtexpassportfile",
name="calculated_price",
field=models.DecimalField(decimal_places=2, max_digits=12, null=True),
),
migrations.AddField(
model_name="mechanicautoevaluationtexpassportfile",
name="status",
field=models.CharField(
choices=[
("yaratildi", "Yaratildi"),
("baxolovchi_biriktirildi", "Baholovchi biriktirildi"),
("baxolandi", "Baholandi"),
("rad_etildi", "Rad etildi"),
("tasdiqlandi", "Tasdiqlandi"),
("pending", "Pending"),
],
default="yaratildi",
max_length=50,
verbose_name="status",
),
),
migrations.AlterField(
model_name="autoevaluationmodel",
name="status",
field=models.CharField(
choices=[
("yaratildi", "Yaratildi"),
("baxolovchi_biriktirildi", "Baholovchi biriktirildi"),
("baxolandi", "Baholandi"),
("rad_etildi", "Rad etildi"),
("tasdiqlandi", "Tasdiqlandi"),
("pending", "Pending"),
],
default="yaratildi",
max_length=50,
verbose_name="status",
),
),
migrations.AlterField(
model_name="mechanicautoevaluationmodel",
name="status",
field=models.CharField(
choices=[
("yaratildi", "Yaratildi"),
("baxolovchi_biriktirildi", "Baholovchi biriktirildi"),
("baxolandi", "Baholandi"),
("rad_etildi", "Rad etildi"),
("tasdiqlandi", "Tasdiqlandi"),
("pending", "Pending"),
],
default="yaratildi",
max_length=50,
verbose_name="status",
),
),
]

View File

@@ -32,6 +32,24 @@ class AutoEvaluationModel(AbstractBaseModel):
null=True, null=True,
blank=True, blank=True,
) )
with_tender_field = models.BooleanField(default=False)
tender_contract_number = models.CharField(
max_length=255,
null=True,
blank=True
)
tender_contract_file = models.FileField(
upload_to="tender_contracts/%Y/%m/",
null=True,
blank=True
)
tender_contract_date = models.DateField(
null=True,
blank=True
)
valuation = models.OneToOneField( valuation = models.OneToOneField(
ValuationModel, ValuationModel,
on_delete=models.CASCADE, on_delete=models.CASCADE,

View File

@@ -1,4 +1,5 @@
from django.db import models from django.db import models
from django.db.models import DecimalField
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django_core.models import AbstractBaseModel from django_core.models import AbstractBaseModel
from model_bakery import baker from model_bakery import baker
@@ -28,6 +29,25 @@ class MechanicAutoEvaluationModel(AbstractBaseModel):
null=True, null=True,
blank=True, blank=True,
) )
with_tender_field = models.BooleanField(default=False)
tender_contract_number = models.CharField(
max_length=255,
null=True,
blank=True
)
tender_contract_file = models.FileField(
upload_to="tender_contracts/%Y/%m/",
null=True,
blank=True
)
tender_contract_date = models.DateField(
null=True,
blank=True
)
valuation = models.OneToOneField( valuation = models.OneToOneField(
ValuationModel, ValuationModel,
on_delete=models.CASCADE, on_delete=models.CASCADE,
@@ -298,6 +318,14 @@ class MechanicAutoEvaluationTexPassportFile(AbstractBaseModel):
verbose_name=_("tech passport file"), verbose_name=_("tech passport file"),
upload_to="mechanic_evaluation/tech_passports/%Y/%m/", upload_to="mechanic_evaluation/tech_passports/%Y/%m/",
) )
status = models.CharField(
verbose_name=_("status"),
max_length=50,
choices=AutoEvaluationStatus.choices,
default=AutoEvaluationStatus.CREATED,
)
calculated_price = DecimalField(max_digits=12, decimal_places=2, null=True)
def __str__(self): def __str__(self):
return f"Tex passport file for MechanicAutoEvaluation #{self.mechanic_auto_evaluation_id}" return f"Tex passport file for MechanicAutoEvaluation #{self.mechanic_auto_evaluation_id}"

View File

@@ -499,3 +499,8 @@ class MechanicAutoEvaluationModelSerializer(serializers.ModelSerializer):
"created_at", "created_at",
"updated_at", "updated_at",
) )
class MechanicAutoEvaluationTexPassportFileCreateSerializer(serializers.ModelSerializer):
class Meta:
model = MechanicAutoEvaluationTexPassportFile
fields = ['mechanic_auto_evaluation','file', 'calculated_price']

View File

@@ -2,7 +2,8 @@ from django.urls import include, path
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from core.apps.evaluation import views from core.apps.evaluation import views
from core.apps.evaluation.views import MechanicAutoEvaluationTexPassportFileCreateView, \
MechanicAutoEvaluationTexPassportFileRetrieveAPIView, MechanicAutoEvaluationTexPassportFileListAPIView
router = DefaultRouter() router = DefaultRouter()
router.register("document-category", views.DocumentCategoryView, basename="DocumentCategory") router.register("document-category", views.DocumentCategoryView, basename="DocumentCategory")
@@ -33,6 +34,7 @@ router.register("bonus-type", views.BonusTypeView, basename="bonus-type")
router.register("bonus-employee", views.BonusEmployeeViewSet, basename="bonus-employee") router.register("bonus-employee", views.BonusEmployeeViewSet, basename="bonus-employee")
router.register("bonus-base", views.BaseBonusViewSet, basename="bonus-base") router.register("bonus-base", views.BaseBonusViewSet, basename="bonus-base")
urlpatterns = [ urlpatterns = [
path("", include(router.urls)), path("", include(router.urls)),
@@ -111,4 +113,14 @@ urlpatterns = [
path("calculate_avg_cost/", views.AvgCostAPIView.as_view()), path("calculate_avg_cost/", views.AvgCostAPIView.as_view()),
path("vehicle_document/", views.GeneratePDFView.as_view()), path("vehicle_document/", views.GeneratePDFView.as_view()),
path("mechanic-auto/", include([
path('upload-passport/', MechanicAutoEvaluationTexPassportFileCreateView.as_view()),
path('passport/<int:pk>', MechanicAutoEvaluationTexPassportFileRetrieveAPIView.as_view()),
path('passport/', MechanicAutoEvaluationTexPassportFileListAPIView.as_view())
]))
] ]

View File

@@ -38,7 +38,7 @@ class BonusTypeView(BaseViewSetMixin, ModelViewSet):
'list': [IsAdminUser], 'list': [IsAdminUser],
} }
@extend_schema(tags=["Bonus-Employee"])
class BonusEmployeeViewSet(BaseViewSetMixin, ModelViewSet): class BonusEmployeeViewSet(BaseViewSetMixin, ModelViewSet):
queryset = EmployeeBonus.objects.all() queryset = EmployeeBonus.objects.all()
serializer_class = BonusEmployeeBonusSerializer serializer_class = BonusEmployeeBonusSerializer

View File

@@ -4,8 +4,10 @@ from django_core.mixins import BaseViewSetMixin
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from drf_spectacular.utils import extend_schema, OpenApiParameter from drf_spectacular.utils import extend_schema, OpenApiParameter
from rest_framework import generics from rest_framework import generics
from rest_framework.decorators import action
from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.generics import GenericAPIView, ListAPIView from rest_framework.generics import GenericAPIView, ListAPIView
from rest_framework.parsers import FormParser, MultiPartParser
from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
@@ -13,15 +15,17 @@ from rest_framework.viewsets import ModelViewSet
from core.apps.accounts.permissions import IsAdminRole from core.apps.accounts.permissions import IsAdminRole
from core.apps.accounts.serializers.user import UserSerializer from core.apps.accounts.serializers.user import UserSerializer
from core.apps.evaluation.choices.auto import AutoEvaluationStatus
from core.apps.evaluation.filters.mechanic_auto import MechanicAutoevaluationFilter from core.apps.evaluation.filters.mechanic_auto import MechanicAutoevaluationFilter
from core.apps.evaluation.models import MechanicAutoEvaluationModel from core.apps.evaluation.models import MechanicAutoEvaluationModel, MechanicAutoEvaluationTexPassportFile
from core.apps.evaluation.serializers.auto.MechanicAutoEvaluation import ( from core.apps.evaluation.serializers.auto.MechanicAutoEvaluation import (
ListMechanicAutoevaluationSerializer, ListMechanicAutoevaluationSerializer,
RetrieveMechanicAutoevaluationSerializer, RetrieveMechanicAutoevaluationSerializer,
CreateMechanicAutoevaluationSerializer, CreateMechanicAutoevaluationSerializer,
UpdateMechanicAutoevaluationSerializer, UpdateMechanicAutoevaluationSerializer,
MechanicAutoEvaluationAppraisersSerializer, MechanicAutoEvaluationAppraisersSerializer,
MechanicAutoEvaluationModelSerializer, MechanicAutoEvaluationModelSerializer, MechanicAutoEvaluationTexPassportFileCreateSerializer,
MechanicAutoEvaluationTexPassportFileSerializer,
) )
@@ -196,3 +200,28 @@ class AdminMechanicEvaluationsAPIView(generics.GenericAPIView):
).distinct() ).distinct()
serializer = MechanicAutoEvaluationModelSerializer(evaluations, many=True) serializer = MechanicAutoEvaluationModelSerializer(evaluations, many=True)
return Response(serializer.data) return Response(serializer.data)
@extend_schema(tags=["MechanicAutoEvaluationTexPassportFile"])
class MechanicAutoEvaluationTexPassportFileCreateView(generics.CreateAPIView):
permission_classes = [IsAuthenticated, IsAdminRole]
serializer_class = MechanicAutoEvaluationTexPassportFileCreateSerializer
queryset = MechanicAutoEvaluationTexPassportFile.objects.all()
def perform_create(self, serializer):
eval_id = self.kwargs.get('eval_id')
serializer.save(mechanic_auto_evaluation_id=eval_id, status=AutoEvaluationStatus.PENDING)
@extend_schema(tags=["MechanicAutoEvaluationTexPassportFile"])
class MechanicAutoEvaluationTexPassportFileRetrieveAPIView(generics.RetrieveAPIView):
permission_classes = [IsAuthenticated, IsAdminRole]
queryset = MechanicAutoEvaluationTexPassportFile.objects.all()
serializer_class = MechanicAutoEvaluationTexPassportFileSerializer
@extend_schema(tags=["MechanicAutoEvaluationTexPassportFile"])
class MechanicAutoEvaluationTexPassportFileListAPIView(generics.ListAPIView):
permission_classes = [IsAuthenticated, IsAdminRole]
queryset = MechanicAutoEvaluationTexPassportFile.objects.all()
serializer_class = MechanicAutoEvaluationTexPassportFileSerializer

View File

@@ -47,6 +47,14 @@ class TaskCreateSerializer(serializers.ModelSerializer):
'assignees', 'assignees',
] ]
extra_kwargs = {
'labels' : {'required' : False},
'description' : {'required' : False},
'from_date' : {'required' : False},
'to_date' : {'required' : False},
}
def create(self, validated_data): def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user validated_data['created_by'] = self.context['request'].user
return super().create(validated_data) return super().create(validated_data)

View File

@@ -16,8 +16,8 @@ class TaskCreateView(generics.GenericAPIView):
@transaction.atomic @transaction.atomic
def post(self, request): def post(self, request):
serializer = self.get_serializer(data=request.data) serializer = self.get_serializer(data=request.data)
if not serializer.is_valid(raise_exception=True): if not serializer.is_valid():
return Response(serializer.validated_data, status=status.HTTP_400_BAD_REQUEST) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializer.save() serializer.save()
return Response(serializer.data) return Response(serializer.data)