Merge pull request 'valuation va vihicle modellari qoshildi' (#7) from feat/evaluation-core into main
All checks were successful
Deploy to Production / build-and-deploy (push) Successful in 4m56s
All checks were successful
Deploy to Production / build-and-deploy (push) Successful in 4m56s
Reviewed-on: #7
This commit is contained in:
@@ -1 +1,3 @@
|
||||
from .customer import * # noqa
|
||||
from .valuation import * # noqa
|
||||
from .vehicle import * # noqa
|
||||
|
||||
12
core/apps/evaluation/admin/valuation.py
Normal file
12
core/apps/evaluation/admin/valuation.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from django.contrib import admin
|
||||
from unfold.admin import ModelAdmin
|
||||
|
||||
from core.apps.evaluation.models import ValuationModel
|
||||
|
||||
|
||||
@admin.register(ValuationModel)
|
||||
class ValuationAdmin(ModelAdmin):
|
||||
list_display = (
|
||||
"id",
|
||||
"__str__",
|
||||
)
|
||||
12
core/apps/evaluation/admin/vehicle.py
Normal file
12
core/apps/evaluation/admin/vehicle.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from django.contrib import admin
|
||||
from unfold.admin import ModelAdmin
|
||||
|
||||
from core.apps.evaluation.models import VehicleModel
|
||||
|
||||
|
||||
@admin.register(VehicleModel)
|
||||
class VehicleAdmin(ModelAdmin):
|
||||
list_display = (
|
||||
"id",
|
||||
"__str__",
|
||||
)
|
||||
33
core/apps/evaluation/choices/valuation.py
Normal file
33
core/apps/evaluation/choices/valuation.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class EvaluationPurpose(models.TextChoices):
|
||||
SALE = "sale", _("Sale")
|
||||
BANK = "bank", _("Bank/Loan")
|
||||
INSURANCE = "insurance", _("Insurance")
|
||||
INHERITANCE = "inheritance", _("Inheritance")
|
||||
COURT = "court", _("Court/Judicial")
|
||||
OTHER = "other", _("Other")
|
||||
|
||||
|
||||
class EvaluationType(models.TextChoices):
|
||||
AUTO = "auto", _("Auto")
|
||||
REAL_ESTATE = "real_estate", _("Real Estate")
|
||||
MOVABLE_PROPERTY = "movable_property", _("Movable Property")
|
||||
|
||||
|
||||
class ValuationStatus(models.TextChoices):
|
||||
DRAFT = "draft", _("Draft")
|
||||
PENDING = "pending", _("Pending")
|
||||
IN_REVIEW = "in_review", _("In Review")
|
||||
APPROVED = "approved", _("Approved")
|
||||
REJECTED = "rejected", _("Rejected")
|
||||
PAID = "paid", _("Paid")
|
||||
COMPLETED = "completed", _("Completed")
|
||||
|
||||
|
||||
class PaymentStatus(models.TextChoices):
|
||||
UNPAID = "unpaid", _("Unpaid")
|
||||
PENDING = "pending", _("Pending")
|
||||
PAID = "paid", _("Paid")
|
||||
28
core/apps/evaluation/choices/vehicle.py
Normal file
28
core/apps/evaluation/choices/vehicle.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
|
||||
class FuelType(models.TextChoices):
|
||||
PETROL = "petrol", _("Petrol")
|
||||
DIESEL = "diesel", _("Diesel")
|
||||
GAS = "gas", _("Gas")
|
||||
ELECTRIC = "electric", _("Electric")
|
||||
HYBRID = "hybrid", _("Hybrid")
|
||||
|
||||
|
||||
class BodyType(models.TextChoices):
|
||||
HATCHBACK = "hatchback", _("Hatchback")
|
||||
SEDAN = "sedan", _("Sedan")
|
||||
UNIVERSAL = "universal", _("Universal")
|
||||
COUPE = "coupe", _("Coupe")
|
||||
CABRIOLET = "cabriolet", _("Cabriolet")
|
||||
LIFTBACK = "liftback", _("Liftback")
|
||||
MINIVAN = "minivan", _("Minivan")
|
||||
CROSSOVER = "crossover", _("Crossover")
|
||||
|
||||
|
||||
class VehicleCondition(models.TextChoices):
|
||||
EXCELLENT = "excellent", _("Excellent")
|
||||
GOOD = "good", _("Good")
|
||||
AVERAGE = "average", _("Average")
|
||||
NEEDS_REPAIR = "needs_repair", _("Needs repair")
|
||||
@@ -1 +1,3 @@
|
||||
from .customer import * # noqa
|
||||
from .valuation import * # noqa
|
||||
from .vehicle import * # noqa
|
||||
|
||||
13
core/apps/evaluation/filters/valuation.py
Normal file
13
core/apps/evaluation/filters/valuation.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from django_filters import rest_framework as filters
|
||||
|
||||
from core.apps.evaluation.models import ValuationModel
|
||||
|
||||
|
||||
class ValuationFilter(filters.FilterSet):
|
||||
# name = filters.CharFilter(field_name="name", lookup_expr="icontains")
|
||||
|
||||
class Meta:
|
||||
model = ValuationModel
|
||||
fields = [
|
||||
"name",
|
||||
]
|
||||
13
core/apps/evaluation/filters/vehicle.py
Normal file
13
core/apps/evaluation/filters/vehicle.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from django_filters import rest_framework as filters
|
||||
|
||||
from core.apps.evaluation.models import VehicleModel
|
||||
|
||||
|
||||
class VehicleFilter(filters.FilterSet):
|
||||
# name = filters.CharFilter(field_name="name", lookup_expr="icontains")
|
||||
|
||||
class Meta:
|
||||
model = VehicleModel
|
||||
fields = [
|
||||
"name",
|
||||
]
|
||||
@@ -1 +1,3 @@
|
||||
from .customer import * # noqa
|
||||
from .valuation import * # noqa
|
||||
from .vehicle import * # noqa
|
||||
|
||||
10
core/apps/evaluation/forms/valuation.py
Normal file
10
core/apps/evaluation/forms/valuation.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django import forms
|
||||
|
||||
from core.apps.evaluation.models import ValuationModel
|
||||
|
||||
|
||||
class ValuationForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = ValuationModel
|
||||
fields = "__all__"
|
||||
10
core/apps/evaluation/forms/vehicle.py
Normal file
10
core/apps/evaluation/forms/vehicle.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django import forms
|
||||
|
||||
from core.apps.evaluation.models import VehicleModel
|
||||
|
||||
|
||||
class VehicleForm(forms.ModelForm):
|
||||
|
||||
class Meta:
|
||||
model = VehicleModel
|
||||
fields = "__all__"
|
||||
@@ -0,0 +1,73 @@
|
||||
# Generated by Django 5.2.7 on 2026-02-13 10:20
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('evaluation', '0002_alter_customermodel_options_and_more'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='VehicleModel',
|
||||
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)),
|
||||
('tech_passport_series', models.CharField(blank=True, max_length=10, null=True, verbose_name='tech passport series')),
|
||||
('tech_passport_number', models.CharField(blank=True, max_length=20, null=True, verbose_name='tech passport number')),
|
||||
('tech_passport_issued_date', models.DateField(blank=True, null=True, verbose_name='tech passport issued date')),
|
||||
('tech_passport_issued_by', models.CharField(blank=True, max_length=255, null=True, verbose_name='tech passport issued by')),
|
||||
('license_plate', models.CharField(blank=True, max_length=20, null=True, verbose_name='license plate')),
|
||||
('brand', models.CharField(blank=True, max_length=100, null=True, verbose_name='brand')),
|
||||
('model', models.CharField(blank=True, max_length=100, null=True, verbose_name='model')),
|
||||
('manufacture_year', models.IntegerField(blank=True, null=True, verbose_name='manufacture year')),
|
||||
('vin_number', models.CharField(blank=True, max_length=25, null=True, verbose_name='VIN number')),
|
||||
('engine_number', models.CharField(blank=True, max_length=50, null=True, verbose_name='engine number')),
|
||||
('color', models.CharField(blank=True, max_length=50, null=True, verbose_name='color')),
|
||||
('mileage', models.IntegerField(blank=True, help_text='Distance in km', null=True, verbose_name='mileage')),
|
||||
('fuel_type', models.CharField(blank=True, choices=[('petrol', 'Petrol'), ('diesel', 'Diesel'), ('gas', 'Gas'), ('electric', 'Electric'), ('hybrid', 'Hybrid')], max_length=20, null=True, verbose_name='fuel type')),
|
||||
('body_type', models.CharField(blank=True, choices=[('hatchback', 'Hatchback'), ('sedan', 'Sedan'), ('universal', 'Universal'), ('coupe', 'Coupe'), ('cabriolet', 'Cabriolet'), ('liftback', 'Liftback'), ('minivan', 'Minivan'), ('crossover', 'Crossover')], max_length=20, null=True, verbose_name='body type')),
|
||||
('condition', models.CharField(blank=True, choices=[('excellent', 'Excellent'), ('good', 'Good'), ('average', 'Average'), ('needs_repair', 'Needs repair')], max_length=20, null=True, verbose_name='condition')),
|
||||
('position', models.CharField(blank=True, max_length=50, null=True, verbose_name='position')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Vehicle',
|
||||
'verbose_name_plural': 'Vehicles',
|
||||
'db_table': 'Vehicle',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ValuationModel',
|
||||
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)),
|
||||
('conclusion_number', models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='conclusion number')),
|
||||
('evaluation_purpose', models.CharField(choices=[('sale', 'Sale'), ('bank', 'Bank/Loan'), ('insurance', 'Insurance'), ('inheritance', 'Inheritance'), ('court', 'Court/Judicial'), ('other', 'Other')], default='sale', max_length=50, verbose_name='evaluation purpose')),
|
||||
('evaluation_type', models.CharField(choices=[('auto', 'Auto'), ('real_estate', 'Real Estate'), ('movable_property', 'Movable Property')], max_length=50, verbose_name='evaluation type')),
|
||||
('evaluation_subtype', models.CharField(blank=True, max_length=100, null=True, verbose_name='evaluation subtype')),
|
||||
('status', models.CharField(choices=[('draft', 'Draft'), ('pending', 'Pending'), ('in_review', 'In Review'), ('approved', 'Approved'), ('rejected', 'Rejected'), ('paid', 'Paid'), ('completed', 'Completed')], default='draft', max_length=20, verbose_name='status')),
|
||||
('estimated_price', models.DecimalField(blank=True, decimal_places=2, max_digits=15, null=True, verbose_name='estimated price')),
|
||||
('final_price', models.DecimalField(blank=True, decimal_places=2, max_digits=15, null=True, verbose_name='final price')),
|
||||
('payment_status', models.CharField(choices=[('unpaid', 'Unpaid'), ('pending', 'Pending'), ('paid', 'Paid')], default='unpaid', max_length=20, verbose_name='payment status')),
|
||||
('is_courier_delivery', models.BooleanField(default=False, verbose_name='courier delivery')),
|
||||
('courier_extra_amount', models.DecimalField(decimal_places=2, default=0, max_digits=12, verbose_name='courier extra amount')),
|
||||
('notes', models.TextField(blank=True, null=True, verbose_name='notes')),
|
||||
('assigned_to', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='assigned_valuations', to=settings.AUTH_USER_MODEL, verbose_name='assigned to')),
|
||||
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='created_valuations', to=settings.AUTH_USER_MODEL, verbose_name='created by')),
|
||||
('customer', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='valuations', to='evaluation.customermodel', verbose_name='customer')),
|
||||
('property_owner', models.ForeignKey(blank=True, help_text='Keep empty if customer is the owner', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='valuations', to='evaluation.propertyownermodel', verbose_name='property owner')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Valuation',
|
||||
'verbose_name_plural': 'Valuations',
|
||||
'db_table': 'Valuation',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -1 +1,3 @@
|
||||
from .customer import * # noqa
|
||||
from .valuation import * # noqa
|
||||
from .vehicle import * # noqa
|
||||
|
||||
127
core/apps/evaluation/models/valuation.py
Normal file
127
core/apps/evaluation/models/valuation.py
Normal file
@@ -0,0 +1,127 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_core.models import AbstractBaseModel
|
||||
from model_bakery import baker
|
||||
|
||||
from core.apps.evaluation.choices.valuation import (
|
||||
EvaluationPurpose,
|
||||
EvaluationType,
|
||||
ValuationStatus,
|
||||
PaymentStatus,
|
||||
)
|
||||
from .customer import CustomerModel, PropertyOwnerModel
|
||||
|
||||
|
||||
class ValuationModel(AbstractBaseModel):
|
||||
# 📋 Asosiy ma'lumotlar
|
||||
conclusion_number = models.CharField(
|
||||
verbose_name=_("conclusion number"),
|
||||
max_length=50,
|
||||
unique=True,
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
evaluation_purpose = models.CharField(
|
||||
verbose_name=_("evaluation purpose"),
|
||||
max_length=50,
|
||||
choices=EvaluationPurpose.choices,
|
||||
default=EvaluationPurpose.SALE,
|
||||
)
|
||||
evaluation_type = models.CharField(
|
||||
verbose_name=_("evaluation type"),
|
||||
max_length=50,
|
||||
choices=EvaluationType.choices,
|
||||
)
|
||||
evaluation_subtype = models.CharField(
|
||||
verbose_name=_("evaluation subtype"),
|
||||
max_length=100,
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
status = models.CharField(
|
||||
verbose_name=_("status"),
|
||||
max_length=20,
|
||||
choices=ValuationStatus.choices,
|
||||
default=ValuationStatus.DRAFT,
|
||||
)
|
||||
|
||||
# 👥 Bog'lanishlar
|
||||
customer = models.ForeignKey(
|
||||
CustomerModel,
|
||||
on_delete=models.PROTECT,
|
||||
related_name="valuations",
|
||||
verbose_name=_("customer"),
|
||||
)
|
||||
property_owner = models.ForeignKey(
|
||||
PropertyOwnerModel,
|
||||
on_delete=models.PROTECT,
|
||||
related_name="valuations",
|
||||
verbose_name=_("property owner"),
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text=_("Keep empty if customer is the owner"),
|
||||
)
|
||||
created_by = models.ForeignKey(
|
||||
"accounts.User",
|
||||
on_delete=models.PROTECT,
|
||||
related_name="created_valuations",
|
||||
verbose_name=_("created by"),
|
||||
)
|
||||
assigned_to = models.ForeignKey(
|
||||
"accounts.User",
|
||||
on_delete=models.SET_NULL,
|
||||
related_name="assigned_valuations",
|
||||
verbose_name=_("assigned to"),
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
# 💰 Narx va To'lov
|
||||
estimated_price = models.DecimalField(
|
||||
verbose_name=_("estimated price"),
|
||||
max_digits=15,
|
||||
decimal_places=2,
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
final_price = models.DecimalField(
|
||||
verbose_name=_("final price"),
|
||||
max_digits=15,
|
||||
decimal_places=2,
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
payment_status = models.CharField(
|
||||
verbose_name=_("payment status"),
|
||||
max_length=20,
|
||||
choices=PaymentStatus.choices,
|
||||
default=PaymentStatus.UNPAID,
|
||||
)
|
||||
|
||||
# 🚚 Yetkazib berish
|
||||
is_courier_delivery = models.BooleanField(
|
||||
verbose_name=_("courier delivery"), default=False
|
||||
)
|
||||
courier_extra_amount = models.DecimalField(
|
||||
verbose_name=_("courier extra amount"),
|
||||
max_digits=12,
|
||||
decimal_places=2,
|
||||
default=0,
|
||||
)
|
||||
|
||||
# 📝 Izohlar
|
||||
notes = models.TextField(verbose_name=_("notes"), blank=True, null=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"Valuation {self.conclusion_number} - {self.customer}"
|
||||
|
||||
@classmethod
|
||||
def _baker(cls):
|
||||
return baker.make(cls)
|
||||
|
||||
class Meta:
|
||||
db_table = "Valuation"
|
||||
verbose_name = _("Valuation")
|
||||
verbose_name_plural = _("Valuations")
|
||||
|
||||
|
||||
87
core/apps/evaluation/models/vehicle.py
Normal file
87
core/apps/evaluation/models/vehicle.py
Normal file
@@ -0,0 +1,87 @@
|
||||
from django.db import models
|
||||
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
|
||||
|
||||
|
||||
class VehicleModel(AbstractBaseModel):
|
||||
# 🌐 Texnik passport ma'lumotlari (API orqali olinadi)
|
||||
tech_passport_series = models.CharField(
|
||||
verbose_name=_("tech passport series"), max_length=10, blank=True, null=True
|
||||
)
|
||||
tech_passport_number = models.CharField(
|
||||
verbose_name=_("tech passport number"), max_length=20, blank=True, null=True
|
||||
)
|
||||
tech_passport_issued_date = models.DateField(
|
||||
verbose_name=_("tech passport issued date"), blank=True, null=True
|
||||
)
|
||||
tech_passport_issued_by = models.CharField(
|
||||
verbose_name=_("tech passport issued by"), max_length=255, blank=True, null=True
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
model = models.CharField(
|
||||
verbose_name=_("model"), max_length=100, blank=True, null=True
|
||||
)
|
||||
manufacture_year = models.IntegerField(
|
||||
verbose_name=_("manufacture year"), blank=True, null=True
|
||||
)
|
||||
vin_number = models.CharField(
|
||||
verbose_name=_("VIN number"), max_length=25, blank=True, null=True
|
||||
)
|
||||
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
|
||||
)
|
||||
|
||||
# 🛠 Texnik holati
|
||||
mileage = models.IntegerField(
|
||||
verbose_name=_("mileage"), blank=True, null=True, help_text=_("Distance in km")
|
||||
)
|
||||
fuel_type = models.CharField(
|
||||
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,
|
||||
null=True,
|
||||
)
|
||||
condition = models.CharField(
|
||||
verbose_name=_("condition"),
|
||||
max_length=20,
|
||||
choices=VehicleCondition.choices,
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
position = models.CharField(
|
||||
verbose_name=_("position"), max_length=50, blank=True, null=True
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.brand} {self.model} ({self.license_plate})"
|
||||
|
||||
@classmethod
|
||||
def _baker(cls):
|
||||
return baker.make(cls)
|
||||
|
||||
class Meta:
|
||||
db_table = "Vehicle"
|
||||
verbose_name = _("Vehicle")
|
||||
verbose_name_plural = _("Vehicles")
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
from .customer import * # noqa
|
||||
from .valuation import * # noqa
|
||||
from .vehicle import * # noqa
|
||||
|
||||
12
core/apps/evaluation/permissions/valuation.py
Normal file
12
core/apps/evaluation/permissions/valuation.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from rest_framework import permissions
|
||||
|
||||
|
||||
class ValuationPermission(permissions.BasePermission):
|
||||
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self
|
||||
|
||||
def has_permission(self, request, view):
|
||||
return True
|
||||
12
core/apps/evaluation/permissions/vehicle.py
Normal file
12
core/apps/evaluation/permissions/vehicle.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from rest_framework import permissions
|
||||
|
||||
|
||||
class VehiclePermission(permissions.BasePermission):
|
||||
|
||||
def __init__(self) -> None: ...
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
return self
|
||||
|
||||
def has_permission(self, request, view):
|
||||
return True
|
||||
@@ -1 +1,3 @@
|
||||
from .customer import * # noqa
|
||||
from .valuation import * # noqa
|
||||
from .vehicle import * # noqa
|
||||
|
||||
49
core/apps/evaluation/serializers/valuation/Valuation.py
Normal file
49
core/apps/evaluation/serializers/valuation/Valuation.py
Normal file
@@ -0,0 +1,49 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from core.apps.evaluation.models import ValuationModel
|
||||
|
||||
|
||||
class BaseValuationSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = ValuationModel
|
||||
fields = [
|
||||
"id",
|
||||
"conclusion_number",
|
||||
"evaluation_purpose",
|
||||
"evaluation_type",
|
||||
"status",
|
||||
"created_at",
|
||||
]
|
||||
|
||||
|
||||
class ListValuationSerializer(BaseValuationSerializer):
|
||||
class Meta(BaseValuationSerializer.Meta):
|
||||
pass
|
||||
|
||||
|
||||
class RetrieveValuationSerializer(BaseValuationSerializer):
|
||||
class Meta(BaseValuationSerializer.Meta):
|
||||
fields = BaseValuationSerializer.Meta.fields + [
|
||||
"customer",
|
||||
"property_owner",
|
||||
"created_by",
|
||||
"assigned_to",
|
||||
"estimated_price",
|
||||
"final_price",
|
||||
"payment_status",
|
||||
"notes",
|
||||
]
|
||||
|
||||
|
||||
class CreateValuationSerializer(BaseValuationSerializer):
|
||||
class Meta(BaseValuationSerializer.Meta):
|
||||
fields = [
|
||||
"customer",
|
||||
"property_owner",
|
||||
"evaluation_purpose",
|
||||
"evaluation_type",
|
||||
"evaluation_subtype",
|
||||
"is_courier_delivery",
|
||||
"notes",
|
||||
]
|
||||
|
||||
1
core/apps/evaluation/serializers/valuation/__init__.py
Normal file
1
core/apps/evaluation/serializers/valuation/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .Valuation import * # noqa
|
||||
39
core/apps/evaluation/serializers/vehicle/Vehicle.py
Normal file
39
core/apps/evaluation/serializers/vehicle/Vehicle.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from rest_framework import serializers
|
||||
|
||||
from core.apps.evaluation.models import VehicleModel
|
||||
|
||||
|
||||
class BaseVehicleSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = VehicleModel
|
||||
fields = [
|
||||
"id",
|
||||
"brand",
|
||||
"model",
|
||||
"license_plate",
|
||||
"manufacture_year",
|
||||
]
|
||||
|
||||
|
||||
class ListVehicleSerializer(BaseVehicleSerializer):
|
||||
class Meta(BaseVehicleSerializer.Meta):
|
||||
pass
|
||||
|
||||
|
||||
class RetrieveVehicleSerializer(BaseVehicleSerializer):
|
||||
class Meta(BaseVehicleSerializer.Meta):
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class CreateVehicleSerializer(BaseVehicleSerializer):
|
||||
class Meta(BaseVehicleSerializer.Meta):
|
||||
fields = [
|
||||
"tech_passport_series",
|
||||
"tech_passport_number",
|
||||
"license_plate",
|
||||
"mileage",
|
||||
"fuel_type",
|
||||
"body_type",
|
||||
"condition",
|
||||
]
|
||||
|
||||
1
core/apps/evaluation/serializers/vehicle/__init__.py
Normal file
1
core/apps/evaluation/serializers/vehicle/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .Vehicle import * # noqa
|
||||
@@ -1 +1,3 @@
|
||||
from .customer import * # noqa
|
||||
from .valuation import * # noqa
|
||||
from .vehicle import * # noqa
|
||||
|
||||
8
core/apps/evaluation/signals/valuation.py
Normal file
8
core/apps/evaluation/signals/valuation.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from core.apps.evaluation.models import ValuationModel
|
||||
|
||||
|
||||
@receiver(post_save, sender=ValuationModel)
|
||||
def ValuationSignal(sender, instance, created, **kwargs): ...
|
||||
8
core/apps/evaluation/signals/vehicle.py
Normal file
8
core/apps/evaluation/signals/vehicle.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from core.apps.evaluation.models import VehicleModel
|
||||
|
||||
|
||||
@receiver(post_save, sender=VehicleModel)
|
||||
def VehicleSignal(sender, instance, created, **kwargs): ...
|
||||
@@ -1 +1,3 @@
|
||||
from .customer import * # noqa
|
||||
from .valuation import * # noqa
|
||||
from .vehicle import * # noqa
|
||||
|
||||
1
core/apps/evaluation/tests/valuation/__init__.py
Normal file
1
core/apps/evaluation/tests/valuation/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .test_Valuation import * # noqa
|
||||
59
core/apps/evaluation/tests/valuation/test_Valuation.py
Normal file
59
core/apps/evaluation/tests/valuation/test_Valuation.py
Normal file
@@ -0,0 +1,59 @@
|
||||
import pytest
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from core.apps.evaluation.models import ValuationModel
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def instance(db):
|
||||
return ValuationModel._baker()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def api_client(instance):
|
||||
client = APIClient()
|
||||
##client.force_authenticate(user=instance.user)
|
||||
return client, instance
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def data(api_client):
|
||||
client, instance = api_client
|
||||
return (
|
||||
{
|
||||
"list": reverse("Valuation-list"),
|
||||
"retrieve": reverse("Valuation-detail", kwargs={"pk": instance.pk}),
|
||||
"retrieve-not-found": reverse("Valuation-detail", kwargs={"pk": 1000}),
|
||||
},
|
||||
client,
|
||||
instance,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_list(data):
|
||||
urls, client, _ = data
|
||||
response = client.get(urls["list"])
|
||||
data_resp = response.json()
|
||||
assert response.status_code == 200
|
||||
assert data_resp["status"] is True
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_retrieve(data):
|
||||
urls, client, _ = data
|
||||
response = client.get(urls["retrieve"])
|
||||
data_resp = response.json()
|
||||
assert response.status_code == 200
|
||||
assert data_resp["status"] is True
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_retrieve_not_found(data):
|
||||
urls, client, _ = data
|
||||
response = client.get(urls["retrieve-not-found"])
|
||||
data_resp = response.json()
|
||||
assert response.status_code == 404
|
||||
assert data_resp["status"] is False
|
||||
|
||||
1
core/apps/evaluation/tests/vehicle/__init__.py
Normal file
1
core/apps/evaluation/tests/vehicle/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .test_Vehicle import * # noqa
|
||||
59
core/apps/evaluation/tests/vehicle/test_Vehicle.py
Normal file
59
core/apps/evaluation/tests/vehicle/test_Vehicle.py
Normal file
@@ -0,0 +1,59 @@
|
||||
import pytest
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
from core.apps.evaluation.models import VehicleModel
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def instance(db):
|
||||
return VehicleModel._baker()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def api_client(instance):
|
||||
client = APIClient()
|
||||
##client.force_authenticate(user=instance.user)
|
||||
return client, instance
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def data(api_client):
|
||||
client, instance = api_client
|
||||
return (
|
||||
{
|
||||
"list": reverse("Vehicle-list"),
|
||||
"retrieve": reverse("Vehicle-detail", kwargs={"pk": instance.pk}),
|
||||
"retrieve-not-found": reverse("Vehicle-detail", kwargs={"pk": 1000}),
|
||||
},
|
||||
client,
|
||||
instance,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_list(data):
|
||||
urls, client, _ = data
|
||||
response = client.get(urls["list"])
|
||||
data_resp = response.json()
|
||||
assert response.status_code == 200
|
||||
assert data_resp["status"] is True
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_retrieve(data):
|
||||
urls, client, _ = data
|
||||
response = client.get(urls["retrieve"])
|
||||
data_resp = response.json()
|
||||
assert response.status_code == 200
|
||||
assert data_resp["status"] is True
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_retrieve_not_found(data):
|
||||
urls, client, _ = data
|
||||
response = client.get(urls["retrieve-not-found"])
|
||||
data_resp = response.json()
|
||||
assert response.status_code == 404
|
||||
assert data_resp["status"] is False
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
from .customer import * # noqa
|
||||
from .valuation import * # noqa
|
||||
from .vehicle import * # noqa
|
||||
|
||||
8
core/apps/evaluation/translation/valuation.py
Normal file
8
core/apps/evaluation/translation/valuation.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from modeltranslation.translator import TranslationOptions, register
|
||||
|
||||
from core.apps.evaluation.models import ValuationModel
|
||||
|
||||
|
||||
@register(ValuationModel)
|
||||
class ValuationTranslation(TranslationOptions):
|
||||
fields = []
|
||||
8
core/apps/evaluation/translation/vehicle.py
Normal file
8
core/apps/evaluation/translation/vehicle.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from modeltranslation.translator import TranslationOptions, register
|
||||
|
||||
from core.apps.evaluation.models import VehicleModel
|
||||
|
||||
|
||||
@register(VehicleModel)
|
||||
class VehicleTranslation(TranslationOptions):
|
||||
fields = []
|
||||
@@ -1,9 +1,11 @@
|
||||
from django.urls import include, path
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from .views import CustomerView, PropertyOwnerView
|
||||
from .views import CustomerView, PropertyOwnerView, ValuationView, VehicleView
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register("Vehicle", VehicleView, basename="Vehicle")
|
||||
router.register("Valuation", ValuationView, basename="Valuation")
|
||||
router.register("property-owner", PropertyOwnerView, basename="property-owner")
|
||||
router.register("customer", CustomerView, basename="customer")
|
||||
urlpatterns = [path("", include(router.urls))]
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
from .customer import * # noqa
|
||||
from .valuation import * # noqa
|
||||
from .vehicle import * # noqa
|
||||
|
||||
8
core/apps/evaluation/validators/valuation.py
Normal file
8
core/apps/evaluation/validators/valuation.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# from django.core.exceptions import ValidationError
|
||||
|
||||
|
||||
class ValuationValidator:
|
||||
def __init__(self): ...
|
||||
|
||||
def __call__(self):
|
||||
return True
|
||||
8
core/apps/evaluation/validators/vehicle.py
Normal file
8
core/apps/evaluation/validators/vehicle.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# from django.core.exceptions import ValidationError
|
||||
|
||||
|
||||
class VehicleValidator:
|
||||
def __init__(self): ...
|
||||
|
||||
def __call__(self):
|
||||
return True
|
||||
@@ -1 +1,3 @@
|
||||
from .customer import * # noqa
|
||||
from .valuation import * # noqa
|
||||
from .vehicle import * # noqa
|
||||
|
||||
25
core/apps/evaluation/views/valuation.py
Normal file
25
core/apps/evaluation/views/valuation.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from django_core.mixins import BaseViewSetMixin
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||
|
||||
from core.apps.evaluation.models import ValuationModel
|
||||
from core.apps.evaluation.serializers.valuation import (
|
||||
CreateValuationSerializer,
|
||||
ListValuationSerializer,
|
||||
RetrieveValuationSerializer,
|
||||
)
|
||||
|
||||
|
||||
@extend_schema(tags=["Valuation"])
|
||||
class ValuationView(BaseViewSetMixin, ReadOnlyModelViewSet):
|
||||
queryset = ValuationModel.objects.all()
|
||||
serializer_class = ListValuationSerializer
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
action_permission_classes = {}
|
||||
action_serializer_class = {
|
||||
"list": ListValuationSerializer,
|
||||
"retrieve": RetrieveValuationSerializer,
|
||||
"create": CreateValuationSerializer,
|
||||
}
|
||||
25
core/apps/evaluation/views/vehicle.py
Normal file
25
core/apps/evaluation/views/vehicle.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from django_core.mixins import BaseViewSetMixin
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework.permissions import AllowAny
|
||||
from rest_framework.viewsets import ReadOnlyModelViewSet
|
||||
|
||||
from core.apps.evaluation.models import VehicleModel
|
||||
from core.apps.evaluation.serializers.vehicle import (
|
||||
CreateVehicleSerializer,
|
||||
ListVehicleSerializer,
|
||||
RetrieveVehicleSerializer,
|
||||
)
|
||||
|
||||
|
||||
@extend_schema(tags=["Vehicle"])
|
||||
class VehicleView(BaseViewSetMixin, ReadOnlyModelViewSet):
|
||||
queryset = VehicleModel.objects.all()
|
||||
serializer_class = ListVehicleSerializer
|
||||
permission_classes = [AllowAny]
|
||||
|
||||
action_permission_classes = {}
|
||||
action_serializer_class = {
|
||||
"list": ListVehicleSerializer,
|
||||
"retrieve": RetrieveVehicleSerializer,
|
||||
"create": CreateVehicleSerializer,
|
||||
}
|
||||
Reference in New Issue
Block a user