diff --git a/cafe.db b/cafe.db deleted file mode 100644 index fcac585..0000000 Binary files a/cafe.db and /dev/null differ diff --git a/project/database.py b/project/database.py index 2bbf052..0a4f512 100644 --- a/project/database.py +++ b/project/database.py @@ -1,4 +1,5 @@ import sqlite3 +import datetime def connect(): return sqlite3.connect("cafe.db") @@ -7,6 +8,7 @@ def setup_database(): db = connect() cur = db.cursor() + # Tabel Users cur.execute(""" CREATE TABLE IF NOT EXISTS users( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -16,44 +18,59 @@ def setup_database(): ) """) + # Tabel Menu cur.execute(""" CREATE TABLE IF NOT EXISTS menu( id INTEGER PRIMARY KEY AUTOINCREMENT, nama TEXT, harga REAL, - gambar TEXT + gambar TEXT, + kategori TEXT ) """) + # Tabel Transaksi (Header nota) cur.execute(""" - CREATE TABLE IF NOT EXISTS orders( + CREATE TABLE IF NOT EXISTS transaksi( id INTEGER PRIMARY KEY AUTOINCREMENT, - nama TEXT, - harga REAL + tanggal TEXT, + total REAL, + meja_id INTEGER, + status TEXT ) """) + # Status: 'Pending' (Masuk Dapur), 'Disajikan' (Waiter selesai), 'Lunas' (Kasir) + # Tabel Detail Transaksi (Isi makanan per nota) cur.execute(""" - CREATE TABLE IF NOT EXISTS pembayaran( + CREATE TABLE IF NOT EXISTS detail_transaksi( id INTEGER PRIMARY KEY AUTOINCREMENT, - order_id INTEGER, - total REAL + transaksi_id INTEGER, + menu_nama TEXT, + harga REAL, + jumlah INTEGER, + subtotal REAL ) """) + # Insert Akun Default jika kosong cur.execute("SELECT COUNT(*) FROM users") if cur.fetchone()[0] == 0: users = [ ("admin","admin","admin"), ("kasir","kasir","kasir"), ("pembeli","pembeli","pembeli"), - ("pemilik","pemilik","pemilik"), - ("waiter","waiter","waiter") + ("waiter","waiter","waiter"), + ("pemilik","pemilik","pemilik") ] - cur.executemany( - "INSERT INTO users(username,password,role) VALUES (?,?,?)", - users - ) + cur.executemany("INSERT INTO users(username,password,role) VALUES (?,?,?)", users) + db.commit() + + # Insert Menu Dummy jika kosong + cur.execute("SELECT COUNT(*) FROM menu") + if cur.fetchone()[0] == 0: + cur.execute("INSERT INTO menu (nama, harga, gambar) VALUES ('Mie Ayam', 15000, 'mie_ayam.webp')") + cur.execute("INSERT INTO menu (nama, harga, gambar) VALUES ('Es Teh', 5000, 'es_teh.webp')") db.commit() - db.close() + db.close() \ No newline at end of file diff --git a/project/kasir.py b/project/kasir.py index 5f9c45d..fc96a20 100644 --- a/project/kasir.py +++ b/project/kasir.py @@ -5,72 +5,60 @@ from database import connect class KasirPage: def __init__(self, parent, controller): self.parent = parent - self.controller = controller self.frame = tk.Frame(parent) self.frame.pack(fill="both", expand=True) - tk.Label(self.frame, text="KASIR PAGE", font=("Arial", 18, "bold")).pack(pady=10) - - # Tombol Logout + tk.Label(self.frame, text="KASIR - PEMBAYARAN", font=("Arial", 18, "bold")).pack(pady=10) tk.Button(self.frame, text="Logout", bg="#f9e79f", command=self.logout).pack(pady=5) + tk.Button(self.frame, text="Refresh", command=self.load_tagihan).pack() - # Listbox untuk menampilkan order - tk.Label(self.frame, text="Daftar Order:", font=("Arial", 12, "bold")).pack(pady=5) - self.listbox = tk.Listbox(self.frame, width=50, height=10) + tk.Label(self.frame, text="Daftar Tagihan (Status: Disajikan):", font=("Arial", 12)).pack(pady=5) + self.listbox = tk.Listbox(self.frame, width=60, height=10) self.listbox.pack(pady=5) - # Tombol bayar - tk.Button(self.frame, text="Bayar", bg="#d1e7dd", command=self.bayar).pack(pady=5) + tk.Button(self.frame, text="Proses Pembayaran", bg="#d1e7dd", command=self.bayar).pack(pady=5) - self.load_orders() # Load order dari database saat awal + self.transaksi_data = [] + self.load_tagihan() - def load_orders(self): + def load_tagihan(self): self.listbox.delete(0, tk.END) + self.transaksi_data = [] + db = connect() cur = db.cursor() - cur.execute("SELECT id, nama, harga FROM orders") - self.data = cur.fetchall() + # Kasir hanya melihat yang sudah disajikan waiter + cur.execute("SELECT id, meja_id, total FROM transaksi WHERE status='Disajikan'") + rows = cur.fetchall() db.close() - for order in self.data: - self.listbox.insert(tk.END, f"ID {order[0]}: {order[1]} - Rp {order[2]:,}") + for row in rows: + t_id, meja, total = row + self.listbox.insert(tk.END, f"Meja {meja} - ID Transaksi: {t_id} - Total: Rp {total:,.0f}") + self.transaksi_data.append(row) def bayar(self): idx = self.listbox.curselection() if not idx: - messagebox.showwarning("Pilih Order", "Pilih order yang ingin dibayar!") + messagebox.showwarning("Pilih", "Pilih tagihan yang akan dibayar!") return - order = self.data[idx[0]] - order_id, nama, total = order + t_id, meja, total = self.transaksi_data[idx[0]] - # Simpan pembayaran di database (opsional, bisa buat tabel pembayaran) - db = connect() - cur = db.cursor() - cur.execute("INSERT INTO pembayaran VALUES (NULL, ?, ?)", (order_id, total)) - cur.execute("DELETE FROM orders WHERE id=?", (order_id,)) - db.commit() - db.close() - - # Tampilkan struk - self.tampil_struk(order_id, nama, total) - - # Update listbox - self.load_orders() - - def tampil_struk(self, order_id, nama, total): - win = tk.Toplevel(self.frame) - win.title("Struk Pembayaran") - - tk.Label(win, text="STRUK PEMBAYARAN", font=("Arial",14,"bold")).pack(pady=5) - tk.Label(win, text=f"Order ID : {order_id}").pack() - tk.Label(win, text=f"Nama Menu: {nama}").pack() - tk.Label(win, text=f"Total : Rp {total:,}").pack() - tk.Label(win, text="Terima kasih 🙏").pack(pady=10) - tk.Button(win, text="Tutup", command=win.destroy).pack(pady=5) + # Konfirmasi pembayaran + confirm = messagebox.askyesno("Konfirmasi", f"Bayar tagihan Meja {meja} sebesar Rp {total:,.0f}?") + if confirm: + db = connect() + cur = db.cursor() + # Ubah status menjadi Lunas + cur.execute("UPDATE transaksi SET status='Lunas' WHERE id=?", (t_id,)) + db.commit() + db.close() + + messagebox.showinfo("Sukses", "Pembayaran Berhasil! Struk dicetak.") + self.load_tagihan() def logout(self): self.frame.destroy() from main import LoginScreen - LoginScreen(self.parent) - + LoginScreen(self.parent) \ No newline at end of file diff --git a/project/pembeli_menu.py b/project/pembeli_menu.py index c57f2bf..bff5477 100644 --- a/project/pembeli_menu.py +++ b/project/pembeli_menu.py @@ -1,41 +1,47 @@ import tkinter as tk +from tkinter import messagebox from PIL import Image, ImageTk from database import connect -from tkinter import messagebox +import datetime class PembeliMenu: def __init__(self, parent): self.parent = parent self.frame = tk.Frame(parent) self.frame.pack(fill="both", expand=True) + + self.cart = [] # List dictionary: {'nama':, 'harga':, 'jumlah':} + self.images = [] + # Header + tk.Label(self.frame, text="MENU PELANGGAN", font=("Arial", 18, "bold")).pack(pady=10) + + # --- INPUT NOMOR MEJA (Fitur Baru) --- + frame_meja = tk.Frame(self.frame) + frame_meja.pack(pady=5) + tk.Label(frame_meja, text="Nomor Meja: ").pack(side=tk.LEFT) + self.entry_meja = tk.Entry(frame_meja, width=5) + self.entry_meja.pack(side=tk.LEFT) - self.cart = [] # Simpan tuple (nama, harga) - self.images = [] # Simpan reference gambar agar tidak dihapus GC - - # --- Judul Halaman --- - tk.Label(self.frame, text="MENU PEMBELI", font=("Arial", 18, "bold")).pack(pady=10) - - # --- Tombol Logout --- + # Logout tk.Button(self.frame, text="Logout", bg="#f9e79f", command=self.logout).pack(pady=5) - # --- Frame Menu --- + # Area Menu & Cart self.menu_frame = tk.Frame(self.frame) - self.menu_frame.pack(pady=10) + self.menu_frame.pack(pady=10, fill="both", expand=True) + + # Load Menu + self.load_menu() - self.load_menu() # Load menu dari database - - # --- Daftar Pesanan --- - tk.Label(self.frame, text="Daftar Pesanan:", font=("Arial", 12, "bold")).pack(pady=5) + # Listbox Keranjang + tk.Label(self.frame, text="Keranjang Pesanan:").pack() self.listbox = tk.Listbox(self.frame, width=50, height=6) self.listbox.pack() - # --- Total --- self.total_lbl = tk.Label(self.frame, text="Total: Rp 0", font=("Arial", 12, "bold")) self.total_lbl.pack(pady=5) - # --- Tombol Checkout --- - tk.Button(self.frame, text="Checkout", bg="#d1e7dd", command=self.checkout).pack(pady=5) + tk.Button(self.frame, text="PESAN SEKARANG", bg="#d1e7dd", command=self.checkout).pack(pady=10) def load_menu(self): db = connect() @@ -44,48 +50,74 @@ class PembeliMenu: data = cur.fetchall() db.close() + row_frame = None for i, (nama, harga, gambar) in enumerate(data): - f = tk.Frame(self.menu_frame, bd=2, relief="ridge") - f.grid(row=i//3, column=i%3, padx=10, pady=10) + if i % 3 == 0: + row_frame = tk.Frame(self.menu_frame) + row_frame.pack() + + f = tk.Frame(row_frame, bd=2, relief="ridge", padx=5, pady=5) + f.pack(side=tk.LEFT, padx=5) try: - img = Image.open(gambar).resize((120, 90)) + # Pastikan nama file gambar sesuai dengan yang ada di folder project/ + img = Image.open(gambar).resize((100, 80)) photo = ImageTk.PhotoImage(img) self.images.append(photo) tk.Label(f, image=photo).pack() - except FileNotFoundError: - tk.Label(f, text="No Image").pack() + except: + tk.Label(f, text="[No Image]").pack() - tk.Label(f, text=nama).pack() - tk.Label(f, text=f"Rp {harga:,}").pack() - tk.Button(f, text="Pesan", bg="#cfe2ff", - command=lambda n=nama, h=harga: self.add(n, h)).pack(pady=3) + tk.Label(f, text=nama, font=("Arial",10,"bold")).pack() + tk.Label(f, text=f"Rp {harga:,.0f}").pack() + tk.Button(f, text="Tambah", command=lambda n=nama, h=harga: self.add_to_cart(n, h)).pack() - def add(self, nama, harga): - self.cart.append((nama, harga)) - self.listbox.insert(tk.END, f"{nama} - Rp {harga:,}") - total = sum(h for _, h in self.cart) - self.total_lbl.config(text=f"Total: Rp {total:,}") + def add_to_cart(self, nama, harga): + self.cart.append({'nama': nama, 'harga': harga}) + self.refresh_cart() + + def refresh_cart(self): + self.listbox.delete(0, tk.END) + total = 0 + for item in self.cart: + self.listbox.insert(tk.END, f"{item['nama']} - Rp {item['harga']:,.0f}") + total += item['harga'] + self.total_lbl.config(text=f"Total: Rp {total:,.0f}") def checkout(self): - if not self.cart: - messagebox.showwarning("Pesan Kosong", "Belum ada pesanan!") + meja = self.entry_meja.get() + if not meja: + messagebox.showwarning("Peringatan", "Isi nomor meja dulu!") return + if not self.cart: + messagebox.showwarning("Kosong", "Pilih menu dulu!") + return + + total_belanja = sum(item['harga'] for item in self.cart) + tanggal = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") db = connect() cur = db.cursor() - for nama, harga in self.cart: - cur.execute("INSERT INTO orders VALUES (NULL, ?, ?)", (nama, harga)) + + # 1. Buat Header Transaksi (Status = Pending) + cur.execute("INSERT INTO transaksi (tanggal, total, meja_id, status) VALUES (?, ?, ?, ?)", + (tanggal, total_belanja, meja, "Pending")) + transaksi_id = cur.lastrowid # Ambil ID transaksi yang baru dibuat + + # 2. Masukkan Detail Item + for item in self.cart: + cur.execute("INSERT INTO detail_transaksi (transaksi_id, menu_nama, harga, jumlah, subtotal) VALUES (?, ?, ?, ?, ?)", + (transaksi_id, item['nama'], item['harga'], 1, item['harga'])) + db.commit() db.close() - messagebox.showinfo("Sukses", "Pesanan dikirim ke kasir") + messagebox.showinfo("Berhasil", "Pesanan terkirim ke Dapur/Waiter!") self.cart.clear() - self.listbox.delete(0, tk.END) - self.total_lbl.config(text="Total: Rp 0") + self.refresh_cart() + self.entry_meja.delete(0, tk.END) def logout(self): self.frame.destroy() from main import LoginScreen - LoginScreen(self.parent) - + LoginScreen(self.parent) \ No newline at end of file diff --git a/project/waiter_dashboard.py b/project/waiter_dashboard.py index a325494..48d7a37 100644 --- a/project/waiter_dashboard.py +++ b/project/waiter_dashboard.py @@ -1,4 +1,6 @@ import tkinter as tk +from tkinter import messagebox +from database import connect class WaiterDashboard: def __init__(self, parent): @@ -6,12 +8,62 @@ class WaiterDashboard: self.frame = tk.Frame(parent) self.frame.pack(fill="both", expand=True) - tk.Label(self.frame, text="WAITER", font=("Arial", 20, "bold")).pack(pady=20) - tk.Label(self.frame, text="(Input pesanan manual)").pack() + tk.Label(self.frame, text="DASHBOARD WAITER (Dapur)", font=("Arial", 18, "bold")).pack(pady=10) + + tk.Button(self.frame, text="Logout", command=self.logout).pack(pady=5) + tk.Button(self.frame, text="Refresh Data", bg="#cfe2ff", command=self.load_orders).pack(pady=5) - tk.Button(self.frame, text="Logout", command=self.logout).pack(pady=10) + # List Pesanan Masuk + self.listbox = tk.Listbox(self.frame, width=80, height=15) + self.listbox.pack(pady=10) + + tk.Button(self.frame, text="Selesai Disajikan / Validasi", bg="#d1e7dd", command=self.validasi_layanan).pack(pady=10) + + self.order_ids = [] # Untuk menyimpan ID transaksi sesuai urutan listbox + self.load_orders() + + def load_orders(self): + self.listbox.delete(0, tk.END) + self.order_ids = [] + + db = connect() + cur = db.cursor() + # Ambil pesanan yang statusnya 'Pending' + cur.execute("SELECT id, meja_id, total, status FROM transaksi WHERE status='Pending'") + rows = cur.fetchall() + + for row in rows: + t_id, meja, total, status = row + # Ambil detail menu untuk ditampilkan + cur.execute("SELECT menu_nama FROM detail_transaksi WHERE transaksi_id=?", (t_id,)) + menus = [r[0] for r in cur.fetchall()] + menu_str = ", ".join(menus) + + display_text = f"[Meja {meja}] ID:{t_id} | Menu: {menu_str} | Status: {status}" + self.listbox.insert(tk.END, display_text) + self.order_ids.append(t_id) + + db.close() + + def validasi_layanan(self): + idx = self.listbox.curselection() + if not idx: + messagebox.showwarning("Pilih", "Pilih pesanan yang sudah disajikan") + return + + selected_id = self.order_ids[idx[0]] + + db = connect() + cur = db.cursor() + # Ubah status jadi 'Disajikan' agar muncul di kasir + cur.execute("UPDATE transaksi SET status='Disajikan' WHERE id=?", (selected_id,)) + db.commit() + db.close() + + messagebox.showinfo("Sukses", "Pesanan selesai disajikan. Pelanggan bisa bayar di kasir.") + self.load_orders() def logout(self): self.frame.destroy() from main import LoginScreen - LoginScreen(self.parent) + LoginScreen(self.parent) \ No newline at end of file