From 23b8c1450facc8638cf18db2ec02adef4e19b455 Mon Sep 17 00:00:00 2001 From: xoliqberdiyev Date: Wed, 6 May 2026 15:12:46 +0500 Subject: [PATCH] feat: add empty_weigh and full_weight fields for auto and mechanic rvalution models --- core/apps/documents/services/cbu_rates.py | 33 ----------- core/apps/documents/views/contract.py | 8 +-- .../migrations/0047_auto_full_empty_weight.py | 31 ++++++++++ core/apps/evaluation/models/auto.py | 10 ++++ core/apps/evaluation/models/mechanic_auto.py | 10 ++++ .../serializers/auto/AutoEvaluation.py | 8 +++ .../auto/MechanicAutoEvaluation.py | 8 +++ core/services/__init__.py | 3 +- core/services/currency.py | 33 +++++++++++ task.txt | 58 ++++++------------- 10 files changed, 123 insertions(+), 79 deletions(-) delete mode 100644 core/apps/documents/services/cbu_rates.py create mode 100644 core/apps/evaluation/migrations/0047_auto_full_empty_weight.py create mode 100644 core/services/currency.py diff --git a/core/apps/documents/services/cbu_rates.py b/core/apps/documents/services/cbu_rates.py deleted file mode 100644 index 5ef4ed6..0000000 --- a/core/apps/documents/services/cbu_rates.py +++ /dev/null @@ -1,33 +0,0 @@ -from datetime import date - -import requests - -CBU_URL = "https://cbu.uz/oz/arkhiv-kursov-valyut/json/{code}/{date}/" -TIMEOUT_SECONDS = 5 -CURRENCY_CODES = ("USD", "EUR", "RUB") - - -def fetch_rates(target_date): - """CBU.uz dan berilgan sanaga oid USD, EUR, RUB kurslarini olish. - - Tarmoq xatosi yoki notogri javob bolsa bosh dict qaytadi. - """ - if target_date is None: - target_date = date.today() - date_str = target_date.strftime("%Y-%m-%d") - rates = {} - for code in CURRENCY_CODES: - try: - resp = requests.get( - CBU_URL.format(code=code, date=date_str), - timeout=TIMEOUT_SECONDS, - ) - resp.raise_for_status() - data = resp.json() - if isinstance(data, list) and data: - rate_value = data[0].get("Rate") - if rate_value: - rates[code] = rate_value - except (requests.RequestException, ValueError): - continue - return rates diff --git a/core/apps/documents/views/contract.py b/core/apps/documents/views/contract.py index 9a8aaa6..88d676e 100644 --- a/core/apps/documents/views/contract.py +++ b/core/apps/documents/views/contract.py @@ -12,7 +12,7 @@ from weasyprint import HTML from core.apps.evaluation.models import AutoEvaluationModel from core.apps.evaluation.choices.auto import ObjectOwnerType from core.apps.documents.serializers.contract import ContractPDFRequestSerializer -from core.apps.documents.services.cbu_rates import fetch_rates +from core.services import CurrencyService UZ_MONTHS = { @@ -301,8 +301,8 @@ class ValuationReportPDFView(APIView): "tech_passport": tech_passport_value, "fuel_type": fuel_type_value, "engine_power": "", - "full_weight": "", - "empty_weight": "", + "full_weight": auto.full_weight if auto.full_weight is not None else "", + "empty_weight": auto.empty_weight if auto.empty_weight is not None else "", } def _customer_context(self, user): @@ -365,7 +365,7 @@ class ValuationReportPDFView(APIView): } def _rates_context(self, target_date): - rates = fetch_rates(target_date) + rates = CurrencyService.get_rates(target_date) return { "rur": rates.get("RUB", ""), "usd": rates.get("USD", ""), diff --git a/core/apps/evaluation/migrations/0047_auto_full_empty_weight.py b/core/apps/evaluation/migrations/0047_auto_full_empty_weight.py new file mode 100644 index 0000000..0d7d555 --- /dev/null +++ b/core/apps/evaluation/migrations/0047_auto_full_empty_weight.py @@ -0,0 +1,31 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("evaluation", "0046_mechanicauto_fields_and_multi_tex_passport"), + ] + + operations = [ + migrations.AddField( + model_name="autoevaluationmodel", + name="full_weight", + field=models.PositiveIntegerField(blank=True, null=True, verbose_name="full weight"), + ), + migrations.AddField( + model_name="autoevaluationmodel", + name="empty_weight", + field=models.PositiveIntegerField(blank=True, null=True, verbose_name="empty weight"), + ), + migrations.AddField( + model_name="mechanicautoevaluationmodel", + name="full_weight", + field=models.PositiveIntegerField(blank=True, null=True, verbose_name="full weight"), + ), + migrations.AddField( + model_name="mechanicautoevaluationmodel", + name="empty_weight", + field=models.PositiveIntegerField(blank=True, null=True, verbose_name="empty weight"), + ), + ] diff --git a/core/apps/evaluation/models/auto.py b/core/apps/evaluation/models/auto.py index b52a6a9..f5a4fa2 100644 --- a/core/apps/evaluation/models/auto.py +++ b/core/apps/evaluation/models/auto.py @@ -260,6 +260,16 @@ class AutoEvaluationModel(AbstractBaseModel): blank=True, null=True, ) + full_weight = models.PositiveIntegerField( + verbose_name=_("full weight"), + blank=True, + null=True, + ) + empty_weight = models.PositiveIntegerField( + verbose_name=_("empty weight"), + blank=True, + null=True, + ) # ── Natija ─────────────────────────────────────────────────────── rating_goal = models.CharField( diff --git a/core/apps/evaluation/models/mechanic_auto.py b/core/apps/evaluation/models/mechanic_auto.py index 9a83192..72a3d09 100644 --- a/core/apps/evaluation/models/mechanic_auto.py +++ b/core/apps/evaluation/models/mechanic_auto.py @@ -256,6 +256,16 @@ class MechanicAutoEvaluationModel(AbstractBaseModel): blank=True, null=True, ) + full_weight = models.PositiveIntegerField( + verbose_name=_("full weight"), + blank=True, + null=True, + ) + empty_weight = models.PositiveIntegerField( + verbose_name=_("empty weight"), + blank=True, + null=True, + ) # ── Natija ─────────────────────────────────────────────────────── rating_goal = models.CharField( diff --git a/core/apps/evaluation/serializers/auto/AutoEvaluation.py b/core/apps/evaluation/serializers/auto/AutoEvaluation.py index 190810a..b117737 100644 --- a/core/apps/evaluation/serializers/auto/AutoEvaluation.py +++ b/core/apps/evaluation/serializers/auto/AutoEvaluation.py @@ -73,6 +73,8 @@ class BaseAutoevaluationSerializer(serializers.ModelSerializer): "car_number", "manufacture_year", "car_color", + "full_weight", + "empty_weight", "distance_covered", "car_position", "body_type", @@ -214,6 +216,8 @@ class UpdateAutoevaluationSerializer(serializers.ModelSerializer): "manufacture_year", "car_dvigatel_number", "car_color", + "full_weight", + "empty_weight", "distance_covered", "car_position", "body_type", @@ -361,6 +365,8 @@ class CreateAutoevaluationSerializer(serializers.ModelSerializer): "manufacture_year", "car_dvigatel_number", "car_color", + "full_weight", + "empty_weight", "distance_covered", "car_position", "body_type", @@ -493,6 +499,8 @@ class AutoEvaluationModelSerializer(serializers.ModelSerializer): "manufacture_year", "car_dvigatel_number", "car_color", + "full_weight", + "empty_weight", "distance_covered", "car_position", "body_type", diff --git a/core/apps/evaluation/serializers/auto/MechanicAutoEvaluation.py b/core/apps/evaluation/serializers/auto/MechanicAutoEvaluation.py index 22ba10e..c1534fb 100644 --- a/core/apps/evaluation/serializers/auto/MechanicAutoEvaluation.py +++ b/core/apps/evaluation/serializers/auto/MechanicAutoEvaluation.py @@ -73,6 +73,8 @@ class BaseMechanicAutoevaluationSerializer(serializers.ModelSerializer): "car_number", "manufacture_year", "car_color", + "full_weight", + "empty_weight", "distance_covered", "car_position", "body_type", @@ -213,6 +215,8 @@ class UpdateMechanicAutoevaluationSerializer(serializers.ModelSerializer): "manufacture_year", "car_dvigatel_number", "car_color", + "full_weight", + "empty_weight", "distance_covered", "car_position", "body_type", @@ -363,6 +367,8 @@ class CreateMechanicAutoevaluationSerializer(serializers.ModelSerializer): "manufacture_year", "car_dvigatel_number", "car_color", + "full_weight", + "empty_weight", "distance_covered", "car_position", "body_type", @@ -480,6 +486,8 @@ class MechanicAutoEvaluationModelSerializer(serializers.ModelSerializer): "manufacture_year", "car_dvigatel_number", "car_color", + "full_weight", + "empty_weight", "distance_covered", "car_position", "body_type", diff --git a/core/services/__init__.py b/core/services/__init__.py index 1c0b226..155645a 100644 --- a/core/services/__init__.py +++ b/core/services/__init__.py @@ -2,4 +2,5 @@ from .otp import * # noqa from .sms import * # noqa from .user import * # noqa from .didox import * # noqa -from .tech_passport import * # noqa \ No newline at end of file +from .tech_passport import * # noqa +from .currency import * # noqa \ No newline at end of file diff --git a/core/services/currency.py b/core/services/currency.py new file mode 100644 index 0000000..f201225 --- /dev/null +++ b/core/services/currency.py @@ -0,0 +1,33 @@ +from datetime import date + +import requests +import logging + +logger = logging.getLogger(__name__) + + +class CurrencyService: + BASE_URL = "https://cbu.uz/oz/arkhiv-kursov-valyut/json" + CODES = ("USD", "EUR", "RUB") + TIMEOUT_SECONDS = 5 + + @classmethod + def get_rates(cls, target_date=None) -> dict: + if target_date is None: + target_date = date.today() + date_str = target_date.strftime("%Y-%m-%d") + + rates = {} + for code in cls.CODES: + url = f"{cls.BASE_URL}/{code}/{date_str}/" + try: + response = requests.get(url, timeout=cls.TIMEOUT_SECONDS) + response.raise_for_status() + payload = response.json() + if isinstance(payload, list) and payload: + rate_value = payload[0].get("Rate") + if rate_value: + rates[code] = rate_value + except (requests.RequestException, ValueError) as e: + logger.exception(f"CBU API error for {code}: {e}") + return rates diff --git a/task.txt b/task.txt index 15fc4f6..962b933 100644 --- a/task.txt +++ b/task.txt @@ -1,41 +1,17 @@ -object_type => Bu hozirda select. O’shanga value qo’shish kerak: bus, moto - - - -car_position => Qo’shish kerak. Bu hozirda select. /api/v1/reference-item/ api’dan value yuboraman - - - -distance_covered => Qo’shish kerak. Number. Bosib o’tilgan masofasi - - - -body_type => Qo’shish kerak. Bu hozirda select. /api/v1/reference-item/ api’dan value yuboraman - - - -fuel_type => Qo’shish kerak. Bu hozirda select. /api/v1/reference-item/ api’dan value yuboraman - - - -state_car => Qo’shish kerak. Bu hozirda select. /api/v1/reference-item/ api’dan value yuboraman - - - -car_type => manashu field ni olib tashlash kerak - - - -tex_passport_file => multiple qilish kerak - - - -assessment_task_type => Baholash vazifasi. Qo’shish kerak. Select bo’ladi. /api/v1/reference-item/ api’dan value yuboraman - - - -object_owner_residence => Obyekt egasi yashash joyi. Qo’shish kerak. string bo’ladi. - - - -manashu fieldlarni detail apidagi serializerga qoshish kerak auto-evaluationda ham va mechnic-auto-evaluationda ham \ No newline at end of file +#Done 1. Valyutalarni kursini olish uchun API topib, malumotlarni pdfga yozish kerak +2. Foydalanuvchi ma'lumotlarni jshir orqali Didox apidan olib uni saqlab, keyin pdfga yozish kerak +3. Bajaruvchi ma'lumotlarni qoshish, tahrishlash uchun model yozishimiz kerak, va uni pdfga yozish kerak +4. Son korinishidan yozuv korinishiga o'tkazadigan funksiya yozish kerak, misol uchun 30 000 000 => "o'ttiz million" +5. Transport ma'lumotlarni tex passport orqali API dan olib uni saqlab, keyin pdfga yozish kerak +6. Obyektning textnik xolatini serializer orqali tanlaydigan qilish kerak va html filedagi yozilgan tabledagi malumotlarga quyidagicha ozgartirish kerak: + Har bir agregat bo'yicha ko'rik ro'yxati: + - Shinalar ko'rigi: tanlangan xolat + - Dvigatel ishlashini ko'rik: tanlangan xolat + - Yurish qismining ko'rigi: tanlangan xolat + - Transmissiya ko'rigi: tanlangan xolat + - Kuzov ko'rigi: tanlangan xolat +7. Baholanishi kerak bolgan mashinaning yangisini malumotlarni kerak. Shuning uchun yangi model ochib, kerakli malumotlarni toldiradigan qilish kerak +8. Eskirish koeffitsiyentlarini belgilash yani qanchadan qanchagacha necha foiz olishini yozish uchun model kerak +9. Solishtirma tahlil jadvali uchun analoglarni olib kelish kerak uzxariddan +10. Solishtirma tahlil jadvali uchun analoglar topilmasa, analoglarni qolda qoshadigan qilish kerak, keyin analoglar bilan birga rasmlar ham yuklay olishi kerak +11. QR code generate qilib pdfning har bir sahifasining ong tomon pastki qismiga joylashtirish kerak va https://{domain}/q/auto-basic/:id manashu urlga redirect qilishi kerak -- 2.49.1