From d66cbf31cc4a9c3bfef2296639f0f8c694c05ce1 Mon Sep 17 00:00:00 2001 From: behruz-dev Date: Thu, 11 Sep 2025 14:28:33 +0500 Subject: [PATCH] change: change income expence serializer --- .../finance/migrations/0018_expence_party.py | 20 +++++ .../0019_expence_user_income_user.py | 26 +++++++ core/apps/finance/models/expence.py | 5 ++ core/apps/finance/models/income.py | 2 + core/apps/finance/serializers/expence.py | 10 +++ core/apps/finance/serializers/income.py | 11 ++- core/apps/finance/views/expence.py | 2 +- core/apps/finance/views/income.py | 2 +- core/apps/orders/serializers/party.py | 74 +++++++++++++++++++ 9 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 core/apps/finance/migrations/0018_expence_party.py create mode 100644 core/apps/finance/migrations/0019_expence_user_income_user.py diff --git a/core/apps/finance/migrations/0018_expence_party.py b/core/apps/finance/migrations/0018_expence_party.py new file mode 100644 index 0000000..c2bc89f --- /dev/null +++ b/core/apps/finance/migrations/0018_expence_party.py @@ -0,0 +1,20 @@ +# Generated by Django 5.2.4 on 2025-09-10 16:44 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('finance', '0017_alter_expence_project_folder_alter_income_date_and_more'), + ('orders', '0023_alter_party_orders'), + ] + + operations = [ + migrations.AddField( + model_name='expence', + name='party', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='expences', to='orders.party'), + ), + ] diff --git a/core/apps/finance/migrations/0019_expence_user_income_user.py b/core/apps/finance/migrations/0019_expence_user_income_user.py new file mode 100644 index 0000000..c66c891 --- /dev/null +++ b/core/apps/finance/migrations/0019_expence_user_income_user.py @@ -0,0 +1,26 @@ +# Generated by Django 5.2.4 on 2025-09-11 14:24 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('finance', '0018_expence_party'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AddField( + model_name='expence', + name='user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='expences', to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='income', + name='user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='incomes', to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/core/apps/finance/models/expence.py b/core/apps/finance/models/expence.py index 0dff0bd..2d1f6ce 100644 --- a/core/apps/finance/models/expence.py +++ b/core/apps/finance/models/expence.py @@ -3,9 +3,11 @@ from django.db import models from core.apps.shared.models import BaseModel from core.apps.finance.models import CashTransaction, PaymentType, ExpenceType from core.apps.counterparty.models import Counterparty +from core.apps.accounts.models import User class Expence(BaseModel): + 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') project_folder = models.ForeignKey( @@ -20,6 +22,9 @@ class Expence(BaseModel): counterparty = models.ForeignKey( Counterparty, on_delete=models.SET_NULL, null=True, blank=True, related_name='expences' ) + party = models.ForeignKey( + 'orders.Party', on_delete=models.SET_NULL, null=True, blank=True, related_name='expences' + ) price = models.PositiveBigIntegerField() exchange_rate = models.PositiveBigIntegerField(default=0, null=True, blank=True) diff --git a/core/apps/finance/models/income.py b/core/apps/finance/models/income.py index d276ca7..19527ed 100644 --- a/core/apps/finance/models/income.py +++ b/core/apps/finance/models/income.py @@ -3,9 +3,11 @@ from django.db import models from core.apps.shared.models import BaseModel from core.apps.finance.models import CashTransaction, PaymentType, TypeIncome from core.apps.counterparty.models import Counterparty +from core.apps.accounts.models import User class Income(BaseModel): + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='incomes', null=True) cash_transaction = models.ForeignKey( CashTransaction, on_delete=models.CASCADE, related_name='incomes' ) diff --git a/core/apps/finance/serializers/expence.py b/core/apps/finance/serializers/expence.py index decf08b..0bb234b 100644 --- a/core/apps/finance/serializers/expence.py +++ b/core/apps/finance/serializers/expence.py @@ -16,6 +16,7 @@ class ExpenceCreateSerializer(serializers.ModelSerializer): def create(self, validated_data): with transaction.atomic(): expence = Expence.objects.create( + user=self.context.get('user'), cash_transaction=validated_data.get('cash_transaction'), payment_type=validated_data.get('payment_type'), project_folder=validated_data.get('project_folder'), @@ -81,14 +82,23 @@ class ExpenceListSerializer(serializers.ModelSerializer): project = serializers.SerializerMethodField(method_name='get_project') counterparty = serializers.SerializerMethodField(method_name='get_counterparty') expence_type = serializers.SerializerMethodField(method_name='get_expence_type') + user = serializers.SerializerMethodField(method_name='get_user') class Meta: model = Expence fields = [ 'id', 'cash_transaction', 'payment_type', 'project_folder', 'project', 'expence_type', 'counterparty', 'price', 'exchange_rate', 'currency', 'date', 'comment', 'audit', 'file' + 'user' ] + def get_user(self, obj): + return { + 'id': obj.user.id, + 'first_name': obj.user.first_name, + 'last_name': obj.user.last_name, + } if obj.user else None + def get_cash_transaction(self, obj): return { 'id': obj.cash_transaction.id, diff --git a/core/apps/finance/serializers/income.py b/core/apps/finance/serializers/income.py index 9f29d5b..3f18b67 100644 --- a/core/apps/finance/serializers/income.py +++ b/core/apps/finance/serializers/income.py @@ -12,13 +12,14 @@ class IncomeListSerializer(serializers.ModelSerializer): project = serializers.SerializerMethodField(method_name='get_project') counterparty = serializers.SerializerMethodField(method_name='get_counterparty') type_income = serializers.SerializerMethodField(method_name='get_type_income') + user = serializers.SerializerMethodField(method_name='get_user') class Meta: model = Income fields = [ 'id', 'cash_transaction', 'payment_type', 'project_folder', 'project', 'counterparty', 'type_income', 'currency', 'price', 'exchange_rate', 'date', - 'comment', 'file', 'audit' + 'comment', 'file', 'audit', 'user' ] def get_cash_transaction(self, obj): @@ -57,6 +58,13 @@ class IncomeListSerializer(serializers.ModelSerializer): 'name': obj.type_income.name } if obj.type_income else None + def get_user(self, obj): + return { + 'id': obj.user.id, + 'first_name': obj.user.first_name, + 'last_name': obj.user.last_name, + } if obj.user else None + class IncomeCreateSerializer(serializers.ModelSerializer): class Meta: @@ -70,6 +78,7 @@ class IncomeCreateSerializer(serializers.ModelSerializer): def create(self, validated_data): with transaction.atomic(): income = Income.objects.create( + user=self.context.get('user'), cash_transaction=validated_data['cash_transaction'], payment_type=validated_data['payment_type'], project_folder=validated_data.get('project_folder'), diff --git a/core/apps/finance/views/expence.py b/core/apps/finance/views/expence.py index c308005..df23dd7 100644 --- a/core/apps/finance/views/expence.py +++ b/core/apps/finance/views/expence.py @@ -16,7 +16,7 @@ class ExpenceCreateApiView(generics.GenericAPIView): parser_classes = [parsers.FormParser, parsers.MultiPartParser] def post(self, request): - serializer = self.serializer_class(data=request.data) + serializer = self.serializer_class(data=request.data, context={'user': request.user}) if serializer.is_valid(raise_exception=True): serializer.save() return Response( diff --git a/core/apps/finance/views/income.py b/core/apps/finance/views/income.py index 4f17916..c415f03 100644 --- a/core/apps/finance/views/income.py +++ b/core/apps/finance/views/income.py @@ -32,7 +32,7 @@ class IncomeCreateApiView(generics.GenericAPIView): parser_classes = [parsers.FormParser, parsers.MultiPartParser] def post(self, request): - ser = self.serializer_class(data=request.data) + ser = self.serializer_class(data=request.data, context={'user': request.user}) if ser.is_valid(raise_exception=True): ser.save() return Response( diff --git a/core/apps/orders/serializers/party.py b/core/apps/orders/serializers/party.py index eb46582..596cffe 100644 --- a/core/apps/orders/serializers/party.py +++ b/core/apps/orders/serializers/party.py @@ -12,6 +12,7 @@ from core.apps.products.models import Product, Unity from core.apps.projects.models import Project, ProjectFolder from core.apps.wherehouse.models import WhereHouse from core.apps.counterparty.models import Counterparty +from core.apps.finance.models import Expence class PartyCreateSerializer(serializers.Serializer): @@ -288,3 +289,76 @@ class PartyUpdateSerializer(serializers.ModelSerializer): ] ) return instance + + + +class PartyExpenceCreateSerializer(serializers.ModelSerializer): + class Meta: + model = Expence + fields = [ + 'cash_transaction', 'payment_type', 'project_folder', 'project', 'counterparty', + 'price', 'exchange_rate', 'currency', 'date', 'comment', 'party' + ] + + 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'), + 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'), + party=validated_data.get('party'), + ) + 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 + + if expence.counterparty: + if expence.counterparty.kredit_uzs != 0: + expence.counterparty.kredit_uzs -= expence.price + expence.counterparty.total_kredit -= expence.price + + expence.counterparty.debit_uzs += expence.counterparty.kredit_uzs - expence.price + expence.counterparty.total_debit += expence.price + else: + expence.counterparty.debit_uzs += expence.price + expence.counterparty.total_debit += expence.price + expence.counterparty.save() + if expence.party.currency == 'uzs': + expence.party.party_amount.payment_amount -= expence.price + expence.party.party_amount.paid_amount += expence.price + expence.party.save() + + elif validated_data.get('currency') == 'usd': + cash_transaction.expence_balance_usd += expence.price + cash_transaction.total_balance_usd = cash_transaction.income_balance_usd - cash_transaction.expence_balance_usd + if payment_type.total_usd > expence.price: + payment_type.total_usd -= expence.price + + if expence.counterparty: + if expence.counterparty.kredit_usd != 0: + expence.counterparty.kredit_usd -= validated_data.get('price') + expence.counterparty.total_kredit -= expence.price + + expence.counterparty.debit_usd += expence.counterparty.kredit_usd - validated_data.get('price') + expence.counterparty.total_debit += expence.price + else: + expence.counterparty.debit_usd += validated_data.get('price') + expence.counterparty.total_debit += expence.price + expence.counterparty.save() + + cash_transaction.save() + payment_type.save() + return expence + \ No newline at end of file