views.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. from django.http import Http404
  2. from rest_framework import viewsets, mixins
  3. from rest_framework import permissions
  4. from rest_framework.response import Response
  5. from .mixins import TransactionsMixin
  6. from django.db.models import (Sum, F, Case, FloatField,
  7. When)
  8. from .serializers import (CreateTransactionSerializer,
  9. BalanceByAccountSerializer)
  10. from .models import Transaction
  11. from django.contrib.auth import get_user_model
  12. User = get_user_model()
  13. class TransactionViewSet(mixins.CreateModelMixin,
  14. viewsets.GenericViewSet):
  15. """
  16. API endpoint to create transactions
  17. Can send one or more transactions by request.
  18. Query example:
  19. ```json
  20. [
  21. {
  22. "reference": "000053",
  23. "account": "C00099",
  24. "date": "2020-01-03",
  25. "amount": -51.13,
  26. "type": "outflow",
  27. "category": "groceries",
  28. "user_id": 1
  29. },
  30. {
  31. "reference": "000054",
  32. "account": "C00099",
  33. "date": "2020-01-10",
  34. "amount": 2500.60,
  35. "type": "inflow",
  36. "category": "groceries",
  37. "user_id": 1
  38. }
  39. ]
  40. ```
  41. """
  42. queryset = Transaction.objects.all()
  43. serializer_class = CreateTransactionSerializer
  44. permission_classes = []
  45. def create(self, request, *args, **kwargs):
  46. serializer = self.get_serializer(data=request.data, many=isinstance(request.data, list))
  47. serializer.is_valid(raise_exception=True)
  48. self.perform_create(serializer)
  49. return Response(serializer.data)
  50. class AccountBalanceViewSet(viewsets.ViewSet, TransactionsMixin):
  51. """
  52. ### Retrieve summary by accounts of user.
  53. Optionally restricts the returned account balance to a given user,
  54. by filtering against a `date_from` and `date_to` query parameter in the URL.
  55. Date Format: `YYYY-MM-DD`
  56. Query example:
  57. /api/transactions/balance/account/1/?date_from=2020-01-10
  58. """
  59. permission_classes = []
  60. lookup_field = 'user_id'
  61. def retrieve(self, request, format=None, user_id=None, *args, **kwargs):
  62. try:
  63. self.user = User.objects.get(pk=user_id)
  64. except User.DoesNotExist:
  65. raise Http404
  66. transactions = self.get_filtered_transactions()
  67. with_annotations = transactions.values('account').annotate(balance=Sum('amount'),
  68. total_inflow=Sum(Case(
  69. When(type='inflow', then=F('amount')),
  70. output_field=FloatField(),
  71. )), total_outflow=Sum(Case(
  72. When(type='outflow', then=F('amount')),
  73. output_field=FloatField(),
  74. )), )
  75. serializer = BalanceByAccountSerializer(with_annotations, many=True)
  76. return Response(serializer.data)
  77. class CashflowViewSet(viewsets.ViewSet, TransactionsMixin):
  78. """
  79. ### Retrieve summary by category
  80. Optionally restricts the returned cashflow to a given user,
  81. by filtering against a `date_from` and `date_to` query parameter in the URL.
  82. Date Format: `YYYY-MM-DD`
  83. Query example:
  84. /api/transactions/cashflow/1/?date_from=2020-01-10
  85. """
  86. permission_classes = []
  87. lookup_field = 'user_id'
  88. def retrieve(self, request, format=None, user_id=None, *args, **kwargs):
  89. try:
  90. self.user = User.objects.get(pk=user_id)
  91. except User.DoesNotExist:
  92. raise Http404
  93. transactions = self.get_filtered_transactions()
  94. inflows_qs = list(
  95. transactions.filter(type='inflow').values('category').annotate(amount=Sum('amount')).values('category',
  96. 'amount'))
  97. outflow_qs = list(
  98. transactions.filter(type='outflow').values('category').annotate(amount=Sum('amount')).values('category',
  99. 'amount'))
  100. inflow = {inf['category']: inf['amount'] for inf in inflows_qs}
  101. outflow = {outf['category']: outf['amount'] for outf in outflow_qs}
  102. return Response({'inflow': inflow, 'outflow': outflow})