-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmini_bank.py
More file actions
279 lines (247 loc) · 10.9 KB
/
mini_bank.py
File metadata and controls
279 lines (247 loc) · 10.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# ---------------------
# --- LIBRARIES ---
# ---------------------
import mysql.connector # Library for connecting and interacting with MySQL database
from decimal import Decimal # Library for precise decimal arithmetic (useful for money)
import tkinter as tk # GUI library for creating windows and widgets
from tkinter import messagebox, simpledialog
# messagebox: for popup messages like info, warning, error
# simpledialog: for input dialogs like askstring or askfloat
# ---------------------
# --- DATABASE CONNECTION ---
# ---------------------
conn = mysql.connector.connect(
host="localhost", # Database host, usually localhost
user="root", # Database username
password="", # Database password (empty in this example)
database="mini_bank" # Database name to connect
)
cursor = conn.cursor() # Cursor object to execute SQL queries
# ---------------------
# --- BANK FUNCTIONS ---
# ---------------------
# Function to register a new user
def register_user(username, password, initial_balance=0):
cursor.execute("SELECT id FROM users WHERE username=%s", (username,))
# Check if username already exists in the database
if cursor.fetchone(): # If query returns a row, username exists
messagebox.showerror(
"Error", "Username already exists! Choose another.")
return False # Registration failed
# Insert new user into database with initial balance
cursor.execute(
"INSERT INTO users (username, password, balance) VALUES (%s, %s, %s)",
(username, password, Decimal(initial_balance)) # Convert balance to Decimal for precision
)
conn.commit() # Commit changes to the database
messagebox.showinfo(
"Success", f"User '{username}' successfully registered!") # Inform user
return True # Registration successful
# Function for user login
def login(username, password):
cursor.execute(
"SELECT id, balance FROM users WHERE username=%s AND password=%s",
(username, password)
)
# Fetch result from database
result = cursor.fetchone()
if result: # If a matching user is found
user_id, balance = result
return user_id, balance # Return user id and balance
else:
messagebox.showerror(
"Login Failed", "Check your username and password.") # Inform about failure
return None, None # Login failed
# Function to deposit money into account
def deposit(user_id, amount):
if amount <= 0: # Check for valid amount
messagebox.showerror(
"Error", "Deposit amount must be greater than zero.")
return
cursor.execute(
"UPDATE users SET balance = balance + %s WHERE id = %s", (amount, user_id)
) # Increase balance
cursor.execute(
"INSERT INTO transactions (user_id, type, amount, details) VALUES (%s, 'deposit', %s, %s)",
(user_id, amount, 'Money deposit')
) # Record the transaction
conn.commit() # Commit changes
messagebox.showinfo("Success", f"Successfully deposited {amount}.") # Inform user
# Function to withdraw money from account
def withdraw(user_id, amount):
if amount <= 0: # Check for valid amount
messagebox.showerror("Error", "Amount must be greater than zero.")
return
cursor.execute("SELECT balance FROM users WHERE id = %s", (user_id,))
balance = cursor.fetchone()[0] # Get current balance
if balance < amount: # Check if enough balance exists
messagebox.showerror(
"Error", f"Insufficient balance! Current balance: {balance}")
return
cursor.execute(
"UPDATE users SET balance = balance - %s WHERE id = %s", (amount, user_id)
) # Deduct balance
cursor.execute(
"INSERT INTO transactions (user_id, type, amount, details) VALUES (%s, 'withdraw', %s, %s)",
(user_id, amount, 'Money withdraw')
) # Record transaction
conn.commit() # Commit changes
messagebox.showinfo("Success", f"Successfully withdrew {amount}.") # Inform user
# Function to transfer money to another user
def transfer(sender_id, receiver_username, amount):
if amount <= 0: # Check for valid amount
messagebox.showerror("Error", "Amount must be greater than zero.")
return
# Get sender's current balance
cursor.execute("SELECT balance FROM users WHERE id = %s", (sender_id,))
sender_balance = cursor.fetchone()[0]
if sender_balance < amount: # Check if sender has enough money
messagebox.showerror("Error", "Insufficient balance for transfer!")
return
# Get receiver's ID from username
cursor.execute("SELECT id FROM users WHERE username = %s", (receiver_username,))
receiver_data = cursor.fetchone()
if not receiver_data: # If receiver does not exist
messagebox.showerror("Error", "Receiver not found!")
return
receiver_id = receiver_data[0]
try:
# Deduct amount from sender
cursor.execute(
"UPDATE users SET balance = balance - %s WHERE id = %s", (amount, sender_id))
# Add amount to receiver
cursor.execute(
"UPDATE users SET balance = balance + %s WHERE id = %s", (amount, receiver_id))
# Record transactions for both users
cursor.execute(
"INSERT INTO transactions (user_id, type, amount, details) VALUES (%s, 'transfer', %s, %s)",
(sender_id, amount, f'Transfer to {receiver_username}')
)
cursor.execute(
"INSERT INTO transactions (user_id, type, amount, details) VALUES (%s, 'transfer', %s, %s)",
(receiver_id, amount, f"Received from sender ID {sender_id}")
)
conn.commit() # Commit changes
messagebox.showinfo(
"Success", f"Successfully transferred {amount} to {receiver_username}.") # Inform user
except Exception as e:
conn.rollback() # Undo changes if error occurs
messagebox.showerror("Error", f"Transfer failed: {e}") # Show error
# Function to show user's transaction history
def show_transactions(user_id):
cursor.execute("""
SELECT type, amount, details, created_at
FROM transactions
WHERE user_id = %s
ORDER BY created_at DESC
""", (user_id,))
transactions = cursor.fetchall() # Fetch all transactions
if not transactions:
messagebox.showinfo("Transactions", "No transactions found.")
return
trans_text = ""
for t in transactions:
trans_text += f"{t[3]} - {t[0]} - {t[1]} - {t[2]}\n"
messagebox.showinfo("Transaction History", trans_text) # Show in popup
# Function to check current balance
def check_balance(user_id):
cursor.execute("SELECT balance FROM users WHERE id = %s", (user_id,))
balance = cursor.fetchone()[0] # Fetch balance
messagebox.showinfo("Balance", f"Your current balance: {balance}") # Show in popup
# ---------------------
# --- GUI SETUP ---
# ---------------------
root = tk.Tk() # Main Tkinter window
root.title("Mini Bank") # Window title
root.geometry("400x400") # Window size
current_user_id = None # Store logged-in user ID
current_username = None # Store logged-in username
# ---------------------
# --- GUI FUNCTIONS ---
# ---------------------
# Register user via GUI inputs
def gui_register():
username = entry_username.get() # Get username from entry
password = entry_password.get() # Get password from entry
balance = entry_balance.get() # Get initial balance from entry
try:
balance = Decimal(balance) if balance else Decimal(0) # Convert to Decimal, default 0
except:
messagebox.showerror("Error", "Invalid balance!") # Show error if conversion fails
return
if register_user(username, password, balance): # Call register function
# Clear input fields if successful
entry_username.delete(0, tk.END)
entry_password.delete(0, tk.END)
entry_balance.delete(0, tk.END)
# Login user via GUI
def gui_login():
global current_user_id, current_username
username = entry_username.get()
password = entry_password.get()
user_id, _ = login(username, password) # Call login function
if user_id:
current_user_id = user_id
current_username = username
open_bank_menu() # Open main menu window
# Open main bank menu for logged-in user
def open_bank_menu():
menu_win = tk.Toplevel(root) # New top-level window
menu_win.title(f"Mini Bank - {current_username}") # Window title with username
menu_win.geometry("400x400") # Window size
# Welcome label
tk.Label(menu_win, text=f"Welcome, {current_username}", font=("Arial", 14)).pack(pady=10)
# Buttons for each bank action
tk.Button(menu_win, text="Check Balance", width=20,
command=lambda: check_balance(current_user_id)).pack(pady=5)
tk.Button(menu_win, text="Deposit", width=20,
command=lambda: deposit_dialog(current_user_id)).pack(pady=5)
tk.Button(menu_win, text="Withdraw", width=20,
command=lambda: withdraw_dialog(current_user_id)).pack(pady=5)
tk.Button(menu_win, text="Transfer", width=20,
command=lambda: transfer_dialog(current_user_id)).pack(pady=5)
tk.Button(menu_win, text="Show Transactions", width=20,
command=lambda: show_transactions(current_user_id)).pack(pady=5)
tk.Button(menu_win, text="Logout", width=20,
command=menu_win.destroy).pack(pady=20) # Close window
# ---------------------
# --- INPUT DIALOGS ---
# ---------------------
# Deposit input dialog
def deposit_dialog(user_id):
amount = simpledialog.askfloat("Deposit", "Enter amount to deposit:")
if amount:
deposit(user_id, Decimal(amount)) # Call deposit function
# Withdraw input dialog
def withdraw_dialog(user_id):
amount = simpledialog.askfloat("Withdraw", "Enter amount to withdraw:")
if amount:
withdraw(user_id, Decimal(amount)) # Call withdraw function
# Transfer input dialog
def transfer_dialog(user_id):
receiver = simpledialog.askstring("Transfer", "Enter receiver username:")
if not receiver: # If cancelled
return
amount = simpledialog.askfloat("Transfer", "Enter amount to transfer:")
if amount:
transfer(user_id, receiver, Decimal(amount)) # Call transfer function
# ---------------------
# --- LOGIN / REGISTER WIDGETS ---
# ---------------------
# Username label and entry
tk.Label(root, text="Username:").pack(pady=5)
entry_username = tk.Entry(root)
entry_username.pack(pady=5)
# Password label and entry
tk.Label(root, text="Password:").pack(pady=5)
entry_password = tk.Entry(root, show="*")
entry_password.pack(pady=5)
# Initial balance label and entry (for registration)
tk.Label(root, text="Initial Balance (for register):").pack(pady=5)
entry_balance = tk.Entry(root)
entry_balance.pack(pady=5)
# Register button
tk.Button(root, text="Register", width=15, command=gui_register).pack(pady=5)
# Login button
tk.Button(root, text="Login", width=15, command=gui_login).pack(pady=5)
root.mainloop() # Start the Tkinter event loop to run the GUI