feat(auto-evaluation): to'liq CRUD API va 4 bosqichli forma qo'shildi

- 10 ta yangi choice klass qo'shildi: ObjectOwnerType, PropertyRights,
  FormOwnership, LocationHighways, LocationConvenience, AutoCarType, AutoCarWheel
- AutoEvaluationModel ga ~30 ta yangi field qo'shildi (4 bosqich):
  1-bosqich: ro'yxatga olish raqami, sanalar, ob'ekt turi
  2-bosqich: egasi ma'lumotlari (jismoniy/yuridik), mulk huquqi, egalik shakli
  3-bosqich: manzil (viloyat, tuman, shahar, mahalla, ko'cha, uy)
  4-bosqich: avtomobil (tex passport, marka, model, raqam, rang, dvigatel)
- CreateSerializer ga validatsiya qo'shildi:
  passport formati (AA 1234567), tex passport formati (AAA 1234567),
  egasi turiga qarab majburiy fieldlar (jismoniy yoki yuridik)
- View ReadOnlyModelViewSet dan ModelViewSet ga o'zgartirildi
- Admin 4 bosqichli fieldset bilan yangilandi
- Yangi filterlar: object_owner_type, property_rights, form_ownership
- VehicleModel fieldlari FK → ReferenceitemModel ga o'tkazildi
- Migratsiyalar: 0015, 0016, 0017
This commit is contained in:
Husanjonazamov
2026-03-10 12:10:28 +05:00
parent b3581233c1
commit 5c2fe032d0
13 changed files with 1021 additions and 78 deletions

View File

@@ -3,6 +3,19 @@ from django.utils.translation import gettext_lazy as _
from django_core.models import AbstractBaseModel
from model_bakery import baker
from core.apps.evaluation.choices.auto import (
AutoCarType,
AutoCarWheel,
AutoEvaluationStatus,
AutoObjectType,
FormOwnership,
LocationConvenience,
LocationHighways,
ObjectOwnerType,
PropertyRights,
RateType,
ValueDetermined,
)
from .valuation import ValuationModel
from .vehicle import VehicleModel
@@ -14,17 +27,260 @@ class AutoEvaluationModel(AbstractBaseModel):
on_delete=models.CASCADE,
related_name="auto_detail",
verbose_name=_("valuation"),
null=True,
blank=True,
)
vehicle = models.OneToOneField(
VehicleModel,
on_delete=models.CASCADE,
related_name="evaluation",
verbose_name=_("vehicle"),
null=True,
blank=True,
)
# ── Step 1 — Umumiy ma'lumotlar ──────────────────────────────────
registration_number = models.CharField(
verbose_name=_("registration number"),
max_length=50,
blank=True,
null=True,
)
contract_date = models.DateField(
verbose_name=_("contract date"),
blank=True,
null=True,
)
object_inspection_date = models.DateField(
verbose_name=_("object inspection date"),
blank=True,
null=True,
)
rate_date = models.DateField(
verbose_name=_("rate date"),
blank=True,
null=True,
)
rate_report_date = models.DateField(
verbose_name=_("rate report date"),
blank=True,
null=True,
)
rate_object_name = models.CharField(
verbose_name=_("rate object name"),
max_length=255,
blank=True,
null=True,
)
object_type = models.CharField(
verbose_name=_("object type"),
max_length=50,
choices=AutoObjectType.choices,
blank=True,
null=True,
)
# ── Step 2 — Shaxs ma'lumotlari ─────────────────────────────────
object_owner_type = models.IntegerField(
verbose_name=_("object owner type"),
choices=ObjectOwnerType.choices,
blank=True,
null=True,
)
object_owner_individual_person_f_name = models.CharField(
verbose_name=_("owner first name"),
max_length=100,
blank=True,
null=True,
)
object_owner_individual_person_l_name = models.CharField(
verbose_name=_("owner last name"),
max_length=100,
blank=True,
null=True,
)
object_owner_individual_person_p_name = models.CharField(
verbose_name=_("owner patronymic"),
max_length=100,
blank=True,
null=True,
)
object_owner_individual_person_passport_num = models.CharField(
verbose_name=_("owner passport number"),
max_length=20,
blank=True,
null=True,
)
object_owner_legal_entity = models.CharField(
verbose_name=_("legal entity name"),
max_length=255,
blank=True,
null=True,
)
object_owner_legal_inn = models.CharField(
verbose_name=_("legal entity INN"),
max_length=20,
blank=True,
null=True,
)
property_rights = models.IntegerField(
verbose_name=_("property rights"),
choices=PropertyRights.choices,
blank=True,
null=True,
)
form_ownership = models.IntegerField(
verbose_name=_("form of ownership"),
choices=FormOwnership.choices,
blank=True,
null=True,
)
value_determined = models.IntegerField(
verbose_name=_("value determined"),
choices=ValueDetermined.choices,
blank=True,
null=True,
)
rate_type = models.IntegerField(
verbose_name=_("rate type"),
choices=RateType.choices,
blank=True,
null=True,
)
# ── 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 ─────────────────────────────
tex_passport_serie_num = models.CharField(
verbose_name=_("tech passport series and number"),
max_length=20,
blank=True,
null=True,
)
tex_passport_gived_date = models.DateField(
verbose_name=_("tech passport given date"),
blank=True,
null=True,
)
tex_passport_gived_location = models.CharField(
verbose_name=_("tech passport given location"),
max_length=255,
blank=True,
null=True,
)
car_type = models.IntegerField(
verbose_name=_("car type"),
choices=AutoCarType.choices,
blank=True,
null=True,
)
car_wheel = models.IntegerField(
verbose_name=_("car wheel"),
choices=AutoCarWheel.choices,
blank=True,
null=True,
)
car_brand = models.CharField(
verbose_name=_("car brand"),
max_length=100,
blank=True,
null=True,
)
car_model = models.CharField(
verbose_name=_("car model"),
max_length=100,
blank=True,
null=True,
)
car_number = models.CharField(
verbose_name=_("car number"),
max_length=20,
blank=True,
null=True,
)
manufacture_year = models.CharField(
verbose_name=_("manufacture year"),
max_length=10,
blank=True,
null=True,
)
car_dvigatel_number = models.CharField(
verbose_name=_("engine number"),
max_length=50,
blank=True,
null=True,
)
car_color = models.CharField(
verbose_name=_("car color"),
max_length=50,
blank=True,
null=True,
)
# ── Natija ───────────────────────────────────────────────────────
rating_goal = models.CharField(
verbose_name=_("rating goal"),
max_length=50,
blank=True,
null=True,
)
status = models.CharField(
verbose_name=_("status"),
max_length=50,
choices=AutoEvaluationStatus.choices,
default=AutoEvaluationStatus.CREATED,
)
def __str__(self):
return f"Auto Evaluation for {self.valuation}"
return f"Auto Evaluation {self.registration_number or self.pk}"
@classmethod
def _baker(cls):

View File

@@ -3,8 +3,7 @@ from django.utils.translation import gettext_lazy as _
from django_core.models import AbstractBaseModel
from model_bakery import baker
from core.apps.evaluation.choices.vehicle import FuelType, BodyType, VehicleCondition
from core.apps.evaluation.choices.vehicle import VehicleCondition
class VehicleModel(AbstractBaseModel):
@@ -25,11 +24,21 @@ class VehicleModel(AbstractBaseModel):
license_plate = models.CharField(
verbose_name=_("license plate"), max_length=20, blank=True, null=True
)
brand = models.CharField(
verbose_name=_("brand"), max_length=100, blank=True, null=True
brand = models.ForeignKey(
"evaluation.ReferenceitemModel",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="vehicle_brands",
verbose_name=_("brand"),
)
model = models.CharField(
verbose_name=_("model"), max_length=100, blank=True, null=True
model = models.ForeignKey(
"evaluation.ReferenceitemModel",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="vehicle_models",
verbose_name=_("model"),
)
manufacture_year = models.IntegerField(
verbose_name=_("manufacture year"), blank=True, null=True
@@ -40,27 +49,34 @@ class VehicleModel(AbstractBaseModel):
engine_number = models.CharField(
verbose_name=_("engine number"), max_length=50, blank=True, null=True
)
color = models.CharField(
verbose_name=_("color"), max_length=50, blank=True, null=True
color = models.ForeignKey(
"evaluation.ReferenceitemModel",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="vehicle_colors",
verbose_name=_("color"),
)
# 🛠 Texnik holati
mileage = models.IntegerField(
verbose_name=_("mileage"), blank=True, null=True, help_text=_("Distance in km")
)
fuel_type = models.CharField(
fuel_type = models.ForeignKey(
"evaluation.ReferenceitemModel",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="vehicle_fuel_types",
verbose_name=_("fuel type"),
max_length=20,
choices=FuelType.choices,
blank=True,
null=True,
)
body_type = models.CharField(
verbose_name=_("body type"),
max_length=20,
choices=BodyType.choices,
blank=True,
body_type = models.ForeignKey(
"evaluation.ReferenceitemModel",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="vehicle_body_types",
verbose_name=_("body type"),
)
condition = models.CharField(
verbose_name=_("condition"),
@@ -69,12 +85,19 @@ class VehicleModel(AbstractBaseModel):
blank=True,
null=True,
)
position = models.CharField(
verbose_name=_("position"), max_length=50, blank=True, null=True
position = models.ForeignKey(
"evaluation.ReferenceitemModel",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name="vehicle_positions",
verbose_name=_("position"),
)
def __str__(self):
return f"{self.brand} {self.model} ({self.license_plate})"
brand_name = self.brand.name if self.brand else ""
model_name = self.model.name if self.model else ""
return f"{brand_name} {model_name} ({self.license_plate})"
@classmethod
def _baker(cls):