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
)