add: income-expence delete api

This commit is contained in:
behruz-dev
2025-09-25 16:37:41 +05:00
parent e854e5a7fe
commit 7ee8531aee
13 changed files with 214 additions and 7 deletions

View File

@@ -1,9 +1,14 @@
from django.contrib import admin
from core.apps.finance.models import Expence
from core.apps.finance.models import Expence, DeletedExpence
@admin.register(Expence)
class ExpenceAdmin(admin.ModelAdmin):
list_display = ['id', 'price', 'cash_transaction', 'status']
@admin.register(DeletedExpence)
class DeletedExpenceAdmin(admin.ModelAdmin):
list_display = ['id', 'comment', 'expence']

View File

@@ -1,9 +1,15 @@
from django.contrib import admin
from core.apps.finance.models import Income
from core.apps.finance.models import Income, DeletedIncome
@admin.register(Income)
class IncomeAdmin(admin.ModelAdmin):
list_display = ['id', 'price', 'cash_transaction']
list_filter = ['cash_transaction', 'payment_type']
@admin.register(DeletedIncome)
class DeletedIncomeAdmin(admin.ModelAdmin):
list_display = ['id', 'comment', 'income']

View File

@@ -0,0 +1,29 @@
# Generated by Django 5.2.4 on 2025-09-25 16:10
import django.db.models.deletion
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0024_expence_status'),
]
operations = [
migrations.CreateModel(
name='DeletedExpence',
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)),
('comment', models.CharField(max_length=200)),
('expence', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='deleted_expences', to='finance.expence')),
],
options={
'verbose_name': "O'chirilgan chiqim",
'verbose_name_plural': "O'chirilgan chiqim",
},
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.2.4 on 2025-09-25 16:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0025_deletedexpence'),
]
operations = [
migrations.AddField(
model_name='expence',
name='is_deleted',
field=models.BooleanField(default=False),
),
]

View File

@@ -0,0 +1,29 @@
# Generated by Django 5.2.4 on 2025-09-25 16:30
import django.db.models.deletion
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0026_expence_is_deleted'),
]
operations = [
migrations.CreateModel(
name='DeletedIncome',
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)),
('comment', models.CharField(max_length=200)),
('income', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='deleted_incomes', to='finance.income')),
],
options={
'verbose_name': "O'chirilgan kirim",
'verbose_name_plural': "O'chirilgan kirimlar",
},
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.2.4 on 2025-09-25 16:36
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0027_deletedincome'),
]
operations = [
migrations.AddField(
model_name='income',
name='is_deleted',
field=models.BooleanField(default=False),
),
]

View File

@@ -41,6 +41,7 @@ class Expence(BaseModel):
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)
is_deleted = models.BooleanField(default=False)
def __str__(self):
return f'{self.cash_transaction} kassa uchun chiqim {self.price}'
@@ -49,3 +50,14 @@ class Expence(BaseModel):
verbose_name = 'chiqim'
verbose_name_plural = 'chiqimlar'
class DeletedExpence(BaseModel):
expence = models.ForeignKey(Expence, on_delete=models.CASCADE, related_name='deleted_expences')
comment = models.CharField(max_length=200)
def __str__(self):
return f'{self.expence} is deleted'
class Meta:
verbose_name = "O'chirilgan chiqim"
verbose_name_plural = "O'chirilgan chiqim"

View File

@@ -32,6 +32,7 @@ class Income(BaseModel):
comment = models.TextField(null=True, blank=True)
file = models.FileField(upload_to='finance/income/file/', null=True, blank=True)
audit = models.CharField(max_length=200, null=True, blank=True)
is_deleted = models.BooleanField(default=False)
def __str__(self):
return f'{self.cash_transaction} kassa uchun kirim {self.price}'
@@ -41,3 +42,13 @@ class Income(BaseModel):
verbose_name_plural = 'kirimlar'
class DeletedIncome(BaseModel):
income = models.ForeignKey(Income, on_delete=models.CASCADE, related_name='deleted_incomes')
comment = models.CharField(max_length=200)
def __str__(self):
return f'{self.income} is deleted'
class Meta:
verbose_name = "O'chirilgan kirim"
verbose_name_plural = "O'chirilgan kirimlar"

View File

@@ -133,3 +133,7 @@ class ExpenceListSerializer(serializers.ModelSerializer):
'id': obj.expence_type.id,
'name': obj.expence_type.name
} if obj.expence_type else None
class ExpenceDeleteSerializer(serializers.Serializer):
comment = serializers.CharField()

View File

@@ -131,3 +131,7 @@ class IncomeCreateSerializer(serializers.ModelSerializer):
cash_transaction.save()
payment_type.save()
return income
class IncomeDeleteSerializer(serializers.Serializer):
comment = serializers.CharField()

View File

@@ -50,6 +50,7 @@ urlpatterns = [
path('list/', income_views.IncomeListApiView.as_view()),
path('create/', income_views.IncomeCreateApiView.as_view()),
path('<uuid:counterparty_id>/list/', income_views.CounterpartyIncomeListApiView.as_view()),
path('<uuid:id>/delete/', income_views.IncomeDeleteApiView.as_view()),
]
)),
path('expence_type/', include(
@@ -66,6 +67,7 @@ urlpatterns = [
path('create/', expence_views.ExpenceCreateApiView.as_view()),
path('<uuid:counterparty_id>/list/', expence_views.CounterpartyExpenceListApiView.as_view()),
path('<uuid:id>/change-status/', expence_views.ChangeExpenceStatusApiView.as_view()),
path('<uuid:id>/delete/', expence_views.ExpenceDeleteApiView.as_view()),
]
)),
path('income_contract/', include(

View File

@@ -6,7 +6,7 @@ from rest_framework.response import Response
from django_filters.rest_framework.backends import DjangoFilterBackend
from core.apps.accounts.permissions.permissions import HasRolePermission
from core.apps.finance.models import Expence
from core.apps.finance.models import Expence, DeletedExpence
from core.apps.finance.serializers import expence as serializers
from core.apps.finance.filters.expence import ExpenceFilter
from core.apps.counterparty.models import Counterparty
@@ -108,3 +108,38 @@ class ChangeExpenceStatusApiView(views.APIView):
},
status=200
)
class ExpenceDeleteApiView(generics.GenericAPIView):
serializer_class = serializers.ExpenceDeleteSerializer
queryset = Expence.objects.all()
permission_classes = [HasRolePermission]
def post(self, request, id):
expence = get_object_or_404(Expence, id=id)
serializer = self.serializer_class(data=request.data)
if serializer.is_valid(raise_exception=True):
comment = serializer.validated_data.get('comment')
DeletedExpence.objects.create(
expence=expence,
comment=comment
)
expence.is_deleted = True
if expence.currency == 'uzs':
expence.cash_transaction.expence_balance_uzs += expence.price
expence.cash_transaction.total_balance_uzs += expence.price
expence.payment_type.total_uzs += expence.price
else:
expence.cash_transaction.expence_balance_usd += expence.price
expence.cash_transaction.total_balance_usd += expence.price
expence.payment_type.total_usd += expence.price
expence.cash_transaction.save()
expence.payment_type.save()
expence.save()
return Response(
{
'success': True,
'message': 'Expence deleted',
}, status=200
)

View File

@@ -5,7 +5,7 @@ from rest_framework.response import Response
from django_filters.rest_framework.backends import DjangoFilterBackend
from core.apps.finance.models import Income
from core.apps.finance.models import Income, DeletedIncome
from core.apps.finance.serializers import income as serializers
from core.apps.accounts.permissions.permissions import HasRolePermission
from core.apps.finance.filters.income import IncomeFilter
@@ -77,3 +77,37 @@ class CounterpartyIncomeListApiView(generics.GenericAPIView):
ser = self.serializer_class(page, many=True)
return self.get_paginated_response(ser.data)
class IncomeDeleteApiView(generics.GenericAPIView):
serializer_class = serializers.IncomeDeleteSerializer
queryset = Income.objects.all()
permission_classes = [HasRolePermission]
def post(self, request, id):
income = get_object_or_404(Income, id=id)
serializer = self.serializer_class(data=request.data)
if serializer.is_valid(raise_exception=True):
comment = serializer.validated_data.get('comment')
DeletedIncome.objects.create(
income=income,
comment=comment
)
income.is_deleted = True
if income.currency == 'uzs':
income.cash_transaction.expence_balance_uzs -= income.price
income.cash_transaction.total_balance_uzs -= income.price
income.payment_type.total_uzs -= income.price
else:
income.cash_transaction.expence_balance_usd -= income.price
income.cash_transaction.total_balance_usd -= income.price
income.payment_type.total_usd -= income.price
income.cash_transaction.save()
income.payment_type.save()
income.save()
return Response(
{
'success': True,
'message': 'Income deleted',
}, status=200
)