Skip to content

Commit

Permalink
Updated expense tracker (#369)
Browse files Browse the repository at this point in the history
* Update requirements.txt

Update the requirements of LinkedIn Bot

* Updated Expense Tracker with GUI and extra features
  • Loading branch information
aditorito authored Oct 31, 2024
1 parent 164d09c commit f9cfa25
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 40 deletions.
1 change: 1 addition & 0 deletions Expense Tracker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Install the required dependencies using pip:
```
pip install -r requirements.txt
```
or you can manually install single Library

Run the expense.py file to start the bot:

Expand Down
219 changes: 181 additions & 38 deletions Expense Tracker/expense.py
Original file line number Diff line number Diff line change
@@ -1,50 +1,193 @@
import csv
import os
import datetime
import sqlite3
from tkcalendar import DateEntry
from tkinter import *
import tkinter.messagebox as tb
import tkinter.ttk as ttk

CSV_FILE = "expenses.csv"
# Functions
def list_all_expenses():
global connector, table

def initialize_csv():
if not os.path.exists(CSV_FILE):
with open(CSV_FILE, "w", newline="") as file:
writer = csv.writer(file)
writer.writerow(["Date", "Description", "Amount"])
table.delete(*table.get_children())

def add_expense(date, description, amount):
with open(CSV_FILE, "a", newline="") as file:
writer = csv.writer(file)
writer.writerow([date, description, amount])
all_data = connector.execute('SELECT * FROM ExpenseTracker')
data = all_data.fetchall()

def view_expenses():
with open(CSV_FILE, "r") as file:
reader = csv.reader(file)
for row in reader:
print(", ".join(row))
for values in data:
table.insert('', END, values=values)

if __name__ == "__main__":
initialize_csv()
def clear_fields():
global Desc, payee, amnt, MoP, date, table

while True:
print("\nExpense Tracker Menu:")
print("1. Add Expense")
print("2. View Expenses")
print("3. Exit")
today_date = datetime.datetime.now().date()

choice = input("Enter your choice: ")
Desc.set('') ; payee.set('') ; amnt.set(0.0) ; MoP.set('Cash'), date.set_date(today_date)
table.selection_remove(*table.selection())

if choice == "1":
date = input("Enter the date (YYYY-MM-DD): ")
description = input("Enter the description: ")
amount = input("Enter the amount: ")
def remove_expense():
if not table.selection():
tb.showerror('No record selected!', 'Please select a record to delete!')
return

add_expense(date, description, amount)
print("Expense added successfully!")
current_selected_expense = table.item(table.focus())
values_selected = current_selected_expense['values']

elif choice == "2":
print("Expenses:")
view_expenses()
surety = tb.askyesno('Are you sure?', f'Are you sure that you want to delete the record of {values_selected[2]}')

elif choice == "3":
break
if surety:
connector.execute('DELETE FROM ExpenseTracker WHERE ID=%d' % values_selected[0])
connector.commit()

else:
print("Invalid choice. Please try again.")
list_all_expenses()
tb.showinfo('Record deleted successfully!', 'The record you wanted to delete has been deleted successfully')

def remove_all_expenses():
surety = tb.askyesno('Are you sure?', 'Are you sure that you want to delete all the expense items from the database?', icon='warning')

if surety:
table.delete(*table.get_children())

connector.execute('DELETE FROM ExpenseTracker')
connector.commit()

clear_fields()
list_all_expenses()
tb.showinfo('All Expenses deleted', 'All the expenses were successfully deleted')
else:
tb.showinfo('Ok then', 'The task was aborted and no expense was deleted!')

def add_another_expense():
global date, payee, Desc, amnt, MoP
global connector

if not date.get() or not payee.get() or not Desc.get() or not amnt.get() or not MoP.get():
tb.showerror('Fields empty!', "Please fill all the missing fields before pressing the add button!")
else:
connector.execute(
'INSERT INTO ExpenseTracker (Date, Payee, Description, Amount, ModeOfPayment) VALUES (?, ?, ?, ?, ?)',
(date.get_date(), payee.get(), Desc.get(), amnt.get(), MoP.get())
)
connector.commit()

clear_fields()
list_all_expenses()
tb.showinfo('Expense added', 'The expense whose details you just entered has been added to the database')

def expense_to_words_before_adding():
global date, Desc, amnt, payee, MoP

if not date or not Desc or not amnt or not payee or not MoP:
tb.showerror('Incomplete data', 'The data is incomplete, meaning fill all the fields first!')

message = f'Your expense can be read like: \n"You paid {amnt.get()} to {payee.get()} for {Desc.get()} on {date.get_date()} via {MoP.get()}"'

add_question = tb.askyesno('Read your record like: ', f'{message}\n\nShould I add it to the database?')

if add_question:
add_another_expense()
else:
tb.showinfo('Ok', 'Please take your time to add this record')

# Connecting to the Database
connector = sqlite3.connect("Expense Tracker.db")
cursor = connector.cursor()

connector.execute(
'CREATE TABLE IF NOT EXISTS ExpenseTracker (ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, Date DATETIME, Payee TEXT, Description TEXT, Amount FLOAT, ModeOfPayment TEXT)'
)
connector.commit()

# Backgrounds and Fonts
dataentery_frame_bg = 'light blue'
buttons_frame_bg = 'tomato'
hlb_btn_bg = 'Indianred'

lbl_font = ('Georgia', 13)
entry_font = 'Times 13 bold'
btn_font = ('Gill Sans MT', 13)

# Initializing the GUI window
root = Tk()
root.title('DebEx')
root.geometry('1200x550')
root.resizable(0, 0)

Label(root, text='DebEx', font=('white', 21, 'bold'), bg=hlb_btn_bg).pack(side=TOP, fill=X)

# StringVar and DoubleVar variables
Desc = StringVar()
amnt = DoubleVar()
payee = StringVar()
MoP = StringVar(value='Cash')

# Frames
data_entry_frame = Frame(root, bg=dataentery_frame_bg)
data_entry_frame.place(x=0, y=35, relheight=0.95, relwidth=0.25)

buttons_frame = Frame(root, bg=buttons_frame_bg)
buttons_frame.place(relx=0.25, rely=0.063, relwidth=0.75, relheight=0.12)

tree_frame = Frame(root)
tree_frame.place(relx=0.25, rely=0.18, relwidth=0.75, relheight=0.8)

# Data Entry Frame
Label(data_entry_frame, text='Date (M/DD/YY) :', font=lbl_font, bg=dataentery_frame_bg).place(x=10, y=50)
date = DateEntry(data_entry_frame, date=datetime.datetime.now().date(), font=entry_font)
date.place(x=160, y=50)

Label(data_entry_frame, text='Payee\t :', font=lbl_font, bg=dataentery_frame_bg).place(x=10, y=230)
Entry(data_entry_frame, font=entry_font, width=31, text=payee).place(x=10, y=260)

Label(data_entry_frame, text='Description :', font=lbl_font, bg=dataentery_frame_bg).place(x=10, y=100)
Entry(data_entry_frame, font=entry_font, width=31, text=Desc).place(x=10, y=130)

Label(data_entry_frame, text='Amount\t :', font=lbl_font, bg=dataentery_frame_bg).place(x=10, y=180)
Entry(data_entry_frame, font=entry_font, width=14, text=amnt).place(x=160, y=180)

Label(data_entry_frame, text='Mode of Payment:', font=lbl_font, bg=dataentery_frame_bg).place(x=10, y=310)
dd1 = OptionMenu(data_entry_frame, MoP, *['Cash', 'Cheque', 'Credit Card', 'Debit Card', 'Paytm', 'Google Pay', 'Razorpay'])
dd1.place(x=160, y=305) ; dd1.configure(width=10, font=entry_font)

Button(data_entry_frame, text='Add expense', command=add_another_expense, font=btn_font, width=30,
bg=hlb_btn_bg).place(x=10, y=395)

# Buttons' Frame
Button(buttons_frame, text='Delete Expense', font=btn_font, width=25, bg=hlb_btn_bg, command=remove_expense).place(x=30, y=5)

Button(buttons_frame, text='Clear Fields in DataEntry Frame', font=btn_font, width=25, bg=hlb_btn_bg,
command=clear_fields).place(x=335, y=5)

Button(buttons_frame, text='Delete All Expenses', font=btn_font, width=25, bg=hlb_btn_bg, command=remove_all_expenses).place(x=640, y=5)

# Treeview Frame
table = ttk.Treeview(tree_frame, selectmode=BROWSE, columns=('ID', 'Date', 'Payee', 'Description', 'Amount', 'Mode of Payment'))

X_Scroller = Scrollbar(table, orient=HORIZONTAL, command=table.xview)
Y_Scroller = Scrollbar(table, orient=VERTICAL, command=table.yview)
X_Scroller.pack(side=BOTTOM, fill=X)
Y_Scroller.pack(side=RIGHT, fill=Y)

table.config(yscrollcommand=Y_Scroller.set, xscrollcommand=X_Scroller.set)

table.heading('ID', text='S No.', anchor=CENTER)
table.heading('Date', text='Date', anchor=CENTER)
table.heading('Payee', text='Payee', anchor=CENTER)
table.heading('Description', text='Description', anchor=CENTER)
table.heading('Amount', text='Amount', anchor=CENTER)
table.heading('Mode of Payment', text='Mode of Payment', anchor=CENTER)

table.column('#0', width=0, stretch=NO)
table.column('#1', width=50, stretch=NO)
table.column('#2', width=95, stretch=NO) # Date column
table.column('#3', width=150, stretch=NO) # Payee column
table.column('#4', width=325, stretch=NO) # Title column
table.column('#5', width=135, stretch=NO) # Amount column
table.column('#6', width=125, stretch=NO) # Mode of Payment column

table.place(relx=0, y=0, relheight=1, relwidth=1)

list_all_expenses()
# Finalizing the GUI window
root.update()
root.mainloop()
6 changes: 4 additions & 2 deletions Expense Tracker/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
csv
os
datetime
sqlite3
tkcalendar
tkinter

0 comments on commit f9cfa25

Please sign in to comment.