diff --git a/core/apps/finance/admin/cash_transaction.py b/core/apps/finance/admin/cash_transaction.py index a8e58fb..d60b56d 100644 --- a/core/apps/finance/admin/cash_transaction.py +++ b/core/apps/finance/admin/cash_transaction.py @@ -1,9 +1,15 @@ from django.contrib import admin -from core.apps.finance.models import CashTransaction +from core.apps.finance.models import CashTransaction, CashTransactionFolder @admin.register(CashTransaction) -class CachTransaction(admin.ModelAdmin): +class CashTransaction(admin.ModelAdmin): + list_display = ['id', 'name'] + search_fields = ['name'] + + +@admin.register(CashTransactionFolder) +class CashTransactionFolderAdmin(admin.ModelAdmin): list_display = ['id', 'name'] search_fields = ['name'] \ No newline at end of file diff --git a/core/apps/finance/migrations/0003_cashtransactionfolder_cashtransaction_folder.py b/core/apps/finance/migrations/0003_cashtransactionfolder_cashtransaction_folder.py new file mode 100644 index 0000000..52945e7 --- /dev/null +++ b/core/apps/finance/migrations/0003_cashtransactionfolder_cashtransaction_folder.py @@ -0,0 +1,33 @@ +# Generated by Django 5.2.4 on 2025-09-05 17:11 + +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('finance', '0002_paymenttype_cashtransaction_employees_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='CashTransactionFolder', + 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={ + 'verbose_name': 'Kassa papkasi', + 'verbose_name_plural': 'Kassa papkalari', + }, + ), + migrations.AddField( + model_name='cashtransaction', + name='folder', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='cash_transactions', to='finance.cashtransactionfolder'), + ), + ] diff --git a/core/apps/finance/models/cash_transaction.py b/core/apps/finance/models/cash_transaction.py index 5d95cee..63b3105 100644 --- a/core/apps/finance/models/cash_transaction.py +++ b/core/apps/finance/models/cash_transaction.py @@ -6,6 +6,17 @@ from core.apps.finance.models.payment_type import PaymentType from core.apps.accounts.models import User +class CashTransactionFolder(BaseModel): + name = models.CharField(max_length=200) + + def __str__(self): + return self.name + + class Meta: + verbose_name = 'Kassa papkasi' + verbose_name_plural = 'Kassa papkalari' + + class CashTransaction(BaseModel): name = models.CharField(max_length=200, unique=True) payment_type = models.ForeignKey( @@ -13,6 +24,10 @@ class CashTransaction(BaseModel): ) employees = models.ManyToManyField(User, related_name='cash_transactions') status = models.BooleanField(default=False) + folder = models.ForeignKey( + CashTransactionFolder, on_delete=models.SET_NULL, related_name='cash_transactions', + null=True, blank=True + ) def __str__(self): return self.name diff --git a/core/apps/finance/serializers/cash_transaction.py b/core/apps/finance/serializers/cash_transaction.py index 4db2763..1ef2017 100644 --- a/core/apps/finance/serializers/cash_transaction.py +++ b/core/apps/finance/serializers/cash_transaction.py @@ -6,6 +6,7 @@ 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 diff --git a/core/apps/finance/serializers/cash_transaction_folder.py b/core/apps/finance/serializers/cash_transaction_folder.py new file mode 100644 index 0000000..af07e4a --- /dev/null +++ b/core/apps/finance/serializers/cash_transaction_folder.py @@ -0,0 +1,20 @@ +from rest_framework import serializers + +from core.apps.finance.models import CashTransactionFolder + + +class CashTransactionFolderSerializer(serializers.ModelSerializer): + cash_transaction_count = serializers.SerializerMethodField(method_name='get_cash_transaction_count') + + class Meta: + model = CashTransactionFolder + fields = [ + 'id', 'name', 'cash_transaction_count' + ] + extra_kwargs = { + 'id': {"read_only": True}, + 'cash_transaction_count': {"read_only": True}, + } + + def get_cash_transaction_count(self, obj): + return obj.cash_transactions.count() diff --git a/core/apps/finance/urls.py b/core/apps/finance/urls.py index 0e435d5..1ccbc14 100644 --- a/core/apps/finance/urls.py +++ b/core/apps/finance/urls.py @@ -1,6 +1,7 @@ from django.urls import path, include from core.apps.finance.views import cash_transaction as cash_views +from core.apps.finance.views import cash_transaction_folder as folder_views urlpatterns = [ @@ -9,5 +10,13 @@ urlpatterns = [ path('list/', cash_views.CashTransactionListApiView.as_view()), path('create/', cash_views.CashTransactionCreateApiView.as_view()), ] - )) + )), + path('cash_transaction_folder/', include( + [ + path('create/', folder_views.CashTransactionCreateApiView.as_view()), + path('list/', folder_views.CashTransactionFolderListApiView.as_view()), + path('/delete/', folder_views.CashTransactionFolderDeleteApiView.as_view()), + path('/update/', folder_views.CashTransactionFolderUpdateApiView.as_view()), + ] + )), ] \ No newline at end of file diff --git a/core/apps/finance/views/cash_transaction_folder.py b/core/apps/finance/views/cash_transaction_folder.py new file mode 100644 index 0000000..e9fd65f --- /dev/null +++ b/core/apps/finance/views/cash_transaction_folder.py @@ -0,0 +1,82 @@ +from django.shortcuts import get_object_or_404 + +from rest_framework import generics, views, status +from rest_framework.response import Response + +from core.apps.accounts.permissions.permissions import HasRolePermission +from core.apps.finance.models import CashTransactionFolder +from core.apps.finance.serializers.cash_transaction_folder import CashTransactionFolderSerializer + + +class CashTransactionCreateApiView(generics.GenericAPIView): + serializer_class = CashTransactionFolderSerializer + queryset = CashTransactionFolder.objects.all() + permission_classes = [HasRolePermission] + + def post(self, request): + serializer = self.serializer_class(data=request.data) + if serializer.is_valid(raise_exception=True): + serializer.save() + return Response( + { + 'success': True, + 'message': 'Cash Transaction Folder created successfully' + }, + status=status.HTTP_201_CREATED + ) + return Response( + { + 'success': False, + 'message': 'Cash Transaction Folder create failed', + 'error': serializer.errors + }, + status=status.HTTP_400_BAD_REQUEST + ) + + +class CashTransactionFolderListApiView(generics.GenericAPIView): + permission_classes = [HasRolePermission] + queryset = CashTransactionFolder.objects.prefetch_related('cash_transactions') + serializer_class = CashTransactionFolderSerializer + + def get(self, request): + page = self.paginate_queryset(self.queryset) + if page is not None: + ser = self.serializer_class(page, many=True) + return self.get_paginated_response(ser.data) + ser = self.serializer_class(self.queryset, many=True) + return Response(ser.data, status=status.HTTP_200_OK) + + +class CashTransactionFolderDeleteApiView(views.APIView): + permission_classes = [HasRolePermission] + + def delete(self, request, id): + folder = get_object_or_404(CashTransactionFolder, id=id) + folder.delete() + return Response( + { + 'success': True, + 'message': 'Cash Transaction Folder successfully deleted!', + }, + status=status.HTTP_204_NO_CONTENT + ) + + +class CashTransactionFolderUpdateApiView(generics.GenericAPIView): + serializer_class = CashTransactionFolderSerializer + queryset = CashTransactionFolder + permission_classes = [HasRolePermission] + + def patch(self, request, id): + folder = get_object_or_404(CashTransactionFolder, id=id) + ser = self.serializer_class(data=request.data, instance=folder, partial=True) + ser.is_valid(raise_exception=True) + ser.save() + return Response( + { + 'success': True, + 'message': 'Cash Transaction Folder successfully updated!', + }, + status=status.HTTP_200_OK + )