From 0c9c7267567976e4bddc8f33ed92151a5d17a956 Mon Sep 17 00:00:00 2001 From: Shaxobff Date: Mon, 4 May 2026 16:15:12 +0500 Subject: [PATCH] add generation_pdf pdf , fix 500 error , install reportlab --- .../evaluation/serializers/vehicle/Vehicle.py | 26 ++++ core/apps/evaluation/urls.py | 1 + core/apps/evaluation/views/vehicle.py | 25 +++- core/apps/tasks/urls.py | 2 +- core/apps/tasks/views/task.py | 9 +- core/utils/generation_pdf.py | 138 ++++++++++++++++++ requirements.txt | 4 +- 7 files changed, 195 insertions(+), 10 deletions(-) create mode 100644 core/utils/generation_pdf.py diff --git a/core/apps/evaluation/serializers/vehicle/Vehicle.py b/core/apps/evaluation/serializers/vehicle/Vehicle.py index 7593e1a..67d99e7 100644 --- a/core/apps/evaluation/serializers/vehicle/Vehicle.py +++ b/core/apps/evaluation/serializers/vehicle/Vehicle.py @@ -87,3 +87,29 @@ class CreateVehicleSerializer(serializers.ModelSerializer): "condition", "position", ] + + +class VehicleApplicationSerializer(serializers.Serializer): + person_name = serializers.CharField() + property_owner = serializers.CharField(max_length=100) + address = serializers.CharField(max_length=255) + marka = serializers.CharField(max_length=100) + model = serializers.CharField(max_length=100) + configuration = serializers.CharField(max_length=100) + auto_number = serializers.CharField(max_length=100) + date_created = serializers.DateTimeField() + mileage = serializers.IntegerField() + vehicle_identification = serializers.CharField(max_length=100) + engine_number = serializers.CharField(max_length=100) + colour = serializers.CharField(max_length=100) + registration_certificate_series = serializers.CharField(max_length=100) + tec_passport_number = serializers.CharField(max_length=100) + tec_passport_date = serializers.DateTimeField() + tec_passport_place = serializers.CharField(max_length=255) + body_type = serializers.CharField(max_length=100) + chassis = serializers.CharField(max_length=100) + plate = serializers.CharField(max_length=100) + value_type = serializers.CharField(max_length=100) + evaluation_purpose = serializers.CharField(max_length=100) + personal_id_number = serializers.IntegerField() + id_number = serializers.CharField(max_length=9) diff --git a/core/apps/evaluation/urls.py b/core/apps/evaluation/urls.py index a9d7247..7e64e0b 100644 --- a/core/apps/evaluation/urls.py +++ b/core/apps/evaluation/urls.py @@ -88,4 +88,5 @@ urlpatterns = [ )), path("calculate_avg_cost/", views.AvgCostAPIView.as_view()), + path("vehicle_document/", views.GeneratePDFView.as_view()), ] diff --git a/core/apps/evaluation/views/vehicle.py b/core/apps/evaluation/views/vehicle.py index b250b7a..f8b956e 100644 --- a/core/apps/evaluation/views/vehicle.py +++ b/core/apps/evaluation/views/vehicle.py @@ -1,16 +1,19 @@ # django core +from django.http import HttpResponse from django_core.mixins import BaseViewSetMixin - # swagger from drf_spectacular.utils import extend_schema - # rest framework from rest_framework.permissions import AllowAny +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework.views import APIView from rest_framework.viewsets import ReadOnlyModelViewSet # core apps from core.apps.evaluation.models import VehicleModel -from core.apps.evaluation.serializers import vehicle as serialziers +from core.apps.evaluation.serializers import vehicle as serialziers, VehicleApplicationSerializer +from core.utils.generation_pdf import PDFService @extend_schema(tags=["Vehicle"]) @@ -27,3 +30,19 @@ class VehicleView(BaseViewSetMixin, ReadOnlyModelViewSet): "retrieve": serialziers.RetrieveVehicleSerializer, "create": serialziers.CreateVehicleSerializer, } + + +@extend_schema(tags=['GenerationDocument'], request=VehicleApplicationSerializer) +class GeneratePDFView(APIView): + permission_classes = [IsAuthenticated] + + def post(self, request): + serializer = VehicleApplicationSerializer(data=request.data) + if not serializer.is_valid(): + return Response(serializer.errors, status=400) + + pdf_buffer = PDFService.generate_vehicle_pdf(serializer.validated_data) + + response = HttpResponse(pdf_buffer, content_type='application/pdf') + response['Content-Disposition'] = 'attachment; filename="ariza.pdf"' + return response diff --git a/core/apps/tasks/urls.py b/core/apps/tasks/urls.py index 29d59af..662b7ac 100644 --- a/core/apps/tasks/urls.py +++ b/core/apps/tasks/urls.py @@ -20,7 +20,7 @@ urlpatterns = [ path('task/', include( [ path('list/', task.TaskListView.as_view()), - path('/', task.TaskDetailView.as_view()), + path('/', task.TaskDetailView.as_view()), path('create/', task.TaskCreateView.as_view()), ] )), diff --git a/core/apps/tasks/views/task.py b/core/apps/tasks/views/task.py index 22dc730..ef79b2a 100644 --- a/core/apps/tasks/views/task.py +++ b/core/apps/tasks/views/task.py @@ -1,9 +1,7 @@ from django.db import transaction - -from rest_framework import permissions, generics -from rest_framework.response import Response - from drf_spectacular.utils import extend_schema +from rest_framework import permissions, generics, status +from rest_framework.response import Response from core.apps.tasks.models.task import Task from core.apps.tasks.serializers.task import TaskSerializer, TaskCreateSerializer @@ -18,7 +16,8 @@ class TaskCreateView(generics.GenericAPIView): @transaction.atomic def post(self, request): serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) + if not serializer.is_valid(raise_exception=True): + return Response(serializer.validated_data, status=status.HTTP_400_BAD_REQUEST) serializer.save() return Response(serializer.data) diff --git a/core/utils/generation_pdf.py b/core/utils/generation_pdf.py new file mode 100644 index 0000000..546719b --- /dev/null +++ b/core/utils/generation_pdf.py @@ -0,0 +1,138 @@ +# services.py +from io import BytesIO + +from reportlab.lib import colors +from reportlab.lib.enums import TA_RIGHT, TA_CENTER +from reportlab.lib.pagesizes import A4 +from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle +from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer + + +class PDFService: + @staticmethod + def generate_vehicle_pdf(data): + buffer = BytesIO() + doc = SimpleDocTemplate( + buffer, pagesize=A4, + rightMargin=40, leftMargin=40, + topMargin=40, bottomMargin=40 + ) + styles = getSampleStyleSheet() + + cell_style = ParagraphStyle( + 'CellStyle', parent=styles['Normal'], + fontSize=9, leading=11 + ) + cell_style_bold = ParagraphStyle( + 'CellStyleBold', parent=cell_style, + fontName='Helvetica-Bold', + textColor=colors.red + ) + header_style = ParagraphStyle( + 'HeaderStyle', parent=styles['Normal'], + alignment=TA_RIGHT, fontSize=10, leading=12 + ) + title_style = ParagraphStyle( + 'TitleStyle', parent=styles['Normal'], + alignment=TA_CENTER, fontSize=14, leading=16 + ) + + elements = [] + + header_text = ( + f'"Sifat baholash" MChJ direktori
' + f"T.R.To'rayevga


" + f"{data.get('address', '')}
" + f"ro'yxatda turuvchi fuqaro
" + f"{data.get('person_name', '')} tomonidan
" + f"Avtotransport vositasini baholash uchun" + ) + elements.append(Paragraph(header_text, header_style)) + elements.append(Spacer(1, 25)) + + elements.append(Paragraph("A R I Z A", title_style)) + elements.append(Spacer(1, 10)) + elements.append(Paragraph( + "Ushbu orqali quyidagi avtotransport vositasini baholab berishingizni so'rayman:", + cell_style + )) + elements.append(Spacer(1, 10)) + + date_created = data.get('date_created') + year_str = str(date_created.year) + " yil" if date_created else "" + + tec_date = data.get('tec_passport_date') + tec_date_str = tec_date.strftime('%d.%m.%Y yil') if tec_date else "" + + raw_data = [ + ["Mulk egasi", data.get('property_owner', '')], + ["Manzil", data.get('address', '')], + ["Marka", data.get('marka', '')], + ["Model", data.get('model', '')], + ["Komplektatsiya", data.get('configuration', '')], + ["Davlat raqami", data.get('auto_number', '')], + ["Ishlab chiqarilgan yili", year_str], + ["Bosib o'tgan masofasi", f"{data.get('mileage', 0):,}".replace(',', ' ')], + ["№ kuzov (VIN)", data.get('vehicle_identification', '')], + ["№ dvigatel", data.get('engine_number', '')], + ["Rang", data.get('colour', '')], + ["Texnik passport seriyasi", data.get('registration_certificate_series', '')], + ["Texnik passport raqami", data.get('tec_passport_number', '')], + ["Texnik passport berilgan sanasi", tec_date_str], + ["Texnik passport berilgan joyi", data.get('tec_passport_place', '')], + ["Kuzov turi", data.get('body_type', '')], + ["Shassi", data.get('chassis', '')], + ["Davlat belgisi (plate)", data.get('plate', '')], # ← was missing + ] + + table_data = [ + [Paragraph(row[0], cell_style), Paragraph(str(row[1]), cell_style_bold)] + for row in raw_data + ] + table = Table(table_data, colWidths=[170, 345]) + table.setStyle(TableStyle([ + ('GRID', (0, 0), (-1, -1), 0.5, colors.black), + ('VALIGN', (0, 0), (-1, -1), 'TOP'), + ('LEFTPADDING', (0, 0), (-1, -1), 6), + ('TOPPADDING', (0, 0), (-1, -1), 4), + ('BOTTOMPADDING', (0, 0), (-1, -1), 4), + ])) + elements.append(table) + elements.append(Spacer(1, 15)) + + elements.append(Paragraph("Baholash maqsadi:", cell_style)) + purpose_raw = [ + ["Aniqlanayotgan qiymat turi", data.get('value_type', '')], + ["Baholash maqsadi", data.get('evaluation_purpose', '')], + ] + purpose_data = [ + [Paragraph(r[0], cell_style), Paragraph(str(r[1]), cell_style_bold)] + for r in purpose_raw + ] + pt = Table(purpose_data, colWidths=[170, 345]) + pt.setStyle(TableStyle([ + ('GRID', (0, 0), (-1, -1), 0.5, colors.black), + ('VALIGN', (0, 0), (-1, -1), 'TOP'), + ])) + elements.append(pt) + elements.append(Spacer(1, 15)) + + elements.append(Paragraph("Buyurtmachi rekvizitlari:", cell_style)) + footer_raw = [ + ["Shaxsiy raqam (PINFL)", str(data.get('personal_id_number', ''))], + ["ID karta raqami", data.get('id_number', '')], + ] + footer_data = [ + [Paragraph(f[0], cell_style), Paragraph(str(f[1]), cell_style_bold)] + for f in footer_raw + ] + ft = Table(footer_data, colWidths=[170, 345]) + ft.setStyle(TableStyle([ + ('GRID', (0, 0), (-1, -1), 0.5, colors.black), + ('VALIGN', (0, 0), (-1, -1), 'TOP'), + ])) + elements.append(ft) + + doc.build(elements) + buffer.seek(0) + return buffer \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 9c56fdb..97411b8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -49,4 +49,6 @@ boto3 grpcio>=1.62.0 grpcio-tools>=1.62.0 -protobuf>=4.25.0 \ No newline at end of file +protobuf>=4.25.0 + +reportlab \ No newline at end of file