From 56262699996ee372ba177c896c35719e85e854c9 Mon Sep 17 00:00:00 2001 From: behruz-dev Date: Wed, 5 Nov 2025 13:54:25 +0500 Subject: [PATCH] fox --- core/apps/contracts/admins/__init__.py | 2 + core/apps/contracts/admins/folder.py | 8 ++++ core/apps/contracts/apps.py | 2 +- ..._alter_contract_company_contract_folder.py | 39 ++++++++++++++++ .../0003_alter_folder_options_folder_user.py | 25 ++++++++++ core/apps/contracts/models/__init__.py | 3 +- core/apps/contracts/models/contract.py | 4 +- core/apps/contracts/models/folder.py | 16 +++++++ core/apps/contracts/serializers/contract.py | 14 +++++- core/apps/contracts/serializers/folder.py | 31 +++++++++++++ core/apps/contracts/urls.py | 11 ++++- core/apps/contracts/views/folder.py | 46 +++++++++++++++++++ 12 files changed, 194 insertions(+), 7 deletions(-) create mode 100644 core/apps/contracts/admins/folder.py create mode 100644 core/apps/contracts/migrations/0002_folder_alter_contract_company_contract_folder.py create mode 100644 core/apps/contracts/migrations/0003_alter_folder_options_folder_user.py create mode 100644 core/apps/contracts/models/folder.py create mode 100644 core/apps/contracts/serializers/folder.py create mode 100644 core/apps/contracts/views/folder.py diff --git a/core/apps/contracts/admins/__init__.py b/core/apps/contracts/admins/__init__.py index e69de29..40f9820 100644 --- a/core/apps/contracts/admins/__init__.py +++ b/core/apps/contracts/admins/__init__.py @@ -0,0 +1,2 @@ +from .contract import * +from .folder import * \ No newline at end of file diff --git a/core/apps/contracts/admins/folder.py b/core/apps/contracts/admins/folder.py new file mode 100644 index 0000000..b405397 --- /dev/null +++ b/core/apps/contracts/admins/folder.py @@ -0,0 +1,8 @@ +from django.contrib import admin + +from core.apps.contracts.models.folder import Folder + + +@admin.register(Folder) +class FolderAdmin(admin.ModelAdmin): + list_display = ['id', 'name'] \ No newline at end of file diff --git a/core/apps/contracts/apps.py b/core/apps/contracts/apps.py index 3a9bb95..a9a42d5 100644 --- a/core/apps/contracts/apps.py +++ b/core/apps/contracts/apps.py @@ -6,4 +6,4 @@ class ContractsConfig(AppConfig): name = 'core.apps.contracts' def ready(self): - import core.apps.contracts.admins.contract \ No newline at end of file + import core.apps.contracts.admins \ No newline at end of file diff --git a/core/apps/contracts/migrations/0002_folder_alter_contract_company_contract_folder.py b/core/apps/contracts/migrations/0002_folder_alter_contract_company_contract_folder.py new file mode 100644 index 0000000..99409a2 --- /dev/null +++ b/core/apps/contracts/migrations/0002_folder_alter_contract_company_contract_folder.py @@ -0,0 +1,39 @@ +# Generated by Django 5.2 on 2025-11-05 12:14 + +import django.db.models.deletion +import uuid +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contracts', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Folder', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('name', models.CharField(max_length=200)), + ], + options={ + 'abstract': False, + }, + ), + migrations.AlterField( + model_name='contract', + name='company', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contracts', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='contract', + name='folder', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='countracts', to='contracts.folder'), + ), + ] diff --git a/core/apps/contracts/migrations/0003_alter_folder_options_folder_user.py b/core/apps/contracts/migrations/0003_alter_folder_options_folder_user.py new file mode 100644 index 0000000..f79f078 --- /dev/null +++ b/core/apps/contracts/migrations/0003_alter_folder_options_folder_user.py @@ -0,0 +1,25 @@ +# Generated by Django 5.2 on 2025-11-05 12:25 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('contracts', '0002_folder_alter_contract_company_contract_folder'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterModelOptions( + name='folder', + options={'verbose_name': 'Fayl', 'verbose_name_plural': 'Fayllar'}, + ), + migrations.AddField( + model_name='folder', + name='user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='folders', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/core/apps/contracts/models/__init__.py b/core/apps/contracts/models/__init__.py index d3aea48..40f9820 100644 --- a/core/apps/contracts/models/__init__.py +++ b/core/apps/contracts/models/__init__.py @@ -1 +1,2 @@ -from .contract import * \ No newline at end of file +from .contract import * +from .folder import * \ No newline at end of file diff --git a/core/apps/contracts/models/contract.py b/core/apps/contracts/models/contract.py index d101b0b..28f0afd 100644 --- a/core/apps/contracts/models/contract.py +++ b/core/apps/contracts/models/contract.py @@ -6,6 +6,7 @@ from django.contrib.auth import get_user_model from django.utils import timezone from core.apps.shared.models.base import BaseModel +from core.apps.contracts.models.folder import Folder from core.apps.contracts.enums.contract import SIDES, STATUS from core.apps.contracts.enums.contract_side import ROLE from core.apps.contracts.enums.contract_signature import SIGNATURE_TYPE, SIGNATURE_STATUS @@ -24,7 +25,8 @@ class Contract(BaseModel): add_folder = models.BooleanField(default=False) add_notification = models.BooleanField(default=False) - company = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='c') + company = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='contracts') + folder = models.ForeignKey(Folder, on_delete=models.SET_NULL, null=True, blank=True, related_name='countracts') def __str__(self): return f'{self.name}' diff --git a/core/apps/contracts/models/folder.py b/core/apps/contracts/models/folder.py new file mode 100644 index 0000000..addf17e --- /dev/null +++ b/core/apps/contracts/models/folder.py @@ -0,0 +1,16 @@ +from django.db import models + +from core.apps.shared.models import BaseModel +from core.apps.accounts.models import User + + +class Folder(BaseModel): + name = models.CharField(max_length=200) + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='folders', null=True ) + + def __str__(self): + return f"{self.name} folder {self.user.username}" + + class Meta: + verbose_name = "Fayl" + verbose_name_plural = "Fayllar" diff --git a/core/apps/contracts/serializers/contract.py b/core/apps/contracts/serializers/contract.py index 10e30ba..d3f469d 100644 --- a/core/apps/contracts/serializers/contract.py +++ b/core/apps/contracts/serializers/contract.py @@ -2,7 +2,7 @@ from django.db import transaction from rest_framework import serializers -from core.apps.contracts.models.contract import Contract +from core.apps.contracts.models.contract import Contract, Folder from core.apps.contracts.serializers.contract_side import ContractSideCreateSerializer, ContractSideListSerializer @@ -15,6 +15,15 @@ class ContractCreateSerializer(serializers.Serializer): attach_file = serializers.BooleanField() add_folder = serializers.BooleanField() add_notification = serializers.BooleanField() + folder_id = serializers.UUIDField(required=False) + + def validate(self, data): + if data.get('folder_id'): + folder = Folder.objects.filter(id=data.get('folder_id')).first() + if not folder: + raise serializers.ValidationError("Folder not found") + data['folder'] = folder + return data def create(self, validated_data): with transaction.atomic(): @@ -28,7 +37,8 @@ class ContractCreateSerializer(serializers.Serializer): attach_file=validated_data.pop('attach_file'), add_folder=validated_data.pop('add_folder'), add_notification=validated_data.pop('add_notification'), - company=user + company=user, + folder=validated_data.get('folder'), ) return contract.id diff --git a/core/apps/contracts/serializers/folder.py b/core/apps/contracts/serializers/folder.py new file mode 100644 index 0000000..16636e4 --- /dev/null +++ b/core/apps/contracts/serializers/folder.py @@ -0,0 +1,31 @@ +from rest_framework import serializers + +from core.apps.contracts.models import Folder + + +class FolderListSerializer(serializers.ModelSerializer): + class Meta: + model = Folder + fields = [ + 'id', 'name' + ] + + +class FolderSerializer(serializers.ModelSerializer): + class Meta: + model = Folder + fields = [ + 'name' + ] + + def create(self, validated_data): + folder = Folder.objects.create( + name=validated_data.get('name'), + user=self.context.get('user'), + ) + return folder + + def update(self, instance, validated_data): + instance.name = validated_data.get('name', instance.name) + instance.save() + return instance \ No newline at end of file diff --git a/core/apps/contracts/urls.py b/core/apps/contracts/urls.py index 3d6d3c6..5cc84ed 100644 --- a/core/apps/contracts/urls.py +++ b/core/apps/contracts/urls.py @@ -3,7 +3,7 @@ from django.urls import path, include from core.apps.contracts.views import contract as contract_views from core.apps.contracts.views import contract_side as contract_side_views from core.apps.contracts.views import contract_signature as contract_signature_views - +from core.apps.contracts.views import folder as folder_views urlpatterns = [ path('contract/', include( @@ -22,5 +22,12 @@ urlpatterns = [ path('send_signature_code//', contract_signature_views.SendContractSignatureCodeApiView.as_view(), name='send-signature-code'), path('sign_contract/', contract_signature_views.SigningContractApiView.as_view(), name='sign-contract'), ] - )) + )), + path('folder/', include( + [ + path('list/', folder_views.FolderListApiView.as_view()), + path('create/', folder_views.FolderCreateApiView.as_view()), + path('/update/', folder_views.FolderUpdateApiView.as_view()), + ] + )), ] \ No newline at end of file diff --git a/core/apps/contracts/views/folder.py b/core/apps/contracts/views/folder.py new file mode 100644 index 0000000..e0bdd58 --- /dev/null +++ b/core/apps/contracts/views/folder.py @@ -0,0 +1,46 @@ +from django.shortcuts import get_object_or_404 +from rest_framework import generics, views +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response + +from core.apps.contracts.models.folder import Folder +from core.apps.contracts.serializers import folder as serializers + + +class FolderListApiView(views.APIView): + permission_classes = [IsAuthenticated] + + def get(self, request): + user = request.user + folders = Folder.objects.filter(user=user) + serializer = serializers.FolderListSerializer(folders, many=True) + return Response(serializer.data, status=200) + + +class FolderCreateApiView(generics.GenericAPIView): + serializer_class = serializers.FolderSerializer + queryset = Folder.objects.all() + permission_classes = [IsAuthenticated] + + def post(self, request): + user = request.user + serializer = self.serializer_class(data=request.data, context={"user": user}) + if serializer.is_valid(raise_exception=True): + serializer.save() + return Response({"message":"Folder qoshild"}, status=200) + return Response(serializer.errors, status=400) + + +class FolderUpdateApiView(generics.GenericAPIView): + serializer_class = serializers.FolderSerializer + queryset = Folder.objects.all() + permission_classes = [IsAuthenticated] + + def patch(self, request, folder_id): + user = request.user + folder = get_object_or_404(Folder, id=folder_id, user=user) + serializer = self.serializer_class(data=request.data, instance=folder) + if serializer.is_valid(raise_exception=True): + serializer.save() + return Response({"message":"Folder tahrirlandi"}, status=200) + return Response(serializer.errors, status=400)