🏨 FuzzuTech – Modern Hotel Management System (Python CTkinter + SQLite Demo) πŸš€

 Demo :


Click Video πŸ‘‡πŸ‘‡πŸ‘‡































Description :
Include the same description as YouTube, embed the YouTube Short, and add screenshots of the UI.


Features :

  • ✅ Fully functional single-file Python project

  • ✅ Professional UI using CTkinter

  • ✅ Built-in database (SQLite)

  • ✅ Ideal for hotel/room booking apps

  • ✅ Beginner-friendly, extendable project


Code :


"""

FuzzuTech - Modern Hotel Management System (CTkinter + SQLite)

Single-file example: app.py

Requires: customtkinter, pillow(optional)

pip install customtkinter pillow

"""


import sqlite3

import os

from datetime import datetime

import customtkinter as ctk

from tkinter import ttk, messagebox, filedialog

from PIL import Image, ImageTk


# --------------------

# App Appearance

# --------------------

ctk.set_appearance_mode("dark")  # "system", "dark", "light"

ctk.set_default_color_theme("blue")  # or provide custom json


DB_FILE = "hotel.db"


# --------------------

# Database Helpers

# --------------------

def init_db():

    conn = sqlite3.connect(DB_FILE)

    cur = conn.cursor()

    # guests table

    cur.execute("""

    CREATE TABLE IF NOT EXISTS guests (

        id INTEGER PRIMARY KEY AUTOINCREMENT,

        name TEXT NOT NULL,

        phone TEXT,

        email TEXT,

        address TEXT,

        created_at TEXT

    )

    """)

    # rooms table

    cur.execute("""

    CREATE TABLE IF NOT EXISTS rooms (

        id INTEGER PRIMARY KEY AUTOINCREMENT,

        room_number TEXT UNIQUE NOT NULL,

        room_type TEXT,

        price REAL,

        status TEXT DEFAULT 'available',

        description TEXT

    )

    """)

    # bookings table

    cur.execute("""

    CREATE TABLE IF NOT EXISTS bookings (

        id INTEGER PRIMARY KEY AUTOINCREMENT,

        guest_id INTEGER,

        room_id INTEGER,

        check_in TEXT,

        check_out TEXT,

        total REAL,

        status TEXT DEFAULT 'booked',

        created_at TEXT,

        FOREIGN KEY(guest_id) REFERENCES guests(id),

        FOREIGN KEY(room_id) REFERENCES rooms(id)

    )

    """)

    conn.commit()

    conn.close()


def query(sql, params=(), fetch=False):

    conn = sqlite3.connect(DB_FILE)

    cur = conn.cursor()

    cur.execute(sql, params)

    data = None

    if fetch:

        data = cur.fetchall()

    conn.commit()

    conn.close()

    return data


# --------------------

# Main App Class

# --------------------

class HotelApp(ctk.CTk):

    def __init__(self):

        super().__init__()

        self.title("FuzzuTech — Hotel Management System")

        self.geometry("1100x700")

        self.minsize(1000, 600)


        # ---- layout: Left menu + Right content ----

        self.grid_columnconfigure(1, weight=1)

        self.grid_rowconfigure(0, weight=1)


        self.sidebar = ctk.CTkFrame(self, width=220, corner_radius=0)

        self.sidebar.grid(row=0, column=0, sticky="nswe")

        self.content = ctk.CTkFrame(self, corner_radius=0)

        self.content.grid(row=0, column=1, sticky="nswe", padx=16, pady=16)


        # Sidebar content

        self._build_sidebar()


        # initially show dashboard

        self.current_frame = None

        self.show_dashboard()


    # --------------------

    # Sidebar

    # --------------------

    def _build_sidebar(self):

        logo_path = os.path.join("assets", "logo.png")

        if os.path.exists(logo_path):

            img = Image.open(logo_path).resize((80, 80))

            self.logo_img = ImageTk.PhotoImage(img)

            ctk.CTkLabel(self.sidebar, image=self.logo_img, text="").pack(pady=(12,6))

        else:

            ctk.CTkLabel(self.sidebar, text="FuzzuTech", font=ctk.CTkFont(size=20, weight="bold")).pack(pady=(18,6))


        ctk.CTkLabel(self.sidebar, text="Hotel Management", font=ctk.CTkFont(size=12)).pack(pady=(0,12))


        btn_dashboard = ctk.CTkButton(self.sidebar, text="Dashboard", command=self.show_dashboard)

        btn_rooms = ctk.CTkButton(self.sidebar, text="Rooms", command=self.show_rooms)

        btn_guests = ctk.CTkButton(self.sidebar, text="Guests", command=self.show_guests)

        btn_bookings = ctk.CTkButton(self.sidebar, text="Bookings", command=self.show_bookings)

        btn_reports = ctk.CTkButton(self.sidebar, text="Reports", command=self.show_reports)

        btn_export = ctk.CTkButton(self.sidebar, text="Export CSV", command=self.export_csv)


        for w in (btn_dashboard, btn_rooms, btn_guests, btn_bookings, btn_reports, btn_export):

            w.pack(fill="x", padx=12, pady=6)


    # --------------------

    # Utility: clear content frame

    # --------------------

    def clear_content(self):

        for child in self.content.winfo_children():

            child.destroy()


    # --------------------

    # Dashboard

    # --------------------

    def show_dashboard(self):

        self.clear_content()

        header = ctk.CTkLabel(self.content, text="Dashboard", font=ctk.CTkFont(size=20, weight="bold"))

        header.pack(anchor="nw")


        frame = ctk.CTkFrame(self.content, corner_radius=10)

        frame.pack(fill="both", expand=True, pady=12)


        # stats

        stats_frame = ctk.CTkFrame(frame)

        stats_frame.pack(fill="x", padx=12, pady=12)


        total_rooms = query("SELECT COUNT(*) FROM rooms", fetch=True)[0][0]

        total_guests = query("SELECT COUNT(*) FROM guests", fetch=True)[0][0]

        active_bookings = query("SELECT COUNT(*) FROM bookings WHERE status='booked'", fetch=True)[0][0]


        stat1 = ctk.CTkLabel(stats_frame, text=f"Rooms\n{total_rooms}", anchor="w")

        stat2 = ctk.CTkLabel(stats_frame, text=f"Guests\n{total_guests}", anchor="w")

        stat3 = ctk.CTkLabel(stats_frame, text=f"Active Bookings\n{active_bookings}", anchor="w")

        stat1.grid(row=0, column=0, padx=18, pady=10)

        stat2.grid(row=0, column=1, padx=18, pady=10)

        stat3.grid(row=0, column=2, padx=18, pady=10)


        # recent bookings table

        recent = ctk.CTkLabel(frame, text="Recent Bookings", font=ctk.CTkFont(size=14, weight="bold"))

        recent.pack(anchor="nw", padx=12)


        cols = ("id", "guest", "room", "check_in", "check_out", "status")

        tree_frame = ctk.CTkFrame(frame)

        tree_frame.pack(fill="both", expand=True, padx=12, pady=8)

        tree = ttk.Treeview(tree_frame, columns=cols, show="headings", height=6)

        for c in cols:

            tree.heading(c, text=c.title())

            tree.column(c, width=120)

        tree.pack(fill="both", expand=True, side="left")

        scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=tree.yview)

        scrollbar.pack(side="right", fill="y")

        tree.configure(yscroll=scrollbar.set)


        bookings = query("""

           SELECT b.id, g.name, r.room_number, b.check_in, b.check_out, b.status

           FROM bookings b

           LEFT JOIN guests g ON b.guest_id = g.id

           LEFT JOIN rooms r ON b.room_id = r.id

           ORDER BY b.created_at DESC LIMIT 10

        """, fetch=True)

        for b in bookings:

            tree.insert("", "end", values=b)


    # --------------------

    # Rooms Management

    # --------------------

    def show_rooms(self):

        self.clear_content()

        header = ctk.CTkLabel(self.content, text="Rooms", font=ctk.CTkFont(size=18, weight="bold"))

        header.pack(anchor="nw")


        topbar = ctk.CTkFrame(self.content)

        topbar.pack(fill="x", pady=8, padx=6)

        add_btn = ctk.CTkButton(topbar, text="Add Room", command=self.open_add_room)

        add_btn.pack(side="left", padx=6)


        search_var = ctk.StringVar()

        search_entry = ctk.CTkEntry(topbar, placeholder_text="Search room number or type...", textvariable=search_var, width=300)

        search_entry.pack(side="right", padx=6)


        # rooms table

        cols = ("id", "room_number", "room_type", "price", "status")

        tree_frame = ctk.CTkFrame(self.content)

        tree_frame.pack(fill="both", expand=True, padx=6, pady=6)

        self.room_tree = ttk.Treeview(tree_frame, columns=cols, show="headings")

        for c in cols:

            self.room_tree.heading(c, text=c.replace("_", " ").title())

            self.room_tree.column(c, width=120)

        self.room_tree.pack(fill="both", expand=True, side="left")

        scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=self.room_tree.yview)

        scrollbar.pack(side="right", fill="y")

        self.room_tree.configure(yscroll=scrollbar.set)

        self.room_tree.bind("<Double-1>", self.on_room_double)


        # load rooms

        self.load_rooms()


        def on_search(*_):

            q = search_var.get().strip()

            if q == "":

                self.load_rooms()

            else:

                rows = query("SELECT id, room_number, room_type, price, status FROM rooms WHERE room_number LIKE ? OR room_type LIKE ?",

                             (f"%{q}%", f"%{q}%"), fetch=True)

                self.room_tree.delete(*self.room_tree.get_children())

                for r in rows:

                    self.room_tree.insert("", "end", values=r)


        search_var.trace_add("write", on_search)


    def load_rooms(self):

        rows = query("SELECT id, room_number, room_type, price, status FROM rooms ORDER BY id DESC", fetch=True)

        self.room_tree.delete(*self.room_tree.get_children())

        for r in rows:

            self.room_tree.insert("", "end", values=r)


    def open_add_room(self):

        popup = ctk.CTkToplevel(self)

        popup.title("Add Room")

        popup.geometry("420x360")

        ctk.CTkLabel(popup, text="New Room", font=ctk.CTkFont(size=16, weight="bold")).pack(pady=10)


        frm = ctk.CTkFrame(popup)

        frm.pack(padx=12, pady=8, fill="both", expand=True)


        rn = ctk.StringVar()

        rtype = ctk.StringVar()

        price = ctk.StringVar()

        desc = ctk.StringVar()


        ctk.CTkLabel(frm, text="Room Number:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=rn).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Room Type:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=rtype).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Price (per night):").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=price).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Description:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=desc).pack(fill="x", pady=4)


        def save_room():

            try:

                query("INSERT INTO rooms (room_number, room_type, price, description) VALUES (?, ?, ?, ?)",

                      (rn.get().strip(), rtype.get().strip(), float(price.get() or 0), desc.get().strip()))

                messagebox.showinfo("Success", "Room added.")

                popup.destroy()

                self.load_rooms()

            except Exception as e:

                messagebox.showerror("Error", f"Failed to add room:\n{e}")


        ctk.CTkButton(popup, text="Save", command=save_room).pack(pady=10)


    def on_room_double(self, event):

        sel = self.room_tree.selection()

        if not sel: return

        item = self.room_tree.item(sel[0])

        room_id = item["values"][0]

        self.open_edit_room(room_id)


    def open_edit_room(self, room_id):

        data = query("SELECT room_number, room_type, price, status, description FROM rooms WHERE id=?", (room_id,), fetch=True)

        if not data: return

        rn, rtype, price, status, desc = data[0]

        popup = ctk.CTkToplevel(self)

        popup.title(f"Edit Room {rn}")

        popup.geometry("420x380")

        frm = ctk.CTkFrame(popup)

        frm.pack(padx=12, pady=8, fill="both", expand=True)


        rn_var = ctk.StringVar(value=rn)

        rtype_var = ctk.StringVar(value=rtype)

        price_var = ctk.StringVar(value=str(price))

        status_var = ctk.StringVar(value=status)

        desc_var = ctk.StringVar(value=desc)


        ctk.CTkLabel(frm, text="Room Number:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=rn_var).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Room Type:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=rtype_var).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Price (per night):").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=price_var).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Status:").pack(anchor="w")

        ctk.CTkComboBox(frm, values=["available", "occupied", "maintenance"], variable=status_var).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Description:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=desc_var).pack(fill="x", pady=4)


        def save():

            try:

                query("UPDATE rooms SET room_number=?, room_type=?, price=?, status=?, description=? WHERE id=?",

                      (rn_var.get().strip(), rtype_var.get().strip(), float(price_var.get() or 0), status_var.get(), desc_var.get().strip(), room_id))

                messagebox.showinfo("Saved", "Room updated.")

                popup.destroy()

                self.load_rooms()

            except Exception as e:

                messagebox.showerror("Error", str(e))


        ctk.CTkButton(popup, text="Save Changes", command=save).pack(pady=8)


    # --------------------

    # Guests Management

    # --------------------

    def show_guests(self):

        self.clear_content()

        ctk.CTkLabel(self.content, text="Guests", font=ctk.CTkFont(size=18, weight="bold")).pack(anchor="nw")

        top = ctk.CTkFrame(self.content)

        top.pack(fill="x", pady=6, padx=6)

        ctk.CTkButton(top, text="Add Guest", command=self.open_add_guest).pack(side="left", padx=6)


        cols = ("id", "name", "phone", "email", "created_at")

        frame = ctk.CTkFrame(self.content)

        frame.pack(fill="both", expand=True, padx=6, pady=6)

        self.guest_tree = ttk.Treeview(frame, columns=cols, show="headings")

        for c in cols:

            self.guest_tree.heading(c, text=c.title())

            self.guest_tree.column(c, width=140)

        self.guest_tree.pack(fill="both", expand=True, side="left")

        scrollbar = ttk.Scrollbar(frame, orient="vertical", command=self.guest_tree.yview)

        scrollbar.pack(side="right", fill="y")

        self.guest_tree.configure(yscroll=scrollbar.set)

        self.guest_tree.bind("<Double-1>", self.on_guest_double)


        self.load_guests()


    def load_guests(self):

        rows = query("SELECT id, name, phone, email, created_at FROM guests ORDER BY id DESC", fetch=True)

        self.guest_tree.delete(*self.guest_tree.get_children())

        for r in rows:

            self.guest_tree.insert("", "end", values=r)


    def open_add_guest(self):

        popup = ctk.CTkToplevel(self)

        popup.title("Add Guest")

        popup.geometry("420x380")

        frm = ctk.CTkFrame(popup)

        frm.pack(padx=12, pady=8, fill="both", expand=True)


        name = ctk.StringVar()

        phone = ctk.StringVar()

        email = ctk.StringVar()

        address = ctk.StringVar()


        ctk.CTkLabel(frm, text="Name:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=name).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Phone:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=phone).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Email:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=email).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Address:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=address).pack(fill="x", pady=4)


        def save():

            if name.get().strip() == "":

                messagebox.showwarning("Required", "Name required")

                return

            query("INSERT INTO guests (name, phone, email, address, created_at) VALUES (?, ?, ?, ?, ?)",

                  (name.get().strip(), phone.get().strip(), email.get().strip(), address.get().strip(), datetime.now().isoformat()))

            messagebox.showinfo("Added", "Guest added.")

            popup.destroy()

            self.load_guests()


        ctk.CTkButton(popup, text="Save", command=save).pack(pady=8)


    def on_guest_double(self, event):

        sel = self.guest_tree.selection()

        if not sel: return

        item = self.guest_tree.item(sel[0])

        gid = item["values"][0]

        self.open_edit_guest(gid)


    def open_edit_guest(self, gid):

        data = query("SELECT name, phone, email, address FROM guests WHERE id=?", (gid,), fetch=True)

        if not data: return

        name, phone, email, address = data[0]

        popup = ctk.CTkToplevel(self)

        popup.title("Edit Guest")

        popup.geometry("420x380")

        frm = ctk.CTkFrame(popup)

        frm.pack(padx=12, pady=8, fill="both", expand=True)


        name_var = ctk.StringVar(value=name)

        phone_var = ctk.StringVar(value=phone)

        email_var = ctk.StringVar(value=email)

        address_var = ctk.StringVar(value=address)


        ctk.CTkLabel(frm, text="Name:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=name_var).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Phone:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=phone_var).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Email:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=email_var).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Address:").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=address_var).pack(fill="x", pady=4)


        def save():

            query("UPDATE guests SET name=?, phone=?, email=?, address=? WHERE id=?",

                  (name_var.get().strip(), phone_var.get().strip(), email_var.get().strip(), address_var.get().strip(), gid))

            messagebox.showinfo("Saved", "Guest updated.")

            popup.destroy()

            self.load_guests()


        ctk.CTkButton(popup, text="Save Changes", command=save).pack(pady=8)


    # --------------------

    # Bookings

    # --------------------

    def show_bookings(self):

        self.clear_content()

        ctk.CTkLabel(self.content, text="Bookings", font=ctk.CTkFont(size=18, weight="bold")).pack(anchor="nw")

        top = ctk.CTkFrame(self.content)

        top.pack(fill="x", pady=6, padx=6)

        ctk.CTkButton(top, text="New Booking", command=self.open_new_booking).pack(side="left", padx=6)

        ctk.CTkButton(top, text="Check-out", command=self.checkout_booking).pack(side="left", padx=6)


        cols = ("id", "guest", "room", "check_in", "check_out", "total", "status")

        frame = ctk.CTkFrame(self.content)

        frame.pack(fill="both", expand=True, padx=6, pady=6)

        self.book_tree = ttk.Treeview(frame, columns=cols, show="headings")

        for c in cols:

            self.book_tree.heading(c, text=c.title())

            self.book_tree.column(c, width=120)

        self.book_tree.pack(fill="both", expand=True, side="left")

        scrollbar = ttk.Scrollbar(frame, orient="vertical", command=self.book_tree.yview)

        scrollbar.pack(side="right", fill="y")

        self.book_tree.configure(yscroll=scrollbar.set)

        self.load_bookings()


    def load_bookings(self):

        rows = query("""

           SELECT b.id, g.name, r.room_number, b.check_in, b.check_out, b.total, b.status

           FROM bookings b

           LEFT JOIN guests g ON b.guest_id = g.id

           LEFT JOIN rooms r ON b.room_id = r.id

           ORDER BY b.created_at DESC

        """, fetch=True)

        self.book_tree.delete(*self.book_tree.get_children())

        for r in rows:

            self.book_tree.insert("", "end", values=r)


    def open_new_booking(self):

        popup = ctk.CTkToplevel(self)

        popup.title("New Booking")

        popup.geometry("560x480")

        frm = ctk.CTkFrame(popup)

        frm.pack(padx=12, pady=8, fill="both", expand=True)


        # Guest selection

        guests = query("SELECT id, name FROM guests ORDER BY name", fetch=True)

        guest_map = {f"{g[1]} (id:{g[0]})": g[0] for g in guests}

        guest_var = ctk.StringVar()

        ctk.CTkLabel(frm, text="Guest:").pack(anchor="w")

        guest_combo = ctk.CTkComboBox(frm, values=list(guest_map.keys()), variable=guest_var)

        guest_combo.pack(fill="x", pady=4)


        # Room selection (only available)

        rooms = query("SELECT id, room_number, price FROM rooms WHERE status='available' ORDER BY room_number", fetch=True)

        room_map = {f"{r[1]} - ₹{r[2]} (id:{r[0]})": r[0] for r in rooms}

        room_var = ctk.StringVar()

        ctk.CTkLabel(frm, text="Room:").pack(anchor="w")

        room_combo = ctk.CTkComboBox(frm, values=list(room_map.keys()), variable=room_var)

        room_combo.pack(fill="x", pady=4)


        check_in = ctk.StringVar(value=datetime.now().date().isoformat())

        check_out = ctk.StringVar(value=(datetime.now().date()).isoformat())

        ctk.CTkLabel(frm, text="Check-in (YYYY-MM-DD):").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=check_in).pack(fill="x", pady=4)

        ctk.CTkLabel(frm, text="Check-out (YYYY-MM-DD):").pack(anchor="w")

        ctk.CTkEntry(frm, textvariable=check_out).pack(fill="x", pady=4)


        def book():

            if not guest_var.get() or not room_var.get():

                messagebox.showwarning("Required", "Select guest and room")

                return

            try:

                g_id = guest_map[guest_var.get()]

                r_id = room_map[room_var.get()]

                ci = datetime.fromisoformat(check_in.get())

                co = datetime.fromisoformat(check_out.get())

                nights = max(1, (co - ci).days or 1)

                price = query("SELECT price FROM rooms WHERE id=?", (r_id,), fetch=True)[0][0]

                total = nights * price

                query("INSERT INTO bookings (guest_id, room_id, check_in, check_out, total, status, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)",

                      (g_id, r_id, check_in.get(), check_out.get(), total, "booked", datetime.now().isoformat()))

                query("UPDATE rooms SET status='occupied' WHERE id=?", (r_id,))

                messagebox.showinfo("Booked", f"Booking created. Total ₹{total}")

                popup.destroy()

                self.load_bookings()

                self.load_rooms()

            except Exception as e:

                messagebox.showerror("Error", str(e))


        ctk.CTkButton(popup, text="Create Booking", command=book).pack(pady=10)


    def checkout_booking(self):

        sel = self.book_tree.selection()

        if not sel:

            messagebox.showwarning("Select", "Select a booking to checkout")

            return

        item = self.book_tree.item(sel[0])

        booking_id = item["values"][0]

        # set status and free the room

        room_num = item["values"][2]

        room = query("SELECT id FROM rooms WHERE room_number=?", (room_num,), fetch=True)

        if room:

            room_id = room[0][0]

            query("UPDATE bookings SET status='checked_out' WHERE id=?", (booking_id,))

            query("UPDATE rooms SET status='available' WHERE id=?", (room_id,))

            messagebox.showinfo("Checked out", "Guest checked out and room freed.")

            self.load_bookings()

            self.load_rooms()

        else:

            messagebox.showerror("Error", "Room not found for booking.")


    # --------------------

    # Reports & Export

    # --------------------

    def show_reports(self):

        self.clear_content()

        ctk.CTkLabel(self.content, text="Reports", font=ctk.CTkFont(size=18, weight="bold")).pack(anchor="nw")

        frame = ctk.CTkFrame(self.content)

        frame.pack(fill="both", expand=True, padx=6, pady=6)

        # Simple revenue report

        revenue = query("SELECT SUM(total) FROM bookings WHERE status IN ('booked','checked_out')", fetch=True)[0][0] or 0

        total_bookings = query("SELECT COUNT(*) FROM bookings", fetch=True)[0][0]

        active_rooms = query("SELECT COUNT(*) FROM rooms WHERE status='occupied'", fetch=True)[0][0]


        ctk.CTkLabel(frame, text=f"Total Revenue: ₹{revenue}", font=ctk.CTkFont(size=14)).pack(anchor="w", pady=6)

        ctk.CTkLabel(frame, text=f"Total Bookings: {total_bookings}", font=ctk.CTkFont(size=14)).pack(anchor="w", pady=6)

        ctk.CTkLabel(frame, text=f"Occupied Rooms: {active_rooms}", font=ctk.CTkFont(size=14)).pack(anchor="w", pady=6)


    def export_csv(self):

        path = filedialog.asksaveasfilename(defaultextension=".csv", filetypes=[("CSV files","*.csv")])

        if not path:

            return

        rows = query("""SELECT b.id, g.name, r.room_number, b.check_in, b.check_out, b.total, b.status 

                        FROM bookings b

                        LEFT JOIN guests g ON b.guest_id=g.id

                        LEFT JOIN rooms r ON b.room_id=r.id""", fetch=True)

        try:

            import csv

            with open(path, "w", newline='', encoding='utf-8') as f:

                writer = csv.writer(f)

                writer.writerow(["BookingID","Guest","Room","CheckIn","CheckOut","Total","Status"])

                writer.writerows(rows)

            messagebox.showinfo("Exported", f"Bookings exported to {path}")

        except Exception as e:

            messagebox.showerror("Error", str(e))



# --------------------

# Launch

# --------------------

if __name__ == "__main__":

    init_db()

    app = HotelApp()

    app.mainloop()

Comments

Popular posts from this blog

πŸš€ Simple Login & Registration System in Python Tkinter πŸ“±

πŸš€ Create a Python Screen Recorder with Audio (Complete Code)

πŸ“‘ Fuzzu Packet Sniffer – Python GUI for Real-Time IP Monitoring | Tkinter + Scapy