From 18ff76aaa66f4b40c84940b0c48aaafd10f5fd31 Mon Sep 17 00:00:00 2001 From: behruz-dev Date: Wed, 6 Aug 2025 13:59:45 +0500 Subject: [PATCH] fix --- config/conf/__init__.py | 6 --- config/conf/drf_yasg.py | 19 ------- config/conf/rest_framework.py | 4 +- config/settings/base.py | 10 +++- config/urls.py | 15 +++++- core/apps/accounts/admin/user.py | 10 ++-- ...rst_name_remove_user_last_name_and_more.py | 36 +++++++++++++ core/apps/accounts/models/user.py | 5 ++ core/apps/accounts/permissions/permissions.py | 4 +- core/apps/accounts/serializers/user.py | 2 +- core/apps/accounts/views/login.py | 4 +- .../finance/serializers/cash_transaction.py | 51 ++++++++++++++++++- core/apps/finance/urls.py | 1 + core/apps/finance/views/cash_transaction.py | 9 +++- core/apps/projects/models/project_estimate.py | 9 ++++ 15 files changed, 144 insertions(+), 41 deletions(-) create mode 100644 core/apps/accounts/migrations/0004_remove_user_first_name_remove_user_last_name_and_more.py create mode 100644 core/apps/projects/models/project_estimate.py diff --git a/config/conf/__init__.py b/config/conf/__init__.py index 44c072c..e69de29 100644 --- a/config/conf/__init__.py +++ b/config/conf/__init__.py @@ -1,6 +0,0 @@ -from .jazzmin import * -from .drf_yasg import * -from .redis import * -from .rest_framework import * -from .rest_framework_simplejwt import * -from .cors_headers import * \ No newline at end of file diff --git a/config/conf/drf_yasg.py b/config/conf/drf_yasg.py index e83e896..b2d6dde 100644 --- a/config/conf/drf_yasg.py +++ b/config/conf/drf_yasg.py @@ -1,22 +1,3 @@ -from rest_framework import permissions -from drf_yasg.views import get_schema_view -from drf_yasg import openapi - - -schema_view = get_schema_view( - openapi.Info( - title="UyQur API", - default_version='v1', - description="Test description", - terms_of_service="https://www.google.com/policies/terms/", - contact=openapi.Contact(email="xoliqberdiyevbehru12@gmail.com"), - license=openapi.License(name="Felix IT Solutions License"), - ), - public=True, - permission_classes=(permissions.IsAuthenticated,), -) - - SWAGGER_SETTINGS = { 'SECURITY_DEFINITIONS': { 'Basic': { diff --git a/config/conf/rest_framework.py b/config/conf/rest_framework.py index b2837b3..1d6598a 100644 --- a/config/conf/rest_framework.py +++ b/config/conf/rest_framework.py @@ -1,7 +1,7 @@ REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ - 'rest_framework.authentication.SessionAuthentication', - 'rest_framework.authentication.BasicAuthentication', + # 'rest_framework.authentication.SessionAuthentication', + # 'rest_framework.authentication.BasicAuthentication', 'rest_framework_simplejwt.authentication.JWTAuthentication', ], 'DEFAULT_PAGINATION_CLASS': 'core.apps.shared.paginations.custom.CustomPageNumberPagination', diff --git a/config/settings/base.py b/config/settings/base.py index c6c0063..d054618 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -1,3 +1,4 @@ +from datetime import timedelta from pathlib import Path from config.env import env @@ -151,4 +152,11 @@ AUTH_USER_MODEL = 'accounts.User' SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') -from config.conf import * + +from config.conf.rest_framework import * +from config.conf.rest_framework_simplejwt import * +from config.conf.logs import * +from config.conf.cors_headers import * +from config.conf.drf_yasg import * +from config.conf.jazzmin import * +from config.conf.redis import * \ No newline at end of file diff --git a/config/urls.py b/config/urls.py index 69d4969..65fdd3d 100644 --- a/config/urls.py +++ b/config/urls.py @@ -3,7 +3,20 @@ from django.urls import path, include from django.conf import settings from django.conf.urls.static import static -from config.conf.drf_yasg import schema_view +from drf_yasg.views import get_schema_view +from drf_yasg import openapi + +schema_view = get_schema_view( + openapi.Info( + title="UyQur API", + default_version='v1', + description="Test description", + terms_of_service="https://www.google.com/policies/terms/", + contact=openapi.Contact(email="xoliqberdiyevbehru12@gmail.com"), + license=openapi.License(name="Felix IT Solutions License"), + ), + public=True, +) urlpatterns = [ diff --git a/core/apps/accounts/admin/user.py b/core/apps/accounts/admin/user.py index ee451b5..68d8ebc 100644 --- a/core/apps/accounts/admin/user.py +++ b/core/apps/accounts/admin/user.py @@ -10,7 +10,9 @@ class UserAdmin(DjangoUserAdmin): change_user_password_template = None fieldsets = ( (None, {"fields": ("username", "password")}), - (_("Personal info"), {"fields": ("first_name", "last_name", "email", "role")}), + (_("Personal info"), {"fields": ( + "full_name", 'phone_number', "role", 'profile_image', 'is_blocked' + )}), (_("Important dates"), {"fields": ("last_login", "date_joined")}), ) add_fieldsets = ( @@ -22,7 +24,7 @@ class UserAdmin(DjangoUserAdmin): }, ), ) - list_display = ("username", "email", "first_name", "last_name", "is_staff") - list_filter = ("is_staff", "is_superuser", "is_active", "groups") - search_fields = ("username", "first_name", "last_name", "email") + list_display = ("username", "phone_number", "full_name", "is_blocked", "is_staff") + list_filter = ("is_staff", "is_superuser", "is_active", "is_blocked") + search_fields = ("username", "full_name", "phone_number") ordering = ("username",) \ No newline at end of file diff --git a/core/apps/accounts/migrations/0004_remove_user_first_name_remove_user_last_name_and_more.py b/core/apps/accounts/migrations/0004_remove_user_first_name_remove_user_last_name_and_more.py new file mode 100644 index 0000000..02529df --- /dev/null +++ b/core/apps/accounts/migrations/0004_remove_user_first_name_remove_user_last_name_and_more.py @@ -0,0 +1,36 @@ +# Generated by Django 5.2.4 on 2025-08-06 12:58 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0003_alter_role_permissions'), + ] + + operations = [ + migrations.RemoveField( + model_name='user', + name='first_name', + ), + migrations.RemoveField( + model_name='user', + name='last_name', + ), + migrations.AddField( + model_name='user', + name='full_name', + field=models.CharField(max_length=200, null=True), + ), + migrations.AddField( + model_name='user', + name='is_blocked', + field=models.BooleanField(default=False), + ), + migrations.AddField( + model_name='user', + name='phone_number', + field=models.CharField(max_length=15, null=True), + ), + ] diff --git a/core/apps/accounts/models/user.py b/core/apps/accounts/models/user.py index bf79d50..b04d6d1 100644 --- a/core/apps/accounts/models/user.py +++ b/core/apps/accounts/models/user.py @@ -11,7 +11,12 @@ class User(BaseModel, AbstractUser): upload_to="users/profile_images/", null=True, blank=True, verbose_name=_('profil rasmi') ) role = models.ForeignKey(Role, on_delete=models.DO_NOTHING, null=True, related_name="users") + full_name = models.CharField(max_length=200, null=True) + is_blocked = models.BooleanField(default=False) + phone_number = models.CharField(max_length=15, null=True) + first_name = None + last_name = None REQUIRED_FIELDS = [] def __str__(self): diff --git a/core/apps/accounts/permissions/permissions.py b/core/apps/accounts/permissions/permissions.py index 436b26c..1e4a78b 100644 --- a/core/apps/accounts/permissions/permissions.py +++ b/core/apps/accounts/permissions/permissions.py @@ -9,10 +9,10 @@ class HasRolePermission(BasePermission): required_permissions = getattr(view, 'required_permissions', []) if not required_permissions: - return True + return True if user.role: user_permissions = user.role.permissions.values_list('code', flat=True) - return all(perm in user_permissions for perm in required_permissions) + return any(perm in user_permissions for perm in required_permissions) return False \ No newline at end of file diff --git a/core/apps/accounts/serializers/user.py b/core/apps/accounts/serializers/user.py index 28c1111..dd4b30b 100644 --- a/core/apps/accounts/serializers/user.py +++ b/core/apps/accounts/serializers/user.py @@ -9,7 +9,7 @@ class UserProfileSerializer(serializers.ModelSerializer): class Meta: model = User fields = [ - 'id', 'first_name', 'last_name', 'username', 'role', 'profile_image', 'permissions' + 'id', 'full_name', 'username', 'phone_number', 'is_blocked', 'role', 'profile_image', 'permissions' ] extra_kwargs = {'role': {'read_only': True}, "permissions": {'read_only': True}} diff --git a/core/apps/accounts/views/login.py b/core/apps/accounts/views/login.py index c063c7a..6c49942 100644 --- a/core/apps/accounts/views/login.py +++ b/core/apps/accounts/views/login.py @@ -18,8 +18,8 @@ class LoginApiView(generics.GenericAPIView): user = serializer.validated_data.get('user') token = RefreshToken.for_user(user) user_data = { - 'role': user.role.name, - 'permissions': user.role.permissions.values_list('code', flat=True), + 'role': user.role.name if user.role else None, + 'permissions': user.role.permissions.values_list('code', flat=True) if user.role else None, } return Response( {"access": str(token.access_token), "refresh": str(token), 'user_data': user_data}, diff --git a/core/apps/finance/serializers/cash_transaction.py b/core/apps/finance/serializers/cash_transaction.py index 98f8c9a..4db2763 100644 --- a/core/apps/finance/serializers/cash_transaction.py +++ b/core/apps/finance/serializers/cash_transaction.py @@ -1,11 +1,58 @@ +from django.db import transaction + from rest_framework import serializers from core.apps.finance.models import CashTransaction +from core.apps.accounts.models import User +from core.apps.finance.models import PaymentType + +class CashTransactionEmployeeListSerializer(serializers.ModelSerializer): + class Meta: + model = User + fields = [ + 'id', 'profile_image', 'first_name', 'last_name', 'username' + ] class CashTransactionListSerializer(serializers.ModelSerializer): + payment_type = serializers.SerializerMethodField(method_name='get_payment_type') + employees = CashTransactionEmployeeListSerializer(many=True) + class Meta: model = CashTransaction fields = [ - 'id', 'name' - ] \ No newline at end of file + 'id', 'name', 'payment_type', 'employees', 'status' + ] + + def get_payment_type(self, obj): + return { + "id": obj.payment_type.id, + "name": obj.payment_type.name + } + + +class CashTransactionCreateSerializer(serializers.Serializer): + payment_type_id = serializers.UUIDField() + employee_ids = serializers.ListSerializer(child=serializers.UUIDField()) + name = serializers.CharField() + status = serializers.BooleanField() + + def validate(self, data): + payment_type = PaymentType.objects.filter(id=data['id']).first() + if payment_type: + raise serializers.ValidationError("Payment Type not found") + data['payment_type'] = payment_type + return data + + def create(self, validated_data): + with transaction.atomic(): + employee_ids = validated_data.pop('employee_ids') + cash_transaction = CashTransaction.objects.create( + name=validated_data.get('name'), + payment_type=validated_data.get('payment_type'), + status=validated_data.get('status') + ) + cash_transaction.employees.set(employee_ids) + cash_transaction.save() + return cash_transaction + \ No newline at end of file diff --git a/core/apps/finance/urls.py b/core/apps/finance/urls.py index e580963..0e435d5 100644 --- a/core/apps/finance/urls.py +++ b/core/apps/finance/urls.py @@ -7,6 +7,7 @@ urlpatterns = [ path('cash_transaction/', include( [ path('list/', cash_views.CashTransactionListApiView.as_view()), + path('create/', cash_views.CashTransactionCreateApiView.as_view()), ] )) ] \ No newline at end of file diff --git a/core/apps/finance/views/cash_transaction.py b/core/apps/finance/views/cash_transaction.py index 8da5f0d..16d938a 100644 --- a/core/apps/finance/views/cash_transaction.py +++ b/core/apps/finance/views/cash_transaction.py @@ -10,5 +10,12 @@ class CashTransactionListApiView(generics.ListAPIView): permission_classes = [HasRolePermission] required_permissions = [] serializer_class = serializers.CashTransactionListSerializer + queryset = CashTransaction.objects.select_related('payment_type').prefetch_related('employees') + pagination_class = CustomPageNumberPagination + + +class CashTransactionCreateApiView(generics.GenericAPIView): + serializer_class = serializers.CashTransactionCreateSerializer queryset = CashTransaction.objects.all() - pagination_class = CustomPageNumberPagination \ No newline at end of file + permission_classes = [HasRolePermission] + required_permissions = ['project', 'project_folder'] \ No newline at end of file diff --git a/core/apps/projects/models/project_estimate.py b/core/apps/projects/models/project_estimate.py new file mode 100644 index 0000000..4b46667 --- /dev/null +++ b/core/apps/projects/models/project_estimate.py @@ -0,0 +1,9 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from core.apps.shared.models import BaseModel +from core.apps.projects.models import Project + + +class ProjectEstimate(BaseModel): + ... \ No newline at end of file