add: add expence api
This commit is contained in:
18
core/apps/finance/migrations/0012_expence_file.py
Normal file
18
core/apps/finance/migrations/0012_expence_file.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.4 on 2025-09-09 14:52
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('finance', '0011_paymenttype_total_usd_paymenttype_total_uzs_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='expence',
|
||||
name='file',
|
||||
field=models.FileField(blank=True, null=True, unique='finance/expence/files/', upload_to=''),
|
||||
),
|
||||
]
|
||||
18
core/apps/finance/migrations/0013_alter_expence_file.py
Normal file
18
core/apps/finance/migrations/0013_alter_expence_file.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.4 on 2025-09-09 15:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('finance', '0012_expence_file'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='expence',
|
||||
name='file',
|
||||
field=models.FileField(blank=True, null=True, upload_to='finance/expence/files/'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.4 on 2025-09-09 15:05
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('finance', '0013_alter_expence_file'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='expence',
|
||||
name='exchange_rate',
|
||||
field=models.PositiveBigIntegerField(blank=True, default=0, null=True),
|
||||
),
|
||||
]
|
||||
@@ -22,13 +22,14 @@ class Expence(BaseModel):
|
||||
)
|
||||
|
||||
price = models.PositiveBigIntegerField()
|
||||
exchange_rate = models.PositiveBigIntegerField(default=0)
|
||||
exchange_rate = models.PositiveBigIntegerField(default=0, null=True, blank=True)
|
||||
currency = models.CharField(
|
||||
max_length=3, choices=[('usd','usd'), ('uzs', 'uzs')]
|
||||
)
|
||||
date = models.DateField(null=True, blank=True)
|
||||
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/')
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.cash_transaction} kassa uchun chiqim {self.price}'
|
||||
|
||||
@@ -23,7 +23,9 @@ class CashTransactionListSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = CashTransaction
|
||||
fields = [
|
||||
'id', 'name', 'payment_type', 'employees', 'status'
|
||||
'id', 'name', 'payment_type', 'employees', 'status', 'total_balance_usd',
|
||||
'income_balance_usd', 'expence_balance_usd', 'total_balance_uzs',
|
||||
'income_balance_uzs', 'expence_balance_uzs'
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
from django.db import transaction
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from core.apps.finance.models import Expence
|
||||
|
||||
|
||||
class ExpenceCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Expence
|
||||
fields = [
|
||||
'cash_transaction', 'payment_type', 'project_folder', 'project', 'expence_type',
|
||||
'counterparty', 'price', 'exchange_rate', 'currency', 'date', 'comment', 'audit', 'file'
|
||||
]
|
||||
|
||||
def create(self, validated_data):
|
||||
with transaction.atomic():
|
||||
expence = Expence.objects.create(
|
||||
cash_transaction=validated_data.get('cash_transaction'),
|
||||
payment_type=validated_data.get('payment_type'),
|
||||
project_folder=validated_data.get('project_folder'),
|
||||
project=validated_data.get('project'),
|
||||
expence_type=validated_data.get('expence_type'),
|
||||
counterparty=validated_data.get('counterparty'),
|
||||
price=validated_data.get('price') * validated_data.get('exchange_rate') if validated_data.get('exchange_rate') else validated_data.get('price'),
|
||||
exchange_rate=validated_data.get('exchange_rate'),
|
||||
currency=validated_data.get('currency'),
|
||||
date=validated_data.get('date'),
|
||||
comment=validated_data.get('comment'),
|
||||
audit=validated_data.get('audit'),
|
||||
file=validated_data.get('file'),
|
||||
)
|
||||
cash_transaction = expence.cash_transaction
|
||||
payment_type = expence.payment_type
|
||||
|
||||
if validated_data.get('currency') == 'uzs':
|
||||
cash_transaction.expence_balance_uzs += expence.price
|
||||
cash_transaction.total_balance_uzs = cash_transaction.income_balance_uzs - cash_transaction.expence_balance_uzs
|
||||
if payment_type.total_uzs > expence.price:
|
||||
payment_type.total_uzs -= expence.price
|
||||
elif validated_data.get('currency') == 'usd':
|
||||
cash_transaction.expence_balance_usd += expence.price
|
||||
if cash_transaction.income_balance_usd > cash_transaction.expence_balance_usd:
|
||||
cash_transaction.total_balance_usd = cash_transaction.income_balance_usd - cash_transaction.expence_balance_usd
|
||||
else:
|
||||
cash_transaction.total_balance_usd = 0
|
||||
if payment_type.total_usd > expence.price:
|
||||
payment_type.total_usd -= expence.price
|
||||
|
||||
cash_transaction.save()
|
||||
payment_type.save()
|
||||
return expence
|
||||
|
||||
|
||||
class ExpenceListSerializer(serializers.ModelSerializer):
|
||||
cash_transaction = serializers.SerializerMethodField(method_name='get_cash_transaction')
|
||||
payment_type = serializers.SerializerMethodField(method_name='get_payment_type')
|
||||
project_folder = serializers.SerializerMethodField(method_name='get_project_folder')
|
||||
project = serializers.SerializerMethodField(method_name='get_project')
|
||||
counterparty = serializers.SerializerMethodField(method_name='get_counterparty')
|
||||
expence_type = serializers.SerializerMethodField(method_name='get_expence_type')
|
||||
|
||||
class Meta:
|
||||
model = Expence
|
||||
fields = [
|
||||
'id', 'cash_transaction', 'payment_type', 'project_folder', 'project', 'expence_type',
|
||||
'counterparty', 'price', 'exchange_rate', 'currency', 'date', 'comment', 'audit', 'file'
|
||||
]
|
||||
|
||||
def get_cash_transaction(self, obj):
|
||||
return {
|
||||
'id': obj.cash_transaction.id,
|
||||
'name': obj.cash_transaction.name
|
||||
}
|
||||
|
||||
def get_payment_type(self, obj):
|
||||
return {
|
||||
'id': obj.payment_type.id,
|
||||
'name': obj.payment_type.name
|
||||
}
|
||||
|
||||
def get_project_folder(self, obj):
|
||||
return {
|
||||
'id': obj.project_folder.id,
|
||||
'name': obj.project_folder.name
|
||||
}
|
||||
|
||||
def get_project(self, obj):
|
||||
return {
|
||||
'id': obj.project.id,
|
||||
'name': obj.project.name
|
||||
} if obj.project else None
|
||||
|
||||
def get_counterparty(self, obj):
|
||||
return {
|
||||
'id': obj.counterparty.id,
|
||||
'name': obj.counterparty.name
|
||||
} if obj.counterparty else None
|
||||
|
||||
def get_expence_type(self, obj):
|
||||
return {
|
||||
'id': obj.expence_type.id,
|
||||
'name': obj.expence_type.name
|
||||
} if obj.expence_type else None
|
||||
|
||||
@@ -6,6 +6,7 @@ from core.apps.finance.views import payment_type as pt_views
|
||||
from core.apps.finance.views import type_income as ti_views
|
||||
from core.apps.finance.views import income as income_views
|
||||
from core.apps.finance.views import expence_type as ex_views
|
||||
from core.apps.finance.views import expence as expence_views
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
@@ -55,4 +56,10 @@ urlpatterns = [
|
||||
path('<uuid:id>/delete/', ex_views.ExpenceTypeDeleteApiView.as_view()),
|
||||
]
|
||||
)),
|
||||
path('expence/', include(
|
||||
[
|
||||
path('list/', expence_views.ExpenceListApiView.as_view()),
|
||||
path('create/', expence_views.ExpenceCreateApiView.as_view()),
|
||||
]
|
||||
))
|
||||
]
|
||||
52
core/apps/finance/views/expence.py
Normal file
52
core/apps/finance/views/expence.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from rest_framework import generics, views, parsers
|
||||
from rest_framework.response import Response
|
||||
|
||||
from core.apps.accounts.permissions.permissions import HasRolePermission
|
||||
from core.apps.finance.models import Expence
|
||||
from core.apps.finance.serializers import expence as serializers
|
||||
|
||||
|
||||
class ExpenceCreateApiView(generics.GenericAPIView):
|
||||
serializer_class = serializers.ExpenceCreateSerializer
|
||||
queryset = Expence.objects.select_related(
|
||||
'cash_transaction', 'payment_type', 'project_folder', 'project',
|
||||
'counterparty', 'expence_type',
|
||||
)
|
||||
permission_classes = [HasRolePermission]
|
||||
parser_classes = [parsers.FormParser, parsers.MultiPartParser]
|
||||
|
||||
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': 'Expence created'
|
||||
},
|
||||
status=201
|
||||
)
|
||||
return Response(
|
||||
{
|
||||
'success': False,
|
||||
'message': 'Expence create failed',
|
||||
'error': serializer.errors
|
||||
},
|
||||
status=400
|
||||
)
|
||||
|
||||
|
||||
class ExpenceListApiView(generics.GenericAPIView):
|
||||
serializer_class = serializers.ExpenceListSerializer
|
||||
queryset = Expence.objects.select_related(
|
||||
'cash_transaction', 'payment_type', 'project_folder', 'project',
|
||||
'counterparty', 'expence_type',
|
||||
)
|
||||
permission_classes = [HasRolePermission]
|
||||
|
||||
def get(self, request):
|
||||
page = self.paginate_queryset(self.queryset)
|
||||
if page is not None:
|
||||
serializer = self.serializer_class(page, many=True)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
|
||||
Reference in New Issue
Block a user