34 Commits

Author SHA1 Message Date
1ad2016790 Merge pull request 'shaxob' (#97) from shaxob into main
Some checks failed
Deploy to Production / build-and-deploy (push) Failing after 49s
Reviewed-on: #97
2026-04-24 11:40:31 +00:00
Shaxobff
3fd0f9959b Merge branch 'main' of https://gitea.felixits.uz/sifatbaho/backend-v1 into shaxob
# Conflicts:
#	core/apps/accounts/serializers/user.py
#	core/apps/accounts/urls.py
#	core/apps/accounts/views/user.py
#	core/apps/evaluation/urls.py
#	core/apps/evaluation/views/request.py
2026-04-24 16:34:02 +05:00
Shaxobff
84cc11fe2a UPDATE 2026-04-24 16:21:19 +05:00
Shaxobff
deebae384c UPDATE 2026-04-24 16:00:17 +05:00
Shaxobff
e27a9b7f11 UPDATE 2026-04-24 11:28:29 +05:00
github-actions[bot]
c89f2b32af 🔄 Update image to 115 [CI SKIP] 2026-04-24 06:23:17 +00:00
Shaxobff
82489cf64c ADD archivedet evaluvation 2026-04-24 11:22:58 +05:00
88dedd85c7 Merge pull request 'Add view for crud user' (#95) from user-crud into main
All checks were successful
Deploy to Production / build-and-deploy (push) Successful in 4m15s
Reviewed-on: #95
2026-04-24 06:21:40 +00:00
komoliddin
fb275a091a Add view for crud user 2026-04-24 11:21:01 +05:00
Shaxobff
af559dadda ADD permission 2026-04-24 11:04:37 +05:00
github-actions[bot]
190480b6f7 🔄 Update image to 114 [CI SKIP] 2026-04-24 05:16:20 +00:00
1a985ffa4b Merge pull request 'Refactor URL patterns for evaluation archiving and remove unused file_url field from BaseCertificateSerializer' (#94) from certificate into main
All checks were successful
Deploy to Production / build-and-deploy (push) Successful in 1m57s
Reviewed-on: #94
2026-04-24 05:14:45 +00:00
komoliddin
3b62c5a7bf Refactor URL patterns for evaluation archiving and remove unused file_url field from BaseCertificateSerializer 2026-04-24 10:14:01 +05:00
Shaxobff
d2f8d73cdd /api/v1/admin-user/list/ edit va post 2026-04-23 20:05:16 +05:00
Shaxobff
c4b2a80b2e /api/v1/admin-user/list/ edit va post 2026-04-23 20:03:58 +05:00
github-actions[bot]
07f8d55966 🔄 Update image to 113 [CI SKIP] 2026-04-23 14:02:58 +00:00
b0b4ccfeee Merge pull request 'makemigrations' (#93) from certificate into main
All checks were successful
Deploy to Production / build-and-deploy (push) Successful in 3m52s
Reviewed-on: #93
2026-04-23 14:01:14 +00:00
komoliddin
ccefe9c119 Merge branch 'main' of https://gitea.felixits.uz/sifatbaho/backend-v1 into certificate 2026-04-23 19:00:42 +05:00
komoliddin
6456283f72 makemigrations 2026-04-23 18:59:06 +05:00
github-actions[bot]
6eed2d998e 🔄 Update image to 112 [CI SKIP] 2026-04-23 13:07:08 +00:00
2c82691166 Merge pull request 'Enhance Certificate model and serializer to support file uploads and URL generation' (#92) from certificate into main
All checks were successful
Deploy to Production / build-and-deploy (push) Successful in 4m27s
Reviewed-on: #92
2026-04-23 13:05:27 +00:00
komoliddin
7a88e39b96 Enhance Certificate model and serializer to support file uploads and URL generation 2026-04-23 18:04:09 +05:00
github-actions[bot]
dc622ce305 🔄 Update image to 111 [CI SKIP] 2026-04-23 11:24:21 +00:00
komoliddin
6e0718c5db merge migrations
All checks were successful
Deploy to Production / build-and-deploy (push) Successful in 1m57s
2026-04-23 16:22:42 +05:00
komoliddin
32d3bea234 Merge branch 'certificate'
Some checks failed
Deploy to Production / build-and-deploy (push) Failing after 47s
2026-04-23 16:18:43 +05:00
komoliddin
129827b495 Merge branch 'main' of https://gitea.felixits.uz/sifatbaho/backend-v1
Some checks failed
Deploy to Production / build-and-deploy (push) Failing after 49s
2026-04-23 16:13:34 +05:00
komoliddin
50cc555783 Merge branch 'request-archive' 2026-04-23 16:10:00 +05:00
komoliddin
76563b3ef0 Add Certificate model and write crud for it 2026-04-23 16:07:37 +05:00
github-actions[bot]
207363dc6a 🔄 Update image to 108 [CI SKIP] 2026-04-23 10:50:59 +00:00
2a08ad9662 Merge pull request 'Add is_archive field to Quickevaluation model. Write apis for update is_archive and list archived quick evaluations' (#89) from tb-archive into main
All checks were successful
Deploy to Production / build-and-deploy (push) Successful in 3m58s
Reviewed-on: #89
2026-04-23 10:49:11 +00:00
Shaxobff
049cd6ff25 /api/v1/admin-user/list/ edit va post 2026-04-23 13:54:31 +05:00
komoliddin
5cf4b950fb Make migrations 2026-04-23 12:25:18 +05:00
komoliddin
4fee037467 Add is_archive field to Quickevaluation model. Write apis for update is_archive and list archived quick evaluations 2026-04-23 11:49:55 +05:00
Shaxobff
b8021c7728 add AutoEvaluationRequestView 2026-04-22 14:23:52 +05:00
27 changed files with 459 additions and 27 deletions

View File

@@ -13,7 +13,7 @@ from config.env import env
def home(request): def home(request):
return HttpResponse("OK: #d4e6d80c86fcf4422f71238c6552dfa4b42f9737") return HttpResponse("OK: #88dedd85c79ccf732b2adac03616bd14e67a1579")
urlpatterns = [ urlpatterns = [

View File

@@ -3,6 +3,7 @@ from django.db import models
from ..choices import RoleChoice from ..choices import RoleChoice
from ..managers import UserManager from ..managers import UserManager
from ...evaluation.permissions.permission import Role
class User(auth_models.AbstractUser): class User(auth_models.AbstractUser):
@@ -17,6 +18,7 @@ class User(auth_models.AbstractUser):
default=RoleChoice.USER, default=RoleChoice.USER,
) )
avatar = models.ImageField(upload_to="avatars/", null=True, blank=True) avatar = models.ImageField(upload_to="avatars/", null=True, blank=True)
permission = models.ForeignKey(Role, on_delete=models.SET_NULL, null=True)
USERNAME_FIELD = "phone" USERNAME_FIELD = "phone"
objects = UserManager() objects = UserManager()

View File

@@ -30,3 +30,28 @@ class UserUpdateSerializer(serializers.ModelSerializer):
"last_name", "last_name",
"avatar" "avatar"
] ]
class AdminUserSerializer(serializers.ModelSerializer):
avatar = serializers.SerializerMethodField(method_name='get_avatar')
class Meta:
model = get_user_model()
fields = "__all__"
def get_avatar(self, obj):
request = self.context.get('request')
if obj.avatar:
return request.build_absolute_uri(obj.avatar.url)
return None
class UserCreateSerializer(serializers.ModelSerializer):
class Meta:
model = get_user_model()
fields = [
"phone",
"first_name",
"last_name",
"password",
"role"]

View File

@@ -4,7 +4,8 @@ Accounts app urls
from django.urls import path, include from django.urls import path, include
from rest_framework_simplejwt import views as jwt_views from rest_framework_simplejwt import views as jwt_views
from .views import RegisterView, ResetPasswordView, MeView, ChangePasswordView, UserListApiView, AdminUserListApiView from .views import RegisterView, ResetPasswordView, MeView, ChangePasswordView, UserListApiView, AdminUserListApiView, \
AdminUserView, AdminCreateAPIView, AdminUpdateAPIView
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
router = DefaultRouter() router = DefaultRouter()
@@ -12,6 +13,7 @@ router.register("auth", RegisterView, basename="auth")
router.register("auth", ResetPasswordView, basename="reset-password") router.register("auth", ResetPasswordView, basename="reset-password")
router.register("auth", MeView, basename="me") router.register("auth", MeView, basename="me")
router.register("auth", ChangePasswordView, basename="change-password") router.register("auth", ChangePasswordView, basename="change-password")
router.register("user", AdminUserView, basename="user-crud")
urlpatterns = [ urlpatterns = [
@@ -25,4 +27,6 @@ urlpatterns = [
), ),
path("user/list/", UserListApiView.as_view(), name="user-list"), path("user/list/", UserListApiView.as_view(), name="user-list"),
path("admin-user/list/", AdminUserListApiView.as_view(), name="admin-user-list"), path("admin-user/list/", AdminUserListApiView.as_view(), name="admin-user-list"),
path("admin/create/", AdminCreateAPIView.as_view(), name="user-create"),
path("admin/update/", AdminUpdateAPIView.as_view(), name="user-update"),
] ]

View File

@@ -1,15 +1,19 @@
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.shortcuts import get_object_or_404
from django_core.mixins import BaseViewSetMixin
from drf_spectacular.utils import extend_schema
from rest_framework import generics, filters from rest_framework import generics, filters
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from drf_spectacular.utils import extend_schema
from core.apps.accounts.serializers.user import UserSerializer
from core.apps.accounts.choices.user import RoleChoice from core.apps.accounts.choices.user import RoleChoice
from core.apps.accounts.serializers.user import UserSerializer, AdminUserSerializer, UserCreateSerializer
User = get_user_model() User = get_user_model()
@extend_schema(tags=['User']) @extend_schema(tags=['User'])
class UserListApiView(generics.ListAPIView): class UserListApiView(generics.ListAPIView):
queryset = User.objects.filter(role=RoleChoice.USER) queryset = User.objects.filter(role=RoleChoice.USER)
@@ -29,3 +33,50 @@ class AdminUserListApiView(generics.ListAPIView):
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
filter_backends = [filters.SearchFilter] filter_backends = [filters.SearchFilter]
search_fields = ['phone', 'first_name', 'last_name'] search_fields = ['phone', 'first_name', 'last_name']
@extend_schema(tags=["User"], request=AdminUserSerializer)
class AdminUserView(BaseViewSetMixin, ModelViewSet):
queryset = User.objects.filter(role=RoleChoice.USER)
serializer_class = AdminUserSerializer
permission_classes = [IsAuthenticated]
filter_backends = [filters.SearchFilter]
search_fields = ['phone', 'first_name', 'last_name']
def serializer_context(self):
return self.serializer_class(context={"request": self.request})
@extend_schema(tags=['User'],
responses={200: UserSerializer},
request=UserCreateSerializer)
class AdminCreateAPIView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
if request.user.role not in (RoleChoice.SUPERUSER, RoleChoice.ADMIN):
return Response({'detail': 'Forbidden'}, status=403)
serializer = UserCreateSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=201)
@extend_schema(tags=['User'],
responses={200: UserSerializer},
request=UserCreateSerializer)
class AdminUpdateAPIView(APIView):
permission_classes = [IsAuthenticated]
def put(self, request, pk):
if request.user.role not in (RoleChoice.SUPERUSER, RoleChoice.ADMIN):
return Response({'detail': 'Forbidden'}, status=403)
user = get_object_or_404(User, pk=pk)
serializer = UserCreateSerializer(user, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=200)

View File

@@ -0,0 +1,28 @@
# Generated by Django 6.0.4 on 2026-04-23 11:07
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evaluation', '0031_remove_autoevaluationmodel_object_location_city_and_more'),
]
operations = [
migrations.CreateModel(
name='CertificateModel',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('title', models.CharField(max_length=255, verbose_name='title')),
('file_url', models.URLField(max_length=255, verbose_name='file url')),
],
options={
'verbose_name': 'Certificate',
'verbose_name_plural': 'Certificates',
'db_table': 'certificate',
},
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 6.0.4 on 2026-04-23 07:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evaluation', '0031_remove_autoevaluationmodel_object_location_city_and_more'),
]
operations = [
migrations.AddField(
model_name='quickevaluationmodel',
name='is_archive',
field=models.BooleanField(default=False, verbose_name='is archive'),
),
]

View File

@@ -0,0 +1,15 @@
# Generated by Django 6.0.4 on 2026-04-23 11:22
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('evaluation', '0032_certificatemodel'),
('evaluation', '0032_evaluationrequestmodel_is_archive'),
('evaluation', '0032_quickevaluationmodel_is_archive'),
]
operations = [
]

View File

@@ -0,0 +1,22 @@
# Generated by Django 6.0.4 on 2026-04-23 13:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('evaluation', '0033_merge_20260423_1622'),
]
operations = [
migrations.RemoveField(
model_name='certificatemodel',
name='file_url',
),
migrations.AddField(
model_name='certificatemodel',
name='file',
field=models.FileField(blank=True, null=True, upload_to='certificates/', verbose_name='file'),
),
]

View File

@@ -11,3 +11,4 @@ from .report import * # noqa
from .request import * # noqa from .request import * # noqa
from .valuation import * # noqa from .valuation import * # noqa
from .vehicle import * # noqa from .vehicle import * # noqa
from .certificate import * # noqa

View File

@@ -267,6 +267,12 @@ class AutoEvaluationModel(AbstractBaseModel):
choices=AutoEvaluationStatus.choices, choices=AutoEvaluationStatus.choices,
default=AutoEvaluationStatus.CREATED, default=AutoEvaluationStatus.CREATED,
) )
is_archived = models.BooleanField(
verbose_name=_("is archived"),
default=False,
)
def __str__(self): def __str__(self):
return f"Auto Evaluation {self.registration_number or self.pk}" return f"Auto Evaluation {self.registration_number or self.pk}"

View File

@@ -0,0 +1,30 @@
from django.db import models
from django_core.models import AbstractBaseModel
from django.utils.translation import gettext_lazy as _
from model_bakery import baker
class CertificateModel(AbstractBaseModel):
title = models.CharField(
verbose_name=_("title"),
max_length=255
)
file = models.FileField(
verbose_name=_("file"),
upload_to="certificates/",
blank=True,
null=True
)
def __str__(self):
return self.title
@classmethod
def _baker(cls):
return baker.make(cls)
class Meta:
db_table = "certificate"
verbose_name = _("Certificate")
verbose_name_plural = _("Certificates")

View File

@@ -132,6 +132,11 @@ class QuickEvaluationModel(AbstractBaseModel):
default=QuickEvaluationStatus.CREATED, default=QuickEvaluationStatus.CREATED,
) )
is_archive = models.BooleanField(
verbose_name=_("is archive"),
default=False,
)
def __str__(self): def __str__(self):
return f"Quick Evaluation {self.pk} by {self.created_by}" return f"Quick Evaluation {self.pk} by {self.created_by}"

View File

@@ -0,0 +1,60 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from pydantic import BaseModel
class PermissionToAction(BaseModel):
name = models.CharField(max_length=200)
code = models.CharField(max_length=100, unique=True)
def __str__(self):
return f"{self.name} - {self.code}"
class Meta:
verbose_name = _('Harakatlar uchun ruxsatnoma')
verbose_name_plural = _('Harakatlar uchun ruxsatnomalar')
class PermissionToTab(BaseModel):
name = models.CharField(max_length=200)
code = models.CharField(max_length=100, unique=True)
permission_to_actions = models.ManyToManyField(
PermissionToAction, related_name='permission_to_tabs'
)
def __str__(self):
return f'{self.name} - {self.code}'
class Meta:
verbose_name = _("Bo'lim uchun ruxsatnoma")
verbose_name_plural = _("Bo'lim uchun ruxsatnomalar")
class Permission(BaseModel):
name = models.CharField(max_length=200)
code = models.CharField(max_length=100, unique=True)
permission_tab = models.ManyToManyField(PermissionToTab, related_name='permissions')
def __str__(self):
return f'{self.name} - {self.code}'
class Meta:
verbose_name = _('Sahifa uchun ruxsatnoma')
verbose_name_plural = _('Sahifa uchun ruxsatnomalar')
class Role(models.Model):
name = models.CharField(max_length=200, unique=True)
permissions = models.ManyToManyField(Permission, related_name='roles', blank=True)
permission_to_tabs = models.ManyToManyField(PermissionToTab, related_name='roles', blank=True)
permission_to_actions = models.ManyToManyField(
PermissionToAction, related_name='roles', blank=True
)
comment = models.CharField(max_length=200, null=True, blank=True)
def __str__(self):
return self.name
class Meta:
verbose_name = _('Rol')
verbose_name_plural = _('Rollar')

View File

@@ -12,3 +12,4 @@ from .request import * # noqa
from .valuation import * # noqa from .valuation import * # noqa
from .vehicle import * # noqa from .vehicle import * # noqa
from .tech_passport import * # noqa from .tech_passport import * # noqa
from .certificate import * # noqa

View File

@@ -1,18 +1,20 @@
import re import re
from django.contrib.auth import get_user_model
from django.contrib.auth import get_user_model
from rest_framework import serializers from rest_framework import serializers
from core.apps.evaluation.models import AutoEvaluationModel,ReferenceitemModel, EvaluationrequestModel
from core.apps.evaluation.serializers.reference import ListReferenceitemSerializer
from core.apps.evaluation.choices.request import RequestStatus from core.apps.evaluation.choices.request import RequestStatus
from core.apps.evaluation.models import AutoEvaluationModel, ReferenceitemModel, EvaluationrequestModel
from core.apps.evaluation.serializers.reference import ListReferenceitemSerializer
User = get_user_model() User = get_user_model()
class BaseAutoevaluationSerializer(serializers.ModelSerializer): class BaseAutoevaluationSerializer(serializers.ModelSerializer):
status_display = serializers.CharField(source="get_status_display", read_only=True) status_display = serializers.CharField(source="get_status_display", read_only=True)
object_type_display = serializers.CharField(source="get_object_type_display", read_only=True, default=None) object_type_display = serializers.CharField(source="get_object_type_display", read_only=True, default=None)
object_owner_type_display = serializers.CharField(source="get_object_owner_type_display", read_only=True, default=None) object_owner_type_display = serializers.CharField(source="get_object_owner_type_display", read_only=True,
default=None)
rate_type = ListReferenceitemSerializer(read_only=True) rate_type = ListReferenceitemSerializer(read_only=True)
value_determined = ListReferenceitemSerializer(read_only=True) value_determined = ListReferenceitemSerializer(read_only=True)
property_rights = ListReferenceitemSerializer(read_only=True) property_rights = ListReferenceitemSerializer(read_only=True)
@@ -72,6 +74,7 @@ class ListAutoevaluationSerializer(BaseAutoevaluationSerializer):
class RetrieveAutoevaluationSerializer(BaseAutoevaluationSerializer): class RetrieveAutoevaluationSerializer(BaseAutoevaluationSerializer):
car_type_display = serializers.CharField(source="get_car_type_display", read_only=True, default=None) car_type_display = serializers.CharField(source="get_car_type_display", read_only=True, default=None)
car_wheel_display = serializers.CharField(source="get_car_wheel_display", read_only=True, default=None) car_wheel_display = serializers.CharField(source="get_car_wheel_display", read_only=True, default=None)
# object_location_highways_display = serializers.CharField( # object_location_highways_display = serializers.CharField(
# source="get_object_location_highways_display", read_only=True, default=None # source="get_object_location_highways_display", read_only=True, default=None
# ) # )
@@ -141,7 +144,6 @@ class UpdateAutoevaluationSerializer(serializers.ModelSerializer):
allow_null=True, allow_null=True,
) )
class Meta: class Meta:
model = AutoEvaluationModel model = AutoEvaluationModel
fields = [ fields = [
@@ -222,6 +224,7 @@ class UpdateAutoevaluationSerializer(serializers.ModelSerializer):
return attrs return attrs
class CreateAutoevaluationSerializer(serializers.ModelSerializer): class CreateAutoevaluationSerializer(serializers.ModelSerializer):
property_rights = serializers.PrimaryKeyRelatedField( property_rights = serializers.PrimaryKeyRelatedField(
queryset=ReferenceitemModel.objects.all(), queryset=ReferenceitemModel.objects.all(),
@@ -254,7 +257,6 @@ class CreateAutoevaluationSerializer(serializers.ModelSerializer):
allow_null=True, allow_null=True,
) )
class Meta: class Meta:
model = AutoEvaluationModel model = AutoEvaluationModel
fields = [ fields = [
@@ -356,3 +358,13 @@ class AutoEvaluationAppraisersSerializer(serializers.Serializer):
raise serializers.ValidationError("Invalid appraisers IDs.") raise serializers.ValidationError("Invalid appraisers IDs.")
data['users'] = users data['users'] = users
return data return data
class AutoEvaluationSerializer(serializers.Serializer):
brand = serializers.CharField()
brand_model = serializers.CharField()
year = serializers.CharField()
color = serializers.CharField()
transmission = serializers.CharField()
condition = serializers.CharField()
fuel_type = serializers.CharField()
mileage = serializers.CharField()

View File

@@ -0,0 +1 @@
from .certificate import * # noqa

View File

@@ -0,0 +1,13 @@
from rest_framework import serializers
from core.apps.evaluation.models import CertificateModel
class BaseCertificateSerializer(serializers.ModelSerializer):
class Meta:
model = CertificateModel
fields = [
"id",
"title",
"file",
]

View File

@@ -38,7 +38,8 @@ class BaseQuickevaluationSerializer(serializers.ModelSerializer):
"state_car_name", "state_car_name",
"created_at", "created_at",
"distance_covered", "distance_covered",
"tex_passport_serie_num" "tex_passport_serie_num",
"is_archive"
] ]
@@ -125,3 +126,8 @@ class CreateQuickevaluationSerializer(serializers.ModelSerializer):
if request and request.user and request.user.is_authenticated: if request and request.user and request.user.is_authenticated:
validated_data["created_by"] = request.user validated_data["created_by"] = request.user
return super().create(validated_data) return super().create(validated_data)
class ArchiveQuickevaluationSerializer(serializers.Serializer):
id = serializers.IntegerField(required=True)
is_archive = serializers.BooleanField(required=True)

View File

@@ -29,7 +29,9 @@ from .views import (
DidoxCompanyInfoAPIView, DidoxCompanyInfoAPIView,
TechPassportAPIView, TechPassportAPIView,
EvaluationStatusChange, EvaluationStatusChange,
ArchiveEvaluationrequestView, CertificateView,
ArchiveQuickEvaluationView,
ArchiveEvaluationrequestView, GetArchivedEvaluationListAPIView, ArchivedEvaluation,
) )
router = DefaultRouter() router = DefaultRouter()
@@ -54,6 +56,7 @@ router.register("vehicle", VehicleView, basename="vehicle")
router.register("valuation", ValuationView, basename="valuation") router.register("valuation", ValuationView, basename="valuation")
router.register("property-owner", PropertyOwnerView, basename="property-owner") router.register("property-owner", PropertyOwnerView, basename="property-owner")
router.register("customer", CustomerView, basename="customer") router.register("customer", CustomerView, basename="customer")
router.register("certificate", CertificateView, basename="certificate")
urlpatterns = [ urlpatterns = [
path("", include(router.urls)), path("", include(router.urls)),
path("auto-evaluation/appraisers/", include( path("auto-evaluation/appraisers/", include(
@@ -75,5 +78,13 @@ urlpatterns = [
), ),
path("evaluation-request/<int:pk>/change-status/", EvaluationStatusChange.as_view(), path("evaluation-request/<int:pk>/change-status/", EvaluationStatusChange.as_view(),
name="evaluation-change-status"), name="evaluation-change-status"),
path("evaluation-request/archive/", ArchiveEvaluationrequestView.as_view(), name="evaluation-request-archive"), path("archive/quick-evaluation/", ArchiveQuickEvaluationView.as_view(), name="quick-evaluation-archive"),
path("archive/evaluation-request/", ArchiveEvaluationrequestView.as_view(), name="evaluation-request-archive"),
path("archived-evaluvation/", GetArchivedEvaluationListAPIView.as_view(),
name="archived-evaluation"),
path("auto-evaluvation-change-status/<int:pk>", ArchivedEvaluation.as_view(),
name="archived-evaluation"),
] ]

View File

@@ -13,3 +13,4 @@ from .valuation import * # noqa
from .vehicle import * # noqa from .vehicle import * # noqa
from .didox import * # noqa from .didox import * # noqa
from .tech_passport import * # noqa from .tech_passport import * # noqa
from .certificate import * # noqa

View File

@@ -1,13 +1,14 @@
from django.db.models import Q from django.db.models import Q
from django_core.mixins import BaseViewSetMixin
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
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.filters import OrderingFilter, SearchFilter from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.generics import GenericAPIView, ListAPIView
from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.viewsets import ModelViewSet
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.viewsets import ModelViewSet
from core.apps.accounts.serializers.user import UserSerializer from core.apps.accounts.serializers.user import UserSerializer
from core.apps.evaluation.filters.auto import AutoevaluationFilter from core.apps.evaluation.filters.auto import AutoevaluationFilter
@@ -154,3 +155,21 @@ class AutoEvaluationListAppraisersView(GenericAPIView):
return self.get_paginated_response(serializer.data) return self.get_paginated_response(serializer.data)
except Exception as e: except Exception as e:
return Response({"error": str(e)}, status=500) return Response({"error": str(e)}, status=500)
@extend_schema(tags=["AutoEvaluation"])
class GetArchivedEvaluationListAPIView(ListAPIView):
permission_classes = [IsAuthenticated]
def get_queryset(self):
return AutoEvaluationModel.objects.filter(is_archived=True)
@extend_schema(tags=["AutoEvaluation"])
class ArchivedEvaluation(APIView):
permission_classes = [IsAuthenticated]
def post(self, request, pk):
auto_evaluation = get_object_or_404(AutoEvaluationModel, pk=pk)
auto_evaluation.is_archived = request.data["is_archived"]
auto_evaluation.save()
return Response({"success": True}, status=200)

View File

@@ -0,0 +1,23 @@
from django_core.mixins import BaseViewSetMixin
from drf_spectacular.utils import extend_schema
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import ModelViewSet
from core.apps.evaluation.models import CertificateModel
from core.apps.evaluation.serializers.certificate import BaseCertificateSerializer
from rest_framework.filters import SearchFilter
from rest_framework.parsers import MultiPartParser, FormParser
@extend_schema(tags=["Certificate"],request=BaseCertificateSerializer)
class CertificateView(BaseViewSetMixin, ModelViewSet):
queryset = CertificateModel.objects.all()
serializer_class = BaseCertificateSerializer
permission_classes = [IsAuthenticated]
parser_classes = [MultiPartParser, FormParser]
filter_backends = [SearchFilter]
search_fields = ["title"]
pagination_class = None
action_permission_classes = {}

View File

@@ -1,6 +1,6 @@
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import status from rest_framework import status
from rest_framework.permissions import AllowAny from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import GenericAPIView from rest_framework.generics import GenericAPIView
@@ -11,7 +11,7 @@ from core.services.didox import DidoxService
class DidoxCompanyInfoAPIView(GenericAPIView): class DidoxCompanyInfoAPIView(GenericAPIView):
authentication_classes = [] authentication_classes = []
permission_classes = [AllowAny] permission_classes = [IsAuthenticated]
@extend_schema( @extend_schema(
tags=["Didox"], tags=["Didox"],

View File

@@ -1,10 +1,14 @@
from django_core.mixins import BaseViewSetMixin 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 from drf_spectacular.utils import extend_schema, OpenApiResponse
from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.parsers import FormParser, MultiPartParser from rest_framework.parsers import FormParser, MultiPartParser
from rest_framework.permissions import AllowAny from rest_framework.permissions import AllowAny, IsAuthenticated
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework import status
from django.shortcuts import get_object_or_404
from core.apps.evaluation.filters.quick import QuickevaluationFilter from core.apps.evaluation.filters.quick import QuickevaluationFilter
from core.apps.evaluation.models import QuickEvaluationModel from core.apps.evaluation.models import QuickEvaluationModel
@@ -12,6 +16,7 @@ from core.apps.evaluation.serializers.quick import (
CreateQuickevaluationSerializer, CreateQuickevaluationSerializer,
ListQuickevaluationSerializer, ListQuickevaluationSerializer,
RetrieveQuickevaluationSerializer, RetrieveQuickevaluationSerializer,
ArchiveQuickevaluationSerializer,
) )
@@ -20,7 +25,7 @@ class QuickEvaluationView(BaseViewSetMixin, ModelViewSet):
queryset = QuickEvaluationModel.objects.select_related( queryset = QuickEvaluationModel.objects.select_related(
"created_by", "brand", "marka", "color", "fuel_type", "created_by", "brand", "marka", "color", "fuel_type",
"body_type", "state_car", "car_position", "body_type", "state_car", "car_position",
).all() ).filter(is_archive=False)
serializer_class = ListQuickevaluationSerializer serializer_class = ListQuickevaluationSerializer
permission_classes = [AllowAny] permission_classes = [AllowAny]
parser_classes = [MultiPartParser, FormParser] parser_classes = [MultiPartParser, FormParser]
@@ -50,3 +55,76 @@ class QuickEvaluationView(BaseViewSetMixin, ModelViewSet):
"retrieve": RetrieveQuickevaluationSerializer, "retrieve": RetrieveQuickevaluationSerializer,
"create": CreateQuickevaluationSerializer, "create": CreateQuickevaluationSerializer,
} }
@extend_schema(tags=["QuickEvaluation"])
class ArchiveQuickEvaluationView(GenericAPIView):
permission_classes = [IsAuthenticated]
def get_serializer_class(self):
if self.request.method == "GET":
return ListQuickevaluationSerializer
return ArchiveQuickevaluationSerializer
@extend_schema(
tags=["QuickEvaluation"],
summary="Get archived quick evaluations list",
description="""
Returns only archived quick evaluations.
This endpoint works like quick-evaluation/,
but only records with is_archive=True are returned.
""",
responses={200: ListQuickevaluationSerializer(many=True)},
)
def get(self, request, *args, **kwargs):
queryset = QuickEvaluationModel.objects.filter(
is_archive=True
).order_by("-created_at")
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
@extend_schema(
tags=["QuickEvaluation"],
summary="Archive or unarchive quick evaluation",
description="""
Update archive status for quick evaluation.
- is_archive=true → archive
- is_archive=false → remove from archive
""",
request=ArchiveQuickevaluationSerializer,
responses={
200: OpenApiResponse(
description="Archive status updated successfully"
),
400: OpenApiResponse(
description="Validation error"
),
404: OpenApiResponse(
description="Quick evaluation not found"
),
},
)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
validated_data = serializer.validated_data
obj = get_object_or_404(
QuickEvaluationModel,
id=validated_data["id"]
)
obj.is_archive = validated_data["is_archive"]
obj.save(update_fields=["is_archive"])
return Response(
{
"success": True,
"message": "Archive status updated successfully"
},
status=status.HTTP_200_OK
)

View File

@@ -1,6 +1,6 @@
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework import status from rest_framework import status
from rest_framework.permissions import AllowAny from rest_framework.permissions import IsAuthenticated
from rest_framework.generics import GenericAPIView from rest_framework.generics import GenericAPIView
from drf_spectacular.utils import ( from drf_spectacular.utils import (
@@ -14,7 +14,7 @@ from ..serializers import TechPassportSerializer
class TechPassportAPIView(GenericAPIView): class TechPassportAPIView(GenericAPIView):
authentication_classes = [] authentication_classes = []
permission_classes = [AllowAny] permission_classes = [IsAuthenticated]
@extend_schema( @extend_schema(
tags=["Tech Passport"], tags=["Tech Passport"],

View File

@@ -84,7 +84,7 @@ services:
max-file: "5" max-file: "5"
web: web:
image: husanjon/sifatbaho:107 image: husanjon/sifatbaho:115
env_file: env_file:
- .env - .env
environment: environment:
@@ -129,7 +129,7 @@ services:
max-file: "5" max-file: "5"
celery: celery:
image: husanjon/sifatbaho:107 image: husanjon/sifatbaho:115
env_file: env_file:
- .env - .env
environment: environment: