from django.http import Http404 from rest_framework import viewsets, mixins from rest_framework import permissions from rest_framework.response import Response from .mixins import TransactionsMixin from django.db.models import (Sum, F, Case, FloatField, When) from .serializers import (CreateTransactionSerializer, BalanceByAccountSerializer) from .models import Transaction from django.contrib.auth import get_user_model User = get_user_model() class TransactionViewSet(mixins.CreateModelMixin, viewsets.GenericViewSet): """ API endpoint to create transactions Can send one or more transactions by request. Query example: ```json [ { "reference": "000053", "account": "C00099", "date": "2020-01-03", "amount": -51.13, "type": "outflow", "category": "groceries", "user_id": 1 }, { "reference": "000054", "account": "C00099", "date": "2020-01-10", "amount": 2500.60, "type": "inflow", "category": "groceries", "user_id": 1 } ] ``` """ queryset = Transaction.objects.all() serializer_class = CreateTransactionSerializer permission_classes = [] def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data, many=isinstance(request.data, list)) serializer.is_valid(raise_exception=True) self.perform_create(serializer) return Response(serializer.data) class AccountBalanceViewSet(viewsets.ViewSet, TransactionsMixin): """ ### Retrieve summary by accounts of user. Optionally restricts the returned account balance to a given user, by filtering against a `date_from` and `date_to` query parameter in the URL. Date Format: `YYYY-MM-DD` Query example: /api/transactions/balance/account/1/?date_from=2020-01-10 """ permission_classes = [] lookup_field = 'user_id' def retrieve(self, request, format=None, user_id=None, *args, **kwargs): try: self.user = User.objects.get(pk=user_id) except User.DoesNotExist: raise Http404 transactions = self.get_filtered_transactions() with_annotations = transactions.values('account').annotate(balance=Sum('amount'), total_inflow=Sum(Case( When(type='inflow', then=F('amount')), output_field=FloatField(), )), total_outflow=Sum(Case( When(type='outflow', then=F('amount')), output_field=FloatField(), )), ) serializer = BalanceByAccountSerializer(with_annotations, many=True) return Response(serializer.data) class CashflowViewSet(viewsets.ViewSet, TransactionsMixin): """ ### Retrieve summary by category Optionally restricts the returned cashflow to a given user, by filtering against a `date_from` and `date_to` query parameter in the URL. Date Format: `YYYY-MM-DD` Query example: /api/transactions/cashflow/1/?date_from=2020-01-10 """ permission_classes = [] lookup_field = 'user_id' def retrieve(self, request, format=None, user_id=None, *args, **kwargs): try: self.user = User.objects.get(pk=user_id) except User.DoesNotExist: raise Http404 transactions = self.get_filtered_transactions() inflows_qs = list( transactions.filter(type='inflow').values('category').annotate(amount=Sum('amount')).values('category', 'amount')) outflow_qs = list( transactions.filter(type='outflow').values('category').annotate(amount=Sum('amount')).values('category', 'amount')) inflow = {inf['category']: inf['amount'] for inf in inflows_qs} outflow = {outf['category']: outf['amount'] for outf in outflow_qs} return Response({'inflow': inflow, 'outflow': outflow})