Final Report File
Final Report File
A PROJECT REPORT
Submitted in Partial Fulfillment of the Requirements for the Award of the Degree of
Bachelor of Technology
in
ON
Submitted By
KADAMBARI [2401020035]
i
Academic Session: 2025 – 2026
CANDIDATE'S DECLARATION
Have been carried out by me in partial fulfillment of the requirements for the award of
the degree of Bachelor of Technology under the supervision of [VYOM
KULSHRESHTRA], Department of Computer Science & Engineering, Sharda
University.
• This project is an authentic record of my own work and has not been
submitted elsewhere for the award of any other degree or diploma.
• All sources of information and references used in this project have been duly
acknowledged.
• The work presented herein is original, and wherever ideas or passages have
been taken from other sources, they have been duly cited.
ii
ACKNOWLEDGEMENTS
I would like to express my sincere gratitude to all those who contributed to the
successful completion of this project.
I extend my heartfelt thanks to the Head of the Department of Computer Science &
Engineering, Sharda University, for providing all the necessary facilities and a
conducive environment for research and development.
I am also grateful to all the faculty members of the Department of Computer Science &
Engineering for their academic support and for imparting knowledge that laid the
foundation for this project.
Special thanks are due to my family and friends whose moral support and
encouragement kept me motivated throughout the course of this project.
Finally, I acknowledge the open-source Python community and the developers of the
tkinter, json, and calendar libraries whose tools made this project possible.
ABSTRACT
iii
In today's fast-paced world, managing personal and household finances has become
increasingly challenging. A large segment of the population struggles to keep track of
daily expenditures, often leading to budget overruns and financial mismanagement.
Existing financial management applications are either too complex for everyday users
or lack the flexibility required for household-level tracking.
This project presents the design and implementation of a Daily Household Expense
Tracker — a desktop application developed using Python and its built-in tkinter GUI
framework. The application provides an intuitive graphical interface that enables users
to record, organize, and analyze their day-to-day household expenses with ease.
Key features of the system include a real-time Purchase Log that displays all
transactions in a sortable tabular format, the ability to delete individual entries or clear
all records, and a comprehensive Monthly Report module. The reporting module
generates category-wise expense summaries with subtotals, grand totals, and visual
percentage bar charts for each spending category. Reports can be exported as formatted
text files for offline reference.
The sidebar provides at-a-glance monthly totals and purchase counts, updating
dynamically as expenses are added or removed. Toast notifications provide immediate
user feedback for all actions. Data is stored persistently in a human-readable JSON file,
ensuring that records are preserved across sessions without the need for a database
server.
iv
home users who require a simple, lightweight, and offline-capable solution for
household budget management.
TABLE OF CONTENTS
Candidate's Declaration i
Certificate by Supervisor ii
Acknowledgements iii
Abstract iv
Table of Contents v
List of Figures vi
Chapter 1 – Introduction 1
1.1 Background 1
1.3 Objectives 2
2.1 Introduction 3
v
2.5 Category-Based Expense Analysis 4
5.1 Conclusion 12
5.3 Summary 13
References 14
LIST OF FIGURES
vi
LIST OF ABBREVIATIONS
UI User Interface
UX User Experience
vii
CHAPTER 1
Introduction
1.1 Background
Financial literacy and effective personal budgeting are critical life skills, yet the tools
available for everyday household expense management are often either overly complex
or lack the granularity needed for meaningful analysis. Smartphones and cloud-based
applications have introduced convenience but frequently require internet connectivity,
user accounts, and subscription fees — barriers that exclude a significant portion of
users.
Desktop-based, offline applications that are lightweight and easy to use fill this gap
effectively. Python, with its rich standard library including the tkinter module for GUI
development, provides an ideal platform for building such tools. This project leverages
Python to create a feature-rich, offline, and user-friendly Daily Household Expense
Tracker.
Many households in India and globally lack a structured mechanism to track daily
expenditures. The absence of a simple, category-organized tool means that users have
no clear picture of where their money is spent, making it difficult to plan budgets or
identify areas of overspending. This project addresses the following specific problems:
• Lack of a lightweight, offline solution that does not require cloud storage or
subscriptions.
1
1.3 Objectives
3. To provide a real-time Purchase Log with features to add, view, and delete
expense entries.
5. To allow users to add custom items and permanently extend the product
register.
6. To persist all expense data locally using JSON file storage, ensuring data
survives across sessions.
2
• Chapter 4 covers the implementation details and presents the results.
3
CHAPTER 2
Literature Review
4
2.1 Introduction
This chapter reviews existing work related to personal finance management systems,
expense tracking applications, and GUI-based Python tools. It identifies the gaps
addressed by this project and justifies the design decisions made.
A variety of commercial and open-source tools exist for personal finance management.
Applications such as Mint, YNAB (You Need A Budget), and Money Manager EX are
widely used globally. These tools offer cloud synchronization, bank account
integration, and advanced analytics. However, they are primarily designed for Western
financial ecosystems and require internet connectivity, user accounts, and in many
cases, subscription fees [1].
Studies by Bhavnani et al. (2020) [2] indicate that the majority of rural and semi-urban
Indian households prefer lightweight, offline financial tools that work without internet
connectivity. This reinforces the need for a locally-hosted, simple-to-use application.
Python is consistently ranked among the top programming languages for educational
and utility application development. Its tkinter module, part of the standard library,
provides a cross-platform toolkit for building graphical user interfaces without any
third-party dependencies [3].
For applications that do not require complex relational queries, JSON file-based data
storage is a widely accepted pattern. JSON provides human-readable, easily parseable
data storage that integrates natively with Python through the built-in json module [5].
5
This approach is particularly appropriate for applications with a small to moderate data
volume, such as household expense records.
• Python-based desktop tools in this domain typically lack a polished GUI and
export functionality.
This project directly addresses these gaps through an offline, GUI-rich, category-
organized expense tracker with report export capability.
CHAPTER 3
6
that manages the entire GUI and user interaction logic. The application launches a
1200×780 pixel window centered on the screen.
The system organizes all expenses into the following categories, each pre-loaded with
common household items:
• Groceries — staple food items such as rice, flour, lentils, sugar, and oil.
7
• Beverages — tea, coffee, cold drinks, and juices.
10. User selects an item (or enters a custom item), sets quantity, and clicks Add.
11. The DataManager appends the expense record (category, name, price,
quantity, total, timestamp) to the JSON data file.
12. The sidebar totals and Purchase Log are updated in real time.
13. The Report module reads the JSON data, filters by selected month/year,
groups by category, and generates the formatted report.
Each expense record stored in the JSON file contains the following fields:
8
The application is organized into the following functional modules:
• Log Module: Renders all expense records in a [Link] table with columns
for Date, Category, Item, Quantity, Unit Price, and Total. Supports row
deletion and full data clear.
• Sidebar Module: Shows real-time monthly spending total and purchase count.
Updates dynamically after every add or delete operation.
CHAPTER 4
9
4.1 Implementation Environment
The application consists of a single Python script containing all classes, constants, and
entry point logic. The key components and their implementation are described below.
The DataManager class is instantiated at application startup. It loads the existing JSON
data file (or creates a new one if none exists) and exposes the following methods:
The ExpenseTracker class manages the complete GUI lifecycle. It initializes the root
window, builds the sidebar navigation, and instantiates three page frames (Shop, Log,
10
Report). The navigation system highlights the active page button and switches frames
using pack/pack_forget. Key methods include:
• _load_category(cat): Populates the Shop page with product cards for the
selected category.
• _refresh_log(): Clears and repopulates the Treeview table with all current
expense records.
11
Quantity Selector Spinbox widget bound to qty_var IntVar; validated between 1 and
99
Real-time Sidebar _update_sidebar() called after every add/delete; reads live month
Totals expenses
Purchase Log [Link] with alternating row shading; supports single-row
Treeview deletion
Monthly Report Grouped by category using defaultdict; ASCII bar chart scaled to
percentage
TXT Export Writes formatted lines to Expense_Report_Month_Year.txt in
working directory
Toast Notifications Borderless Toplevel window, auto-destroyed after 1800 ms
Custom Item Stored under custom_products key in JSON; reloaded on next
Persistence session
• Adding items from all seven categories — verified that records appear
correctly in the Purchase Log with accurate date, category, quantity, unit price,
and total.
• Register item addition — confirmed items appear in the product card grid on
next category load.
• Entry deletion — confirmed individual row deletion and Clear All correctly
remove records from the JSON file.
• Monthly report — verified correct grouping, subtotals, grand totals, and bar
chart percentages for months with mixed category data.
• TXT export — confirmed the generated file matches the on-screen report
content.
12
4.4.2 Sample Report Output
A sample monthly report generated by the system for a test month (April 2025) is shown
below. The report demonstrates category-wise grouping, item-level detail, subtotals,
and the grand total summary.
4.4.3 Performance
CHAPTER 5
5.1 Conclusion
13
addressing the specific needs of everyday users who require an offline, lightweight, and
organized expense tracking tool.
The system achieves all stated objectives: it organizes expenses into seven meaningful
categories, provides a real-time purchase log with deletion capabilities, generates
detailed category-wise monthly reports with visual spending breakdowns, supports
custom item entry and register extension, and persists all data locally using JSON
storage. The export feature further extends its utility by allowing users to archive
monthly reports as text files.
The project validates the practical applicability of Python's standard library for building
production-quality desktop applications without any external dependencies, making it
readily deployable across Windows, macOS, and Linux platforms.
• Budget Limits: Allow users to set monthly spending limits per category with
visual alerts when approaching or exceeding the budget.
• Search and Filter: Implement a search bar in the Purchase Log to filter records
by date range, category, item name, or amount.
14
• Voice Input: Integrate speech recognition to allow hands-free expense entry.
5.3 Summary
REFERENCES
[1] Intuit Inc., "Mint – Personal Finance & Money," [Online]. Available:
[Link] [Accessed: 01 Apr. 2025].
[2] A. Bhavnani, R. Chiu, S. Janakiram, and P. Silarszky, "The Role of Mobile Phones
in Sustainable Rural Poverty Reduction," World Bank ICT Sector Unit Report, 2020.
[3] Python Software Foundation, "tkinter — Python interface to Tcl/Tk," Python 3.11
Documentation, [Online]. Available: [Link]
[Accessed: 01 Apr. 2025].
[5] Python Software Foundation, "json — JSON encoder and decoder," Python 3.11
Documentation, [Online]. Available: [Link]
[Accessed: 01 Apr. 2025].
15
[8] F. Lundh, "An Introduction to Tkinter," PythonWare, [Online]. Available:
[Link] [Accessed: 01 Apr. 2025].
APPENDIX A
The complete source code of the Daily Household Expense Tracker is provided below.
The application is contained in a single Python script (expense_tracker.py) and requires
only Python 3.x with no third-party packages.
"""
Daily Household Expense Tracker
A GUI-based personal finance management system built with Python and tkinter.
"""
import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import datetime
import json
import os
import calendar
from collections import defaultdict
16
("Ginger", 100), ("Spinach", 20), ("Cauliflower", 30),
("Banana", 50), ("Apple", 120), ("Mango", 80),
],
"Dairy & Eggs": [
("Milk (1L)", 25), ("Curd (500g)", 30), ("Butter (100g)", 55),
("Paneer (200g)", 80), ("Cheese Slice", 120), ("Eggs (12)", 90),
],
"Beverages": [
("Tea (250g)", 120), ("Coffee (100g)", 90), ("Cold Drink (2L)", 80),
("Juice Pack", 60), ("Mineral Water", 20), ("Lassi (500ml)", 40),
],
"Household Supplies": [
("Detergent Powder", 120), ("Dish Soap", 40), ("Floor Cleaner", 80),
("Toilet Cleaner", 60), ("Broom", 80), ("Mop", 150),
("Trash Bags", 50), ("Tissue Box", 45),
],
"Personal Care": [
("Shampoo", 180), ("Soap (3-pack)", 90), ("Toothpaste", 60),
("Toothbrush", 40), ("Moisturizer", 200), ("Deo/Perfume", 150),
("Sanitary Pads", 90), ("Razor", 50),
],
"Utilities & Bills": [
("Electricity Bill", 0), ("Water Bill", 0), ("Internet Bill", 0),
("Gas Cylinder", 900), ("Mobile Recharge", 0), ("DTH Recharge", 0),
],
}
DATA_FILE = "expenses_data.json"
def _load(self):
if [Link](DATA_FILE):
try:
with open(DATA_FILE, "r", encoding="utf-8") as f:
return [Link](f)
except Exception:
pass
return {"expenses": [], "custom_products": {}}
def save(self):
with open(DATA_FILE, "w", encoding="utf-8") as f:
[Link]([Link], f, indent=2, ensure_ascii=False)
17
"category": category,
"name": name,
"price": price,
"qty": qty,
"total": round(price * qty, 2),
"date": [Link]().isoformat(sep=" ", timespec="seconds")
}
[Link]["expenses"].append(record)
[Link]()
def get_all_expenses(self):
return [Link]["expenses"]
def _build_ui(self):
# ── Sidebar ────────────────────────────────────────────
sidebar = [Link]([Link], bg=SIDEBAR_BG, width=200)
[Link](side="left", fill="y")
sidebar.pack_propagate(False)
[Link](sidebar, text="Expense\nTracker",
font=("Georgia", 16, "bold"),
bg=SIDEBAR_BG, fg=TEXT_LIGHT,
justify="center").pack(pady=(28, 4))
18
[Link](fill="x", padx=16, pady=(0, 16))
self.nav_btns = {}
nav_items = [("Shop", self._show_shop),
("Log", self._show_log),
("Report", self._show_report)]
labels = ["Shop", "Log", "Report"]
emojis = ["Shopping", "Purchase Log", "Monthly Report"]
nav_data = [
("Shop", "Shop", self._show_shop),
("Log", "Log", self._show_log),
("Report", "Report", self._show_report),
]
nav_labels = {
"Shop": "Shopping",
"Log": "Purchase Log",
"Report": "Monthly Report",
}
nav_emojis = {
"Shop": "Cart",
"Log": "Log",
"Report": "Chart",
}
b = [Link](sidebar, text=display,
font=("Segoe UI", 10),
bg=SIDEBAR_BG, fg="#a0aabf",
relief="flat", bd=0,
padx=20, pady=10,
anchor="w", cursor="hand2",
command=cmd)
[Link](fill="x", pady=2)
self.nav_btns[nav_key] = b
self.nav_btns["active"] = self.nav_btns["Shop"]
19
self.page_log = [Link](content, bg=BG)
self.page_report = [Link](content, bg=BG)
self._build_shop_page()
self._build_log_page()
self._build_report_page()
self._show_shop()
self._update_sidebar()
# Top bar
top = [Link](p, bg=BG)
[Link](fill="x", padx=20, pady=(18, 8))
# Quantity selector
qty_frame = [Link](top, bg=BG)
qty_frame.pack(side="right")
[Link](qty_frame, text="Qty:",
font=("Segoe UI", 10), bg=BG, fg=TEXT_MID).pack(side="left")
[Link](qty_frame, from_=1, to=99,
textvariable=self.qty_var,
font=("Segoe UI", 10), width=4,
bg=CARD_BG, fg=TEXT_DARK,
relief="flat", bd=0,
highlightthickness=1,
highlightbackground=BORDER).pack(side="left", padx=(4, 12))
# Category tabs
cat_bar = [Link](p, bg=SIDEBAR_BG)
cat_bar.pack(fill="x")
self.cat_btns = {}
for cat in CATEGORIES:
short = [Link](" ", 1)[-1][:10]
20
b = [Link](cat_inner, text=short,
font=("Segoe UI", 8),
bg=SIDEBAR_BG, fg="#a0aabf",
relief="flat", bd=0,
padx=8, pady=4, cursor="hand2",
command=lambda c=cat: self._load_category(c))
[Link](side="left", padx=3)
self.cat_btns[cat] = b
def _on_resize(e):
[Link](self.card_win, width=[Link])
[Link]("<Configure>", _on_resize)
def _on_frame_configure(e):
[Link](scrollregion=[Link]("all"))
self.card_frame.bind("<Configure>", _on_frame_configure)
self._canvas = canvas
self._load_category(list([Link]())[0])
# Clear cards
for w in self.card_frame.winfo_children():
[Link]()
[Link](card, text=name,
21
font=("Segoe UI", 10, "bold"),
bg=CARD_BG, fg=TEXT_DARK,
wraplength=140).pack(pady=(14, 4), padx=10)
[Link](card, text="Add",
font=("Segoe UI", 9, "bold"),
bg=ACCENT2, fg=TEXT_LIGHT,
relief="flat", bd=0,
padx=16, pady=5, cursor="hand2",
command=lambda n=name, pr=price: self._add_item(n, pr)
).pack(pady=(8, 14))
def _add_custom_item(self):
name = [Link]("Custom Item", "Item name:")
if not name:
return
price = [Link]("Custom Item", f"Price of '{name}' (Rs.):",
minvalue=0, maxvalue=99999)
if price is None:
return
cat = self.selected_cat.get()
qty = self.qty_var.get()
[Link].add_expense(cat, name, round(price, 2), qty)
self._toast(f"Added custom: {name}")
self._refresh_log()
self._update_sidebar()
def _add_item_to_register(self):
"""Permanently add a new product card into a category in the register."""
dialog = [Link]([Link])
[Link]("Add Item to Register")
[Link](bg=BG)
[Link](False, False)
dialog.grab_set()
dialog.update_idletasks()
22
dw, dh = 400, 310
rx = [Link].winfo_x() + ([Link].winfo_width() - dw) // 2
ry = [Link].winfo_y() + ([Link].winfo_height() - dh) // 2
[Link](f"{dw}x{dh}+{rx}+{ry}")
def lbl(text):
[Link](form, text=text, font=("Segoe UI", 9),
bg=BG, fg=TEXT_MID, anchor="w").pack(fill="x", pady=(8, 2))
lbl("Item Name")
name_var = [Link]()
[Link](form, textvariable=name_var,
font=("Segoe UI", 10), bg=CARD_BG, fg=TEXT_DARK,
relief="flat", bd=0,
highlightthickness=1, highlightbackground=BORDER,
highlightcolor=ACCENT).pack(fill="x", ipady=5)
lbl("Category")
cat_var = [Link](value=self.selected_cat.get())
cat_cb = [Link](form, textvariable=cat_var,
values=list([Link]()),
state="readonly", font=("Segoe UI", 10))
cat_cb.pack(fill="x")
def confirm():
name = name_var.get().strip()
cat = cat_var.get()
if not name:
[Link]("Missing Name",
"Please enter an item name.", parent=dialog)
return
try:
price = float(price_var.get())
if price < 0:
raise ValueError
except ValueError:
[Link]("Invalid Price",
"Enter a valid price (>= 0).", parent=dialog)
return
23
CATEGORIES[cat].append((name, int(price) if price == int(price) else
price))
cp = [Link]("custom_products", {})
[Link](cat, [])
if (name, price) not in cp[cat]:
cp[cat].append((name, price))
[Link]()
[Link]()
if cat == self.selected_cat.get():
self._load_category(cat)
self._toast(f"'{name}' added to {[Link](' ', 1)[-1]}")
[Link](btn_row, text="Cancel",
font=("Segoe UI", 9),
bg=CARD_BG, fg=TEXT_MID,
relief="flat", bd=0, padx=16, pady=7, cursor="hand2",
command=[Link]).pack(side="left", padx=6)
24
fieldbackground=CARD_BG, rowheight=30,
font=("Segoe UI", 9))
[Link]("[Link]",
background=SIDEBAR_BG, foreground=TEXT_LIGHT,
font=("Segoe UI", 9, "bold"), relief="flat")
[Link]("[Link]",
background=[("selected", ACCENT)],
foreground=[("selected", TEXT_LIGHT)])
def _refresh_log(self):
if not hasattr(self, 'tree'):
return
for row in [Link].get_children():
[Link](row)
expenses = [Link].get_all_expenses()
for i, e in enumerate(reversed(expenses)):
date_str = e["date"][:16]
tag = "odd" if i % 2 == 0 else "even"
[Link]("", "end", iid=str(i),
values=(date_str, e["category"].split(" ", 1)[-1],
e["name"], e["qty"],
f"Rs.{e['price']:.0f}",
f"Rs.{e['total']:.0f}"),
tags=(tag,))
[Link].tag_configure("odd", background="#fafafa")
[Link].tag_configure("even", background=CARD_BG)
self._update_sidebar()
def _delete_selected(self):
sel = [Link]()
if not sel:
[Link]("Select Entry", "Click on a row to select it first.")
return
idx = int(sel[0])
total_entries = len([Link].get_all_expenses())
25
real_idx = total_entries - 1 - idx
if [Link]("Confirm", "Delete this entry?"):
[Link].delete_expense(real_idx)
self._refresh_log()
def _clear_all(self):
if [Link]("Clear All", "Delete ALL expense records?"):
[Link]["expenses"] = []
[Link]()
self._refresh_log()
now = [Link]()
self.rep_month = [Link](value=[Link])
self.rep_year = [Link](value=[Link])
months = list(calendar.month_name)[1:]
[Link](ctrl, values=months, width=11,
textvariable=[Link](value=months[[Link] - 1]),
state="readonly",
font=("Segoe UI", 10)).pack(side="left", padx=4)
month_cb = ctrl.winfo_children()[0]
month_cb.bind("<<ComboboxSelected>>",
lambda e: self.rep_month.set([Link](month_cb.get()) + 1))
self.report_text = [Link](rep_frame,
26
font=("Courier New", 10),
bg=CARD_BG, fg=TEXT_DARK,
relief="flat", bd=0,
highlightthickness=1,
highlightbackground=BORDER,
wrap="word", padx=20, pady=16,
state="disabled")
rep_vsb = [Link](rep_frame, orient="vertical",
command=self.report_text.yview)
self.report_text.configure(yscrollcommand=rep_vsb.set)
rep_vsb.pack(side="right", fill="y")
self.report_text.pack(side="left", fill="both", expand=True)
self._generate_report()
def _generate_report(self):
year = self.rep_year.get()
month = self.rep_month.get()
expenses = [Link].get_month_expenses(year, month)
t = self.report_text
[Link](state="normal")
[Link]("1.0", "end")
month_name = calendar.month_name[month]
line = "=" * 60
if not expenses:
[Link]("end", "\n No expenses recorded for this month.\n", "item")
[Link](state="disabled")
return
cat_map = defaultdict(list)
for e in expenses:
cat_map[e["category"]].append(e)
grand_total = 0
grand_qty = 0
27
[Link]("end", f" {'-'*55}\n", "sep")
for i in items:
dt = i["date"][5:16]
line_str = (f" {dt} {i['name']:<26}"
f" {i['qty']:>2}x Rs.{i['price']:<8.0f}"
f" Rs.{i['total']:.0f}\n")
[Link]("end", line_str, "item")
grand_qty += i["qty"]
[Link]("end", f" {'':>50}Subtotal: Rs.{cat_total:.0f}\n", "header")
self._update_sidebar(year, month)
def _export_report(self):
year = self.rep_year.get()
month = self.rep_month.get()
expenses = [Link].get_month_expenses(year, month)
month_name = calendar.month_name[month]
filename = f"Expense_Report_{month_name}_{year}.txt"
lines = [
f"HOUSEHOLD EXPENSE REPORT",
f"{month_name} {year}",
"=" * 60,
""
]
cat_map = defaultdict(list)
for e in expenses:
cat_map[e["category"]].append(e)
grand_total = 0
for cat, items in sorted(cat_map.items()):
cat_total = sum(i["total"] for i in items)
28
grand_total += cat_total
[Link](f"\n{cat}")
[Link]("-" * 55)
for i in items:
[Link](f" {i['date'][:16]} {i['name']:<26}"
f" {i['qty']}x Rs.{i['price']:.0f}"
f" = Rs.{i['total']:.0f}")
[Link](f" {'':>48}Subtotal: Rs.{cat_total:.0f}")
def _show_shop(self):
self._show_page(self.page_shop, "Shop")
def _show_log(self):
self._refresh_log()
self._show_page(self.page_log, "Log")
def _show_report(self):
self._generate_report()
self._show_page(self.page_report, "Report")
29
root = [Link]()
[Link](bg=BG)
root.update_idletasks()
sw, sh = root.winfo_screenwidth(), root.winfo_screenheight()
[Link](f"1200x780+{(sw-1200)//2}+{(sh-780)//2}")
app = ExpenseTracker(root)
[Link]()
30
31