Started implementation of new_transacion page and other minor changes

This commit is contained in:
Lucas Mathews
2024-05-31 18:27:18 +02:00
parent b6d798251f
commit fd2622ac2c
7 changed files with 151 additions and 29 deletions

View File

@@ -4,6 +4,7 @@
import tkinter as tk import tkinter as tk
import sys import sys
import os import os
import json
import customtkinter import customtkinter
from tkinter import ttk, messagebox from tkinter import ttk, messagebox
from config import CONFIG from config import CONFIG
@@ -152,7 +153,16 @@ def save_details():
except Exception as e: except Exception as e:
messagebox.showerror("Error", f"Could not update account details: {str(e)}") messagebox.showerror("Error", f"Could not update account details: {str(e)}")
def open_transaction_window():
"""Opens a new window for creating a new transaction."""
try:
session = json.load(open('application\\session_data.json', 'r'))
command = f"python application\\new_transaction.py {session['client_id']}"
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}")
############## ##############
### Layout ### ### Layout ###

View File

@@ -117,6 +117,7 @@ def get_transactions(account_id):
def get_account(account_id): def get_account(account_id):
"""Retrieves the account details for the given account_id.""" """Retrieves the account details for the given account_id."""
print(f"Getting account details for account_id: {account_id}")
try: try:
with open('application\\session_data.json', 'r') as f: with open('application\\session_data.json', 'r') as f:
session_data = json.load(f) session_data = json.load(f)

View File

@@ -8,17 +8,12 @@ import os
from config import CONFIG from config import CONFIG
from connection import logout_client, get_client, update_client, get_accounts, format_balance, generate_otp, change_password, new_transaction from connection import logout_client, get_client, update_client, get_accounts, format_balance, generate_otp, change_password, new_transaction
# Global variables
email_entry = None email_entry = None
phone_entry = None phone_entry = None
address_entry = None address_entry = None
otp_entry = None otp_entry = None
frame = None frame = None
fields = [('Name', 'name'), ('Client ID', 'client_id'), ('Email', 'email'), ('Phone', 'phone_number'),
('Address', 'address'), ('Account Opened', 'opening_timestamp')]
################# #################
### Functions ### ### Functions ###
################# #################
@@ -58,7 +53,6 @@ def display_client_info():
else: else:
frame = customtkinter.CTkFrame(root) frame = customtkinter.CTkFrame(root)
frame.grid(row=1, column=0, padx=20, pady=20) frame.grid(row=1, column=0, padx=20, pady=20)
try: try:
with open('application\\session_data.json', 'r') as f: with open('application\\session_data.json', 'r') as f:
session_data = json.load(f) session_data = json.load(f)
@@ -66,6 +60,8 @@ def display_client_info():
client_info = get_client(client_id) client_info = get_client(client_id)
if client_info.get('success'): if client_info.get('success'):
client = client_info['data'] 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): for i, (display_name, key) in enumerate(fields):
value = client.get(key, 'N/A') value = client.get(key, 'N/A')
label_key = customtkinter.CTkLabel(frame, text=f"{display_name}: ", font=("Helvetica", 14)) label_key = customtkinter.CTkLabel(frame, text=f"{display_name}: ", font=("Helvetica", 14))
@@ -123,18 +119,14 @@ def save_details():
new_phone = phone_entry.get() if phone_entry.get() != '' else None new_phone = phone_entry.get() if phone_entry.get() != '' else None
new_address = address_entry.get() if address_entry.get() != '' else None new_address = address_entry.get() if address_entry.get() != '' else None
otp_code = otp_entry.get() otp_code = otp_entry.get()
if not otp_code: if not otp_code:
messagebox.showerror("Error", "OTP code must be entered.") messagebox.showerror("Error", "OTP code must be entered.")
return return
with open('application\\session_data.json', 'r') as f: with open('application\\session_data.json', 'r') as f:
session_data = json.load(f) session_data = json.load(f)
client_id = session_data['client_id'] client_id = session_data['client_id']
if not messagebox.askyesno("Confirmation", "Are you sure you want to update the details?"): if not messagebox.askyesno("Confirmation", "Are you sure you want to update the details?"):
return return
try: try:
result = update_client(client_id, otp_code, new_email, new_phone, new_address) result = update_client(client_id, otp_code, new_email, new_phone, new_address)
if result['success']: if result['success']:
@@ -161,7 +153,6 @@ def populate_table():
accounts = response.get('data', []) accounts = response.get('data', [])
if not isinstance(accounts, list): if not isinstance(accounts, list):
raise ValueError(f"Expected a list of accounts, but got {type(accounts)}") raise ValueError(f"Expected a list of accounts, but got {type(accounts)}")
for account in accounts: for account in accounts:
formatted_balance = format_balance(account['balance']) formatted_balance = format_balance(account['balance'])
table.insert('', 'end', values=(account['description'], account['account_id'], formatted_balance, account['account_type'])) table.insert('', 'end', values=(account['description'], account['account_id'], formatted_balance, account['account_type']))
@@ -233,26 +224,20 @@ def change_password_save():
new_password = password_entry.get() new_password = password_entry.get()
confirm_password = confirm_password_entry.get() confirm_password = confirm_password_entry.get()
otp_code = otp_entry.get() otp_code = otp_entry.get()
if not otp_code: if not otp_code:
messagebox.showerror("Error", "OTP code must be entered.") messagebox.showerror("Error", "OTP code must be entered.")
return return
if not new_password or not confirm_password: if not new_password or not confirm_password:
messagebox.showerror("Error", "New password and confirm password must be entered.") messagebox.showerror("Error", "New password and confirm password must be entered.")
return return
if new_password != confirm_password: if new_password != confirm_password:
messagebox.showerror("Error", "New password and confirm password do not match.") messagebox.showerror("Error", "New password and confirm password do not match.")
return return
with open('application\\session_data.json', 'r') as f: with open('application\\session_data.json', 'r') as f:
session_data = json.load(f) session_data = json.load(f)
client_id = session_data['client_id'] client_id = session_data['client_id']
if not messagebox.askyesno("Confirmation", "Are you sure you want to change the password?"): if not messagebox.askyesno("Confirmation", "Are you sure you want to change the password?"):
return return
try: try:
response = change_password(client_id, old_password, new_password, otp_code) response = change_password(client_id, old_password, new_password, otp_code)
if response['success']: if response['success']:
@@ -263,6 +248,17 @@ def change_password_save():
except Exception as e: except Exception as e:
messagebox.showerror("Error", f"Could not change password: {str(e)}") messagebox.showerror("Error", f"Could not change password: {str(e)}")
def open_transaction_window():
"""Opens a new window for creating a new transaction."""
try:
session = json.load(open('application\\session_data.json', 'r'))
command = f"python application\\new_transaction.py {session['client_id']}"
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}")
############## ##############
### Layout ### ### Layout ###
############## ##############
@@ -288,7 +284,7 @@ otp_button = customtkinter.CTkButton(button_frame, text="Get OTP Code", command=
otp_button.grid(row=0, column=0, padx=3) otp_button.grid(row=0, column=0, padx=3)
# Create the new transaction button # Create the new transaction button
transaction_button = customtkinter.CTkButton(button_frame, text="New Transaction", command=new_transaction, width=100) transaction_button = customtkinter.CTkButton(button_frame, text="New Transaction", command=open_transaction_window, width=100)
transaction_button.grid(row=0, column=1, padx=3) transaction_button.grid(row=0, column=1, padx=3)
# Create the edit client Details button # Create the edit client Details button

View File

@@ -5,21 +5,84 @@ import tkinter as tk
from tkinter import ttk, messagebox from tkinter import ttk, messagebox
import customtkinter import customtkinter
from config import CONFIG from config import CONFIG
from connection import format_balance, get_account, new_transaction, generate_otp from connection import new_transaction, generate_otp, get_account, get_accounts
import sys import sys
import requests
account_id = None
recipient_id = None
################# #################
### Functions ### ### Functions ###
################# #################
if len(sys.argv) > 3: # Check if the account description is provided as a command line argument if len(sys.argv) > 1: # Check if the account description is provided as a command line argument
account_id = sys.argv[1] client_id = sys.argv[1]
account_description = sys.argv[3] # This is passed so that the window can be titled appopriately
else: else:
messagebox.showerror("Error", "Account ID and description were not provided by the server.") messagebox.showerror("Error", "Account ID and description were not provided by the server.")
sys.exit(1) sys.exit(1)
def submit_transaction():
"""Submit a new transaction to the server."""
global account_id, recipient_id
account_id = account_combobox.get()
recipient_id = recipient_text.get()
amount = amount_text.get() if amount_text.get() != "" else None
description = description_text.get() if description_text.get() != "" else None
if not description or not amount or not recipient_id or not account_id:
messagebox.showerror("Error", "Please fill in all fields.")
return
account_verification = verify_accounts(account_id, recipient_id)
if account_verification is False:
messagebox.showerror("Error", "Could not verify account IDs.")
return
response = new_transaction(account_id, description, amount, recipient_id)
if response is None or "data" not in response:
messagebox.showerror("Error", "Could not submit transaction.")
return
transaction_id = response["data"]
otp = generate_otp(account_id, transaction_id)
if otp is None or "data" not in otp:
messagebox.showerror("Error", "Could not generate OTP.")
return
messagebox.showinfo("Success", f"Transaction submitted successfully. OTP: {otp['data']}")
def verify_accounts():
"""Verify that the account IDs are valid."""
try:
account = get_account(account_id)
recipient_account = get_account(recipient_id)
print(account)
print(recipient_account)
except requests.exceptions.RequestException as e:
messagebox.showerror("Error", f"Failed to get account details: {e}")
return False
if account is None or recipient_account is None or "data" not in account or "data" not in recipient_account:
messagebox.showerror("Error", "Server did not return the expected response.")
return False
if "account_id" not in account["data"]:
messagebox.showerror("Error", "Account ID not found.")
return False
if "account_id" not in recipient_account["data"]:
messagebox.showerror("Error", "Recipient Account ID not found.")
return False
#check balance
if account["data"]["balance"] < float(amount_text.get("1.0", "end-1c")):
messagebox.showerror("Error", "Insufficient funds.")
return False
submit_button.configure(state=tk.NORMAL) # Enable the submit button if the accounts are valid
messagebox.showinfo("Success", "Accounts verified successfully.")
return True
def populate_accounts(client_id):
"""Populate the account combobox with accounts for the given client ID."""
accounts = get_accounts(client_id)
if accounts is None or "data" not in accounts:
messagebox.showerror("Error", "Could not retrieve accounts.")
return
account_ids = [account["account_id"] for account in accounts["data"]]
account_combobox['values'] = account_ids
############## ##############
### Layout ### ### Layout ###
@@ -27,9 +90,9 @@ else:
# Initialise the main window # Initialise the main window
root = customtkinter.CTk() root = customtkinter.CTk()
root.title(f"Transactions: {transaction_description}") root.title("New Transaction")
root.iconbitmap("application/luxbank.ico") root.iconbitmap("application/luxbank.ico")
root.geometry("800x400") root.geometry("400x600")
if CONFIG["preferences"]["dark_theme"] == "dark": # Check if dark mode is enabled if CONFIG["preferences"]["dark_theme"] == "dark": # Check if dark mode is enabled
customtkinter.set_appearance_mode("dark") # Set the style for dark mode customtkinter.set_appearance_mode("dark") # Set the style for dark mode
@@ -37,7 +100,57 @@ else:
customtkinter.set_appearance_mode("light") # Set the style for light mode customtkinter.set_appearance_mode("light") # Set the style for light mode
# Display main window title # Display main window title
welcome_label = customtkinter.CTkLabel(root, text=f"Transactions for: {account_description}", font=("Helvetica", 24)) welcome_label = customtkinter.CTkLabel(root, text="New Transaction", font=("Helvetica", 24))
welcome_label.pack(pady=10) welcome_label.pack(pady=20)
# Create a close button at the top of the window
close_button = customtkinter.CTkButton(root, text="Cancel and Close", command=root.destroy)
close_button.pack(side="top", anchor="e", padx=10, pady=10)
# Create the account ID label and combobox
account_label = customtkinter.CTkLabel(root, text="Account ID:", font=("Helvetica", 14))
account_label.pack(pady=5)
account_combobox = ttk.Combobox(root, height=1, width=250)
account_combobox.pack(pady=5)
# Create the recipient ID label and text box
recipient_label = customtkinter.CTkLabel(root, text="Recipient ID:", font=("Helvetica", 14))
recipient_label.pack(pady=5)
recipient_text = customtkinter.CTkTextbox(root, height=2, width=250)
recipient_text.pack(pady=5)
# Create the verify buttons
verify_button = customtkinter.CTkButton(root, text="Verify Accounts", command=verify_accounts)
verify_button.pack(pady=10)
# Create the transaction description label and text box
description_label = customtkinter.CTkLabel(root, text="Description:", font=("Helvetica", 14))
description_label.pack(pady=5)
description_text = customtkinter.CTkTextbox(root, height=4, width=250)
description_text.pack(pady=5)
# Create the transaction amount label and text box
amount_label = customtkinter.CTkLabel(root, text="Amount:", font=("Helvetica", 14))
amount_label.pack(pady=5)
amount_text = customtkinter.CTkTextbox(root, height=2, width=250)
amount_text.pack(pady=5)
# Create the OTP button
otp_button = customtkinter.CTkButton(root, text="Request OTP", command=generate_otp)
otp_button.pack(pady=10)
# Create the OTP label and text box
otp_label = customtkinter.CTkLabel(root, text="OTP:", font=("Helvetica", 14))
otp_label.pack(pady=5)
otp_text = customtkinter.CTkTextbox(root, height=2, width=250)
otp_text.pack(pady=5)
# Create the submit button
submit_button = customtkinter.CTkButton(root, text="Submit", command=submit_transaction, state=tk.DISABLED)
submit_button.pack(pady=5)
# Populate accounts combobox with the given client_id
populate_accounts(client_id)
# Display the main window
root.mainloop() root.mainloop()

View File

@@ -1 +1 @@
{"session_cookie": {"session": "9pRNUPAL2SDrVihKeZcAAb_uw6GzpPm2uTHqrE8urjE"}, "client_id": "9755c18f"} {"session_cookie": {"session": "rVrt6XfG-HNcgZwJHJGmwEg8boBPPRljoCFcrRfQ-ss"}, "client_id": "9755c18f"}

View File

@@ -162,7 +162,7 @@ def generate_otp(client_id: str):
otps[client_id] = (password, time.time()) # Store the OTP and the current time otps[client_id] = (password, time.time()) # Store the OTP and the current time
return format_response(True, "OTP generated and sent successfully."), 200 return format_response(True, "OTP generated and sent successfully."), 200
except EmailSendingError as e: except EmailSendingError as e:
print(f"Error sending email: {e}") log_event(f"Error sending email: {str(e)}")
error_message = "Error sending email. Please try again later." error_message = "Error sending email. Please try again later."
if e.original_error: if e.original_error:
error_message += f" Original error: {str(e.original_error)}" error_message += f" Original error: {str(e.original_error)}"
@@ -251,6 +251,8 @@ def get_accounts(client_id: str):
@login_required @login_required
def get_account(account_id:str): def get_account(account_id:str):
"""Returns a specific account in the database. If the account is not found, returns an error message."""
print(account_id)
current_client_id, is_admin = get_current_client() current_client_id, is_admin = get_current_client()
account_owner = session.query(Account).filter_by(account_id=account_id).one_or_none().client_id 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: if not is_admin and account_owner != current_client_id: