From b5f69b6b98c4c584931690c7639c626ecc73ebcc Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Fri, 3 Feb 2023 00:02:20 +0000 Subject: [PATCH] Add summary table to admin transactions --- apiserver/apiserver/api/views.py | 25 +++++++++++++++ webclient/src/AdminTransactions.js | 49 ++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/apiserver/apiserver/api/views.py b/apiserver/apiserver/api/views.py index 1ff3b45..a91bb25 100644 --- a/apiserver/apiserver/api/views.py +++ b/apiserver/apiserver/api/views.py @@ -557,6 +557,31 @@ class TransactionViewSet(Base, List, Create, Retrieve, Update): transaction.save() return Response(200) + @action(detail=False, methods=['get']) + def summary(self, request): + txs = models.Transaction.objects + month = self.request.query_params.get('month', '') + + try: + dt = datetime.datetime.strptime(month, '%Y-%m') + except ValueError: + raise exceptions.ValidationError(dict(month='Should be YYYY-MM.')) + + txs = txs.filter(date__year=dt.year) + txs = txs.filter(date__month=dt.month) + txs = txs.exclude(category='Memberships:Fake Months') + + result = [] + + for category in ['Membership', 'Snacks', 'OnAcct', 'Donation', 'Consumables', 'Purchases']: + result.append(dict( + category = category, + dollar = txs.filter(category=category).aggregate(Sum('amount'))['amount__sum'] or 0, + protocoin = -1 * (txs.filter(category=category).aggregate(Sum('protocoin'))['protocoin__sum'] or 0), + )) + + return Response(result) + class UserView(views.APIView): permission_classes = [AllowMetadata | IsAuthenticated] diff --git a/webclient/src/AdminTransactions.js b/webclient/src/AdminTransactions.js index fd24870..afc979c 100644 --- a/webclient/src/AdminTransactions.js +++ b/webclient/src/AdminTransactions.js @@ -1,7 +1,7 @@ import React, { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import './light.css'; -import { Container, Checkbox, Form, Header, Segment } from 'semantic-ui-react'; +import { Container, Checkbox, Form, Header, Segment, Table } from 'semantic-ui-react'; import * as Datetime from 'react-datetime'; import 'react-datetime/css/react-datetime.css'; import moment from 'moment'; @@ -42,12 +42,14 @@ export function AdminReportedTransactions(props) { }; let transactionsCache = false; +let summaryCache = false; let excludePayPalCache = false; export function AdminHistoricalTransactions(props) { const { token } = props; const [input, setInput] = useState({ month: moment() }); const [transactions, setTransactions] = useState(transactionsCache); + const [summary, setSummary] = useState(summaryCache); const [excludePayPal, setExcludePayPal] = useState(excludePayPalCache); const [loading, setLoading] = useState(false); const [error, setError] = useState(false); @@ -75,6 +77,19 @@ export function AdminHistoricalTransactions(props) { console.log(err); setError(true); }); + + requester('/transactions/summary/?month=' + month, 'GET', token) + .then(res => { + setLoading(false); + setError(false); + setSummary(res); + summaryCache = res; + }) + .catch(err => { + setLoading(false); + console.log(err); + setError(true); + }); }; return ( @@ -96,10 +111,40 @@ export function AdminHistoricalTransactions(props) { + {transactions &&

Found {transactions.length} transactions.

} + + {!error ? + summary &&
+
Summary
+ + + + + Category + Dollar + Protocoin + + + + + {summary.map(x => + + {x.category} + {'$ ' + x.dollar.toFixed(2)} + {'₱ ' + x.protocoin.toFixed(2)} + + )} + +
+
+ : +

Error loading summary.

+ } + +

{!error ? transactions &&

-

Found {transactions.length} transactions.

{!!transactions.length &&
{moment(transactions[0].date, 'YYYY-MM-DD').format('MMMM YYYY')} Transactions
}