From b5a0aa607ea9936d5aebb86b94d9ca8c187bfd37 Mon Sep 17 00:00:00 2001 From: behruz-dev Date: Wed, 24 Sep 2025 18:51:25 +0500 Subject: [PATCH] add: add new api for expence --- core/apps/finance/admin/expence.py | 2 +- .../finance/migrations/0024_expence_status.py | 18 +++++++++++ core/apps/finance/models/expence.py | 6 ++++ core/apps/finance/urls.py | 1 + core/apps/finance/views/expence.py | 31 +++++++++++++++++-- 5 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 core/apps/finance/migrations/0024_expence_status.py diff --git a/core/apps/finance/admin/expence.py b/core/apps/finance/admin/expence.py index c57127d..13317c9 100644 --- a/core/apps/finance/admin/expence.py +++ b/core/apps/finance/admin/expence.py @@ -5,5 +5,5 @@ from core.apps.finance.models import Expence @admin.register(Expence) class ExpenceAdmin(admin.ModelAdmin): - list_display = ['id', 'price', 'cash_transaction'] + list_display = ['id', 'price', 'cash_transaction', 'status'] \ No newline at end of file diff --git a/core/apps/finance/migrations/0024_expence_status.py b/core/apps/finance/migrations/0024_expence_status.py new file mode 100644 index 0000000..cd45167 --- /dev/null +++ b/core/apps/finance/migrations/0024_expence_status.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.4 on 2025-09-24 18:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('finance', '0023_alter_expencecontract_project_folder'), + ] + + operations = [ + migrations.AddField( + model_name='expence', + name='status', + field=models.CharField(blank=True, choices=[('CANCELLED', 'rad etildi'), ('PENDING', 'kutilmoqda'), ('CONFIRMED', 'tasdiqlangan')], default='PENDING', max_length=20, null=True), + ), + ] diff --git a/core/apps/finance/models/expence.py b/core/apps/finance/models/expence.py index 2d1f6ce..dd387cf 100644 --- a/core/apps/finance/models/expence.py +++ b/core/apps/finance/models/expence.py @@ -7,6 +7,11 @@ from core.apps.accounts.models import User class Expence(BaseModel): + STATUS = ( + ('CANCELLED', 'rad etildi'), + ('PENDING', 'kutilmoqda'), + ('CONFIRMED', 'tasdiqlangan'), + ) user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='expences', null=True) cash_transaction = models.ForeignKey(CashTransaction, on_delete=models.CASCADE, related_name='expences') payment_type = models.ForeignKey(PaymentType, on_delete=models.CASCADE, related_name='expences') @@ -35,6 +40,7 @@ class Expence(BaseModel): comment = models.TextField(null=True, blank=True) audit = models.CharField(max_length=200, null=True, blank=True) file = models.FileField(null=True, blank=True, upload_to='finance/expence/files/') + status = models.CharField(max_length=20, choices=STATUS, default='PENDING', null=True, blank=True) def __str__(self): return f'{self.cash_transaction} kassa uchun chiqim {self.price}' diff --git a/core/apps/finance/urls.py b/core/apps/finance/urls.py index 93e77fd..d723b6b 100644 --- a/core/apps/finance/urls.py +++ b/core/apps/finance/urls.py @@ -65,6 +65,7 @@ urlpatterns = [ path('list/', expence_views.ExpenceListApiView.as_view()), path('create/', expence_views.ExpenceCreateApiView.as_view()), path('/list/', expence_views.CounterpartyExpenceListApiView.as_view()), + path('/change-status/', expence_views.ChangeExpenceStatusApiView.as_view()), ] )), path('income_contract/', include( diff --git a/core/apps/finance/views/expence.py b/core/apps/finance/views/expence.py index 8758211..8ae0d31 100644 --- a/core/apps/finance/views/expence.py +++ b/core/apps/finance/views/expence.py @@ -57,8 +57,11 @@ class ExpenceListApiView(generics.GenericAPIView): def get(self, request): cash_transaction_ids = request.query_params.getlist('cash_transaction') + status = request.query_params.get('status') if cash_transaction_ids: - self.queryset = self.queryset.filter(cash_transaction__in=cash_transaction_ids) + self.queryset = self.queryset.filter(cash_transaction__in=cash_transaction_ids).distinct() + if status: + self.queryset = self.queryset.filter(status=status).distinct() page = self.paginate_queryset(self.filter_queryset(self.queryset)) if page is not None: serializer = self.serializer_class(page, many=True) @@ -80,4 +83,28 @@ class CounterpartyExpenceListApiView(generics.GenericAPIView): if page is not None: ser = self.serializer_class(page, many=True) return self.get_paginated_response(ser.data) - \ No newline at end of file + + +class ChangeExpenceStatusApiView(views.APIView): + permission_classes = [HasRolePermission] + + def post(self, request, id): + expence = get_object_or_404(Expence, id=id) + status = request.data.get('status', None) + if status is None: + return Response( + { + 'success': False, + 'message': 'status field is required, choices PENDING, CANCELLED, CONFIRMED' + }, + status=400 + ) + expence.status = status + expence.save() + return Response( + { + 'success': True, + 'message': 'expence status successfully updated', + }, + status=200 + ) \ No newline at end of file