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.accounts.permissions.permissions import HasRolePermission 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 class ExpenceCreateApiView(generics.GenericAPIView): serializer_class = serializers.ExpenceCreateSerializer queryset = Expence.objects.select_related( 'cash_transaction', 'payment_type', 'project_folder', 'project', 'counterparty', 'expence_type', 'user' ) permission_classes = [HasRolePermission] parser_classes = [parsers.FormParser, parsers.MultiPartParser] def post(self, request): serializer = self.serializer_class(data=request.data, context={'user': request.user}) 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', ).exclude(is_deleted=True) permission_classes = [HasRolePermission] filter_backends = [DjangoFilterBackend, filters.SearchFilter] filterset_class = ExpenceFilter search_fields = [ 'cash_transaction__name', 'payment_type__name', 'project_folder__name', 'project__name', 'counterparty__name', 'expence_type__name', 'user__full_name' ] 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).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) return self.get_paginated_response(serializer.data) class CounterpartyExpenceListApiView(generics.GenericAPIView): permission_classes = [HasRolePermission] queryset = Expence.objects.select_related( 'cash_transaction', 'payment_type', 'project_folder', 'project', 'counterparty', 'expence_type', 'user' ).exclude(counterparty__isnull=True).distinct() serializer_class = serializers.ExpenceListSerializer 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 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 ) 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, 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 = expence.currency.lower() DeletedExpence.objects.create( expence=expence, comment=comment, user=request.user, ) cash_transaction = expence.cash_transaction payment_type = expence.payment_type counterparty = expence.counterparty if currency == 'uzs': cash_transaction.expence_balance_uzs -= expence.price cash_transaction.total_balance_uzs = ( cash_transaction.income_balance_uzs - cash_transaction.expence_balance_uzs ) payment_type.total_uzs += expence.price if counterparty and hasattr(counterparty, 'balance'): counterparty.balance.balance_uzs -= expence.price counterparty.balance.save() elif currency == 'usd': cash_transaction.expence_balance_usd -= expence.price cash_transaction.total_balance_usd = ( cash_transaction.income_balance_usd - cash_transaction.expence_balance_usd ) payment_type.total_usd += expence.price if counterparty and hasattr(counterparty, 'balance'): counterparty.balance.balance_usd -= expence.price counterparty.balance.save() expence.is_deleted = True cash_transaction.save() payment_type.save() expence.save() return Response( { 'success': True, 'message': "Expence o'chirildi", 'data': { 'expence_id': expence.id, 'price': expence.price, 'currency': expence.currency } }, status=200 ) class ExpenceUpdateApiView(generics.GenericAPIView): serializer_class = serializers.ExpenceUpdateSerializer queryset = Expence.objects.all() permission_classes = [HasRolePermission] def patch(self, request, id): expence = get_object_or_404(Expence, id=id) serializer = self.serializer_class(data=request.data, instance=expence) if serializer.is_valid(raise_exception=True): serializer.save() return Response( { 'success': True, 'message': 'Expence updated' }, status=200 ) return Response( { 'success': False, 'message': serializer.errors, }, status=400 )