0% found this document useful (0 votes)
14 views21 pages

Personal Expense Tracker Project Report

The document is a project report for a personal expense tracker created using Python and MySQL. It includes sections such as the aim, algorithm, flowchart, source code, and scope for improvement. The project focuses on tracking personal expenses, allowing users to add, delete, view expenses, generate charts, and export data to CSV.

Uploaded by

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

Personal Expense Tracker Project Report

The document is a project report for a personal expense tracker created using Python and MySQL. It includes sections such as the aim, algorithm, flowchart, source code, and scope for improvement. The project focuses on tracking personal expenses, allowing users to add, delete, view expenses, generate charts, and export data to CSV.

Uploaded by

vaibhav24317
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

VEL INTERNATIONAL PUBLIC

SCHOOL

A Project Report on
Personal expense tracker

By
Gautam Sunil XII A
Index:
 Acknowledgement
 Bonafide Certificate
 Aim
 Algorithm
 Flowchart
 Source Code
 Output
 Scope of Improvement
 Bibliography
ACKNOWLEDGEMENT
I_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ do hereby
declare that this project is my original
work and I would like to express my
special thanks to our Principal_ _ _ _ _ _ _
_ _ _ _ _and to my teacher_ _ _ _ _ _ _ _
who gave me the opportunity to do
this wonderful project on the
Topic_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ . This also helped me in doing a lot
of research and I have come to know
about so many new things. I also would
like to than my parents and my friends
for their support and guidance without
which this project would not have been
completed.
BONAFIDE
CERTIFICATE
This is to certify that this project titled
________________________________
_ _ _ _ _ _ _ _ _ is the Bonafide work of
Miss/Master __________________________ of
class _ _ _ _ _ studying in Vel International Public
School during the Academic Year _ _ _ _ _ _ _ .

Signature of the Internal Examiner : _ _ _ _ _ _ _ _

Signature of the School Principal : _ _ _ _ _ _ _ _

Submitted for All-India Senior Secondary School


Practical Examination held on_ _ _ _ _ _ _ _ _ _ _at
Vel International Public School.

Date : _ _ _ _ _ _ _

Signature of the
External Examiner

School Seal
Aim:
To create a personal expense tracker with
python and MySQL using
database connectivity.

Algorithm: Expense Tracker


Program
1. Start
·Import required libraries:
[Link], datetime, matplotlib, csv, tkinter.
·Ensure all modules are installed.

2. Database Setup
·Define MySQL credentials (host, user, password,
database name).
·Connect to MySQL server.
·Create database expense_tracker_db if not exists.
·Create table expenses with fields: id, description,
category, amount, date.
·Commit changes and confirm connection.

3. GUI Initialization
·Create the main Tkinter window.
·Set window title, size, and design styles.
·Configure close event and layout settings.
4. GUI Layout:
·Left Panel:
Input fields: Description, Category (dropdown),
Amount, Date (default today).
Buttons: Add, Delete, Show Chart, Export CSV.
·Right Panel:
Treeview table with columns (ID, Description,
Category, Amount, Date).
Scrollbar and total amount label at bottom.

5. Add Expense
·On “Add” click:
Read input values.
Validate (non-empty, positive amount, valid
date).
Insert record into database.
Clear form and refresh table.
Show success message or error if invalid.

6. Delete Expense
·On “Delete” click:
Check if a record is selected.
Ask for confirmation.
Execute DELETE query using ID.
Commit and refresh table.
7. View Expenses
·Clear Treeview.
·Execute SELECT query to fetch all records sorted by
date.
·Insert each record into table.
·Update total amount displayed.

8. Show Chart
·Run query to sum expenses by category.
·If data exists:
Extract categories and amounts.
Plot a pie chart using Matplotlib.
·If no data:
Show a “No expenses to plot” message.

9. Export to CSV
·Open file save dialog.
·Write headers and records to selected file.
·Show success message on completion.

10. Exit Program


·On close:
Check and close database connection.
Destroy main window.
End execution.

11. Main Function


·Initialize Tkinter root.
·Create ExpenseTracker object.
·Run main event loop.
Flowchart:
Program Code:
import [Link]
from [Link] import Error
from datetime import datetime, date
import [Link] as plt
import csv
from tkinter import *
from tkinter import ttk, messagebox
from [Link] import asksaveasfilename

DB_HOST = "localhost"
DB_USER = "root"
DB_PASSWORD = "password"
DB_NAME = "expense_tracker_db"

class ExpenseTracker:
def __init__(self, root):
[Link] = root
[Link]("Expense Tracker")
[Link]("1000x700")
[Link](False, False)
# Style configuration
[Link] = [Link]()
[Link]('TFrame', background='#f0f8ff')
[Link]('TButton', font=('Arial', 10, 'bold'), padding=5)
[Link]('[Link]',
font=('Arial', 18, 'bold'),
background='#4b7bec',
foreground='white',
padding=10)
self.db_connection = None
self.connect_db()
if self.db_connection and self.db_connection.is_connected():
self.create_gui()
self.view_expenses()
else:
[Link]()

[Link]("WM_DELETE_WINDOW", self.on_exit)
def connect_db(self):
"""Connects to MySQL, creates DB if not exists, then connects to it."""
try:
self.db_connection = [Link](
host=DB_HOST, user=DB_USER, password=DB_PASSWORD
)
cursor = self.db_connection.cursor()
[Link](f"CREATE DATABASE IF NOT EXISTS {DB_NAME}")
self.db_connection.database = DB_NAME
print(f"Connected to MySQL database '{DB_NAME}'.")
self.create_table()
except Error as e:
[Link]("Database Error", f"Failed to connect or
create DB: {str(e)}\n"
f"Ensure MySQL server is running & credentials are correct.")
[Link]()

def create_table(self):
"""Creates the 'expenses' table if it doesn't exist."""
if not self.db_connection or not self.db_connection.is connected():
[Link]("Database Error", "No active DB
connection to create table.")
return
query = """
CREATE TABLE IF NOT EXISTS expenses (
id INT AUTO_INCREMENT PRIMARY KEY,
description VARCHAR(255) NOT NULL,
category VARCHAR(50),
amount DECIMAL(10,2) NOT NULL,
date DATE NOT NULL
)
"""
try:
cursor = self.db_connection.cursor()
[Link](query)
self.db_connection.commit()
print("Table 'expenses' checked/created.")
except Error as e:
[Link]("Database Error", f"Failed to create
table: {str(e)}")
def create_gui(self):
"""Sets up all GUI elements: form, buttons, and expense display."""
header_frame = [Link]([Link], style='[Link]')
header_frame.pack(fill=X)
[Link](header_frame, text="EXPENSE TRACKER ",
style='[Link]').pack(fill=X)

main_frame = [Link]([Link])
main_frame.pack(fill=BOTH, expand=True, padx=20, pady=10)
main_frame.grid_columnconfigure(0, weight=1)
main_frame.grid_columnconfigure(1, weight=3)
main_frame.grid_rowconfigure(0, weight=1)

# Left Frame - Input Form

left_frame = [Link](main_frame)
left_frame.grid(row=0, column=0, padx=10, pady=5,
sticky=N+S+E+W)
left_frame.grid_rowconfigure(0, weight=1)

form_frame = [Link](left_frame, text="Add New


Expense",padding=10)
form_frame.pack(fill=BOTH, expand=True, padx=5, pady=5)
form_frame.grid_columnconfigure(1, weight=1)

[Link](form_frame, text="Description:").grid(row=0, column=0,


sticky=W, pady=5, padx=5)
self.desc_entry = [Link](form_frame, width=30)
self.desc_entry.grid(row=0, column=1, pady=5, padx=5,
sticky=EW)
[Link](form_frame, text="Category:").grid(row=1, column=0,
sticky=W, pady=5, padx=5)
self.category_var = StringVar()
self.category_combo = [Link](form_frame,
textvariable=self.category_var,
values=("Food", "Transport", "Shopping", "Bills", "Other"),
width=27, state="readonly")
self.category_combo.grid(row=1, column=1, pady=5, padx=5,
sticky=EW)
self.category_combo.set("Food")
[Link](form_frame, text="Amount (₹):").grid(row=2, column=0,
sticky=W, pady=5, padx=5)
self.amount_entry = [Link](form_frame, width=30)
self.amount_entry.grid(row=2, column=1, pady=5, padx=5,
sticky=EW)
[Link](form_frame, text="Date (YYYY-MM-DD):").grid(row=3,
column=0, sticky=W, pady=5, padx=5)
self.date_entry = [Link](form_frame, width=30)
self.date_entry.insert(0, [Link]().strftime("%Y-%m-%d"))
self.date_entry.grid(row=3, column=1, pady=5, padx=5,
sticky=EW)

# Buttons

button_frame = [Link](form_frame)
button_frame.grid(row=4, column=0, columnspan=2, pady=10)
for i in range(4): button_frame.grid_columnconfigure(i, weight=1)

[Link](button_frame, text="Add Expense",


command=self.add_expense).grid(row=0, column=0, padx=5,
pady=5, sticky=EW)
[Link](button_frame, text="Delete Expense",
command=self.delete_expense).grid(row=0, column=1, padx=5,
pady=5, sticky=EW)
[Link](button_frame, text="Show Chart",
command=self.plot_chart).grid(row=0, column=2, padx=5,
pady=5, sticky=EW)
[Link](button_frame, text="Export to CSV",
command=self.export_csv).grid(row=0, column=3, padx=5,
pady=5, sticky=EW)

# Right Frame – Display

right_frame = [Link](main_frame)
right_frame.grid(row=0, column=1, sticky=N+S+E+W, padx=10,
pady=5)
right_frame.grid_rowconfigure(0, weight=1)
display_frame = [Link](right_frame, text="Expense
Records", padding=10)
display_frame.pack(fill=BOTH, expand=True)

[Link] = [Link](display_frame, columns=("ID", "Description",


"Category", "Amount", "Date"), show="headings", height=20)
[Link]("ID", width=40, anchor=CENTER); [Link]
("ID", text="ID")
[Link]("Description", width=200, anchor=W);
[Link]("Description", text="Description")
[Link]("Category", width=100, anchor=W);
[Link]("Category", text="Category")
[Link]("Amount", width=100, anchor=E);
[Link]("Amount", text="Amount (₹)")
[Link]("Date", width=100, anchor=CENTER);
[Link]("Date", text="Date")
vsb = [Link](display_frame, orient="vertical",
command=[Link])
[Link](yscrollcommand=[Link])
[Link](side=LEFT, fill=BOTH, expand=True)
[Link](side=RIGHT, fill=Y)
self.total_label = [Link](right_frame, text="Total: ₹0.00", font=
('Arial', 12, 'bold'), background='#f0f8ff')
self.total_label.pack(fill=X, pady=5)
def add_expense(self):
"""Adds a new expense to the database after validation."""
desc, cat, amt_str, date_str = self.desc_entry.get().strip(),
self.category_var.get(), self.amount_entry.get().strip(),
self.date_entry.get().strip()
if not all([desc, cat, amt_str, date_str]):
[Link]("Input Error", "All fields are required!")
; return
try:
amount = float(amt_str)
if amount <= 0: [Link]("Input Error", "Amount
must be positive!") ;
return
except ValueError: [Link]("Input Error", "Invalid
amount!") ; return
try: expense_date = [Link](date_str, "%Y-%m-%d")
.date()
except ValueError: [Link]("Input Error", "Invalid
date format (YYYY-MM-DD)!") ; return

query = "INSERT INTO expenses (description, category, amount,


date) VALUES (%s, %s, %s, %s)"
values = (desc, cat, amount, expense_date)
try:
cursor = self.db_connection.cursor()
[Link](query, values)
self.db_connection.commit()
[Link]("Success", "Expense added successfully!")
self.clear_form() ; self.view_expenses()
except Error as e: [Link]("Database Error",
f"Failed to add expense: {str(e)}")
def delete_expense(self):
"""Deletes selected expense from database with confirmation."""
selected_item = [Link]()
if not selected_item: [Link]("Selection
Error", "Select an expense to delete!") ; return

expense_id = [Link](selected_item)['values'][0]
if not [Link]("Confirm Deletion", f"Delete ID:
{expense_id}?\nCannot be undone."): return
try:
query = "DELETE FROM expenses WHERE id = %s"
cursor = self.db_connection.cursor()
[Link](query, (expense_id,))
self.db_connection.commit()
[Link]("Success", "Expense deleted successfully!")
self.view_expenses()
except Error as e: [Link]("Database Error",
f"Failed to delete expense: {str(e)}")
def view_expenses(self):
"""Displays all expenses in the treeview and updates total."""
for item in [Link].get_children(): [Link](item)
total = 0.0
try:
query = "SELECT * FROM expenses ORDER BY date DESC"
cursor = self.db_connection.cursor()
[Link](query)
expenses = [Link]()
for expense in expenses:
[Link]("", END, values=expense)
total += float(expense[3])
self.total_label.config(text=f"Total: ₹{total:.2f}")
except Error as e: [Link]("Database Error",
f"Failed to fetch expenses: {str(e)}")

def plot_chart(self):
"""Generates and displays a pie chart of expenses by category."""
try:
query = "SELECT category, SUM(amount) FROM expenses
GROUP BY category"
cursor = self.db_connection.cursor()
[Link](query)
data = [Link]()
if not data: [Link]("No Data", "No expenses
to plot!") ; return
categories = [item[0] for item in data]
amounts = [float(item[1]) for item in data]
[Link](figsize=(9, 7))
[Link]("Expenses by Category", fontsize=16, fontweight=
'bold', color='#333333')
colors = ['#ff9999','#66b3ff','#99ff99','#ffcc99','#c2c2f0', '#ffb3e6'
,'#c4e17f', '#a8d8ea', '#f7d794']
display_colors = colors[:len(categories)]
[Link](amounts, labels=categories, autopct='%1.1f%%',
colors=display_colors,
startangle=90, shadow=True, pctdistance=0.85,
wedgeprops={'edgecolor': 'black', 'linewidth': 0.5})
centre_circle = [Link]((0,0), 0.70, fc='white')
[Link]().gca().add_artist(centre_circle)
[Link]('equal')
plt.tight_layout()
[Link]()
except Error as e: [Link]("Database Error",
f"Failed to fetch chart data: {str(e)}")
except Exception as e: [Link]("Chart Error",
f"Error plotting chart: {str(e)}")

def export_csv(self):
"""Exports all expenses to a CSV file."""
file_path = asksaveasfilename(defaultextension=".csv", filetypes=
[("CSV Files", "*.csv"), ("All Files", "*.*")], title="Save Expenses as CSV")
if not file_path: return
try:
with open(file_path, mode='w', newline='', encoding='utf-8') as file:
writer = [Link](file)
[Link](["ID", "Description", "Category", "Amount",
"Date"])
for item in [Link].get_children():
[Link]([Link](item)['values'])
[Link]("Success", f"Expenses exported to:
\n{file_path}")
except Exception as e: [Link]("Export Error",
f"Failed to export: {str(e)}")
def clear_form(self):
"""Clears input fields and resets defaults."""
self.desc_entry.delete(0, END)
self.category_var.set('Food')
self.amount_entry.delete(0, END)
self.date_entry.delete(0, END)
self.date_entry.insert(0, [Link]().strftime("%Y-%m-%d"))
def on_exit(self):
"""Closes DB connection and exits application."""
if self.db_connection and self.db_connection.is_connected():
self.db_connection.close() ; print("DB connection closed.")
[Link]() ; print("Application exited.")
def main():
"""Main function to run the application."""
root = Tk()
app = ExpenseTracker(root)
[Link]()

if __name__ == "__main__":
main()
OUTPUT:

Exggpzas by Caœgory
Scope of improvement:
1. Modularize the code
·Separate into files:
odb_handler.py → Database connection & queries
[Link] → Tkinter UI
[Link] → Plotting functions

2. Improve Database Handling


·Use with self.db_connection.cursor () for auto-closing
cursors.
·Centralize queries in one class.
·Add rollback in case of errors.

3. Better Input Validation


·Centralize all validation (amount, date, description).
·Give clearer error messages.

4. Enhance GUI/UX
·Add edit/update, search/filter (by category/date).
·Use themes for modern look.
·Add keyboard shortcuts or a status bar.

5. Security
·Move DB credentials to .env file (use python-dotenv).
·Don’t hardcode passwords in the script.

6. Performance
·Use pagination or threading for large datasets.
·Don’t block UI with heavy operations (charts, queries).
7. Charting & Export
·Add optional bar/line charts.
·Export as Excel or PDF in addition to CSV.

8. Logging & Style


·Replace print() with logging.
·Follow PEP 8 (shorter methods, type hints,
docstrings).
Bibliography:
[Link]
[Link]
[Link]
[Link]
Class 11 and 12 Computer Science with
Python by Sumita Arora

You might also like