Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion frontend/classes/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,43 @@ def refresh_token_auth(self, email: str, tokens: dict) -> dict:
except Exception as e:
raise Exception(f"There was an issue getting a refresh token")

def basiq_api_transaction_data(self) -> dict:
try:


url = self.base_url+"/basiq/transactions"

payload = {}
headers = {
"accepts": "application/json",
"Authorization": "eyJraWQiOiJlcXhraW1yN21mRkwySmpjMmx1ZCtuT0JlNk5DVU00aHNMaEtta1p6MjVRPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJlN2NlM2ZhYy0zOGNjLTRiNjAtOTc4MC1jMDBiMTZjYmI3OTYiLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAuYXAtc291dGhlYXN0LTIuYW1hem9uYXdzLmNvbVwvYXAtc291dGhlYXN0LTJfNzNlY0FOdWRNIiwiY29nbml0bzp1c2VybmFtZSI6ImU3Y2UzZmFjLTM4Y2MtNGI2MC05NzgwLWMwMGIxNmNiYjc5NiIsIm9yaWdpbl9qdGkiOiI2ODFmNjBmNy01YjIzLTQzYzItYjA0OC03OWFkNmQyYTgyNzUiLCJhdWQiOiI1N2kzOW9xcG1wdGIxZmxxZmoxdXUzaWJwYSIsImV2ZW50X2lkIjoiYTJlNTc0OTAtMDQzZS00ZGI4LTk0MzktNGI0ZGNlZGJlMWI1IiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE2ODQzNTkzNTYsIm5hbWUiOiJkYW5ubm5vcnIiLCJleHAiOjE2ODQzNjI5NTYsImlhdCI6MTY4NDM1OTM1NiwianRpIjoiNGEwM2JlNmItNTM5NC00MWRlLWFiMGEtMTQwOWNhMzk0MzZlIiwiZW1haWwiOiJkYW5AZW1haWwuY29tbSJ9.ZVlGgqM_Bxz1IdF65eN097rh0KBUeVxkw2zm806uwqpAeiGoxGXjJYVLx3kIwcSk50dhqNCu5_MZqt9lIfHNobFGs7Xjz-g2GVEPDttMELqllmCGier9m8QjhAmE3VJ3TwXbR1-oN1IxPkJe4slxKiFKN4OMqdZpAYETsfX0IJc2WQFrC4A00LYmgTLD4Uk0lxToGStsqK3UOp4ZZhmzRUfbKYgOcfNIGvpuUqWmHFjqtxgSG2g5s7Wa1QCloLmIadL3GEOqw8ulTS_BoPNYusy2VW63VSJX2VjO3DPYY41ViBBnaE7Ih7TuuTNiE4mVetBN8XZJ5bLdc4UuMvtFhw"
}

response = requests.request("GET", url, headers=headers, data=payload)

if response.status_code > 299:
raise Exception("HTTP {response.statuscode} Bad Status Code")
#print(response.json())
return json.loads(response.text)

except Exception as e:
raise Exception("Error getting dashboard data failed")

def get_accounts_for_user(self) -> dict:
basiq_id="11103cba-4a08-4397-84a5-22ac125ed2f6"
try:
url = self.base_url + "/basiq/balance"

payload = {}
headers = {
"accepts": "application/json",
"Authorization": "eyJraWQiOiJlcXhraW1yN21mRkwySmpjMmx1ZCtuT0JlNk5DVU00aHNMaEtta1p6MjVRPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJlN2NlM2ZhYy0zOGNjLTRiNjAtOTc4MC1jMDBiMTZjYmI3OTYiLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAuYXAtc291dGhlYXN0LTIuYW1hem9uYXdzLmNvbVwvYXAtc291dGhlYXN0LTJfNzNlY0FOdWRNIiwiY29nbml0bzp1c2VybmFtZSI6ImU3Y2UzZmFjLTM4Y2MtNGI2MC05NzgwLWMwMGIxNmNiYjc5NiIsIm9yaWdpbl9qdGkiOiI2ODFmNjBmNy01YjIzLTQzYzItYjA0OC03OWFkNmQyYTgyNzUiLCJhdWQiOiI1N2kzOW9xcG1wdGIxZmxxZmoxdXUzaWJwYSIsImV2ZW50X2lkIjoiYTJlNTc0OTAtMDQzZS00ZGI4LTk0MzktNGI0ZGNlZGJlMWI1IiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE2ODQzNTkzNTYsIm5hbWUiOiJkYW5ubm5vcnIiLCJleHAiOjE2ODQzNjI5NTYsImlhdCI6MTY4NDM1OTM1NiwianRpIjoiNGEwM2JlNmItNTM5NC00MWRlLWFiMGEtMTQwOWNhMzk0MzZlIiwiZW1haWwiOiJkYW5AZW1haWwuY29tbSJ9.ZVlGgqM_Bxz1IdF65eN097rh0KBUeVxkw2zm806uwqpAeiGoxGXjJYVLx3kIwcSk50dhqNCu5_MZqt9lIfHNobFGs7Xjz-g2GVEPDttMELqllmCGier9m8QjhAmE3VJ3TwXbR1-oN1IxPkJe4slxKiFKN4OMqdZpAYETsfX0IJc2WQFrC4A00LYmgTLD4Uk0lxToGStsqK3UOp4ZZhmzRUfbKYgOcfNIGvpuUqWmHFjqtxgSG2g5s7Wa1QCloLmIadL3GEOqw8ulTS_BoPNYusy2VW63VSJX2VjO3DPYY41ViBBnaE7Ih7TuuTNiE4mVetBN8XZJ5bLdc4UuMvtFhw"
}

response = requests.request("GET", url, headers=headers)
if response.status_code > 299:
raise Exception("HTTP {response.statuscode} Bad Status Code")
#print(response.json())
return json.loads(response.text)

except Exception as e:
raise Exception("Error getting account details failed")
2 changes: 1 addition & 1 deletion frontend/environment/.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ HOST=0.0.0.0
PORT=8080
DEBUG=True
DEV_TOOLS_PROPS_CHECK=False
BASE_API_URL="https://tz2pv43ci1.execute-api.ap-southeast-2.amazonaws.com/prod"
BASE_API_URL="https://9u48mrkt22.execute-api.ap-southeast-2.amazonaws.com/prod"
2 changes: 1 addition & 1 deletion frontend/environment/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ HOST=127.0.0.1
PORT=8080
DEBUG=True
DEV_TOOLS_PROPS_CHECK=True
BASE_API_URL="https://tz2pv43ci1.execute-api.ap-southeast-2.amazonaws.com/prod"
BASE_API_URL="https://pu0s16t327.execute-api.ap-southeast-2.amazonaws.com/prod"
12 changes: 4 additions & 8 deletions frontend/pages/breakdown/breakdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@
from app import app
from pages.breakdown import breakdown_callbacks


df = pd.read_csv('pages/breakdown/dummies.csv')
dfIncoming, dfOutgoing = breakdown_callbacks.get_incoming_outgoing_transactions()

layout = dbc.Container([
dbc.Row([
dbc.Col(html.H1("YOUR FINANCIAL DASHBOARD",
className='text-center text-primary mb-4',id="title"),
width=12)

width=12)
]),

dbc.Row([
Expand All @@ -25,7 +23,7 @@

dbc.Col([
dcc.Dropdown(id = 'yearly_spending_dd', multi = False, placeholder = 'Select a year',
options = [{'label':x, 'value':x} for x in sorted(df.iloc[:,3].unique())]),
options = [{'label':x, 'value':x} for x in sorted(dfOutgoing.iloc[:,0].unique())]),

dcc.Graph(id = 'yearly_spending_graph', figure={})
], width = {'size':6}),
Expand All @@ -35,15 +33,14 @@

]),


dbc.Row([

dbc.Col(html.H2("Yearly Saving",
className='text-left text-primary mb-4 '), width = 12),

dbc.Col([
dcc.Dropdown(id = 'yearly_saving_dd', multi = False, placeholder = 'Select a year',
options = [{'label':x, 'value':x} for x in sorted(df.iloc[:,3].unique())]),
options = [{'label':x, 'value':x} for x in sorted(dfIncoming.iloc[:,0].unique())]),

dcc.Graph(id = 'yearly_saving_graph', figure={})
], width = {'size':6}),
Expand All @@ -53,4 +50,3 @@

])
], fluid = False)

107 changes: 97 additions & 10 deletions frontend/pages/breakdown/breakdown_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,115 @@
from app import app
import pandas as pd
import plotly.express as px

df = pd.read_csv('pages/breakdown/dummies.csv')
import json

@app.callback(
Output('yearly_spending_graph', 'figure'),
Input('yearly_spending_dd', 'value')
)
def update_graph(year):
dff = df[df.iloc[:,3]==year]
figln = px.line(dff, x='Month', y='Spending')
dfIncoming, dfOutgoing = get_incoming_outgoing_transactions()
dff = dfOutgoing[dfOutgoing.iloc[:,0]==year]
figln = px.line(dff, x='month', y='amount')
return figln


@app.callback(
Output('yearly_saving_graph', 'figure'),
Input('yearly_saving_dd', 'value')
)
def update_graph(year):
dff = df[df.iloc[:,3]==year]
figln = px.line(dff, x='Month', y='Saving')
dfIncoming, dfOutgoing = get_incoming_outgoing_transactions()
dff = dfIncoming[dfIncoming.iloc[:,0]==year]
figln = px.line(dff, x='month', y='amount')
return figln

# def callback(n):
# api = API()
# return f"{n}"
def get_transaction_data():
api = API()
transaction_result = api.basiq_api_transaction_data()
data = transaction_result["data"]

accounts = get_accounts()

df = pd.json_normalize(data)
accounts_df = pd.json_normalize(accounts)

processedData = df.filter(["id", "status", "amount", "direction", "account", "class", "postDate", "subClass.title"], axis=1)
monthsForProcessing = ["Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sep", "Oct", "Nov", "Dec"]

#Renamed 'subClass.title' as 'category'. This is not the category I was looking to use but it could do the job
processedData.rename(columns = {'subClass.title':'category'}, inplace = True)

#Processing the date value that is returned. It will be split from a string in to 3 arrays listed below
year = []
month = []
day = []

#Account name included to give something human readable to the account id number
accountName = []
#Here I am transforming the data in the postDate and account columns.
for column in df[["postDate", "account"]]:
for val in df[column]:
if column == "postDate":

#postDate has the initial string value split, giving us a date formatted to yyy-mm-dd at the 0th index. This is then
#split at the '-' into separate years, months and dates and added in to the appropriate array above

initialSplit = val.split('T')
yearMonthDay = initialSplit[0].split("-")
year.append(yearMonthDay[0])
month.append(monthsForProcessing[int(yearMonthDay[1]) - 1])
day.append(yearMonthDay[2])
if column == "account":

#If the account id matches the account id in the 'Accounts' dataframe (created 2 cells above) then the account name
#is added to the accountName array, to be added in to the dataframe
for index, accountNumber in enumerate(accounts_df["id"]):
if val == accountNumber:
accountName.append(accounts_df["name"][index])
break

#All of the new values are added to the existing dataframe
processedData["year"] = year
processedData["month"] = month
processedData["day"] = day
# processedData["accountName"] = accountName
processedData = processedData.drop('postDate', axis=1)
processedData["category"].fillna("Unknown", inplace = True)

return processedData

def get_accounts():
api = API()
account_details = api.get_accounts_for_user()
data = account_details["data"]

return data

def get_incoming_outgoing_transactions():
processedData = get_transaction_data()

outgoingTransactions = processedData[processedData.amount.astype('float64') < 0]

#transforming values to absolute value to prevent the issue mentioned above
for index, row in outgoingTransactions.iterrows():
row["amount"] = abs(float(row["amount"]))

incomingTransactions = processedData[processedData.amount.astype('float64') > 0]

for index, row in incomingTransactions.iterrows():
row["amount"] = abs(float(row["amount"]))

monthlySpending = outgoingTransactions.groupby(['year', 'month']).sum().reset_index().filter(['year', 'month', 'amount'], axis=1)
monthlySaving = incomingTransactions.groupby(['year', 'month']).sum().reset_index().filter(['year', 'month', 'amount'], axis=1)

ordered_months = ["Jan", "Feb", "Mar", "Apr", "May", "June",
"July", "Aug", "Sep", "Oct", "Nov", "Dec"]

#Both incoming models are sorted by month
monthlySaving['to_sort']=monthlySaving['month'].apply(lambda x:ordered_months.index(x))
monthlySaving = monthlySaving.sort_values('to_sort')

monthlySpending['to_sort']=monthlySpending['month'].apply(lambda x:ordered_months.index(x))
monthlySpending = monthlySpending.sort_values('to_sort')

return monthlySaving, monthlySpending
37 changes: 0 additions & 37 deletions frontend/pages/breakdown/dummies.csv

This file was deleted.

23 changes: 17 additions & 6 deletions frontend/pages/dashboard/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,20 @@
from pages.dashboard import dashboard_callbacks
import pandas as pd
import dash_table
import json

df_outgoing_transactions = dashboard_callbacks.get_outgoing_transactions()
df_absolute_spending_transaction_values = dashboard_callbacks.list_outgoing_transactions()

df = pd.read_csv('pages/dashboard/dummies.csv')
accounts = dashboard_callbacks.get_accounts()

accounts_df = pd.json_normalize(accounts)

columns = [{"name": i, "id": i} for i in df_absolute_spending_transaction_values.columns]
columns[2]["name"] = "Amount"
columns[6]["name"] = "Category"
columns[7]["name"] = "Year"
columns[8]["name"] = "Month"

layout = dbc.Container([

Expand All @@ -16,24 +27,24 @@

html.H3("YEARLY SPENDING CATEGORIES",
className='text-center text-primary mb-4'),

dbc.Row([

dbc.Col(html.P('Chart shows categories of spending over the selected year.', className='text-right text-primary, mb-4'),
width = {'size': 3,'offset' : 0}),
dbc.Col([
dcc.Dropdown(id = 'piechart_dd', multi = False, placeholder = 'Select a year',
options = [{'label':x, 'value':x} for x in sorted(df.iloc[:,3].unique())]),
options = [{'label':x, 'value':x} for x in sorted(df_absolute_spending_transaction_values.iloc[:,7].unique())]),

dcc.Graph(id = 'piechart', figure={})
])
]
),

dbc.Row(
dash_table.DataTable(
data = df.to_dict('records'),
columns = [{"name": i, "id": i} for i in df.columns],
data = df_outgoing_transactions.to_dict('records'),
columns = columns,
hidden_columns = ["index", "transactionNumber", "id", "status", "direction", "account", "class", "day"],
style_cell = {'textAlign':'left'},
style_header={
'backgroundColor': '#4f8fe3',
Expand Down
Loading