Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
16 views27 pages

$R9NXSGU

nothing

Uploaded by

rr.second1414
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views27 pages

$R9NXSGU

nothing

Uploaded by

rr.second1414
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 27

import mysql.

connector

import csv

import sys # Import sys to allow exiting the application cleanly

# --- Database Setup ---

def setup_database():

"""

Connects to MySQL and sets up the 'expense_db' database and necessary


tables

for users and expenses if they don't already exist.

"""

conn = None # Initialize conn to None

cursor = None # Initialize cursor to None

try:

# Establish connection to MySQL server (without specifying a database


initially)

conn = mysql.connector.connect(

host="localhost",

user="root",

password="1234" # IMPORTANT: Replace with your actual MySQL root


password

cursor = conn.cursor()
# Create the database if it doesn't exist

cursor.execute("CREATE DATABASE IF NOT EXISTS expense_db")

print("✅ Database 'expense_db' checked/created.")

# Switch to the newly created or existing database

cursor.execute("USE expense_db")

print("✅ Switched to 'expense_db'.")

# Create 'users' table if it doesn't exist

cursor.execute("""

CREATE TABLE IF NOT EXISTS users (

id INT AUTO_INCREMENT PRIMARY KEY,

username VARCHAR(50) UNIQUE NOT NULL,

password VARCHAR(50) NOT NULL

""")

print("✅ Table 'users' checked/created.")

# Create 'expenses' table if it doesn't exist

cursor.execute("""

CREATE TABLE IF NOT EXISTS expenses (

id INT AUTO_INCREMENT PRIMARY KEY,

user_id INT,
date DATE NOT NULL,

category VARCHAR(100) NOT NULL,

amount FLOAT NOT NULL,

description TEXT,

FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE

""")

print("✅ Table 'expenses' checked/created.")

conn.commit()

print("✅ MySQL database and tables set up successfully.")

except mysql.connector.Error as err:

print(f"❌ Error setting up database: {err}")

print("Please ensure MySQL is running and your 'root' user password is


correct in the script.")

finally:

if cursor:

cursor.close()

if conn and conn.is_connected():

conn.close()

# --- MySQL Connection ---

def connect():
"""

Establishes a connection to the 'expense_db' database.

Returns the connection object.

"""

try:

return mysql.connector.connect(

host="localhost",

user="root",

password="your_mysql_password", # IMPORTANT: Replace with your


actual MySQL root password

database="expense_db"

except mysql.connector.Error as err:

print(f"❌ Database connection error: {err}")

print("Please ensure MySQL is running, the 'expense_db' exists, and


connection details are correct.")

return None

# --- User Authentication ---

def register():

"""

Registers a new user by taking username and password input.

Checks for duplicate usernames.

"""
username = input("New username: ").strip()

password = input("New password: ").strip()

if not username:

print("❌ Username cannot be empty.")

return

if not password:

print("❌ Password cannot be empty.")

return

conn = connect()

if not conn:

return

cursor = conn.cursor()

try:

cursor.execute("INSERT INTO users (username, password) VALUES (%s,


%s)", (username, password))

conn.commit()

print(f"✅ User '{username}' registered successfully.")

except mysql.connector.IntegrityError:

print("❌ Username already exists. Please choose a different username.")

except mysql.connector.Error as err:

print(f"❌ Error during registration: {err}")


finally:

if cursor:

cursor.close()

if conn and conn.is_connected():

conn.close()

def login():

"""

Authenticates a user by checking provided username and password.

Returns the user's ID if successful, otherwise None.

"""

username = input("Username: ").strip()

password = input("Password: ").strip()

if not username or not password:

print("❌ Username and password cannot be empty.")

return None

conn = connect()

if not conn:

return None

cursor = conn.cursor()
try:

cursor.execute("SELECT id FROM users WHERE username = %s AND


password = %s", (username, password))

user = cursor.fetchone()

if user:

print(f"✅ Logged in as {username}.")

return user[0] # Return user_id

else:

print("❌ Invalid username or password.")

return None

except mysql.connector.Error as err:

print(f"❌ Error during login: {err}")

return None

finally:

if cursor:

cursor.close()

if conn and conn.is_connected():

conn.close()

# --- Expense Functions ---

def add_expense(user_id):

"""

Adds a new expense record for the logged-in user.

"""
date = input("Enter date (YYYY-MM-DD): ").strip()

category = input("Enter category: ").strip()

amount_str = input("Enter amount: ").strip()

description = input("Enter description (optional): ").strip()

if not date:

print("❌ Date cannot be empty.")

return

if not category:

print("❌ Category cannot be empty.")

return

try:

amount = float(amount_str)

if amount <= 0:

print("❌ Amount must be a positive number.")

return

except ValueError:

print("❌ Invalid amount. Please enter a number (e.g., 50.00).")

return

conn = connect()

if not conn:
return

cursor = conn.cursor()

try:

cursor.execute(

"INSERT INTO expenses (user_id, date, category, amount, description)


VALUES (%s, %s, %s, %s, %s)",

(user_id, date, category, amount, description)

conn.commit()

print("✅ Expense added successfully.")

except mysql.connector.Error as err:

print(f"❌ Error adding expense: {err}")

finally:

if cursor:

cursor.close()

if conn and conn.is_connected():

conn.close()

def view_expenses(user_id):

"""

Displays all expenses for the logged-in user, ordered by date.

"""

conn = connect()
if not conn:

return

cursor = conn.cursor()

try:

cursor.execute("SELECT id, date, category, amount, description FROM


expenses WHERE user_id = %s ORDER BY date DESC", (user_id,))

rows = cursor.fetchall()

print("\n--- Your Expenses ---")

if not rows:

print("No expenses recorded yet.")

return

print("{:<5} {:<12} {:<15} {:<10} {}".format("ID", "Date", "Category",


"Amount", "Description"))

print("-" * 60)

for row in rows:

# Format amount to two decimal places for display, handle None for
description

print("{:<5} {:<12} {:<15} {:<10.2f} {}".format(row[0], str(row[1]), row[2],


row[3], row[4] or ''))

except mysql.connector.Error as err:

print(f"❌ Error viewing expenses: {err}")

finally:
if cursor:

cursor.close()

if conn and conn.is_connected():

conn.close()

def update_expense(user_id):

"""

Updates an existing expense record for the logged-in user.

Allows partial updates by leaving fields blank.

"""

expense_id_str = input("Enter the ID of the expense to update: ").strip()

try:

expense_id = int(expense_id_str)

except ValueError:

print("❌ Invalid expense ID. Please enter a number.")

return

# First, check if the expense exists and belongs to the user

conn_check = connect()

if not conn_check:

return

cursor_check = conn_check.cursor()
try:

cursor_check.execute("SELECT id FROM expenses WHERE id = %s AND


user_id = %s", (expense_id, user_id))

if not cursor_check.fetchone():

print("❌ Expense not found or you don't have permission to update it.")

return

except mysql.connector.Error as err:

print(f"❌ Error checking expense: {err}")

return

finally:

if cursor_check:

cursor_check.close()

if conn_check and conn_check.is_connected():

conn_check.close()

print(f"\nEnter new details for expense ID {expense_id} (leave blank to keep


current value):")

new_date = input(f"New date (YYYY-MM-DD): ").strip()

new_category = input(f"New category: ").strip()

new_amount_str = input(f"New amount: ").strip()

new_description = input(f"New description: ").strip()

conn = connect()

if not conn:
return

cursor = conn.cursor()

try:

updates = []

params = []

if new_date:

updates.append("date = %s")

params.append(new_date)

if new_category:

updates.append("category = %s")

params.append(new_category)

if new_amount_str:

try:

new_amount = float(new_amount_str)

if new_amount <= 0:

print("❌ Amount must be a positive number. Update cancelled.")

return # Exit if amount is invalid

updates.append("amount = %s")

params.append(new_amount)

except ValueError:

print("❌ Invalid amount. Please enter a number (e.g., 100.50). Update


cancelled.")

return # Exit if amount is invalid


if new_description:

updates.append("description = %s")

params.append(new_description)

if not updates:

print("❗ No new information provided. Nothing to update.")

return

query = f"UPDATE expenses SET {', '.join(updates)} WHERE id = %s AND


user_id = %s"

params.extend([expense_id, user_id])

cursor.execute(query, tuple(params))

conn.commit()

if cursor.rowcount > 0:

print(f"✅ Expense ID {expense_id} updated successfully.")

else:

print("❗ No changes were made, or expense was not found/owned by


you (this shouldn't happen after the initial check).")

except mysql.connector.Error as err:

print(f"❌ Error updating expense: {err}")

finally:

if cursor:

cursor.close()
if conn and conn.is_connected():

conn.close()

def delete_expense(user_id):

"""

Deletes an expense record for the logged-in user.

Includes a confirmation step.

"""

expense_id_str = input("Enter the ID of the expense to delete: ").strip()

try:

expense_id = int(expense_id_str)

except ValueError:

print("❌ Invalid expense ID. Please enter a number.")

return

conn = connect()

if not conn:

return

cursor = conn.cursor()

try:

# Check if the expense exists and belongs to the user before asking for
confirmation
cursor.execute("SELECT id FROM expenses WHERE id = %s AND user_id =
%s", (expense_id, user_id))

if not cursor.fetchone():

print("❌ Expense not found or you don't have permission to delete it.")

return

confirm = input(f"Are you sure you want to delete expense ID


{expense_id}? This cannot be undone. (y/n): ").strip().lower()

if confirm != 'y':

print("Deletion cancelled.")

return

cursor.execute("DELETE FROM expenses WHERE id = %s AND user_id =


%s", (expense_id, user_id))

conn.commit()

if cursor.rowcount > 0:

print(f" Expense ID {expense_id} deleted successfully.")

else:

# This case should ideally not be reached if the initial check passed

print("❗ Expense not found or no changes were applied.")

except mysql.connector.Error as err:

print(f"❌ Error deleting expense: {err}")

finally:

if cursor:
cursor.close()

if conn and conn.is_connected():

conn.close()

# --- Reporting and Analysis Functions ---

def category_summary(user_id):

"""

Provides a summary of total spending per category for the logged-in user.

"""

conn = connect()

if not conn:

return

cursor = conn.cursor()

try:

cursor.execute("SELECT category, SUM(amount) FROM expenses WHERE


user_id = %s GROUP BY category", (user_id,))

rows = cursor.fetchall()

print("\n--- Category-wise Summary ---")

if not rows:

print("No expenses recorded to summarize by category.")

return
for row in rows:

print("Category: {:<15} Total: ₹{:.2f}".format(row[0], row[1]))

except mysql.connector.Error as err:

print(f"❌ Error generating category summary: {err}")

finally:

if cursor:

cursor.close()

if conn and conn.is_connected():

conn.close()

def monthly_report(user_id):

"""

Generates a report of expenses for a specific month (YYYY-MM) for the


logged-in user.

"""

month = input("Enter month for report (YYYY-MM): ").strip()

# Basic validation for month format

if not (len(month) == 7 and month[4] == '-' and month[:4].isdigit() and


month[5:].isdigit()):

print("❌ Invalid month format. Please use YYYY-MM (e.g., 2023-10).")

return

conn = connect()
if not conn:

return

cursor = conn.cursor()

try:

# Use DATE_FORMAT to compare only year and month

cursor.execute("SELECT id, date, category, amount, description FROM


expenses WHERE user_id = %s AND DATE_FORMAT(date, '%%Y-%%m') = %s
ORDER BY date ASC", (user_id, month))

rows = cursor.fetchall()

print(f"\n--- Monthly Report for {month} ---")

if not rows:

print(f"No expenses recorded for {month}.")

return

print("{:<5} {:<12} {:<15} {:<10} {}".format("ID", "Date", "Category",


"Amount", "Description"))

print("-" * 60)

total_monthly_spent = 0

for row in rows:

print("{:<5} {:<12} {:<15} {:<10.2f} {}".format(row[0], str(row[1]), row[2],


row[3], row[4] or ''))

total_monthly_spent += row[3]

print("-" * 60)
print(f"Total spent in {month}: ₹{total_monthly_spent:.2f}")

except mysql.connector.Error as err:

print(f"❌ Error generating monthly report: {err}")

finally:

if cursor:

cursor.close()

if conn and conn.is_connected():

conn.close()

def export_to_csv(user_id):

"""

Exports all expenses for the logged-in user to a CSV file.

"""

filename = input("Enter desired CSV filename (e.g., my_expenses.csv):


").strip()

if not filename:

print("❌ Filename cannot be empty.")

return

if not filename.lower().endswith(".csv"):

filename += ".csv"

conn = connect()
if not conn:

return

cursor = conn.cursor()

try:

cursor.execute("SELECT id, date, category, amount, description FROM


expenses WHERE user_id = %s ORDER BY date ASC", (user_id,))

rows = cursor.fetchall()

if not rows:

print("No expenses to export.")

return

with open(filename, mode='w', newline='', encoding='utf-8') as file:

writer = csv.writer(file)

writer.writerow(['ID', 'Date', 'Category', 'Amount', 'Description'])

for row in rows:

writer.writerow([row[0], str(row[1]), row[2], row[3], row[4] or ''])

print(f"✅ Data exported to '{filename}' successfully.")

except IOError as io_err:

print(f"❌ Error writing to file '{filename}': {io_err}")

print("Please check if you have write permissions in the current


directory.")
except mysql.connector.Error as db_err:

print(f"❌ Error fetching data for export: {db_err}")

finally:

if cursor:

cursor.close()

if conn and conn.is_connected():

conn.close()

def analyze_expenses(user_id):

"""

Analyzes expense patterns and provides suggestions.

Identifies the highest spending category and offers a tip if spending is high in
one category.

"""

conn = connect()

if not conn:

return

cursor = conn.cursor()

try:

cursor.execute("SELECT category, SUM(amount) as total FROM expenses


WHERE user_id = %s GROUP BY category ORDER BY total DESC", (user_id,))

rows = cursor.fetchall()
if not rows:

print("No expenses to analyze. Add some expenses first!")

return

print("\n--- Expense Analysis ---")

total_spent = sum([row[1] for row in rows])

if total_spent == 0:

print("No spending recorded yet to analyze.")

return

print(f"Total spending across all categories: ₹{total_spent:.2f}")

print("\nSpending by Category:")

for row in rows:

percentage = (row[1] / total_spent) * 100

print(f"- {row[0]}: ₹{row[1]:.2f} ({percentage:.1f}%)")

max_category = rows[0] # Already ordered by total DESC

print(f"\n🔍 Your highest spending category is: **{max_category[0]}** (₹


{max_category[1]:.2f})")

# Simple suggestion logic

if max_category[1] / total_spent > 0.4: # If more than 40% of total is in one


category
print("💡 Suggestion: Consider reviewing your expenses in this category.
Small adjustments here can significantly impact your overall budget.")

elif max_category[1] / total_spent > 0.2:

print("👍 Tip: Keep an eye on your spending in this category. Consistent


tracking can help identify areas for saving.")

else:

print("📊 Your spending seems well-distributed across categories. Great


job!")

except mysql.connector.Error as err:

print(f"❌ Error analyzing expenses: {err}")

finally:

if cursor:

cursor.close()

if conn and conn.is_connected():

conn.close()

# --- Main Program ---

def main():

"""

Main function to run the expense tracker application.

Handles user login, registration, and navigates the main menu.

"""

print("Initializing database...")
setup_database()

while True:

print("\n===== EXPENSE TRACKER =====")

print("1. Register")

print("2. Login")

print("3. Exit")

option = input("Choose an option: ").strip()

if option == '1':

register()

elif option == '2':

user_id = login()

if user_id:

# User is logged in, show main expense menu

while True:

print("\n--- Main Menu ---")

print("1. Add Expense")

print("2. View Expenses")

print("3. Update Expense")

print("4. Delete Expense")

print("5. Category Summary")

print("6. Monthly Report")


print("7. Export to CSV")

print("8. Analyze & Suggest")

print("9. Logout")

choice = input("Enter your choice: ").strip()

if choice == '1':

add_expense(user_id)

elif choice == '2':

view_expenses(user_id)

elif choice == '3':

update_expense(user_id)

elif choice == '4':

delete_expense(user_id)

elif choice == '5':

category_summary(user_id)

elif choice == '6':

monthly_report(user_id)

elif choice == '7':

export_to_csv(user_id)

elif choice == '8':

analyze_expenses(user_id)

elif choice == '9':


print("Logging out...")

break # Break out of the inner loop to return to login/register


menu

else:

print("Invalid choice. Please try again.")

elif option == '3':

print("Goodbye! 👋")

sys.exit() # Exit the program cleanly

else:

print("Invalid option. Please choose 1, 2, or 3.")

if __name__ == "__main__":

main()

You might also like