nova-web/web/finances.py

130 lines
4.3 KiB
Python
Raw Normal View History

2023-09-22 01:00:00 +02:00
import os
import io
import time
import json
import flask
import requests
2023-10-09 00:29:33 +02:00
import pandas as pd
2023-09-22 01:00:00 +02:00
from dotenv import load_dotenv
load_dotenv()
2023-09-23 18:06:27 +02:00
# cache get_finances() for 5 minutes
2023-09-22 01:00:00 +02:00
def get_finances():
2023-10-12 00:07:30 +02:00
res = requests.get(
2023-09-22 01:00:00 +02:00
url=f'{os.environ["CORE_API_URL"]}/finances',
headers={
'Authorization': f'{os.environ["CORE_API_KEY"]}'
},
timeout=5
2023-10-12 00:07:30 +02:00
)
res.raise_for_status()
return res.json()
2023-09-22 01:00:00 +02:00
def register(app):
@app.route('/finances')
def finances_view():
2023-09-23 17:08:19 +02:00
try:
data = get_finances()
2023-10-12 00:07:30 +02:00
except Exception as exc:
print(exc)
2023-10-09 00:29:33 +02:00
return flask.Response('Error fetching finances from database. This might be cause the data is still being processed. Please allow up to a few minutes.', status=500)
donations = data['donations']
expenses = data['expenses']
2023-09-23 17:08:19 +02:00
2023-10-16 00:51:43 +02:00
try:
avg = round(sum([i['amount_usd'] for i in donations]) / len(donations), 2)
except ZeroDivisionError:
avg = 0
try:
most_donation = max(donations, key=lambda x: x['amount_usd'])['currency']
except ValueError:
most_donation = '?'
try:
most_expense = max(expenses, key=lambda x: x['amount_usd'])['currency']
except ValueError:
most_expense = '?'
try:
donations_max = round(max([i['amount_usd'] for i in donations]))
except ValueError:
donations_max = 0
2023-09-22 01:00:00 +02:00
finances = {
2023-09-23 18:06:27 +02:00
'last_update': data['timestamp'],
2023-10-09 00:29:33 +02:00
'donations_total': round(sum([i['amount_usd'] for i in donations])),
'donations_num': len(donations),
2023-10-16 00:51:43 +02:00
'donations_avg': avg,
'donations_max': donations_max,
'most_used_donation_currency': most_donation,
2023-10-09 00:29:33 +02:00
'expenses_total': round(sum([i['amount_usd'] for i in expenses])),
'expenses_wages': round(sum([i['amount_usd'] for i in expenses if i['type'] == 'wage'])),
2023-10-16 00:51:43 +02:00
'most_used_expense_currency': most_expense,
2023-09-22 01:00:00 +02:00
}
2023-10-09 00:29:33 +02:00
transaction_table = []
transactions = [{'change': '+', **donation} for donation in donations] + [{'change': '-', **expense} for expense in expenses]
transactions = sorted(transactions, key=lambda x: x['timestamp'], reverse=True)
for transaction in transactions:
description = ''
if transaction['change'] == '+':
description = f'Discord/{transaction["user"]}'
if transaction['change'] == '-':
description = f'{transaction["reason"]} -> {transaction["to"]}'
if transaction['currency'] in ['USD', 'EUR', 'GBP', 'CAD', 'AUD', 'NZD', 'CHF', 'JPY', 'CNY', 'HKD', 'SGD']:
transaction['proof'] = ''
if transaction['change'] == '-':
transaction['amount_usd'] = -transaction['amount_usd']
amount = f'{round(transaction["amount_usd"])}'
transaction_table.append({
'Amount (USD)': amount,
'Currency': transaction['currency'],
'Type': transaction.get('type', 'donation'),
'Description': description,
'Timestamp': time.strftime('%Y-%m-%d %H:%M', time.localtime(transaction['timestamp'])),
'Proof': transaction['proof'],
})
# convert transaction_table to html
transaction_table = pd.DataFrame(transaction_table).to_html(
index=False,
classes=['table', 'table-striped', 'table-hover'],
table_id='transactionTable'
)
return flask.render_template('finances.html', finances=finances, transaction_table=transaction_table)
2023-09-22 01:00:00 +02:00
@app.route('/finances/json')
def finances_download():
2023-09-23 18:06:27 +02:00
try:
data = get_finances()
except Exception:
2023-10-09 00:29:33 +02:00
return flask.Response('Error fetching finances from database. This might be cause the data is still being processed. Please allow up to a few minutes.', status=500)
2023-09-23 18:06:27 +02:00
2023-09-22 01:00:00 +02:00
virtual_file = io.StringIO()
2023-09-23 18:06:27 +02:00
json.dump(data, virtual_file, indent=4)
2023-09-22 01:00:00 +02:00
name = f'finances-{time.strftime("%Y-%m-%d")}.json'
virtual_file.seek(0)
return flask.send_file(
io.BytesIO(virtual_file.read().encode('utf-8')),
mimetype='application/json',
as_attachment=True,
download_name=name
)