From feecb580c1d51d76a3cc950890ae5ffd94f74702 Mon Sep 17 00:00:00 2001 From: Shaxobff Date: Fri, 1 May 2026 16:54:38 +0500 Subject: [PATCH] update --- core/apps/evaluation/choices/bonus.py | 8 +++ core/apps/evaluation/migrations/0039_bonus.py | 31 ++++++++++ ...us_bonustype_employeebonus_delete_bonus.py | 59 +++++++++++++++++++ core/apps/evaluation/models/auto.py | 5 -- core/apps/evaluation/models/bonus.py | 38 ++++++++++++ core/apps/evaluation/models/movable.py | 4 +- .../evaluation/serializers/bonus/Bonus.py | 44 ++++++++++++++ .../evaluation/serializers/bonus/__init__.py | 0 core/apps/evaluation/urls.py | 2 + core/apps/evaluation/views/__init__.py | 1 + core/apps/evaluation/views/bonus.py | 55 +++++++++++++++++ 11 files changed, 239 insertions(+), 8 deletions(-) create mode 100644 core/apps/evaluation/choices/bonus.py create mode 100644 core/apps/evaluation/migrations/0039_bonus.py create mode 100644 core/apps/evaluation/migrations/0040_basevaluebonus_bonustype_employeebonus_delete_bonus.py create mode 100644 core/apps/evaluation/models/bonus.py create mode 100644 core/apps/evaluation/serializers/bonus/Bonus.py create mode 100644 core/apps/evaluation/serializers/bonus/__init__.py create mode 100644 core/apps/evaluation/views/bonus.py diff --git a/core/apps/evaluation/choices/bonus.py b/core/apps/evaluation/choices/bonus.py new file mode 100644 index 0000000..7c13ce2 --- /dev/null +++ b/core/apps/evaluation/choices/bonus.py @@ -0,0 +1,8 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ + + +class EvaluationCategory(models.TextChoices): + AUTO = "auto_transport", _("Avtotransport") + REAL_ESTATE = "real estate", _("ko'chmas mulk") + EQUIPMENT = "equipment", _("uskuna va jihozlar") diff --git a/core/apps/evaluation/migrations/0039_bonus.py b/core/apps/evaluation/migrations/0039_bonus.py new file mode 100644 index 0000000..138a813 --- /dev/null +++ b/core/apps/evaluation/migrations/0039_bonus.py @@ -0,0 +1,31 @@ +# Generated by Django 5.2.7 on 2026-05-01 06:45 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('evaluation', '0038_evaluationrequestmodel_distance_covered_and_more'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Bonus', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('updated_at', models.DateTimeField(auto_now=True)), + ('bonus_type', models.CharField(choices=[('lightweight_auto', 'Yengil automobil'), ('truck_car', 'Yuk automobil'), ('special_tech', 'Maxsus texnika')], max_length=50)), + ('percentage', models.FloatField()), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('price', models.FloatField()), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bonuses', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/core/apps/evaluation/migrations/0040_basevaluebonus_bonustype_employeebonus_delete_bonus.py b/core/apps/evaluation/migrations/0040_basevaluebonus_bonustype_employeebonus_delete_bonus.py new file mode 100644 index 0000000..8d43c63 --- /dev/null +++ b/core/apps/evaluation/migrations/0040_basevaluebonus_bonustype_employeebonus_delete_bonus.py @@ -0,0 +1,59 @@ +# Generated by Django 5.2.7 on 2026-05-01 11:43 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('evaluation', '0039_bonus'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='BaseValueBonus', + 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)), + ('base_price', models.DecimalField(decimal_places=2, max_digits=12)), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='BonusType', + 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)), + ('name', models.CharField(max_length=255)), + ('category', models.CharField(choices=[('auto_transport', 'Avtotransport'), ('real estate', "ko'chmas mulk"), ('equipment', 'uskuna va jihozlar')], max_length=50)), + ('percentage', models.PositiveIntegerField()), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='EmployeeBonus', + 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)), + ('percentage', models.PositiveIntegerField()), + ('bonus_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='evaluation.bonustype')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bonuses', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'unique_together': {('user', 'bonus_type')}, + }, + ), + migrations.DeleteModel( + name='Bonus', + ), + ] diff --git a/core/apps/evaluation/models/auto.py b/core/apps/evaluation/models/auto.py index 799fe53..9a406f0 100644 --- a/core/apps/evaluation/models/auto.py +++ b/core/apps/evaluation/models/auto.py @@ -9,14 +9,11 @@ from core.apps.evaluation.choices.auto import ( AutoEvaluationStatus, AutoObjectType, # FormOwnership, - LocationConvenience, - LocationHighways, ObjectOwnerType, # PropertyRights, # RateType, # ValueDetermined, ) - from .valuation import ValuationModel from .vehicle import VehicleModel @@ -244,8 +241,6 @@ class AutoEvaluationModel(AbstractBaseModel): default=False, ) - - def __str__(self): return f"Auto Evaluation {self.registration_number or self.pk}" diff --git a/core/apps/evaluation/models/bonus.py b/core/apps/evaluation/models/bonus.py new file mode 100644 index 0000000..9c18840 --- /dev/null +++ b/core/apps/evaluation/models/bonus.py @@ -0,0 +1,38 @@ +from django.db import models +from django.db.models.fields import PositiveIntegerField +from django_core.models import AbstractBaseModel + +from core.apps.evaluation.choices.bonus import EvaluationCategory + + +class BaseValueBonus(AbstractBaseModel): + base_price = models.DecimalField(max_digits=12, decimal_places=2) + + def __str__(self): + return f"Base: {self.base_price}" + + def save(self, *args, **kwargs): + if not self.pk and BaseValueBonus.objects.exists(): + raise ValueError("Value Bonus already exists") + return super().save(*args, **kwargs) + + +class BonusType(AbstractBaseModel): + name = models.CharField(max_length=255) + category = models.CharField( + max_length=50, + choices=EvaluationCategory.choices + ) + percentage = PositiveIntegerField() + + def __str__(self): + return self.name + + +class EmployeeBonus(AbstractBaseModel): + user = models.ForeignKey("accounts.User", on_delete=models.CASCADE, related_name="bonuses", ) + bonus_type = models.ForeignKey(BonusType, on_delete=models.CASCADE) + percentage = models.PositiveIntegerField() + + class Meta: + unique_together = ("user", "bonus_type") diff --git a/core/apps/evaluation/models/movable.py b/core/apps/evaluation/models/movable.py index c6075db..c762f4a 100644 --- a/core/apps/evaluation/models/movable.py +++ b/core/apps/evaluation/models/movable.py @@ -3,12 +3,11 @@ from django.utils.translation import gettext_lazy as _ from django_core.models import AbstractBaseModel from model_bakery import baker - -from .valuation import ValuationModel from core.apps.evaluation.choices.movable import ( MovablePropertyCategory, MovablePropertyCondition, ) +from .valuation import ValuationModel class MovablePropertyEvaluationModel(AbstractBaseModel): @@ -51,4 +50,3 @@ class MovablePropertyEvaluationModel(AbstractBaseModel): db_table = "MovablePropertyEvaluation" verbose_name = _("Movable Property Evaluation") verbose_name_plural = _("Movable Property Evaluations") - diff --git a/core/apps/evaluation/serializers/bonus/Bonus.py b/core/apps/evaluation/serializers/bonus/Bonus.py new file mode 100644 index 0000000..51482cd --- /dev/null +++ b/core/apps/evaluation/serializers/bonus/Bonus.py @@ -0,0 +1,44 @@ +from rest_framework import serializers + +from core.apps.evaluation.models.bonus import BonusType, EmployeeBonus, BaseValueBonus + + +class BonusTypeCreateSerializer(serializers.ModelSerializer): + class Meta: + model = BonusType + fields = 'name', 'category', 'percentage' + + +class BonusTypeListSerializer(serializers.ModelSerializer): + price = serializers.SerializerMethodField() + + class Meta: + model = BonusType + fields = 'name', 'category', 'percentage' + + def get_price(self, obj): + base_obj = BaseValueBonus.objects.first() + if not base_obj: + return 0 + + return (base_obj.base_price * obj.percentage) / 100 + + +class BonusEmployeeBonusSerializer(serializers.ModelSerializer): + class Meta: + model = EmployeeBonus + fields = 'user' , 'bonus_type' , 'percentage' + + +class EmployeeBonusSerializer(serializers.ModelSerializer): + price = serializers.SerializerMethodField() + + class Meta: + model = EmployeeBonus + fields = 'user', 'bonus_type', 'percentage' + + def get_price(self, obj): + base_obj = BaseValueBonus.objects.first() + if not base_obj: + return 0 + return (base_obj.base_price * obj.percentage) / 100 diff --git a/core/apps/evaluation/serializers/bonus/__init__.py b/core/apps/evaluation/serializers/bonus/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/evaluation/urls.py b/core/apps/evaluation/urls.py index 59e1718..dea563e 100644 --- a/core/apps/evaluation/urls.py +++ b/core/apps/evaluation/urls.py @@ -27,6 +27,8 @@ router.register("valuation", views.ValuationView, basename="valuation") router.register("property-owner", views.PropertyOwnerView, basename="property-owner") router.register("customer", views.CustomerView, basename="customer") router.register("certificate", views.CertificateView, basename="certificate") +router.register("bonus-type", views.BonusTypeView, basename="bonus-type") +router.register("bonus-employee", views.BonusEmployeeViewSet, basename="bonus-employee") urlpatterns = [ path("", include(router.urls)), diff --git a/core/apps/evaluation/views/__init__.py b/core/apps/evaluation/views/__init__.py index 64a46d9..5f9ff27 100644 --- a/core/apps/evaluation/views/__init__.py +++ b/core/apps/evaluation/views/__init__.py @@ -15,3 +15,4 @@ from .didox import * # noqa from .tech_passport import * # noqa from .certificate import * # noqa from .avg_cost import * +from .bonus import * \ No newline at end of file diff --git a/core/apps/evaluation/views/bonus.py b/core/apps/evaluation/views/bonus.py new file mode 100644 index 0000000..4c3d312 --- /dev/null +++ b/core/apps/evaluation/views/bonus.py @@ -0,0 +1,55 @@ +from django_core.mixins import BaseViewSetMixin +from drf_spectacular.utils import extend_schema +from rest_framework.permissions import AllowAny, IsAdminUser +from rest_framework.viewsets import ModelViewSet + +# core +from core.apps.evaluation.models.bonus import BonusType, EmployeeBonus +from core.apps.evaluation.serializers.bonus.Bonus import BonusTypeCreateSerializer, \ + BonusTypeListSerializer, EmployeeBonusSerializer, BonusEmployeeBonusSerializer + + +@extend_schema(tags=["Bonus"]) +class BonusTypeView(BaseViewSetMixin, ModelViewSet): + queryset = BonusType.objects.all() + + serializer_class = BonusTypeCreateSerializer + + action_serializer_class = { + 'create': BonusTypeCreateSerializer, + 'update': BonusTypeCreateSerializer, + 'partial_update': BonusTypeCreateSerializer, + 'list': BonusTypeListSerializer, + 'retrieve': BonusTypeListSerializer, + } + + action_permission_classes = { + 'create': [IsAdminUser], + 'update': [IsAdminUser], + 'partial_update': [IsAdminUser], + 'destroy': [IsAdminUser], + 'list': [IsAdminUser], + } + + +class BonusEmployeeViewSet(BaseViewSetMixin, ModelViewSet): + queryset = EmployeeBonus.objects.all() + serializer_class = EmployeeBonusSerializer + + + + action_serializer_class = { + 'create': BonusEmployeeBonusSerializer, + 'update': BonusEmployeeBonusSerializer, + 'partial_update': BonusEmployeeBonusSerializer, + 'list': EmployeeBonusSerializer, + 'retrieve': EmployeeBonusSerializer, + } + + action_permission_classes = { + 'create': [IsAdminUser], + 'update': [IsAdminUser], + 'partial_update': [IsAdminUser], + 'destroy': [IsAdminUser], + 'list': [IsAdminUser], + } \ No newline at end of file