Expense Tracker

import datetime

import sqlite3

from tkcalendar import DateEntry

from tkinter import *

import tkinter.messagebox as mb

import tkinter.ttk as ttk

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()

def list_all_expenses():

global connector, table

table.delete(*table.get_children())

all_data = connector.execute('SELECT * FROM ExpenseTracker')

data = all_data.fetchall()

for values in data:

table.insert('', END, values=values)

def view_expense_details():

global table

global date, payee, desc, amnt, MoP

if not table.selection():

mb.showerror('No expense selected', 'Please select an expense from the table to view its details')

current_selected_expense = table.item(table.focus())

values = current_selected_expense['values']

expenditure_date = datetime.date(int(values[1][:4]), int(values[1][5:7]), int(values[1][8:]))

date.set_date(expenditure_date) ; payee.set(values[2]) ; desc.set(values[3]) ; amnt.set(values[4]) ; MoP.set(values[5])

def clear_fields():

global desc, payee, amnt, MoP, date, table

today_date = datetime.datetime.now().date()

desc.set('') ; payee.set('') ; amnt.set(0.0) ; MoP.set('Cash'), date.set_date(today_date)

table.selection_remove(*table.selection())

def remove_expense():

if not table.selection():

mb.showerror('No record selected!', 'Please select a record to delete!')

return

current_selected_expense = table.item(table.focus())

values_selected = current_selected_expense['values']

surety = mb.askyesno('Are you sure?', f'Are you sure that you want to delete the record of {values_selected[2]}')

if surety:

connector.execute('DELETE FROM ExpenseTracker WHERE ID=%d' % values_selected[0])

connector.commit()

list_all_expenses()

mb.showinfo('Record deleted successfully!', 'The record you wanted to delete has been deleted successfully')

def remove_all_expenses():

surety = mb.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()

mb.showinfo('All Expenses deleted', 'All the expenses were successfully deleted')

else:

mb.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():

mb.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()

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

def edit_expense():

global table


def edit_existing_expense():

global date, amnt, desc, payee, MoP

global connector, table

current_selected_expense = table.item(table.focus())

contents = current_selected_expense['values']


connector.execute('UPDATE ExpenseTracker SET Date = ?, Payee = ?, Description = ?, Amount = ?, ModeOfPayment = ? WHERE ID = ?',

                  (date.get_date(), payee.get(), desc.get(), amnt.get(), MoP.get(), contents[0]))

connector.commit()

clear_fields()

list_all_expenses()

mb.showinfo('Data edited', 'We have updated the data and stored in the database as you wanted')

edit_btn.destroy()

return

if not table.selection():

mb.showerror('No expense selected!', 'You have not selected any expense in the table for us to edit; please do that!')

return

view_expense_details()

edit_btn = Button(data_entry_frame, text='Edit expense', font=btn_font, width=30,

                  bg=hlb_btn_bg, command=edit_existing_expense)

edit_btn.place(x=10, y=395)

def selected_expense_to_words():

global table

if not table.selection():

mb.showerror('No expense selected!', 'Please select an expense from the table for us to read')

return

current_selected_expense = table.item(table.focus())

values = current_selected_expense['values']

message = f'Your expense can be read like: \n"You paid {values[4]} to {values[2]} for {values[3]} on {values[1]} via {values[5]}"'

mb.showinfo('Here\'s how to read your expense', message)

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:

mb.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 = mb.askyesno('Read your record like: ', f'{message}\n\nShould I add it to the database?')

if add_question:

add_another_expense()

else:

mb.showinfo('Ok', 'Please take your time to add this record')

dataentery_frame_bg = 'light blue'

buttons_frame_bg = 'light blue'

hlb_btn_bg = 'light pink'

lbl_font = ('Georgia', 13)

entry_font = 'Times 13 bold'

btn_font = ('Gill Sans MT', 13)

root = Tk()

root.title('Expense Tracker')

root.geometry('1200x550')

root.resizable(0, 0)

Label(root, text='EXPENSE TRACKER', font=('Noto Sans CJK TC', 15, 'bold'), bg=hlb_btn_bg).pack(side=TOP, fill=X)

desc = StringVar()

amnt = DoubleVar()

payee = StringVar()

MoP = StringVar(value='Cash')

data_entry_frame = Frame(root, bg=dataentery_frame_bg)

data_entry_frame.place(x=0, y=30, relheight=0.95, relwidth=0.25)

buttons_frame = Frame(root, bg=buttons_frame_bg)

buttons_frame.place(relx=0.25, rely=0.05, relwidth=0.75, relheight=0.21)

tree_frame = Frame(root)

tree_frame.place(relx=0.25, rely=0.26, relwidth=0.75, relheight=0.74)

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'])

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)

Button(data_entry_frame, text='Convert to words before adding', font=btn_font, width=30, bg=hlb_btn_bg).place(x=10,y=450)

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)

Button(buttons_frame, text='View Selected Expense\'s Details', font=btn_font, width=25, bg=hlb_btn_bg,

       command=view_expense_details).place(x=30, y=65)

Button(buttons_frame, text='Edit Selected Expense', command=edit_expense, font=btn_font, width=25, bg=hlb_btn_bg).place(x=335,y=65)

Button(buttons_frame, text='Convert Expense to a sentence', font=btn_font, width=25, bg=hlb_btn_bg,

       command=selected_expense_to_words).place(x=640, y=65)

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()

root.update()

root.mainloop()

No comments: