Compare commits
48 Commits
7ab1e0b1e0
...
certificat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
190480b6f7 | ||
| 1a985ffa4b | |||
|
|
3b62c5a7bf | ||
|
|
07f8d55966 | ||
| b0b4ccfeee | |||
|
|
ccefe9c119 | ||
|
|
6456283f72 | ||
|
|
6eed2d998e | ||
| 2c82691166 | |||
|
|
7a88e39b96 | ||
|
|
dc622ce305 | ||
|
|
6e0718c5db | ||
|
|
32d3bea234 | ||
|
|
129827b495 | ||
|
|
50cc555783 | ||
|
|
76563b3ef0 | ||
|
|
207363dc6a | ||
| 2a08ad9662 | |||
|
|
5cf4b950fb | ||
|
|
3a08c81ff3 | ||
|
|
4fee037467 | ||
|
|
320f490d23 | ||
| d4e6d80c86 | |||
| 1f0e942be8 | |||
|
|
2af67333e2 | ||
| 81c689e7e9 | |||
|
|
09d2e0954c | ||
| 84a5afb2ee | |||
|
|
cc8fc345d9 | ||
| 03e4387e4d | |||
|
|
64993805af | ||
|
|
01711b5927 | ||
|
|
33aa06f80b | ||
|
|
cb2d83b00d | ||
| 46c9621457 | |||
|
|
8d73fa09a7 | ||
| 3367063707 | |||
|
|
ae926914a5 | ||
|
|
229676be5c | ||
| d2f517baf4 | |||
|
|
6df20f35c2 | ||
|
|
fa676bfa96 | ||
| ca9f12ae32 | |||
|
|
56f693abfd | ||
|
|
5049919865 | ||
| ca3c9bfe4a | |||
|
|
8d8744731a | ||
|
|
8207b750b8 |
4
.github/workflows/deploy.yaml
vendored
4
.github/workflows/deploy.yaml
vendored
@@ -153,7 +153,7 @@ jobs:
|
|||||||
update_env \
|
update_env \
|
||||||
"DB_HOST=postgres" \
|
"DB_HOST=postgres" \
|
||||||
"DB_NAME=sifatbahodb" \
|
"DB_NAME=sifatbahodb" \
|
||||||
"DB_PORT=5432"
|
"DB_PORT=5432" \
|
||||||
|
"DIDOX_TOKEN=${{ secrets.DIDOX_TOKEN }}"
|
||||||
export PORT=8085
|
export PORT=8085
|
||||||
docker stack deploy -c stack.yaml ${{ env.PROJECT_NAME }} --with-registry-auth
|
docker stack deploy -c stack.yaml ${{ env.PROJECT_NAME }} --with-registry-auth
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ from config.env import env
|
|||||||
|
|
||||||
|
|
||||||
def home(request):
|
def home(request):
|
||||||
return HttpResponse("OK: #f66a35ec80028f5b7cd09a5e540a1b6bf91e653e")
|
return HttpResponse("OK: #1a985ffa4b785b63a71b9e0cdd78042c3fcda239")
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
|||||||
@@ -67,27 +67,20 @@ class ChatConsumer(AsyncWebsocketConsumer):
|
|||||||
|
|
||||||
await self._save_message(user, text)
|
await self._save_message(user, text)
|
||||||
|
|
||||||
# Uz
|
|
||||||
# Bu funksiya ishlatilmayapti, shuning uchun commentga olib qoydim, bu funksiya orniga /core/apps/chat/tasks/message.py ichida rest api yordamida message
|
async def chat_message(self, event):
|
||||||
# yuborilsa ishlatiladigan task bor.
|
await self.send(
|
||||||
|
text_data=json.dumps(
|
||||||
# En
|
{
|
||||||
# This function is not used, so I commented it out. Instead, a task is used in /core/apps/chat/tasks/message.py
|
"id": event["id"],
|
||||||
# to send message when message is added from REST API.
|
"message_type": event["message_type"],
|
||||||
|
"text": event["text"],
|
||||||
# async def chat_message(self, event):
|
"file_url": event["file_url"],
|
||||||
# await self.send(
|
"sender": event["sender"],
|
||||||
# text_data=json.dumps(
|
"created_at": event["created_at"],
|
||||||
# {
|
}
|
||||||
# "id": event["id"],
|
)
|
||||||
# "message_type": event["message_type"],
|
)
|
||||||
# "text": event["text"],
|
|
||||||
# "file_url": event["file_url"],
|
|
||||||
# "sender": event["sender"],
|
|
||||||
# "created_at": event["created_at"],
|
|
||||||
# }
|
|
||||||
# )
|
|
||||||
# )
|
|
||||||
|
|
||||||
@database_sync_to_async
|
@database_sync_to_async
|
||||||
def _save_message(self, user, text):
|
def _save_message(self, user, text):
|
||||||
|
|||||||
@@ -50,15 +50,8 @@ class AutoEvaluationAdmin(ModelAdmin):
|
|||||||
("value_determined", "rate_type"),
|
("value_determined", "rate_type"),
|
||||||
),
|
),
|
||||||
}),
|
}),
|
||||||
("Step 3 — Manzil ma'lumotlari", {
|
|
||||||
"fields": (
|
("Step 3 — Avtomobil ma'lumotlari", {
|
||||||
("object_location_province", "object_location_district"),
|
|
||||||
("object_location_city", "object_location_neighborhood"),
|
|
||||||
("object_location_street", "object_location_home"),
|
|
||||||
("object_location_highways", "object_location_covenience"),
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
("Step 4 — Avtomobil ma'lumotlari", {
|
|
||||||
"fields": (
|
"fields": (
|
||||||
"tex_passport_serie_num",
|
"tex_passport_serie_num",
|
||||||
("tex_passport_gived_date", "tex_passport_gived_location"),
|
("tex_passport_gived_date", "tex_passport_gived_location"),
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
# Generated by Django 5.2.7 on 2026-04-21 10:22
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('evaluation', '0030_autoevaluationmodel_evaluation_request'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='autoevaluationmodel',
|
||||||
|
name='object_location_city',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='autoevaluationmodel',
|
||||||
|
name='object_location_covenience',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='autoevaluationmodel',
|
||||||
|
name='object_location_district',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='autoevaluationmodel',
|
||||||
|
name='object_location_highways',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='autoevaluationmodel',
|
||||||
|
name='object_location_home',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='autoevaluationmodel',
|
||||||
|
name='object_location_neighborhood',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='autoevaluationmodel',
|
||||||
|
name='object_location_province',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='autoevaluationmodel',
|
||||||
|
name='object_location_street',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='quickevaluationmodel',
|
||||||
|
name='tex_passport_file',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='autoevaluationmodel',
|
||||||
|
name='tex_passport_file',
|
||||||
|
field=models.FileField(blank=True, null=True, upload_to='quick_evaluation/tech_passports/%Y/%m/', verbose_name='tech passport file'),
|
||||||
|
),
|
||||||
|
]
|
||||||
28
core/apps/evaluation/migrations/0032_certificatemodel.py
Normal file
28
core/apps/evaluation/migrations/0032_certificatemodel.py
Normal 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',
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 6.0.4 on 2026-04-23 07:22
|
||||||
|
|
||||||
|
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='evaluationrequestmodel',
|
||||||
|
name='is_archive',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='is archive'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -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'),
|
||||||
|
),
|
||||||
|
]
|
||||||
15
core/apps/evaluation/migrations/0033_merge_20260423_1622.py
Normal file
15
core/apps/evaluation/migrations/0033_merge_20260423_1622.py
Normal 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 = [
|
||||||
|
]
|
||||||
@@ -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'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -62,6 +62,13 @@ class AutoEvaluationModel(AbstractBaseModel):
|
|||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tex_passport_file = models.FileField(
|
||||||
|
verbose_name=_("tech passport file"),
|
||||||
|
upload_to="quick_evaluation/tech_passports/%Y/%m/",
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
# ── Step 1 — Umumiy ma'lumotlar ──────────────────────────────────
|
# ── Step 1 — Umumiy ma'lumotlar ──────────────────────────────────
|
||||||
registration_number = models.CharField(
|
registration_number = models.CharField(
|
||||||
verbose_name=_("registration number"),
|
verbose_name=_("registration number"),
|
||||||
@@ -180,56 +187,6 @@ class AutoEvaluationModel(AbstractBaseModel):
|
|||||||
related_name='evaluation_auto_rate_type'
|
related_name='evaluation_auto_rate_type'
|
||||||
)
|
)
|
||||||
|
|
||||||
# ── Step 3 — Manzil ma'lumotlari ────────────────────────────────
|
|
||||||
object_location_province = models.CharField(
|
|
||||||
verbose_name=_("object location province"),
|
|
||||||
max_length=100,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
)
|
|
||||||
object_location_district = models.CharField(
|
|
||||||
verbose_name=_("object location district"),
|
|
||||||
max_length=100,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
)
|
|
||||||
object_location_city = models.CharField(
|
|
||||||
verbose_name=_("object location city"),
|
|
||||||
max_length=100,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
)
|
|
||||||
object_location_neighborhood = models.CharField(
|
|
||||||
verbose_name=_("object location neighborhood"),
|
|
||||||
max_length=100,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
)
|
|
||||||
object_location_street = models.CharField(
|
|
||||||
verbose_name=_("object location street"),
|
|
||||||
max_length=100,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
)
|
|
||||||
object_location_home = models.CharField(
|
|
||||||
verbose_name=_("object location home"),
|
|
||||||
max_length=50,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
)
|
|
||||||
object_location_highways = models.IntegerField(
|
|
||||||
verbose_name=_("location highways"),
|
|
||||||
choices=LocationHighways.choices,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
)
|
|
||||||
object_location_covenience = models.IntegerField(
|
|
||||||
verbose_name=_("location convenience"),
|
|
||||||
choices=LocationConvenience.choices,
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
# ── Step 4 — Avtomobil ma'lumotlari ─────────────────────────────
|
# ── Step 4 — Avtomobil ma'lumotlari ─────────────────────────────
|
||||||
tex_passport_serie_num = models.CharField(
|
tex_passport_serie_num = models.CharField(
|
||||||
verbose_name=_("tech passport series and number"),
|
verbose_name=_("tech passport series and number"),
|
||||||
|
|||||||
30
core/apps/evaluation/models/certificate.py
Normal file
30
core/apps/evaluation/models/certificate.py
Normal 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")
|
||||||
@@ -34,12 +34,6 @@ class QuickEvaluationModel(AbstractBaseModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
)
|
)
|
||||||
tex_passport_file = models.FileField(
|
|
||||||
verbose_name=_("tech passport file"),
|
|
||||||
upload_to="quick_evaluation/tech_passports/%Y/%m/",
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Car info
|
# Car info
|
||||||
car_type = models.CharField(
|
car_type = models.CharField(
|
||||||
@@ -138,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}"
|
||||||
|
|
||||||
|
|||||||
@@ -118,9 +118,12 @@ class EvaluationrequestModel(AbstractBaseModel):
|
|||||||
choices=RequestStatus.choices,
|
choices=RequestStatus.choices,
|
||||||
default=RequestStatus.PENDING,
|
default=RequestStatus.PENDING,
|
||||||
)
|
)
|
||||||
|
is_archive = models.BooleanField(
|
||||||
|
verbose_name=_("is archive"),
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"Request #{self.pk} — {self.get_rate_type_display()}"
|
return f"Requests #{self.pk} — {self.get_rate_type_display()}"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _baker(cls):
|
def _baker(cls):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ class BaseAutoevaluationSerializer(serializers.ModelSerializer):
|
|||||||
"object_owner_legal_inn",
|
"object_owner_legal_inn",
|
||||||
"tex_passport_serie_num",
|
"tex_passport_serie_num",
|
||||||
"rating_goal",
|
"rating_goal",
|
||||||
"object_location_province",
|
|
||||||
"registration_number",
|
"registration_number",
|
||||||
"object_type",
|
"object_type",
|
||||||
"object_type_display",
|
"object_type_display",
|
||||||
@@ -73,12 +72,12 @@ 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
|
||||||
)
|
# )
|
||||||
object_location_covenience_display = serializers.CharField(
|
# object_location_covenience_display = serializers.CharField(
|
||||||
source="get_object_location_covenience_display", read_only=True, default=None
|
# source="get_object_location_covenience_display", read_only=True, default=None
|
||||||
)
|
# )
|
||||||
|
|
||||||
class Meta(BaseAutoevaluationSerializer.Meta):
|
class Meta(BaseAutoevaluationSerializer.Meta):
|
||||||
fields = BaseAutoevaluationSerializer.Meta.fields + [
|
fields = BaseAutoevaluationSerializer.Meta.fields + [
|
||||||
@@ -97,19 +96,9 @@ class RetrieveAutoevaluationSerializer(BaseAutoevaluationSerializer):
|
|||||||
"object_owner_individual_person_passport_num",
|
"object_owner_individual_person_passport_num",
|
||||||
"object_owner_legal_entity",
|
"object_owner_legal_entity",
|
||||||
"object_owner_legal_inn",
|
"object_owner_legal_inn",
|
||||||
# Step 3
|
|
||||||
"object_location_province",
|
|
||||||
"object_location_district",
|
|
||||||
"object_location_city",
|
|
||||||
"object_location_neighborhood",
|
|
||||||
"object_location_street",
|
|
||||||
"object_location_home",
|
|
||||||
"object_location_highways",
|
|
||||||
"object_location_highways_display",
|
|
||||||
"object_location_covenience",
|
|
||||||
"object_location_covenience_display",
|
|
||||||
# Step 4
|
# Step 4
|
||||||
"tex_passport_serie_num",
|
"tex_passport_serie_num",
|
||||||
|
"tex_passport_file",
|
||||||
"tex_passport_gived_date",
|
"tex_passport_gived_date",
|
||||||
"tex_passport_gived_location",
|
"tex_passport_gived_location",
|
||||||
"car_type",
|
"car_type",
|
||||||
@@ -176,16 +165,8 @@ class UpdateAutoevaluationSerializer(serializers.ModelSerializer):
|
|||||||
"form_ownership",
|
"form_ownership",
|
||||||
"value_determined",
|
"value_determined",
|
||||||
"rate_type",
|
"rate_type",
|
||||||
# Step 3
|
|
||||||
"object_location_province",
|
|
||||||
"object_location_district",
|
|
||||||
"object_location_city",
|
|
||||||
"object_location_neighborhood",
|
|
||||||
"object_location_street",
|
|
||||||
"object_location_home",
|
|
||||||
"object_location_highways",
|
|
||||||
"object_location_covenience",
|
|
||||||
# Step 4
|
# Step 4
|
||||||
|
"tex_passport_file",
|
||||||
"tex_passport_serie_num",
|
"tex_passport_serie_num",
|
||||||
"tex_passport_gived_date",
|
"tex_passport_gived_date",
|
||||||
"tex_passport_gived_location",
|
"tex_passport_gived_location",
|
||||||
@@ -298,17 +279,9 @@ class CreateAutoevaluationSerializer(serializers.ModelSerializer):
|
|||||||
"form_ownership",
|
"form_ownership",
|
||||||
"value_determined",
|
"value_determined",
|
||||||
"rate_type",
|
"rate_type",
|
||||||
# Step 3
|
|
||||||
"object_location_province",
|
|
||||||
"object_location_district",
|
|
||||||
"object_location_city",
|
|
||||||
"object_location_neighborhood",
|
|
||||||
"object_location_street",
|
|
||||||
"object_location_home",
|
|
||||||
"object_location_highways",
|
|
||||||
"object_location_covenience",
|
|
||||||
# Step 4
|
# Step 4
|
||||||
"tex_passport_serie_num",
|
"tex_passport_serie_num",
|
||||||
|
"tex_passport_file",
|
||||||
"tex_passport_gived_date",
|
"tex_passport_gived_date",
|
||||||
"tex_passport_gived_location",
|
"tex_passport_gived_location",
|
||||||
"car_type",
|
"car_type",
|
||||||
@@ -366,8 +339,9 @@ class CreateAutoevaluationSerializer(serializers.ModelSerializer):
|
|||||||
user = self.context.get('request').user
|
user = self.context.get('request').user
|
||||||
validated_data['user'] = user
|
validated_data['user'] = user
|
||||||
evaluation_req = validated_data.get("evaluation_request")
|
evaluation_req = validated_data.get("evaluation_request")
|
||||||
evaluation_req.status = RequestStatus.IN_PROGRESS
|
if evaluation_req:
|
||||||
evaluation_req.save()
|
evaluation_req.status = RequestStatus.IN_PROGRESS
|
||||||
|
evaluation_req.save()
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
1
core/apps/evaluation/serializers/certificate/__init__.py
Normal file
1
core/apps/evaluation/serializers/certificate/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from .certificate import * # noqa
|
||||||
13
core/apps/evaluation/serializers/certificate/certificate.py
Normal file
13
core/apps/evaluation/serializers/certificate/certificate.py
Normal 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",
|
||||||
|
]
|
||||||
@@ -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)
|
||||||
@@ -55,6 +55,7 @@ class BaseEvaluationrequestSerializer(serializers.ModelSerializer):
|
|||||||
"user",
|
"user",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
|
"is_archive",
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_location(self, obj):
|
def get_location(self, obj):
|
||||||
@@ -183,3 +184,7 @@ class CreateEvaluationrequestSerializer(serializers.ModelSerializer):
|
|||||||
validated_data["location_name"] = str(location_name)
|
validated_data["location_name"] = str(location_name)
|
||||||
validated_data["user"] = self.context["request"].user
|
validated_data["user"] = self.context["request"].user
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
class ArchiveEvaluationrequestSerializer(serializers.Serializer):
|
||||||
|
id = serializers.IntegerField(required=True)
|
||||||
|
is_archive = serializers.BooleanField(required=True)
|
||||||
@@ -28,6 +28,10 @@ from .views import (
|
|||||||
AutoEvaluationRemoveAppraisersView,
|
AutoEvaluationRemoveAppraisersView,
|
||||||
DidoxCompanyInfoAPIView,
|
DidoxCompanyInfoAPIView,
|
||||||
TechPassportAPIView,
|
TechPassportAPIView,
|
||||||
|
EvaluationStatusChange,
|
||||||
|
CertificateView,
|
||||||
|
ArchiveQuickEvaluationView,
|
||||||
|
ArchiveEvaluationrequestView,
|
||||||
)
|
)
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
@@ -52,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(
|
||||||
@@ -71,4 +76,8 @@ urlpatterns = [
|
|||||||
TechPassportAPIView.as_view(),
|
TechPassportAPIView.as_view(),
|
||||||
name="tech-passport"
|
name="tech-passport"
|
||||||
),
|
),
|
||||||
|
path("evaluation-request/<int:pk>/change-status/", EvaluationStatusChange.as_view(),
|
||||||
|
name="evaluation-change-status"),
|
||||||
|
path("archive/quick-evaluation/", ArchiveQuickEvaluationView.as_view(), name="quick-evaluation-archive"),
|
||||||
|
path("archive/evaluation-request/", ArchiveEvaluationrequestView.as_view(), name="evaluation-request-archive"),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
23
core/apps/evaluation/views/certificate.py
Normal file
23
core/apps/evaluation/views/certificate.py
Normal 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 = {}
|
||||||
@@ -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"],
|
||||||
@@ -31,7 +31,6 @@ class DidoxCompanyInfoAPIView(GenericAPIView):
|
|||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
tin = kwargs.get("tin")
|
tin = kwargs.get("tin")
|
||||||
|
|
||||||
# 🔥 TYPE CHECK
|
|
||||||
try:
|
try:
|
||||||
tin = int(tin)
|
tin = int(tin)
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
@@ -48,4 +47,14 @@ class DidoxCompanyInfoAPIView(GenericAPIView):
|
|||||||
status=status.HTTP_502_BAD_GATEWAY
|
status=status.HTTP_502_BAD_GATEWAY
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# if both name and personalNum are null/empty -> 404
|
||||||
|
name = data.get("name")
|
||||||
|
personal_num = data.get("personalNum")
|
||||||
|
|
||||||
|
if not name and not personal_num:
|
||||||
|
return Response(
|
||||||
|
{"detail": "Company or person not found"},
|
||||||
|
status=status.HTTP_404_NOT_FOUND
|
||||||
|
)
|
||||||
|
|
||||||
return Response(data, status=status.HTTP_200_OK)
|
return Response(data, status=status.HTTP_200_OK)
|
||||||
@@ -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
|
||||||
|
)
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
|
||||||
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
|
||||||
@@ -5,6 +7,9 @@ from rest_framework.filters import OrderingFilter, SearchFilter
|
|||||||
from rest_framework.pagination import PageNumberPagination
|
from rest_framework.pagination import PageNumberPagination
|
||||||
from rest_framework.permissions import AllowAny, IsAuthenticated
|
from rest_framework.permissions import AllowAny, IsAuthenticated
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework import status
|
||||||
|
|
||||||
from core.apps.evaluation.filters.request import EvaluationrequestFilter
|
from core.apps.evaluation.filters.request import EvaluationrequestFilter
|
||||||
from core.apps.evaluation.models import EvaluationrequestModel
|
from core.apps.evaluation.models import EvaluationrequestModel
|
||||||
@@ -12,7 +17,11 @@ from core.apps.evaluation.serializers.request import (
|
|||||||
CreateEvaluationrequestSerializer,
|
CreateEvaluationrequestSerializer,
|
||||||
ListEvaluationrequestSerializer,
|
ListEvaluationrequestSerializer,
|
||||||
RetrieveEvaluationrequestSerializer,
|
RetrieveEvaluationrequestSerializer,
|
||||||
|
ArchiveEvaluationrequestSerializer,
|
||||||
)
|
)
|
||||||
|
from core.apps.evaluation.choices.request import RequestStatus
|
||||||
|
from rest_framework.generics import GenericAPIView
|
||||||
|
from drf_spectacular.utils import OpenApiResponse
|
||||||
|
|
||||||
|
|
||||||
# class RequestPagination(PageNumberPagination):
|
# class RequestPagination(PageNumberPagination):
|
||||||
@@ -128,3 +137,114 @@ class AdminEvaluationrequestView(BaseViewSetMixin, ModelViewSet):
|
|||||||
|
|
||||||
def serializer_context(self):
|
def serializer_context(self):
|
||||||
return self.serializer_class(context={"request": self.request})
|
return self.serializer_class(context={"request": self.request})
|
||||||
|
|
||||||
|
|
||||||
|
@extend_schema(tags=["EvaluationRequest"])
|
||||||
|
class EvaluationStatusChange(APIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def post(self, request, pk):
|
||||||
|
if request.user.role not in [RoleChoice.ADMIN, RoleChoice.SUPERUSER]:
|
||||||
|
return Response({'detail': 'Forbidden'}, status=status.HTTP_403_FORBIDDEN)
|
||||||
|
|
||||||
|
evaluation = get_object_or_404(EvaluationrequestModel, pk=pk)
|
||||||
|
|
||||||
|
|
||||||
|
status_value = request.data.get('status')
|
||||||
|
if not status_value:
|
||||||
|
return Response({'detail': 'Status is required'}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
valid_statuses = [
|
||||||
|
RequestStatus.PENDING,
|
||||||
|
RequestStatus.IN_PROGRESS,
|
||||||
|
RequestStatus.COMPLETED,
|
||||||
|
RequestStatus.REJECTED
|
||||||
|
]
|
||||||
|
|
||||||
|
if status_value not in valid_statuses:
|
||||||
|
return Response(
|
||||||
|
{'detail': f'Invalid status. Must be one of: {valid_statuses}'},
|
||||||
|
status=status.HTTP_400_BAD_REQUEST
|
||||||
|
)
|
||||||
|
|
||||||
|
evaluation.status = status_value
|
||||||
|
evaluation.save()
|
||||||
|
|
||||||
|
return Response({
|
||||||
|
'success': True,
|
||||||
|
'status': evaluation.status,
|
||||||
|
'id': evaluation.pk
|
||||||
|
})
|
||||||
|
|
||||||
|
@extend_schema(tags=["EvaluationRequest"])
|
||||||
|
class ArchiveEvaluationrequestView(GenericAPIView):
|
||||||
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.request.method == "GET":
|
||||||
|
return ListEvaluationrequestSerializer
|
||||||
|
return ArchiveEvaluationrequestSerializer
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
tags=["EvaluationRequest"],
|
||||||
|
summary="Get archived evaluation requests list",
|
||||||
|
description="""
|
||||||
|
Returns only archived evaluation requests.
|
||||||
|
|
||||||
|
This endpoint works like evaluation-request/,
|
||||||
|
but only records with is_archive=True are returned.
|
||||||
|
""",
|
||||||
|
responses={200: ListEvaluationrequestSerializer(many=True)},
|
||||||
|
)
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
queryset = EvaluationrequestModel.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=["EvaluationRequest"],
|
||||||
|
summary="Archive or unarchive evaluation request",
|
||||||
|
description="""
|
||||||
|
Update archive status for evaluation request.
|
||||||
|
|
||||||
|
- is_archive=true → archive
|
||||||
|
- is_archive=false → remove from archive
|
||||||
|
""",
|
||||||
|
request=ArchiveEvaluationrequestSerializer,
|
||||||
|
responses={
|
||||||
|
200: OpenApiResponse(
|
||||||
|
description="Archive status updated successfully"
|
||||||
|
),
|
||||||
|
400: OpenApiResponse(
|
||||||
|
description="Validation error"
|
||||||
|
),
|
||||||
|
404: OpenApiResponse(
|
||||||
|
description="Evaluation request 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(
|
||||||
|
EvaluationrequestModel,
|
||||||
|
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
|
||||||
|
)
|
||||||
@@ -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"],
|
||||||
@@ -33,18 +33,27 @@ class TechPassportAPIView(GenericAPIView):
|
|||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
serializer = TechPassportSerializer(data=request.data)
|
serializer = TechPassportSerializer(data=request.data)
|
||||||
serializer.is_valid(raise_exception=True)
|
serializer.is_valid(raise_exception=True)
|
||||||
|
|
||||||
data = serializer.validated_data
|
data = serializer.validated_data
|
||||||
|
|
||||||
try:
|
result = TechPassportService.get_auto_info(
|
||||||
result = TechPassportService.get_auto_info(
|
autonumber=data["autonumber"],
|
||||||
autonumber=data["autonumber"],
|
tech_pass_number=data["tech_pass_number"],
|
||||||
tech_pass_number=data["tech_pass_number"],
|
tech_pass_series=data["tech_pass_series"],
|
||||||
tech_pass_series=data["tech_pass_series"],
|
)
|
||||||
)
|
|
||||||
return Response(result, status=status.HTTP_200_OK)
|
|
||||||
|
|
||||||
except Exception as e:
|
response_data = result["data"]
|
||||||
|
status_code = result["status_code"]
|
||||||
|
|
||||||
|
# success bo‘lsa faqat data ichidagi data qaytariladi
|
||||||
|
if status_code == 200:
|
||||||
return Response(
|
return Response(
|
||||||
{"detail": str(e)},
|
response_data.get("data", {}),
|
||||||
status=status.HTTP_400_BAD_REQUEST
|
status=status.HTTP_200_OK
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# error bo‘lsa original response qaytariladi
|
||||||
|
return Response(
|
||||||
|
response_data,
|
||||||
|
status=status_code
|
||||||
|
)
|
||||||
@@ -1,10 +1,28 @@
|
|||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
||||||
|
from drf_spectacular.utils import extend_schema, OpenApiParameter
|
||||||
|
from drf_spectacular.types import OpenApiTypes
|
||||||
|
|
||||||
from core.apps.shared.serializers.region.district import DistrictSerializer, VillageSerializer, RegionSerializer
|
from core.apps.shared.serializers.region.district import DistrictSerializer, VillageSerializer, RegionSerializer
|
||||||
from core.apps.shared.models import RegionModel, VillageModel, DistrictModel
|
from core.apps.shared.models import RegionModel, VillageModel, DistrictModel
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
parameters=[
|
||||||
|
OpenApiParameter(
|
||||||
|
name="region",
|
||||||
|
type=OpenApiTypes.INT,
|
||||||
|
location=OpenApiParameter.QUERY,
|
||||||
|
description="Filter by region ID"
|
||||||
|
),
|
||||||
|
OpenApiParameter(
|
||||||
|
name="name",
|
||||||
|
type=OpenApiTypes.STR,
|
||||||
|
location=OpenApiParameter.QUERY,
|
||||||
|
description="Filter by district name"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
class DistrictListCreateView(generics.ListCreateAPIView):
|
class DistrictListCreateView(generics.ListCreateAPIView):
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
serializer_class = DistrictSerializer
|
serializer_class = DistrictSerializer
|
||||||
@@ -19,7 +37,22 @@ class DistrictListCreateView(generics.ListCreateAPIView):
|
|||||||
return self.queryset.filter(region=region)
|
return self.queryset.filter(region=region)
|
||||||
return super().get_queryset()
|
return super().get_queryset()
|
||||||
|
|
||||||
|
@extend_schema(
|
||||||
|
parameters=[
|
||||||
|
OpenApiParameter(
|
||||||
|
name="district",
|
||||||
|
type=OpenApiTypes.INT,
|
||||||
|
location=OpenApiParameter.QUERY,
|
||||||
|
description="Filter by district ID"
|
||||||
|
),
|
||||||
|
OpenApiParameter(
|
||||||
|
name="name",
|
||||||
|
type=OpenApiTypes.STR,
|
||||||
|
location=OpenApiParameter.QUERY,
|
||||||
|
description="Filter by village name"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
class VillageListCreateView(generics.ListCreateAPIView):
|
class VillageListCreateView(generics.ListCreateAPIView):
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
serializer_class = VillageSerializer
|
serializer_class = VillageSerializer
|
||||||
|
|||||||
@@ -44,21 +44,28 @@ class TechPassportService:
|
|||||||
verify=False
|
verify=False
|
||||||
)
|
)
|
||||||
|
|
||||||
response.raise_for_status()
|
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Tech passport info fetched successfully: {response.status_code}"
|
f"Tech passport response status: {response.status_code}"
|
||||||
)
|
)
|
||||||
|
|
||||||
response_data = response.json()
|
try:
|
||||||
|
response_data = response.json()
|
||||||
|
except ValueError:
|
||||||
|
response_data = {
|
||||||
|
"detail": "Invalid response from external service"
|
||||||
|
}
|
||||||
|
|
||||||
return response_data.get("data", {})
|
return {
|
||||||
|
"status_code": response.status_code,
|
||||||
|
"data": response_data
|
||||||
|
}
|
||||||
|
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
logger.error(
|
logger.error(str(e))
|
||||||
f"Error while fetching tech passport info: {str(e)}"
|
|
||||||
)
|
|
||||||
return {
|
return {
|
||||||
"success": False,
|
"status_code": 500,
|
||||||
"message": str(e)
|
"data": {
|
||||||
|
"detail": str(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ services:
|
|||||||
max-file: "5"
|
max-file: "5"
|
||||||
|
|
||||||
web:
|
web:
|
||||||
image: husanjon/sifatbaho:98
|
image: husanjon/sifatbaho:114
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
@@ -129,7 +129,7 @@ services:
|
|||||||
max-file: "5"
|
max-file: "5"
|
||||||
|
|
||||||
celery:
|
celery:
|
||||||
image: husanjon/sifatbaho:98
|
image: husanjon/sifatbaho:114
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
Reference in New Issue
Block a user