Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu
This commit is contained in:
commit
a3ae8295b9
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,126 +0,0 @@
|
|||||||
import tkinter as tk
|
|
||||||
from tkinter import messagebox, filedialog
|
|
||||||
from database import connect
|
|
||||||
import os
|
|
||||||
import shutil
|
|
||||||
|
|
||||||
class AdminPage(tk.Frame): # Ganti nama class jadi AdminPage
|
|
||||||
def __init__(self, parent, controller):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.controller = controller
|
|
||||||
self.selected_image_path = None
|
|
||||||
|
|
||||||
# --- Header ---
|
|
||||||
top = tk.Frame(self, bg="#333")
|
|
||||||
top.pack(fill="x")
|
|
||||||
tk.Label(top, text="ADMIN DASHBOARD", font=("Arial", 16, "bold"), fg="white", bg="#333").pack(side="left", padx=10, pady=10)
|
|
||||||
tk.Button(top, text="Logout", bg="#ff6b6b", command=lambda: self.controller.show_frame("LoginPage")).pack(side="right", padx=10)
|
|
||||||
|
|
||||||
# --- Form Input (Kiri) ---
|
|
||||||
left_frame = tk.Frame(self, padx=10, pady=10)
|
|
||||||
left_frame.pack(side="left", fill="y")
|
|
||||||
|
|
||||||
tk.Label(left_frame, text="Nama Menu:").pack(anchor="w")
|
|
||||||
self.entry_nama = tk.Entry(left_frame, width=30)
|
|
||||||
self.entry_nama.pack(pady=5)
|
|
||||||
|
|
||||||
tk.Label(left_frame, text="Harga:").pack(anchor="w")
|
|
||||||
self.entry_harga = tk.Entry(left_frame, width=30)
|
|
||||||
self.entry_harga.pack(pady=5)
|
|
||||||
|
|
||||||
tk.Label(left_frame, text="Stok Awal:").pack(anchor="w")
|
|
||||||
self.entry_stok = tk.Entry(left_frame, width=30)
|
|
||||||
self.entry_stok.pack(pady=5)
|
|
||||||
|
|
||||||
tk.Label(left_frame, text="Gambar:").pack(anchor="w")
|
|
||||||
self.btn_img = tk.Button(left_frame, text="Pilih Gambar", command=self.browse_image)
|
|
||||||
self.btn_img.pack(pady=5, anchor="w")
|
|
||||||
self.lbl_img_path = tk.Label(left_frame, text="Belum ada gambar", fg="gray", font=("Arial", 8))
|
|
||||||
self.lbl_img_path.pack(anchor="w")
|
|
||||||
|
|
||||||
# Tombol Aksi
|
|
||||||
btn_box = tk.Frame(left_frame, pady=20)
|
|
||||||
btn_box.pack()
|
|
||||||
tk.Button(btn_box, text="TAMBAH", bg="#4CAF50", fg="white", command=self.add_menu).grid(row=0, column=0, padx=5)
|
|
||||||
tk.Button(btn_box, text="HAPUS", bg="#f44336", fg="white", command=self.delete_menu).grid(row=0, column=1, padx=5)
|
|
||||||
|
|
||||||
# --- Tabel Menu (Kanan) ---
|
|
||||||
right_frame = tk.Frame(self, padx=10, pady=10)
|
|
||||||
right_frame.pack(side="right", fill="both", expand=True)
|
|
||||||
|
|
||||||
tk.Label(right_frame, text="Daftar Menu Database:", font=("Arial", 10, "bold")).pack(anchor="w")
|
|
||||||
|
|
||||||
self.list_menu = tk.Listbox(right_frame)
|
|
||||||
self.list_menu.pack(fill="both", expand=True)
|
|
||||||
|
|
||||||
scrollbar = tk.Scrollbar(self.list_menu)
|
|
||||||
scrollbar.pack(side="right", fill="y")
|
|
||||||
self.list_menu.config(yscrollcommand=scrollbar.set)
|
|
||||||
scrollbar.config(command=self.list_menu.yview)
|
|
||||||
|
|
||||||
def update_data(self):
|
|
||||||
self.list_menu.delete(0, tk.END)
|
|
||||||
self.data_menu = []
|
|
||||||
|
|
||||||
db = connect()
|
|
||||||
cur = db.cursor()
|
|
||||||
cur.execute("SELECT id, nama, harga, stok FROM menu")
|
|
||||||
rows = cur.fetchall()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
for row in rows:
|
|
||||||
self.data_menu.append(row)
|
|
||||||
self.list_menu.insert(tk.END, f"{row[1]} - Rp {int(row[2])} (Stok: {row[3]})")
|
|
||||||
|
|
||||||
def browse_image(self):
|
|
||||||
filename = filedialog.askopenfilename(title="Pilih Gambar", filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")])
|
|
||||||
if filename:
|
|
||||||
self.selected_image_path = filename
|
|
||||||
self.lbl_img_path.config(text=os.path.basename(filename), fg="black")
|
|
||||||
|
|
||||||
def add_menu(self):
|
|
||||||
nama = self.entry_nama.get()
|
|
||||||
harga = self.entry_harga.get()
|
|
||||||
stok = self.entry_stok.get()
|
|
||||||
|
|
||||||
if not nama or not harga:
|
|
||||||
messagebox.showwarning("Warning", "Nama dan Harga wajib diisi!")
|
|
||||||
return
|
|
||||||
|
|
||||||
final_image_path = "default.png"
|
|
||||||
if self.selected_image_path:
|
|
||||||
if not os.path.exists("img"): os.makedirs("img")
|
|
||||||
nama_file_asli = os.path.basename(self.selected_image_path)
|
|
||||||
destinasi = os.path.join("img", nama_file_asli)
|
|
||||||
shutil.copy(self.selected_image_path, destinasi)
|
|
||||||
final_image_path = destinasi
|
|
||||||
|
|
||||||
db = connect()
|
|
||||||
cur = db.cursor()
|
|
||||||
try:
|
|
||||||
cur.execute("INSERT INTO menu (nama, harga, stok, gambar) VALUES (?, ?, ?, ?)",
|
|
||||||
(nama, harga, stok if stok else 0, final_image_path))
|
|
||||||
db.commit()
|
|
||||||
messagebox.showinfo("Sukses", "Menu berhasil ditambahkan!")
|
|
||||||
self.entry_nama.delete(0, tk.END)
|
|
||||||
self.entry_harga.delete(0, tk.END)
|
|
||||||
self.entry_stok.delete(0, tk.END)
|
|
||||||
self.update_data()
|
|
||||||
except Exception as e:
|
|
||||||
messagebox.showerror("Error", str(e))
|
|
||||||
finally:
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
def delete_menu(self):
|
|
||||||
idx = self.list_menu.curselection()
|
|
||||||
if not idx:
|
|
||||||
messagebox.showwarning("Pilih", "Pilih menu dulu!")
|
|
||||||
return
|
|
||||||
|
|
||||||
id_menu = self.data_menu[idx[0]][0]
|
|
||||||
if messagebox.askyesno("Hapus", "Yakin hapus menu ini?"):
|
|
||||||
db = connect()
|
|
||||||
db.cursor().execute("DELETE FROM menu WHERE id=?", (id_menu,))
|
|
||||||
db.commit()
|
|
||||||
db.close()
|
|
||||||
self.update_data()
|
|
||||||
@ -1,74 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
|
|
||||||
def connect():
|
|
||||||
return sqlite3.connect("cafe.db")
|
|
||||||
|
|
||||||
def setup_database():
|
|
||||||
db = connect()
|
|
||||||
cur = db.cursor()
|
|
||||||
|
|
||||||
# 1. Users
|
|
||||||
cur.execute("""
|
|
||||||
CREATE TABLE IF NOT EXISTS users(
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
username TEXT,
|
|
||||||
password TEXT,
|
|
||||||
role TEXT
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
# 2. Menu
|
|
||||||
cur.execute("""
|
|
||||||
CREATE TABLE IF NOT EXISTS menu(
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
nama TEXT,
|
|
||||||
kategori TEXT,
|
|
||||||
harga REAL,
|
|
||||||
stok INTEGER,
|
|
||||||
gambar TEXT
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
# 3. Transaksi (Header)
|
|
||||||
cur.execute("""
|
|
||||||
CREATE TABLE IF NOT EXISTS transaksi(
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
nama_pelanggan TEXT,
|
|
||||||
meja_id INTEGER,
|
|
||||||
tanggal TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
total REAL,
|
|
||||||
metode_pembayaran TEXT,
|
|
||||||
status TEXT DEFAULT 'Pending'
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
# Status Flow: 'Pending' (Dipesan) -> 'Served' (Diantar Waiter) -> 'Paid' (Dibayar di Kasir)
|
|
||||||
|
|
||||||
# 4. Detail Transaksi
|
|
||||||
cur.execute("""
|
|
||||||
CREATE TABLE IF NOT EXISTS detail_transaksi(
|
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
transaksi_id INTEGER,
|
|
||||||
menu_id INTEGER,
|
|
||||||
jumlah INTEGER,
|
|
||||||
subtotal REAL
|
|
||||||
)
|
|
||||||
""")
|
|
||||||
|
|
||||||
# Seeding Data User Dummy
|
|
||||||
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")
|
|
||||||
]
|
|
||||||
cur.executemany("INSERT INTO users(username,password,role) VALUES (?,?,?)", users)
|
|
||||||
|
|
||||||
db.commit()
|
|
||||||
db.close()
|
|
||||||
print("Database Ready bos!")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
setup_database()
|
|
||||||
@ -1,49 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import os
|
|
||||||
# PERHATIKAN: Ini harus setup_database, BUKAN init_db
|
|
||||||
from database import setup_database
|
|
||||||
|
|
||||||
def isi_data_awal():
|
|
||||||
# 1. Pastikan database dan tabel sudah dibuat
|
|
||||||
setup_database()
|
|
||||||
|
|
||||||
db_name = "cafe.db"
|
|
||||||
|
|
||||||
# 2. Cek folder aset
|
|
||||||
# Pastikan kamu punya folder bernama 'aset' dan di dalamnya ada gambar-gambarnya
|
|
||||||
if not os.path.exists("aset"):
|
|
||||||
print("❌ WADUH! Folder 'aset' gak ketemu. Pastikan nama folder di kiri adalah 'aset'.")
|
|
||||||
return
|
|
||||||
|
|
||||||
conn = sqlite3.connect(db_name)
|
|
||||||
cur = conn.cursor()
|
|
||||||
|
|
||||||
print("♻️ Membersihkan data lama...")
|
|
||||||
cur.execute("DELETE FROM menu")
|
|
||||||
cur.execute("DELETE FROM sqlite_sequence WHERE name='menu'") # Reset ID jadi 1
|
|
||||||
|
|
||||||
# 3. Data Menu (Path gambar pakai 'aset/')
|
|
||||||
menus = [
|
|
||||||
("Ayam Goreng", "Makanan", 15000, 20, "aset/ayam_goreng.jpg"),
|
|
||||||
("Bakso Urat", "Makanan", 12000, 15, "aset/bakso.jpg"),
|
|
||||||
("Mie Ayam", "Makanan", 10000, 25, "aset/mie_ayam.jpg"),
|
|
||||||
("Es Teh Manis", "Minuman", 3000, 50, "aset/es_teh.jpg"),
|
|
||||||
("Jus Jeruk", "Minuman", 5000, 30, "aset/jus_jeruk.jpg"),
|
|
||||||
]
|
|
||||||
|
|
||||||
print("📥 Sedang mengisi data menu...")
|
|
||||||
|
|
||||||
try:
|
|
||||||
cur.executemany("""
|
|
||||||
INSERT INTO menu (nama, kategori, harga, stok, gambar)
|
|
||||||
VALUES (?, ?, ?, ?, ?)
|
|
||||||
""", menus)
|
|
||||||
conn.commit()
|
|
||||||
print("✅ MANTAP! Data menu berhasil masuk. Sekarang jalankan main.py!")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"❌ Error: {e}")
|
|
||||||
finally:
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
isi_data_awal()
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
import tkinter as tk
|
|
||||||
from tkinter import messagebox
|
|
||||||
from database import connect
|
|
||||||
|
|
||||||
class KasirPage(tk.Frame):
|
|
||||||
def __init__(self, parent, controller):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.controller = controller
|
|
||||||
|
|
||||||
# Header
|
|
||||||
top = tk.Frame(self, bg="#ddd")
|
|
||||||
top.pack(fill="x")
|
|
||||||
tk.Button(top, text="Logout", command=lambda: controller.show_frame("LoginPage")).pack(side="right", padx=10, pady=5)
|
|
||||||
tk.Label(top, text="KASIR - PEMBAYARAN", font=("Arial", 16, "bold"), bg="#ddd").pack(side="left", padx=10)
|
|
||||||
|
|
||||||
# List
|
|
||||||
tk.Label(self, text="Tagihan Belum Bayar (Status: Served):", font=("Arial", 11)).pack(pady=10)
|
|
||||||
self.order_list = tk.Listbox(self, width=80, height=15)
|
|
||||||
self.order_list.pack(pady=5)
|
|
||||||
|
|
||||||
tk.Button(self, text="Refresh Data", command=self.update_data).pack(pady=5)
|
|
||||||
tk.Button(self, text="💰 PROSES BAYAR & LUNAS", bg="#81C784", height=2, command=self.bayar).pack(fill="x", padx=20, pady=20)
|
|
||||||
|
|
||||||
def update_data(self):
|
|
||||||
self.order_list.delete(0, tk.END)
|
|
||||||
self.data_orders = []
|
|
||||||
|
|
||||||
db = connect()
|
|
||||||
cur = db.cursor()
|
|
||||||
# Kasir melihat yang sudah diantar (Served) tapi belum bayar
|
|
||||||
cur.execute("SELECT id, nama_pelanggan, meja_id, total FROM transaksi WHERE status='Served'")
|
|
||||||
self.data_orders = cur.fetchall()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
for item in self.data_orders:
|
|
||||||
self.order_list.insert(tk.END, f"ID Transaksi: {item[0]} | Meja {item[2]} | {item[1]} | Tagihan: Rp {int(item[3]):,}")
|
|
||||||
|
|
||||||
def bayar(self):
|
|
||||||
idx = self.order_list.curselection()
|
|
||||||
if not idx:
|
|
||||||
messagebox.showwarning("Pilih", "Pilih tagihan dulu!")
|
|
||||||
return
|
|
||||||
|
|
||||||
selected = self.data_orders[idx[0]]
|
|
||||||
trans_id = selected[0]
|
|
||||||
total = selected[3]
|
|
||||||
|
|
||||||
# Konfirmasi
|
|
||||||
if not messagebox.askyesno("Konfirmasi", f"Terima pembayaran sebesar Rp {int(total):,}?"):
|
|
||||||
return
|
|
||||||
|
|
||||||
db = connect()
|
|
||||||
cur = db.cursor()
|
|
||||||
|
|
||||||
# Update status jadi 'Paid'
|
|
||||||
cur.execute("UPDATE transaksi SET status='Paid', metode_pembayaran='CASH' WHERE id=?", (trans_id,))
|
|
||||||
|
|
||||||
db.commit()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
messagebox.showinfo("Lunas", "Transaksi Selesai & Lunas!")
|
|
||||||
self.update_data()
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
import tkinter as tk
|
|
||||||
from tkinter import messagebox
|
|
||||||
from database import connect
|
|
||||||
|
|
||||||
# Pastikan import ini sesuai
|
|
||||||
from admin_menu import AdminPage
|
|
||||||
from pembeli_menu import PembeliPage
|
|
||||||
from kasir import KasirPage
|
|
||||||
from pemilik import PemilikPage
|
|
||||||
from waiter_dashboard import WaiterPage
|
|
||||||
|
|
||||||
class LoginPage(tk.Frame):
|
|
||||||
def __init__(self, parent, controller):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.controller = controller
|
|
||||||
|
|
||||||
tk.Label(self, text="LOGIN SYSTEM", font=("Arial", 20, "bold")).pack(pady=40)
|
|
||||||
|
|
||||||
frame_login = tk.Frame(self)
|
|
||||||
frame_login.pack()
|
|
||||||
|
|
||||||
tk.Label(frame_login, text="Username:").pack()
|
|
||||||
self.user = tk.Entry(frame_login)
|
|
||||||
self.user.pack(pady=5)
|
|
||||||
|
|
||||||
tk.Label(frame_login, text="Password:").pack()
|
|
||||||
self.passw = tk.Entry(frame_login, show="*")
|
|
||||||
self.passw.pack(pady=5)
|
|
||||||
|
|
||||||
tk.Button(frame_login, text="LOGIN", command=self.login, width=20, bg="#2196F3", fg="white").pack(pady=20)
|
|
||||||
|
|
||||||
def login(self):
|
|
||||||
u = self.user.get()
|
|
||||||
p = self.passw.get()
|
|
||||||
|
|
||||||
db = connect()
|
|
||||||
cur = db.cursor()
|
|
||||||
cur.execute("SELECT role FROM users WHERE username=? AND password=?", (u, p))
|
|
||||||
res = cur.fetchone()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
if not res:
|
|
||||||
messagebox.showerror("Gagal", "Username/Password salah!")
|
|
||||||
return
|
|
||||||
|
|
||||||
role = res[0]
|
|
||||||
# Reset input
|
|
||||||
self.user.delete(0, tk.END)
|
|
||||||
self.passw.delete(0, tk.END)
|
|
||||||
|
|
||||||
# Redirect sesuai Role
|
|
||||||
if role == "admin":
|
|
||||||
self.controller.show_frame("AdminPage")
|
|
||||||
elif role == "pembeli":
|
|
||||||
self.controller.show_frame("PembeliPage")
|
|
||||||
elif role == "kasir":
|
|
||||||
self.controller.show_frame("KasirPage")
|
|
||||||
elif role == "pemilik":
|
|
||||||
self.controller.show_frame("PemilikPage")
|
|
||||||
elif role == "waiter":
|
|
||||||
self.controller.show_frame("WaiterPage")
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
import tkinter as tk
|
|
||||||
from database import setup_database
|
|
||||||
|
|
||||||
# Import class yang sudah kita benerin namanya
|
|
||||||
from login import LoginPage
|
|
||||||
from admin_menu import AdminPage
|
|
||||||
from pembeli_menu import PembeliPage
|
|
||||||
from kasir import KasirPage
|
|
||||||
from pemilik import PemilikPage
|
|
||||||
from waiter_dashboard import WaiterPage
|
|
||||||
|
|
||||||
class CafeApp(tk.Tk):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.title("Sistem Manajemen Kafe Python")
|
|
||||||
self.geometry("1000x700")
|
|
||||||
|
|
||||||
setup_database() # Auto bikin tabel
|
|
||||||
|
|
||||||
self.container = tk.Frame(self)
|
|
||||||
self.container.pack(side="top", fill="both", expand=True)
|
|
||||||
self.container.grid_rowconfigure(0, weight=1)
|
|
||||||
self.container.grid_columnconfigure(0, weight=1)
|
|
||||||
|
|
||||||
self.frames = {}
|
|
||||||
|
|
||||||
# Loop semua halaman
|
|
||||||
for F in (LoginPage, AdminPage, PembeliPage, KasirPage, PemilikPage, WaiterPage):
|
|
||||||
page_name = F.__name__
|
|
||||||
frame = F(parent=self.container, controller=self)
|
|
||||||
self.frames[page_name] = frame
|
|
||||||
frame.grid(row=0, column=0, sticky="nsew")
|
|
||||||
|
|
||||||
self.show_frame("LoginPage")
|
|
||||||
|
|
||||||
def show_frame(self, page_name):
|
|
||||||
frame = self.frames[page_name]
|
|
||||||
if hasattr(frame, "update_data"):
|
|
||||||
frame.update_data()
|
|
||||||
frame.tkraise()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
app = CafeApp()
|
|
||||||
app.mainloop()
|
|
||||||
@ -1,169 +0,0 @@
|
|||||||
import tkinter as tk
|
|
||||||
from tkinter import messagebox, ttk
|
|
||||||
from database import connect
|
|
||||||
|
|
||||||
class PembeliPage(tk.Frame): # Ganti nama class jadi PembeliPage
|
|
||||||
def __init__(self, parent, controller):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.controller = controller
|
|
||||||
self.cart = {}
|
|
||||||
self.nama_pelanggan = ""
|
|
||||||
self.no_meja = ""
|
|
||||||
|
|
||||||
self.login_frame = tk.Frame(self)
|
|
||||||
self.menu_frame = tk.Frame(self)
|
|
||||||
self.show_login_ui()
|
|
||||||
|
|
||||||
# --- UI 1: LOGIN PEMBELI ---
|
|
||||||
def show_login_ui(self):
|
|
||||||
self.menu_frame.pack_forget()
|
|
||||||
self.login_frame.pack(fill="both", expand=True)
|
|
||||||
|
|
||||||
for w in self.login_frame.winfo_children(): w.destroy()
|
|
||||||
|
|
||||||
tk.Label(self.login_frame, text="SELAMAT DATANG", font=("Arial", 20, "bold")).pack(pady=50)
|
|
||||||
|
|
||||||
box = tk.Frame(self.login_frame, bd=2, relief="groove", padx=20, pady=20)
|
|
||||||
box.pack()
|
|
||||||
|
|
||||||
tk.Label(box, text="Nama Anda:").pack(anchor="w")
|
|
||||||
self.entry_nama = tk.Entry(box, width=30)
|
|
||||||
self.entry_nama.pack(pady=5)
|
|
||||||
|
|
||||||
tk.Label(box, text="Nomor Meja:").pack(anchor="w")
|
|
||||||
self.combo_meja = ttk.Combobox(box, values=[str(i) for i in range(1, 21)], state="readonly")
|
|
||||||
self.combo_meja.current(0)
|
|
||||||
self.combo_meja.pack(pady=5)
|
|
||||||
|
|
||||||
tk.Button(box, text="MULAI PESAN", bg="#4CAF50", fg="white", command=self.validate_login).pack(pady=20, fill="x")
|
|
||||||
tk.Button(self.login_frame, text="Kembali", command=lambda: self.controller.show_frame("LoginPage")).pack(pady=10)
|
|
||||||
|
|
||||||
def validate_login(self):
|
|
||||||
if not self.entry_nama.get():
|
|
||||||
messagebox.showwarning("Oops", "Nama wajib diisi!")
|
|
||||||
return
|
|
||||||
self.nama_pelanggan = self.entry_nama.get()
|
|
||||||
self.no_meja = self.combo_meja.get()
|
|
||||||
self.show_menu_ui()
|
|
||||||
|
|
||||||
# --- UI 2: MENU MAKANAN ---
|
|
||||||
def show_menu_ui(self):
|
|
||||||
self.login_frame.pack_forget()
|
|
||||||
self.menu_frame.pack(fill="both", expand=True)
|
|
||||||
|
|
||||||
# Bersihkan frame lama biar gak numpuk
|
|
||||||
for w in self.menu_frame.winfo_children(): w.destroy()
|
|
||||||
|
|
||||||
# Header
|
|
||||||
top = tk.Frame(self.menu_frame, bg="#eee", pady=10)
|
|
||||||
top.pack(fill="x")
|
|
||||||
tk.Label(top, text=f"👤 {self.nama_pelanggan} | Meja {self.no_meja}", font=("Arial", 12)).pack(side="left", padx=20)
|
|
||||||
tk.Button(top, text="Keluar", bg="#ff6b6b", fg="white", command=self.logout).pack(side="right", padx=20)
|
|
||||||
|
|
||||||
content = tk.Frame(self.menu_frame)
|
|
||||||
content.pack(fill="both", expand=True, padx=10, pady=10)
|
|
||||||
|
|
||||||
# Kiri: Daftar Menu
|
|
||||||
left_frame = tk.LabelFrame(content, text=" Menu Tersedia ")
|
|
||||||
left_frame.pack(side="left", fill="both", expand=True)
|
|
||||||
|
|
||||||
canvas = tk.Canvas(left_frame)
|
|
||||||
scrollbar = tk.Scrollbar(left_frame, orient="vertical", command=canvas.yview)
|
|
||||||
self.scroll_frame = tk.Frame(canvas)
|
|
||||||
|
|
||||||
self.scroll_frame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
|
|
||||||
canvas.create_window((0, 0), window=self.scroll_frame, anchor="nw")
|
|
||||||
canvas.configure(yscrollcommand=scrollbar.set)
|
|
||||||
|
|
||||||
canvas.pack(side="left", fill="both", expand=True)
|
|
||||||
scrollbar.pack(side="right", fill="y")
|
|
||||||
|
|
||||||
# Kanan: Keranjang
|
|
||||||
right_frame = tk.LabelFrame(content, text=" Keranjang ")
|
|
||||||
right_frame.pack(side="right", fill="both", width=300, padx=5)
|
|
||||||
|
|
||||||
self.cart_list = tk.Listbox(right_frame)
|
|
||||||
self.cart_list.pack(fill="both", expand=True, padx=5, pady=5)
|
|
||||||
|
|
||||||
self.lbl_total = tk.Label(right_frame, text="Total: Rp 0", font=("Arial", 14, "bold"), fg="red")
|
|
||||||
self.lbl_total.pack(pady=5)
|
|
||||||
|
|
||||||
tk.Button(right_frame, text="PESAN SEKARANG", bg="green", fg="white", height=2, command=self.checkout).pack(fill="x", padx=5, pady=5)
|
|
||||||
|
|
||||||
self.load_menu_items()
|
|
||||||
|
|
||||||
def load_menu_items(self):
|
|
||||||
for w in self.scroll_frame.winfo_children(): w.destroy()
|
|
||||||
|
|
||||||
db = connect()
|
|
||||||
cur = db.cursor()
|
|
||||||
cur.execute("SELECT id, nama, harga, stok FROM menu WHERE stok > 0")
|
|
||||||
items = cur.fetchall()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
row, col = 0, 0
|
|
||||||
for item in items:
|
|
||||||
m_id, nama, harga, stok = item
|
|
||||||
card = tk.Frame(self.scroll_frame, bd=2, relief="ridge", padx=5, pady=5)
|
|
||||||
card.grid(row=row, column=col, padx=5, pady=5, sticky="nsew")
|
|
||||||
|
|
||||||
tk.Label(card, text=nama, font=("Arial", 10, "bold")).pack()
|
|
||||||
tk.Label(card, text=f"Rp {int(harga):,}", fg="green").pack()
|
|
||||||
tk.Button(card, text="Tambah +", command=lambda i=m_id, n=nama, h=harga: self.add_to_cart(i, n, h)).pack(pady=2)
|
|
||||||
|
|
||||||
col += 1
|
|
||||||
if col > 2:
|
|
||||||
col = 0
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
def add_to_cart(self, m_id, nama, harga):
|
|
||||||
if m_id in self.cart:
|
|
||||||
self.cart[m_id]['qty'] += 1
|
|
||||||
else:
|
|
||||||
self.cart[m_id] = {'nama': nama, 'harga': harga, 'qty': 1}
|
|
||||||
self.refresh_cart()
|
|
||||||
|
|
||||||
def refresh_cart(self):
|
|
||||||
self.cart_list.delete(0, tk.END)
|
|
||||||
total = 0
|
|
||||||
for m_id, item in self.cart.items():
|
|
||||||
sub = item['harga'] * item['qty']
|
|
||||||
total += sub
|
|
||||||
self.cart_list.insert(tk.END, f"{item['qty']}x {item['nama']} = {sub:,}")
|
|
||||||
self.lbl_total.config(text=f"Total: Rp {int(total):,}")
|
|
||||||
|
|
||||||
def checkout(self):
|
|
||||||
if not self.cart: return
|
|
||||||
|
|
||||||
total_val = int(self.lbl_total.cget("text").replace("Total: Rp ","").replace(",",""))
|
|
||||||
|
|
||||||
db = connect()
|
|
||||||
cur = db.cursor()
|
|
||||||
|
|
||||||
# Simpan ke tabel TRANSAKSI (Bukan orders)
|
|
||||||
cur.execute("INSERT INTO transaksi (nama_pelanggan, meja_id, total, status) VALUES (?, ?, ?, 'Pending')",
|
|
||||||
(self.nama_pelanggan, self.no_meja, total_val))
|
|
||||||
trans_id = cur.lastrowid
|
|
||||||
|
|
||||||
# Simpan Detail
|
|
||||||
for m_id, item in self.cart.items():
|
|
||||||
sub = item['harga'] * item['qty']
|
|
||||||
cur.execute("INSERT INTO detail_transaksi (transaksi_id, menu_id, jumlah, subtotal) VALUES (?,?,?,?)",
|
|
||||||
(trans_id, m_id, item['qty'], sub))
|
|
||||||
# Kurangi Stok
|
|
||||||
cur.execute("UPDATE menu SET stok = stok - ? WHERE id=?", (item['qty'], m_id))
|
|
||||||
|
|
||||||
db.commit()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
messagebox.showinfo("Sukses", "Pesanan terkirim! Mohon tunggu.")
|
|
||||||
self.cart = {}
|
|
||||||
self.refresh_cart()
|
|
||||||
self.load_menu_items()
|
|
||||||
|
|
||||||
def logout(self):
|
|
||||||
self.cart = {}
|
|
||||||
self.show_login_ui()
|
|
||||||
|
|
||||||
def update_data(self):
|
|
||||||
self.show_login_ui()
|
|
||||||
@ -1,36 +0,0 @@
|
|||||||
import tkinter as tk
|
|
||||||
from database import connect
|
|
||||||
|
|
||||||
class PemilikPage(tk.Frame): # HARUS inherit tk.Frame
|
|
||||||
def __init__(self, parent, controller):
|
|
||||||
super().__init__(parent) # Init parent class
|
|
||||||
self.controller = controller
|
|
||||||
|
|
||||||
tk.Label(self, text="LAPORAN PENJUALAN (OWNER)", font=("Arial", 18, "bold")).pack(pady=20)
|
|
||||||
|
|
||||||
self.box = tk.Frame(self, bd=2, relief="groove", padx=40, pady=40)
|
|
||||||
self.box.pack()
|
|
||||||
|
|
||||||
# Label Total
|
|
||||||
self.total_lbl = tk.Label(self.box, text="Total Pendapatan: Rp 0", font=("Arial", 20, "bold"), fg="green")
|
|
||||||
self.total_lbl.pack(pady=10)
|
|
||||||
|
|
||||||
self.count_lbl = tk.Label(self.box, text="Jumlah Transaksi: 0", font=("Arial", 12))
|
|
||||||
self.count_lbl.pack(pady=5)
|
|
||||||
|
|
||||||
tk.Button(self, text="Refresh Laporan", bg="#cfe2ff", command=self.update_data).pack(pady=10)
|
|
||||||
tk.Button(self, text="Logout", bg="#f9e79f", command=lambda: controller.show_frame("LoginPage")).pack(pady=5)
|
|
||||||
|
|
||||||
def update_data(self):
|
|
||||||
db = connect()
|
|
||||||
cur = db.cursor()
|
|
||||||
# Hitung total dari transaksi yang statusnya 'Paid'
|
|
||||||
cur.execute("SELECT SUM(total), COUNT(id) FROM transaksi WHERE status='Paid'")
|
|
||||||
res = cur.fetchone()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
total_duit = res[0] if res[0] else 0
|
|
||||||
total_transaksi = res[1] if res[1] else 0
|
|
||||||
|
|
||||||
self.total_lbl.config(text=f"Total Pendapatan: Rp {int(total_duit):,}")
|
|
||||||
self.count_lbl.config(text=f"Jumlah Transaksi Sukses: {total_transaksi}")
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
project/
|
|
||||||
│ main.py
|
|
||||||
│ database.py
|
|
||||||
│ pembeli_menu.py
|
|
||||||
│ kasir_page.py
|
|
||||||
│ pemilik_page.py
|
|
||||||
│ mie ayam.webp
|
|
||||||
│ mie kuah.webp
|
|
||||||
│ es teh.webp
|
|
||||||
│ jus jeruk.webp
|
|
||||||
@ -1,59 +0,0 @@
|
|||||||
import tkinter as tk
|
|
||||||
from tkinter import messagebox
|
|
||||||
from database import connect
|
|
||||||
|
|
||||||
class WaiterPage(tk.Frame):
|
|
||||||
def __init__(self, parent, controller):
|
|
||||||
super().__init__(parent)
|
|
||||||
self.controller = controller
|
|
||||||
|
|
||||||
# Header
|
|
||||||
top = tk.Frame(self, bg="#FF9800")
|
|
||||||
top.pack(fill="x")
|
|
||||||
tk.Label(top, text="WAITER DASHBOARD", font=("Arial", 16, "bold"), bg="#FF9800", fg="white").pack(side="left", padx=10, pady=10)
|
|
||||||
tk.Button(top, text="Logout", command=lambda: controller.show_frame("LoginPage")).pack(side="right", padx=10)
|
|
||||||
|
|
||||||
# Content
|
|
||||||
tk.Label(self, text="Pesanan Pending (Perlu Diantar):", font=("Arial", 12)).pack(pady=10)
|
|
||||||
|
|
||||||
self.list_orders = tk.Listbox(self, width=80, height=15)
|
|
||||||
self.list_orders.pack(pady=5)
|
|
||||||
|
|
||||||
btn_frame = tk.Frame(self)
|
|
||||||
btn_frame.pack(pady=10)
|
|
||||||
|
|
||||||
tk.Button(btn_frame, text="Refresh", command=self.update_data).pack(side="left", padx=5)
|
|
||||||
tk.Button(btn_frame, text="✅ Selesai Diantar (Served)", bg="#81C784", command=self.mark_served).pack(side="left", padx=5)
|
|
||||||
|
|
||||||
def update_data(self):
|
|
||||||
self.list_orders.delete(0, tk.END)
|
|
||||||
self.data_orders = []
|
|
||||||
|
|
||||||
db = connect()
|
|
||||||
cur = db.cursor()
|
|
||||||
# Ambil transaksi yang statusnya 'Pending'
|
|
||||||
cur.execute("SELECT id, nama_pelanggan, meja_id, total FROM transaksi WHERE status='Pending'")
|
|
||||||
self.data_orders = cur.fetchall()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
for item in self.data_orders:
|
|
||||||
# item = (id, nama, meja, total)
|
|
||||||
self.list_orders.insert(tk.END, f"ID: {item[0]} | Meja: {item[2]} | A.N: {item[1]} | Total: Rp {int(item[3]):,}")
|
|
||||||
|
|
||||||
def mark_served(self):
|
|
||||||
idx = self.list_orders.curselection()
|
|
||||||
if not idx:
|
|
||||||
messagebox.showwarning("Pilih", "Pilih pesanan dulu!")
|
|
||||||
return
|
|
||||||
|
|
||||||
trans_id = self.data_orders[idx[0]][0]
|
|
||||||
|
|
||||||
db = connect()
|
|
||||||
cur = db.cursor()
|
|
||||||
# Update status jadi 'Served' biar muncul di Kasir
|
|
||||||
cur.execute("UPDATE transaksi SET status='Served' WHERE id=?", (trans_id,))
|
|
||||||
db.commit()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
messagebox.showinfo("Sukses", "Pesanan Meja ini sudah dilayani!")
|
|
||||||
self.update_data()
|
|
||||||
Loading…
x
Reference in New Issue
Block a user