Skip to content

Commit f9cfa25

Browse files
authored
Updated expense tracker (DhanushNehru#369)
* Update requirements.txt Update the requirements of LinkedIn Bot * Updated Expense Tracker with GUI and extra features
1 parent 164d09c commit f9cfa25

File tree

3 files changed

+186
-40
lines changed

3 files changed

+186
-40
lines changed

Expense Tracker/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Install the required dependencies using pip:
77
```
88
pip install -r requirements.txt
99
```
10+
or you can manually install single Library
1011

1112
Run the expense.py file to start the bot:
1213

Expense Tracker/expense.py

+181-38
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,193 @@
1-
import csv
2-
import os
1+
import datetime
2+
import sqlite3
3+
from tkcalendar import DateEntry
4+
from tkinter import *
5+
import tkinter.messagebox as tb
6+
import tkinter.ttk as ttk
37

4-
CSV_FILE = "expenses.csv"
8+
# Functions
9+
def list_all_expenses():
10+
global connector, table
511

6-
def initialize_csv():
7-
if not os.path.exists(CSV_FILE):
8-
with open(CSV_FILE, "w", newline="") as file:
9-
writer = csv.writer(file)
10-
writer.writerow(["Date", "Description", "Amount"])
12+
table.delete(*table.get_children())
1113

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

17-
def view_expenses():
18-
with open(CSV_FILE, "r") as file:
19-
reader = csv.reader(file)
20-
for row in reader:
21-
print(", ".join(row))
17+
for values in data:
18+
table.insert('', END, values=values)
2219

23-
if __name__ == "__main__":
24-
initialize_csv()
20+
def clear_fields():
21+
global Desc, payee, amnt, MoP, date, table
2522

26-
while True:
27-
print("\nExpense Tracker Menu:")
28-
print("1. Add Expense")
29-
print("2. View Expenses")
30-
print("3. Exit")
23+
today_date = datetime.datetime.now().date()
3124

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

34-
if choice == "1":
35-
date = input("Enter the date (YYYY-MM-DD): ")
36-
description = input("Enter the description: ")
37-
amount = input("Enter the amount: ")
28+
def remove_expense():
29+
if not table.selection():
30+
tb.showerror('No record selected!', 'Please select a record to delete!')
31+
return
3832

39-
add_expense(date, description, amount)
40-
print("Expense added successfully!")
33+
current_selected_expense = table.item(table.focus())
34+
values_selected = current_selected_expense['values']
4135

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

46-
elif choice == "3":
47-
break
38+
if surety:
39+
connector.execute('DELETE FROM ExpenseTracker WHERE ID=%d' % values_selected[0])
40+
connector.commit()
4841

49-
else:
50-
print("Invalid choice. Please try again.")
42+
list_all_expenses()
43+
tb.showinfo('Record deleted successfully!', 'The record you wanted to delete has been deleted successfully')
44+
45+
def remove_all_expenses():
46+
surety = tb.askyesno('Are you sure?', 'Are you sure that you want to delete all the expense items from the database?', icon='warning')
47+
48+
if surety:
49+
table.delete(*table.get_children())
50+
51+
connector.execute('DELETE FROM ExpenseTracker')
52+
connector.commit()
53+
54+
clear_fields()
55+
list_all_expenses()
56+
tb.showinfo('All Expenses deleted', 'All the expenses were successfully deleted')
57+
else:
58+
tb.showinfo('Ok then', 'The task was aborted and no expense was deleted!')
59+
60+
def add_another_expense():
61+
global date, payee, Desc, amnt, MoP
62+
global connector
63+
64+
if not date.get() or not payee.get() or not Desc.get() or not amnt.get() or not MoP.get():
65+
tb.showerror('Fields empty!', "Please fill all the missing fields before pressing the add button!")
66+
else:
67+
connector.execute(
68+
'INSERT INTO ExpenseTracker (Date, Payee, Description, Amount, ModeOfPayment) VALUES (?, ?, ?, ?, ?)',
69+
(date.get_date(), payee.get(), Desc.get(), amnt.get(), MoP.get())
70+
)
71+
connector.commit()
72+
73+
clear_fields()
74+
list_all_expenses()
75+
tb.showinfo('Expense added', 'The expense whose details you just entered has been added to the database')
76+
77+
def expense_to_words_before_adding():
78+
global date, Desc, amnt, payee, MoP
79+
80+
if not date or not Desc or not amnt or not payee or not MoP:
81+
tb.showerror('Incomplete data', 'The data is incomplete, meaning fill all the fields first!')
82+
83+
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()}"'
84+
85+
add_question = tb.askyesno('Read your record like: ', f'{message}\n\nShould I add it to the database?')
86+
87+
if add_question:
88+
add_another_expense()
89+
else:
90+
tb.showinfo('Ok', 'Please take your time to add this record')
91+
92+
# Connecting to the Database
93+
connector = sqlite3.connect("Expense Tracker.db")
94+
cursor = connector.cursor()
95+
96+
connector.execute(
97+
'CREATE TABLE IF NOT EXISTS ExpenseTracker (ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, Date DATETIME, Payee TEXT, Description TEXT, Amount FLOAT, ModeOfPayment TEXT)'
98+
)
99+
connector.commit()
100+
101+
# Backgrounds and Fonts
102+
dataentery_frame_bg = 'light blue'
103+
buttons_frame_bg = 'tomato'
104+
hlb_btn_bg = 'Indianred'
105+
106+
lbl_font = ('Georgia', 13)
107+
entry_font = 'Times 13 bold'
108+
btn_font = ('Gill Sans MT', 13)
109+
110+
# Initializing the GUI window
111+
root = Tk()
112+
root.title('DebEx')
113+
root.geometry('1200x550')
114+
root.resizable(0, 0)
115+
116+
Label(root, text='DebEx', font=('white', 21, 'bold'), bg=hlb_btn_bg).pack(side=TOP, fill=X)
117+
118+
# StringVar and DoubleVar variables
119+
Desc = StringVar()
120+
amnt = DoubleVar()
121+
payee = StringVar()
122+
MoP = StringVar(value='Cash')
123+
124+
# Frames
125+
data_entry_frame = Frame(root, bg=dataentery_frame_bg)
126+
data_entry_frame.place(x=0, y=35, relheight=0.95, relwidth=0.25)
127+
128+
buttons_frame = Frame(root, bg=buttons_frame_bg)
129+
buttons_frame.place(relx=0.25, rely=0.063, relwidth=0.75, relheight=0.12)
130+
131+
tree_frame = Frame(root)
132+
tree_frame.place(relx=0.25, rely=0.18, relwidth=0.75, relheight=0.8)
133+
134+
# Data Entry Frame
135+
Label(data_entry_frame, text='Date (M/DD/YY) :', font=lbl_font, bg=dataentery_frame_bg).place(x=10, y=50)
136+
date = DateEntry(data_entry_frame, date=datetime.datetime.now().date(), font=entry_font)
137+
date.place(x=160, y=50)
138+
139+
Label(data_entry_frame, text='Payee\t :', font=lbl_font, bg=dataentery_frame_bg).place(x=10, y=230)
140+
Entry(data_entry_frame, font=entry_font, width=31, text=payee).place(x=10, y=260)
141+
142+
Label(data_entry_frame, text='Description :', font=lbl_font, bg=dataentery_frame_bg).place(x=10, y=100)
143+
Entry(data_entry_frame, font=entry_font, width=31, text=Desc).place(x=10, y=130)
144+
145+
Label(data_entry_frame, text='Amount\t :', font=lbl_font, bg=dataentery_frame_bg).place(x=10, y=180)
146+
Entry(data_entry_frame, font=entry_font, width=14, text=amnt).place(x=160, y=180)
147+
148+
Label(data_entry_frame, text='Mode of Payment:', font=lbl_font, bg=dataentery_frame_bg).place(x=10, y=310)
149+
dd1 = OptionMenu(data_entry_frame, MoP, *['Cash', 'Cheque', 'Credit Card', 'Debit Card', 'Paytm', 'Google Pay', 'Razorpay'])
150+
dd1.place(x=160, y=305) ; dd1.configure(width=10, font=entry_font)
151+
152+
Button(data_entry_frame, text='Add expense', command=add_another_expense, font=btn_font, width=30,
153+
bg=hlb_btn_bg).place(x=10, y=395)
154+
155+
# Buttons' Frame
156+
Button(buttons_frame, text='Delete Expense', font=btn_font, width=25, bg=hlb_btn_bg, command=remove_expense).place(x=30, y=5)
157+
158+
Button(buttons_frame, text='Clear Fields in DataEntry Frame', font=btn_font, width=25, bg=hlb_btn_bg,
159+
command=clear_fields).place(x=335, y=5)
160+
161+
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)
162+
163+
# Treeview Frame
164+
table = ttk.Treeview(tree_frame, selectmode=BROWSE, columns=('ID', 'Date', 'Payee', 'Description', 'Amount', 'Mode of Payment'))
165+
166+
X_Scroller = Scrollbar(table, orient=HORIZONTAL, command=table.xview)
167+
Y_Scroller = Scrollbar(table, orient=VERTICAL, command=table.yview)
168+
X_Scroller.pack(side=BOTTOM, fill=X)
169+
Y_Scroller.pack(side=RIGHT, fill=Y)
170+
171+
table.config(yscrollcommand=Y_Scroller.set, xscrollcommand=X_Scroller.set)
172+
173+
table.heading('ID', text='S No.', anchor=CENTER)
174+
table.heading('Date', text='Date', anchor=CENTER)
175+
table.heading('Payee', text='Payee', anchor=CENTER)
176+
table.heading('Description', text='Description', anchor=CENTER)
177+
table.heading('Amount', text='Amount', anchor=CENTER)
178+
table.heading('Mode of Payment', text='Mode of Payment', anchor=CENTER)
179+
180+
table.column('#0', width=0, stretch=NO)
181+
table.column('#1', width=50, stretch=NO)
182+
table.column('#2', width=95, stretch=NO) # Date column
183+
table.column('#3', width=150, stretch=NO) # Payee column
184+
table.column('#4', width=325, stretch=NO) # Title column
185+
table.column('#5', width=135, stretch=NO) # Amount column
186+
table.column('#6', width=125, stretch=NO) # Mode of Payment column
187+
188+
table.place(relx=0, y=0, relheight=1, relwidth=1)
189+
190+
list_all_expenses()
191+
# Finalizing the GUI window
192+
root.update()
193+
root.mainloop()

Expense Tracker/requirements.txt

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
csv
2-
os
1+
datetime
2+
sqlite3
3+
tkcalendar
4+
tkinter

0 commit comments

Comments
 (0)