from django.shortcuts import get_object_or_404 from django.db import transaction from rest_framework import generics, views, parsers, filters from rest_framework.response import Response from django_filters.rest_framework.backends import DjangoFilterBackend 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 from core.apps.counterparty.models import Counterparty class IncomeListApiView(generics.GenericAPIView): serializer_class = serializers.IncomeListSerializer queryset = Income.objects.select_related( 'cash_transaction', 'payment_type', 'project_folder', 'project', 'counterparty', 'type_income', 'user' ).exclude(is_deleted=True) permission_classes = [HasRolePermission] filter_backends = [DjangoFilterBackend, filters.SearchFilter] filterset_class = IncomeFilter search_fields = [ 'cash_transaction__name', 'payment_type__name', 'project_folder__name', 'project__name', 'counterparty__name', 'type_income__name', 'user__full_name' ] def get(self, request): cash_transaction_ids = request.query_params.getlist('cash_transaction') if cash_transaction_ids: self.queryset = self.queryset.filter(cash_transaction__in=cash_transaction_ids) page = self.paginate_queryset(self.filter_queryset(self.queryset)) if page is not None: serializer = self.serializer_class(page, many=True) return self.get_paginated_response(serializer.data) class IncomeCreateApiView(generics.GenericAPIView): serializer_class = serializers.IncomeCreateSerializer queryset = Income.objects.all() permission_classes = [HasRolePermission] parser_classes = [parsers.FormParser, parsers.MultiPartParser] def post(self, request): ser = self.serializer_class(data=request.data, context={'user': request.user}) if ser.is_valid(raise_exception=True): ser.save() return Response( { 'success': True, 'message': 'income created' }, status=201 ) return Response( { 'success': False, 'message': 'income create failed', 'error': ser.errors, }, status=400 ) class CounterpartyIncomeListApiView(generics.GenericAPIView): permission_classes = [HasRolePermission] queryset = Income.objects.select_related( 'cash_transaction', 'payment_type', 'project_folder', 'project', 'counterparty', 'type_income', 'user' ).exclude(counterparty__isnull=True).distinct() serializer_class = serializers.IncomeListSerializer def get(self, request, counterparty_id): counterparty = get_object_or_404(Counterparty, id=counterparty_id) page = self.paginate_queryset(self.queryset.filter(counterparty=counterparty)) if page is not None: 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, is_deleted=False) serializer = self.serializer_class(data=request.data) if serializer.is_valid(raise_exception=True): with transaction.atomic(): comment = serializer.validated_data.get('comment') currency = income.currency.lower() # Deleted record yaratish DeletedIncome.objects.create( income=income, comment=comment ) cash_transaction = income.cash_transaction payment_type = income.payment_type counterparty = income.counterparty if currency == 'uzs': # Balanslarni qaytarish (o'chirilgani teskari qilish) cash_transaction.income_balance_uzs -= income.price # ✅ INCOME BALANCE KAMAYISHI KERAK cash_transaction.total_balance_uzs = ( cash_transaction.income_balance_uzs - cash_transaction.expence_balance_uzs ) payment_type.total_uzs -= income.price # ✅ QAYTARISH # Kontrapartiya hisobini qaytarish if counterparty: if counterparty.kredit_uzs > 0: # Agar kredit bo'lsa, uni kamayitish (teskari) counterparty.kredit_uzs -= income.price counterparty.total_kredit -= income.price counterparty.debit_uzs += income.price counterparty.total_debit += income.price else: # Agar debit bo'lsa, uni oshirish (teskari) counterparty.debit_uzs += income.price counterparty.total_debit += income.price counterparty.save() elif currency == 'usd': # Balanslarni qaytarish (o'chirilgani teskari qilish) cash_transaction.income_balance_usd -= income.price # ✅ INCOME BALANCE KAMAYISHI KERAK cash_transaction.total_balance_usd = ( cash_transaction.income_balance_usd - cash_transaction.expence_balance_usd ) payment_type.total_usd -= income.price # ✅ QAYTARISH # Kontrapartiya hisobini qaytarish if counterparty: if counterparty.kredit_usd > 0: # Agar kredit bo'lsa, uni kamayitish (teskari) counterparty.kredit_usd -= income.price counterparty.total_kredit -= income.price counterparty.debit_usd += income.price counterparty.total_debit += income.price else: # Agar debit bo'lsa, uni oshirish (teskari) counterparty.debit_usd += income.price counterparty.total_debit += income.price counterparty.save() # is_deleted = True qilish (hard delete emas, soft delete) income.is_deleted = True # Barcha o'zgarishlari saqlash cash_transaction.save() payment_type.save() income.save() return Response( { 'success': True, 'message': 'Income o\'chirildi', 'data': { 'income_id': income.id, 'price': income.price, 'currency': income.currency } }, status=200 ) class IncomeUpdateApiView(generics.GenericAPIView): serializer_class = serializers.IncomeUpdateSerializer queryset = Income.objects.all() permission_classes = [HasRolePermission] def patch(self, request, id): income = get_object_or_404(Income, id=id) serializer = self.serializer_class(data=request.data, instance=income) if serializer.is_valid(raise_exception=True): serializer.save() return Response( { 'success': True, 'message': 'Income updated' }, status=200 ) return Response( { 'success': False, 'message': serializer.errors, }, status=400 )