import tkinter as tk
from tkinter import ttk, messagebox
import sqlite3
from fpdf import FPDF
# ---------------------------------------------------
# DATABASE SETUP
# ---------------------------------------------------
conn = sqlite3.connect("travel_expenses.db")
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS members (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL
)
""")
cursor.execute("""
CREATE TABLE IF NOT EXISTS expenses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
member_id INTEGER,
description TEXT,
amount REAL,
FOREIGN KEY(member_id) REFERENCES members(id)
)
""")
conn.commit()
# ---------------------------------------------------
# MAIN APPLICATION
# ---------------------------------------------------
class TravelExpenseApp:
def __init__(self, root):
self.root = root
self.root.title("Travel Expense Splitter")
self.root.geometry("600x500")
self.create_ui()
# ------------------------ UI ------------------------
def create_ui(self):
tab_control = ttk.Notebook(self.root)
self.tab_members = ttk.Frame(tab_control)
self.tab_expenses = ttk.Frame(tab_control)
self.tab_summary = ttk.Frame(tab_control)
tab_control.add(self.tab_members, text="Members")
tab_control.add(self.tab_expenses, text="Expenses")
tab_control.add(self.tab_summary, text="Summary")
tab_control.pack(expand=1, fill="both")
self.setup_members_tab()
self.setup_expenses_tab()
self.setup_summary_tab()
# ------------------------ MEMBERS TAB ------------------------
def setup_members_tab(self):
tk.Label(self.tab_members, text="Add Member", font=("Arial", 14)).pack(pady=10)
self.member_entry = tk.Entry(self.tab_members, font=("Arial", 12))
self.member_entry.pack(pady=5)
tk.Button(self.tab_members, text="Add Member", command=self.add_member).pack(pady=10)
self.members_list = tk.Listbox(self.tab_members, width=40, height=10)
self.members_list.pack(pady=10)
self.load_members()
def add_member(self):
name = self.member_entry.get()
if not name:
messagebox.showerror("Error", "Please enter a name!")
return
cursor.execute("INSERT INTO members (name) VALUES (?)", (name,))
conn.commit()
self.member_entry.delete(0, tk.END)
self.load_members()
def load_members(self):
self.members_list.delete(0, tk.END)
cursor.execute("SELECT name FROM members")
for row in cursor.fetchall():
self.members_list.insert(tk.END, row[0])
# ------------------------ EXPENSE TAB ------------------------
def setup_expenses_tab(self):
tk.Label(self.tab_expenses, text="Add Expense", font=("Arial", 14)).pack(pady=10)
tk.Label(self.tab_expenses, text="Select Member:").pack()
self.member_dropdown = ttk.Combobox(self.tab_expenses, state="readonly")
self.member_dropdown.pack(pady=5)
self.load_member_dropdown()
tk.Label(self.tab_expenses, text="Description:").pack()
self.desc_entry = tk.Entry(self.tab_expenses, font=("Arial", 12))
self.desc_entry.pack(pady=5)
tk.Label(self.tab_expenses, text="Amount:").pack()
self.amount_entry = tk.Entry(self.tab_expenses, font=("Arial", 12))
self.amount_entry.pack(pady=5)
tk.Button(self.tab_expenses, text="Add Expense", command=self.add_expense).pack(pady=10)
self.expense_tree = ttk.Treeview(self.tab_expenses, columns=("member", "desc", "amount"), show="headings")
self.expense_tree.heading("member", text="Member")
self.expense_tree.heading("desc", text="Description")
self.expense_tree.heading("amount", text="Amount")
self.expense_tree.pack(fill="both", expand=True)
self.load_expenses()
def load_member_dropdown(self):
cursor.execute("SELECT name FROM members")
members = [row[0] for row in cursor.fetchall()]
self.member_dropdown["values"] = members
def add_expense(self):
member = self.member_dropdown.get()
desc = self.desc_entry.get()
amount = self.amount_entry.get()
if not member or not desc or not amount:
messagebox.showerror("Error", "All fields are required!")
return
try:
amount = float(amount)
except:
messagebox.showerror("Error", "Amount must be a number!")
return
cursor.execute("SELECT id FROM members WHERE name=?", (member,))
member_id = cursor.fetchone()[0]
cursor.execute("INSERT INTO expenses (member_id, description, amount) VALUES (?, ?, ?)",
(member_id, desc, amount))
conn.commit()
self.desc_entry.delete(0, tk.END)
self.amount_entry.delete(0, tk.END)
self.load_expenses()
def load_expenses(self):
for i in self.expense_tree.get_children():
self.expense_tree.delete(i)
cursor.execute("""
SELECT members.name, expenses.description, expenses.amount
FROM expenses
JOIN members ON expenses.member_id = members.id
""")
for row in cursor.fetchall():
self.expense_tree.insert("", tk.END, values=row)
# ------------------------ SUMMARY TAB ------------------------
def setup_summary_tab(self):
tk.Label(self.tab_summary, text="Expense Summary", font=("Arial", 14)).pack(pady=10)
tk.Button(self.tab_summary, text="Calculate Summary", command=self.calculate_summary).pack(pady=10)
tk.Button(self.tab_summary, text="Export PDF", command=self.export_pdf).pack(pady=10)
self.summary_box = tk.Text(self.tab_summary, height=20, width=70)
self.summary_box.pack()
def calculate_summary(self):
cursor.execute("SELECT COUNT(*) FROM members")
num_members = cursor.fetchone()[0]
cursor.execute("SELECT SUM(amount) FROM expenses")
total_expense = cursor.fetchone()[0] or 0
split_amount = total_expense / num_members if num_members > 0 else 0
self.summary_box.delete(1.0, tk.END)
self.summary_box.insert(tk.END, f"Total Expense: ₹{total_expense:.2f}\n")
self.summary_box.insert(tk.END, f"Each Person Should Pay: ₹{split_amount:.2f}\n\n")
cursor.execute("""
SELECT members.name, SUM(expenses.amount)
FROM members
LEFT JOIN expenses ON members.id = expenses.member_id
GROUP BY members.name
""")
for name, paid in cursor.fetchall():
paid = paid or 0
diff = paid - split_amount
status = "owes" if diff < 0 else "gets back"
self.summary_box.insert(tk.END, f"{name}: Paid ₹{paid:.2f} → {status} ₹{abs(diff):.2f}\n")
# ------------------------ PDF EXPORT ------------------------
def export_pdf(self):
pdf = FPDF()
pdf.add_page()
pdf.set_font("Arial", size=12)
pdf.cell(200, 10, "Travel Expense Summary", ln=True, align="C")
pdf.ln(10)
summary_text = self.summary_box.get(1.0, tk.END).split("\n")
for line in summary_text:
pdf.cell(0, 10, txt=line, ln=True)
pdf.output("Travel_Expense_Summary.pdf")
messagebox.showinfo("Success", "PDF Exported Successfully!")
# ------------------------ RUN APP ------------------------
root = tk.Tk()
app = TravelExpenseApp(root)
root.mainloop()