feat: add new api and fix some problems

This commit is contained in:
xoliqberdiyev
2026-05-06 17:57:07 +05:00
parent 67558e77de
commit 6a9cf9fa1f
10 changed files with 265 additions and 28 deletions

View File

@@ -0,0 +1,37 @@
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="ExecutorInfoModel",
fields=[
("id", models.AutoField(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)),
("name", models.CharField(blank=True, max_length=255, null=True, verbose_name="name")),
("address", models.TextField(blank=True, null=True, verbose_name="address")),
("account_number", models.CharField(blank=True, max_length=50, null=True, verbose_name="account number")),
("tin", models.CharField(blank=True, max_length=20, null=True, verbose_name="STIR / TIN")),
("bank", models.CharField(blank=True, max_length=255, null=True, verbose_name="bank")),
("mfo", models.CharField(blank=True, max_length=20, null=True, verbose_name="MFO")),
("oked", models.CharField(blank=True, max_length=20, null=True, verbose_name="OKED")),
("email", models.EmailField(blank=True, max_length=254, null=True, verbose_name="email")),
("phone", models.CharField(blank=True, max_length=255, null=True, verbose_name="phone")),
("evaluator_full_name", models.CharField(blank=True, max_length=255, null=True, verbose_name="evaluator full name")),
("evaluator_certificate", models.CharField(blank=True, max_length=255, null=True, verbose_name="evaluator certificate")),
("license_info", models.TextField(blank=True, null=True, verbose_name="license info")),
("insurance_info", models.TextField(blank=True, null=True, verbose_name="insurance info")),
],
options={
"verbose_name": "Executor Info",
"verbose_name_plural": "Executor Info",
"db_table": "ExecutorInfo",
},
),
]

View File

@@ -0,0 +1 @@
from .executor import ExecutorInfoModel # noqa

View File

@@ -0,0 +1,88 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from django_core.models import AbstractBaseModel
class ExecutorInfoModel(AbstractBaseModel):
name = models.CharField(
verbose_name=_("name"),
max_length=255,
blank=True,
null=True,
)
address = models.TextField(
verbose_name=_("address"),
blank=True,
null=True,
)
account_number = models.CharField(
verbose_name=_("account number"),
max_length=50,
blank=True,
null=True,
)
tin = models.CharField(
verbose_name=_("STIR / TIN"),
max_length=20,
blank=True,
null=True,
)
bank = models.CharField(
verbose_name=_("bank"),
max_length=255,
blank=True,
null=True,
)
mfo = models.CharField(
verbose_name=_("MFO"),
max_length=20,
blank=True,
null=True,
)
oked = models.CharField(
verbose_name=_("OKED"),
max_length=20,
blank=True,
null=True,
)
email = models.EmailField(
verbose_name=_("email"),
blank=True,
null=True,
)
phone = models.CharField(
verbose_name=_("phone"),
max_length=255,
blank=True,
null=True,
)
evaluator_full_name = models.CharField(
verbose_name=_("evaluator full name"),
max_length=255,
blank=True,
null=True,
)
evaluator_certificate = models.CharField(
verbose_name=_("evaluator certificate"),
max_length=255,
blank=True,
null=True,
)
license_info = models.TextField(
verbose_name=_("license info"),
blank=True,
null=True,
)
insurance_info = models.TextField(
verbose_name=_("insurance info"),
blank=True,
null=True,
)
def __str__(self):
return self.name or f"ExecutorInfo #{self.pk}"
class Meta:
db_table = "ExecutorInfo"
verbose_name = _("Executor Info")
verbose_name_plural = _("Executor Info")

View File

@@ -0,0 +1,27 @@
from rest_framework import serializers
from core.apps.documents.models import ExecutorInfoModel
class ExecutorInfoSerializer(serializers.ModelSerializer):
class Meta:
model = ExecutorInfoModel
fields = [
"id",
"name",
"address",
"account_number",
"tin",
"bank",
"mfo",
"oked",
"email",
"phone",
"evaluator_full_name",
"evaluator_certificate",
"license_info",
"insurance_info",
"created_at",
"updated_at",
]
read_only_fields = ["id", "created_at", "updated_at"]

View File

@@ -1,7 +1,9 @@
from django.urls import path
from core.apps.documents.views.contract import ValuationReportPDFView
from core.apps.documents.views.executor import ExecutorInfoView
urlpatterns = [
path('generate-contract-pdf/<int:pk>/', ValuationReportPDFView.as_view(), name='generate_contract_pdf'),
path('executor-info/', ExecutorInfoView.as_view(), name='executor_info'),
]

View File

@@ -11,6 +11,7 @@ from weasyprint import HTML
from core.apps.evaluation.models import AutoEvaluationModel
from core.apps.evaluation.choices.auto import ObjectOwnerType
from core.apps.documents.models import ExecutorInfoModel
from core.apps.documents.serializers.contract import ContractPDFRequestSerializer
from core.services import CurrencyService
@@ -194,6 +195,7 @@ class ValuationReportPDFView(APIView):
contract_ctx = self._contract_context(auto, report_date)
inspection_ctx = self._inspection_context(payload)
rates_ctx = self._rates_context(valuation_date)
executor_ctx = self._executor_context()
ctx = {
"logo_url": "",
@@ -211,8 +213,9 @@ class ValuationReportPDFView(APIView):
"owner": owner_ctx,
"contract": contract_ctx,
"company": {
"director": "",
"director": executor_ctx.get("evaluator_full_name") or "",
},
"executor": executor_ctx,
"rates": rates_ctx,
"inspection": inspection_ctx,
"cost": {
@@ -372,6 +375,40 @@ class ValuationReportPDFView(APIView):
"eur": rates.get("EUR", ""),
}
def _executor_context(self):
instance = ExecutorInfoModel.objects.order_by("-created_at").first()
if not instance:
return {
"name": "",
"address": "",
"account_number": "",
"tin": "",
"bank": "",
"mfo": "",
"oked": "",
"email": "",
"phone": "",
"evaluator_full_name": "",
"evaluator_certificate": "",
"license_info": "",
"insurance_info": "",
}
return {
"name": instance.name or "",
"address": instance.address or "",
"account_number": instance.account_number or "",
"tin": instance.tin or "",
"bank": instance.bank or "",
"mfo": instance.mfo or "",
"oked": instance.oked or "",
"email": instance.email or "",
"phone": instance.phone or "",
"evaluator_full_name": instance.evaluator_full_name or "",
"evaluator_certificate": instance.evaluator_certificate or "",
"license_info": instance.license_info or "",
"insurance_info": instance.insurance_info or "",
}
def _empty_analog(self):
return {
"source": "",

View File

@@ -0,0 +1,47 @@
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from core.apps.documents.models import ExecutorInfoModel
from core.apps.documents.serializers.executor import ExecutorInfoSerializer
class ExecutorInfoView(APIView):
"""Singleton endpoint — faqat bitta ExecutorInfo yozuvi bo'ladi."""
def get(self, request, *args, **kwargs):
instance = ExecutorInfoModel.objects.order_by("created_at").first()
if not instance:
return Response({}, status=status.HTTP_200_OK)
return Response(ExecutorInfoSerializer(instance).data)
def post(self, request, *args, **kwargs):
if ExecutorInfoModel.objects.exists():
return Response(
{"detail": "ExecutorInfo allaqachon mavjud. Yangilash uchun PUT/PATCH ishlating."},
status=status.HTTP_400_BAD_REQUEST,
)
serializer = ExecutorInfoSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
def put(self, request, *args, **kwargs):
return self._upsert(request, partial=False)
def patch(self, request, *args, **kwargs):
return self._upsert(request, partial=True)
def delete(self, request, *args, **kwargs):
instance = ExecutorInfoModel.objects.order_by("created_at").first()
if not instance:
return Response(status=status.HTTP_404_NOT_FOUND)
instance.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
def _upsert(self, request, partial):
instance = ExecutorInfoModel.objects.order_by("created_at").first()
serializer = ExecutorInfoSerializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)