continue developing account page, start transaction pages
This commit is contained in:
6
.gitignore
vendored
6
.gitignore
vendored
@@ -1,4 +1,8 @@
|
||||
flask_session
|
||||
flask_session/
|
||||
application/__pycache__/
|
||||
application/session_data.json
|
||||
bank.db
|
||||
test_database.db
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
|
||||
7
api.yml
7
api.yml
@@ -301,6 +301,13 @@ paths:
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: otp_code
|
||||
in: query
|
||||
description: OTP to verify
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
- name: description
|
||||
in: query
|
||||
description: Account description
|
||||
|
||||
Binary file not shown.
@@ -1,9 +1,17 @@
|
||||
# Lucas Mathews - Fontys Student ID: 5023572
|
||||
# Banking System Account Page
|
||||
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
import customtkinter
|
||||
from config import CONFIG
|
||||
from connection import get_transactions, format_balance, get_account
|
||||
import sys
|
||||
import os
|
||||
import customtkinter
|
||||
from tkinter import ttk, messagebox
|
||||
from config import CONFIG
|
||||
from connection import get_transactions, format_balance, get_account, generate_otp, update_account
|
||||
|
||||
description_entry = None
|
||||
notes_entry = None
|
||||
otp_entry = None
|
||||
|
||||
#################
|
||||
### Functions ###
|
||||
@@ -45,10 +53,10 @@ def display_account_info(account_id):
|
||||
messagebox.showerror("Error", "Could not fetch account details.")
|
||||
return
|
||||
account = account_info['data']
|
||||
print(account)
|
||||
if 'description' not in account:
|
||||
messagebox.showerror("Error", "Account description not found.")
|
||||
return
|
||||
global account_description
|
||||
account_description = account['description']
|
||||
fields = {'Account ID': account_id, 'Description': account_description, 'Balance': format_balance(account['balance']), 'Account Type': account['account_type']}
|
||||
for i, (key, value) in enumerate(fields.items()):
|
||||
@@ -57,6 +65,90 @@ def display_account_info(account_id):
|
||||
label_key.grid(row=0, column=i*2, sticky='w', padx=10)
|
||||
label_value.grid(row=0, column=i*2+1, sticky='w', padx=10)
|
||||
|
||||
def on_transaction_double_click(event):
|
||||
"""Handles double-click event on a transaction in the table."""
|
||||
try:
|
||||
selected_transaction = transactions_table.item(transactions_table.selection())
|
||||
transaction_id = selected_transaction['values'][0]
|
||||
command = f"python application\\transaction.py {transaction_id} \"{selected_transaction['values'][4]}\""
|
||||
return_code = os.system(command)
|
||||
if return_code != 0:
|
||||
print(f"Error: The command failed with return code {return_code}")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
def add_transaction():
|
||||
"""Open the add transaction dialog."""
|
||||
command = f"python application\\new_transaction.py {account_id}"
|
||||
return_code = os.system(command)
|
||||
if return_code != 0:
|
||||
print(f"Error: The command failed with return code {return_code}")
|
||||
|
||||
def edit_account_details():
|
||||
"""Opens a new window for editing the account details."""
|
||||
global edit_window, otp_entry, description_entry, notes_entry
|
||||
edit_window = customtkinter.CTkToplevel(root)
|
||||
edit_window.title("Edit Account Details")
|
||||
edit_window.iconbitmap("application/luxbank.ico")
|
||||
edit_window.geometry("300x350")
|
||||
edit_window.attributes('-topmost', True)
|
||||
|
||||
description_label = customtkinter.CTkLabel(edit_window, text="Description: ")
|
||||
description_entry = customtkinter.CTkEntry(edit_window)
|
||||
description_label.pack()
|
||||
description_entry.pack()
|
||||
|
||||
notes_label = customtkinter.CTkLabel(edit_window, text="Notes: ")
|
||||
notes_entry = customtkinter.CTkEntry(edit_window)
|
||||
notes_label.pack()
|
||||
notes_entry.pack()
|
||||
|
||||
customtkinter.CTkLabel(edit_window, text=" ").pack() # Add space under the address box
|
||||
|
||||
otp_button = customtkinter.CTkButton(edit_window, text="Get OTP Code", command=generate_otp)
|
||||
otp_button.pack()
|
||||
|
||||
otp_label = customtkinter.CTkLabel(edit_window, text="OTP Code: ")
|
||||
otp_entry = customtkinter.CTkEntry(edit_window)
|
||||
otp_label.pack()
|
||||
otp_entry.pack()
|
||||
|
||||
save_button = customtkinter.CTkButton(edit_window, text="Verify OTP and Save", command=save_details)
|
||||
save_button.pack()
|
||||
edit_window.lift()
|
||||
|
||||
def save_details():
|
||||
"""Saves the edited account details."""
|
||||
global edit_window, otp_entry, description_entry, notes_entry, account_description
|
||||
description = description_entry.get() if description_entry.get() != '' else None
|
||||
notes = notes_entry.get() if notes_entry.get() != '' else None
|
||||
otp_code = otp_entry.get() if otp_entry.get() != '' else None
|
||||
|
||||
if not otp_code:
|
||||
messagebox.showerror("Error", "OTP code must be entered.")
|
||||
return
|
||||
|
||||
if not messagebox.askyesno("Confirmation", "Are you sure you want to save the changes?"):
|
||||
return
|
||||
|
||||
try:
|
||||
result = update_account(account_id, otp_code, description, notes)
|
||||
if 'success' in result and result['success']:
|
||||
display_account_info(account_id)
|
||||
messagebox.showinfo("Success", "Account details have been updated.")
|
||||
root.title(f"Transactions for: {account_description}") # Update the window title
|
||||
welcome_label.configure(text=f"Transactions for: {account_description}")
|
||||
edit_window.destroy()
|
||||
else:
|
||||
if result['message'] == "Invalid OTP.":
|
||||
messagebox.showerror("Error", "Invalid OTP code. Please try again.")
|
||||
else:
|
||||
messagebox.showerror("Error", f"Could not update account details: {result['message']}")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Error", f"Could not update account details: {str(e)}")
|
||||
|
||||
|
||||
|
||||
##############
|
||||
### Layout ###
|
||||
##############
|
||||
@@ -89,7 +181,7 @@ button_frame = customtkinter.CTkFrame(root)
|
||||
button_frame.pack(fill=tk.X, pady=10)
|
||||
add_transaction_button = customtkinter.CTkButton(button_frame, text="Add Transaction", command=add_transaction)
|
||||
add_transaction_button.grid(row=0, column=0, padx=10)
|
||||
request_otp_button = customtkinter.CTkButton(button_frame, text="Request OTP", command=request_otp)
|
||||
request_otp_button = customtkinter.CTkButton(button_frame, text="Request OTP", command=generate_otp)
|
||||
request_otp_button.grid(row=0, column=1, padx=10)
|
||||
edit_account_details_button = customtkinter.CTkButton(button_frame, text="Edit Account Details", command=edit_account_details)
|
||||
edit_account_details_button.grid(row=0, column=2, padx=10)
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# Lucas Mathews - Fontys Student ID: 5023572
|
||||
# Banking System Connection Page
|
||||
|
||||
import requests
|
||||
from requests.models import Response
|
||||
from config import CONFIG
|
||||
@@ -124,12 +127,12 @@ def get_account(account_id):
|
||||
print(f"RequestException: {e}")
|
||||
return {'success': False, 'message': "Could not connect to the server. Please try again later."}
|
||||
|
||||
def update_account(account_id, description=None, notes=None):
|
||||
def update_account(account_id, otp_code:int, description=None, notes=None):
|
||||
"""Updates the account details for the given account_id."""
|
||||
try:
|
||||
with open('application\\session_data.json', 'r') as f:
|
||||
session_data = json.load(f)
|
||||
params = {'account_id': account_id}
|
||||
params = {'account_id': account_id, 'otp_code': otp_code}
|
||||
if description is not None:
|
||||
params['description'] = description
|
||||
if notes is not None:
|
||||
@@ -137,6 +140,11 @@ def update_account(account_id, description=None, notes=None):
|
||||
response = requests.put(CONFIG["server"]["url"] + "/Account", cookies=session_data['session_cookie'], params=params)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except requests.exceptions.HTTPError as e:
|
||||
if response.status_code == 400:
|
||||
return {'success': False, 'message': "Invalid OTP."}
|
||||
print(f"HTTPError: {e}")
|
||||
return {'success': False, 'message': "Could not connect to the server. Please try again later."}
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f"RequestException: {e}")
|
||||
return {'success': False, 'message': "Could not connect to the server. Please try again later."}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# Lucas Mathews - Fontys Student ID: 5023572
|
||||
# Banking System Dashboard Page
|
||||
|
||||
from tkinter import messagebox, ttk
|
||||
import customtkinter
|
||||
import json
|
||||
@@ -13,6 +16,9 @@ address_entry = None
|
||||
otp_entry = None
|
||||
frame = None
|
||||
|
||||
fields = [('Name', 'name'), ('Client ID', 'client_id'), ('Email', 'email'), ('Phone', 'phone_number'),
|
||||
('Address', 'address'), ('Account Opened', 'opening_timestamp')]
|
||||
|
||||
#################
|
||||
### Functions ###
|
||||
#################
|
||||
@@ -42,6 +48,7 @@ def exit_application():
|
||||
else:
|
||||
messagebox.showerror("Logout failed", json_response['message'])
|
||||
|
||||
|
||||
def display_client_info():
|
||||
"""Displays the client's information on the dashboard."""
|
||||
global frame
|
||||
@@ -50,7 +57,7 @@ def display_client_info():
|
||||
widget.destroy()
|
||||
else:
|
||||
frame = customtkinter.CTkFrame(root)
|
||||
frame.pack(anchor='w', side='left', padx=20, pady=20)
|
||||
frame.grid(row=1, column=0, padx=20, pady=20)
|
||||
|
||||
try:
|
||||
with open('application\\session_data.json', 'r') as f:
|
||||
@@ -59,12 +66,10 @@ def display_client_info():
|
||||
client_info = get_client(client_id)
|
||||
if client_info.get('success'):
|
||||
client = client_info['data']
|
||||
fields = [('Name', 'name'), ('Client ID', 'client_id'), ('Email', 'email'), ('Phone', 'phone_number'),
|
||||
('Address', 'address'), ('Account Opened', 'opening_timestamp')]
|
||||
for i, (display_name, key) in enumerate(fields):
|
||||
value = client.get(key, 'N/A')
|
||||
label_key = customtkinter.CTkLabel(frame, text=f"{display_name}: ", font=("Helvetica", 14))
|
||||
label_value = customtkinter.CTkLabel(frame, text=value, font=("Helvetica", 14))
|
||||
label_value = customtkinter.CTkLabel(frame, text=value, font=("Helvetica", 14), anchor='w')
|
||||
label_key.grid(row=i, column=0, sticky='e')
|
||||
label_value.grid(row=i, column=1, sticky='w')
|
||||
else:
|
||||
@@ -73,16 +78,13 @@ def display_client_info():
|
||||
except Exception as e:
|
||||
messagebox.showerror("Error", f"Could not retrieve client information: {e}")
|
||||
|
||||
edit_button = customtkinter.CTkButton(frame, text="Edit Details", command=edit_details)
|
||||
edit_button.grid(row=len(fields), column=0, columnspan=2)
|
||||
|
||||
def edit_details():
|
||||
"""Opens a new window for editing client details."""
|
||||
global edit_window, email_entry, phone_entry, address_entry, otp_entry
|
||||
edit_window = customtkinter.CTkToplevel(root)
|
||||
edit_window.title("Edit Details")
|
||||
edit_window.geometry("300x350")
|
||||
edit_window.iconbitmap("application/luxbank.ico")
|
||||
edit_window.geometry("300x350")
|
||||
edit_window.attributes('-topmost', True)
|
||||
|
||||
email_label = customtkinter.CTkLabel(edit_window, text="Email: ")
|
||||
@@ -143,14 +145,15 @@ def save_details():
|
||||
if result['message'] == "Invalid OTP.":
|
||||
messagebox.showerror("Error", "MFA details not correct. Please try again.")
|
||||
else:
|
||||
messagebox.showerror("Update Failed", result.get('message', 'Unknown error'))
|
||||
messagebox.showerror("Error", f"Could not update client details: {result['message']}")
|
||||
except Exception as e:
|
||||
messagebox.showerror("Error", f"An error occurred: {e}")
|
||||
|
||||
messagebox.showerror("Error", f"Could not update client details: {str(e)}")
|
||||
|
||||
def populate_table():
|
||||
"""Populates the accounts table with client accounts."""
|
||||
try:
|
||||
for row in table.get_children(): # Clear the table before populating it
|
||||
table.delete(row)
|
||||
try:
|
||||
with open('application\\session_data.json', 'r') as f:
|
||||
session_data = json.load(f)
|
||||
client_id = session_data['client_id']
|
||||
@@ -178,6 +181,12 @@ def on_account_double_click(event):
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
def reload_info_and_accounts():
|
||||
"""Reloads the client information and the accounts table."""
|
||||
display_client_info()
|
||||
populate_table()
|
||||
|
||||
|
||||
##############
|
||||
### Layout ###
|
||||
##############
|
||||
@@ -192,29 +201,41 @@ customtkinter.set_appearance_mode(CONFIG["preferences"].get("dark_theme", "light
|
||||
|
||||
# Create a label for the title
|
||||
welcome_label = customtkinter.CTkLabel(root, text="Welcome to the Luxbank Dashboard!", font=("Helvetica", 24))
|
||||
welcome_label.pack(pady=20)
|
||||
|
||||
display_client_info()
|
||||
welcome_label.grid(row=0, column=0, columnspan=2, pady=20)
|
||||
|
||||
# Create a frame for buttons
|
||||
button_frame = customtkinter.CTkFrame(root)
|
||||
button_frame.pack(pady=15, side='top')
|
||||
button_frame.grid(row=1, column=0, columnspan=2, sticky='ew', pady=15)
|
||||
|
||||
# Create the OTP button
|
||||
otp_button = customtkinter.CTkButton(button_frame, text="Get OTP Code", command=generate_otp)
|
||||
otp_button.pack(side='left', padx=5)
|
||||
otp_button.grid(row=0, column=0, padx=5)
|
||||
|
||||
# Create the reload button
|
||||
reload_button = customtkinter.CTkButton(button_frame, text="Reload", command=reload_info_and_accounts)
|
||||
reload_button.grid(row=0, column=1, padx=5)
|
||||
|
||||
# Create the logout button
|
||||
logout_button = customtkinter.CTkButton(button_frame, text="Logout", command=logout)
|
||||
logout_button.pack(side='left', padx=5)
|
||||
logout_button.grid(row=0, column=2, padx=5)
|
||||
|
||||
# Create the exit button
|
||||
exit_button = customtkinter.CTkButton(button_frame, text="Exit", command=exit_application)
|
||||
exit_button.pack(side='left', padx=5)
|
||||
exit_button.grid(row=0, column=3, padx=5)
|
||||
|
||||
# Display client info after creating the buttons
|
||||
frame = customtkinter.CTkFrame(root)
|
||||
frame.grid(row=2, column=0, padx=20, pady=20, sticky='n') # Adjusted grid placement
|
||||
display_client_info()
|
||||
|
||||
# Create a frame for the table
|
||||
table_frame = ttk.Frame(root)
|
||||
table_frame.pack(side='right', fill='both', expand=True)
|
||||
table_frame.grid(row=2, column=1, sticky='nsew') # Adjusted grid placement
|
||||
|
||||
# Configure the grid
|
||||
root.grid_rowconfigure(2, weight=1) # Adjusted row index
|
||||
root.grid_columnconfigure(1, weight=1)
|
||||
|
||||
|
||||
# Create the table
|
||||
table = ttk.Treeview(table_frame, columns=('Name', 'Account ID', 'Balance', 'Account Type'), show='headings')
|
||||
|
||||
36
application/new_transaction.py
Normal file
36
application/new_transaction.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# Lucas Mathews - Fontys Student ID: 5023572
|
||||
# Banking System New Transaction Page
|
||||
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
import customtkinter
|
||||
from config import CONFIG
|
||||
from connection import
|
||||
import sys
|
||||
|
||||
#################
|
||||
### Functions ###
|
||||
#################
|
||||
|
||||
def get_transactoin
|
||||
|
||||
|
||||
|
||||
##############
|
||||
### Layout ###
|
||||
##############
|
||||
|
||||
# Initialise the main window
|
||||
root = customtkinter.CTk()
|
||||
root.title(f"Transactions: {transaction_description}")
|
||||
root.iconbitmap("application/luxbank.ico")
|
||||
root.geometry("800x400")
|
||||
|
||||
if CONFIG["preferences"]["dark_theme"] == "dark": # Check if dark mode is enabled
|
||||
customtkinter.set_appearance_mode("dark") # Set the style for dark mode
|
||||
else:
|
||||
customtkinter.set_appearance_mode("light") # Set the style for light mode
|
||||
|
||||
# Display main window title
|
||||
welcome_label = customtkinter.CTkLabel(root, text=f"Transactions for: {account_description}", font=("Helvetica", 24))
|
||||
welcome_label.pack(pady=10)
|
||||
@@ -1 +1 @@
|
||||
{"session_cookie": {"session": "CjjpiVUxx009emp27lUSxMpJ4Dt1sUi3fV-_VILXFrw"}, "client_id": "d18e5ae0"}
|
||||
{"session_cookie": {"session": "nwHUYOr9vg2nOaZmrYNmWgjMgJ47QLIz71_dX_kFH_o"}, "client_id": "d18e5ae0"}
|
||||
36
application/transaction.py
Normal file
36
application/transaction.py
Normal file
@@ -0,0 +1,36 @@
|
||||
# Lucas Mathews - Fontys Student ID: 5023572
|
||||
# Banking System Transaction Page
|
||||
|
||||
import tkinter as tk
|
||||
from tkinter import ttk, messagebox
|
||||
import customtkinter
|
||||
from config import CONFIG
|
||||
from connection import get_transaction, format_balance
|
||||
import sys
|
||||
|
||||
#################
|
||||
### Functions ###
|
||||
#################
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
##############
|
||||
### Layout ###
|
||||
##############
|
||||
|
||||
# Initialise the main window
|
||||
root = customtkinter.CTk()
|
||||
root.title(f"Transactions: {transaction_description}")
|
||||
root.iconbitmap("application/luxbank.ico")
|
||||
root.geometry("800x400")
|
||||
|
||||
if CONFIG["preferences"]["dark_theme"] == "dark": # Check if dark mode is enabled
|
||||
customtkinter.set_appearance_mode("dark") # Set the style for dark mode
|
||||
else:
|
||||
customtkinter.set_appearance_mode("light") # Set the style for light mode
|
||||
|
||||
# Display main window title
|
||||
welcome_label = customtkinter.CTkLabel(root, text=f"Transactions: {transaction_description}", font=("Helvetica", 24))
|
||||
welcome_label.pack(pady=10)
|
||||
@@ -173,7 +173,7 @@ def get_client(client_id:str):
|
||||
return format_response(False, "Client not found."), 404
|
||||
|
||||
@login_required
|
||||
def update_client(client_id: str, otp_code: int, **kwargs):
|
||||
def update_client(client_id:str, otp_code:int, **kwargs):
|
||||
"""Updates a client in the database. If the client is not found, returns an error message."""
|
||||
current_client_id, is_admin = get_current_client()
|
||||
if not verify_otp(current_client_id, otp_code):
|
||||
@@ -260,9 +260,11 @@ def add_account(client_id:str, description:str, account_type:str, **kwargs):
|
||||
return format_response(True, f"New account has been added: account_id: {account_id}"), 200
|
||||
|
||||
@login_required
|
||||
def update_account(account_id:str, **kwargs):
|
||||
def update_account(account_id:str, otp_code:str, **kwargs):
|
||||
"""Updates an account in the database. If the account is not found, returns an error message."""
|
||||
current_client_id, is_admin = get_current_client()
|
||||
if not verify_otp(current_client_id, otp_code):
|
||||
return format_response(False, "Invalid OTP."), 400
|
||||
account_owner = session.query(Account).filter_by(account_id=account_id).one_or_none().client_id
|
||||
if not is_admin and account_owner != current_client_id:
|
||||
return format_response(False, "You can only view your own client information."), 403
|
||||
|
||||
BIN
test_database.db
BIN
test_database.db
Binary file not shown.
Reference in New Issue
Block a user