This commit is contained in:
Nathan 2025-12-15 01:10:04 +07:00
commit 40a0ed8d5b
5 changed files with 191 additions and 102 deletions

BIN
cafe.db

Binary file not shown.

View File

@ -1,4 +1,5 @@
import sqlite3 import sqlite3
import datetime
def connect(): def connect():
return sqlite3.connect("cafe.db") return sqlite3.connect("cafe.db")
@ -7,6 +8,7 @@ def setup_database():
db = connect() db = connect()
cur = db.cursor() cur = db.cursor()
# Tabel Users
cur.execute(""" cur.execute("""
CREATE TABLE IF NOT EXISTS users( CREATE TABLE IF NOT EXISTS users(
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
@ -16,44 +18,59 @@ def setup_database():
) )
""") """)
# Tabel Menu
cur.execute(""" cur.execute("""
CREATE TABLE IF NOT EXISTS menu( CREATE TABLE IF NOT EXISTS menu(
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
nama TEXT, nama TEXT,
harga REAL, harga REAL,
gambar TEXT gambar TEXT,
kategori TEXT
) )
""") """)
# Tabel Transaksi (Header nota)
cur.execute(""" cur.execute("""
CREATE TABLE IF NOT EXISTS orders( CREATE TABLE IF NOT EXISTS transaksi(
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
nama TEXT, tanggal TEXT,
harga REAL 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(""" cur.execute("""
CREATE TABLE IF NOT EXISTS pembayaran( CREATE TABLE IF NOT EXISTS detail_transaksi(
id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id INTEGER, transaksi_id INTEGER,
total REAL menu_nama TEXT,
harga REAL,
jumlah INTEGER,
subtotal REAL
) )
""") """)
# Insert Akun Default jika kosong
cur.execute("SELECT COUNT(*) FROM users") cur.execute("SELECT COUNT(*) FROM users")
if cur.fetchone()[0] == 0: if cur.fetchone()[0] == 0:
users = [ users = [
("admin","admin","admin"), ("admin","admin","admin"),
("kasir","kasir","kasir"), ("kasir","kasir","kasir"),
("pembeli","pembeli","pembeli"), ("pembeli","pembeli","pembeli"),
("pemilik","pemilik","pemilik"), ("waiter","waiter","waiter"),
("waiter","waiter","waiter") ("pemilik","pemilik","pemilik")
] ]
cur.executemany( cur.executemany("INSERT INTO users(username,password,role) VALUES (?,?,?)", users)
"INSERT INTO users(username,password,role) VALUES (?,?,?)", db.commit()
users
) # 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.commit()
db.close() db.close()

View File

@ -5,72 +5,60 @@ from database import connect
class KasirPage: class KasirPage:
def __init__(self, parent, controller): def __init__(self, parent, controller):
self.parent = parent self.parent = parent
self.controller = controller
self.frame = tk.Frame(parent) self.frame = tk.Frame(parent)
self.frame.pack(fill="both", expand=True) self.frame.pack(fill="both", expand=True)
tk.Label(self.frame, text="KASIR PAGE", font=("Arial", 18, "bold")).pack(pady=10) tk.Label(self.frame, text="KASIR - PEMBAYARAN", font=("Arial", 18, "bold")).pack(pady=10)
# Tombol Logout
tk.Button(self.frame, text="Logout", bg="#f9e79f", command=self.logout).pack(pady=5) 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 Tagihan (Status: Disajikan):", font=("Arial", 12)).pack(pady=5)
tk.Label(self.frame, text="Daftar Order:", font=("Arial", 12, "bold")).pack(pady=5) self.listbox = tk.Listbox(self.frame, width=60, height=10)
self.listbox = tk.Listbox(self.frame, width=50, height=10)
self.listbox.pack(pady=5) self.listbox.pack(pady=5)
# Tombol bayar tk.Button(self.frame, text="Proses Pembayaran", bg="#d1e7dd", command=self.bayar).pack(pady=5)
tk.Button(self.frame, text="Bayar", 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.listbox.delete(0, tk.END)
self.transaksi_data = []
db = connect() db = connect()
cur = db.cursor() cur = db.cursor()
cur.execute("SELECT id, nama, harga FROM orders") # Kasir hanya melihat yang sudah disajikan waiter
self.data = cur.fetchall() cur.execute("SELECT id, meja_id, total FROM transaksi WHERE status='Disajikan'")
rows = cur.fetchall()
db.close() db.close()
for order in self.data: for row in rows:
self.listbox.insert(tk.END, f"ID {order[0]}: {order[1]} - Rp {order[2]:,}") 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): def bayar(self):
idx = self.listbox.curselection() idx = self.listbox.curselection()
if not idx: if not idx:
messagebox.showwarning("Pilih Order", "Pilih order yang ingin dibayar!") messagebox.showwarning("Pilih", "Pilih tagihan yang akan dibayar!")
return return
order = self.data[idx[0]] t_id, meja, total = self.transaksi_data[idx[0]]
order_id, nama, total = order
# Simpan pembayaran di database (opsional, bisa buat tabel pembayaran) # Konfirmasi pembayaran
confirm = messagebox.askyesno("Konfirmasi", f"Bayar tagihan Meja {meja} sebesar Rp {total:,.0f}?")
if confirm:
db = connect() db = connect()
cur = db.cursor() cur = db.cursor()
cur.execute("INSERT INTO pembayaran VALUES (NULL, ?, ?)", (order_id, total)) # Ubah status menjadi Lunas
cur.execute("DELETE FROM orders WHERE id=?", (order_id,)) cur.execute("UPDATE transaksi SET status='Lunas' WHERE id=?", (t_id,))
db.commit() db.commit()
db.close() db.close()
# Tampilkan struk messagebox.showinfo("Sukses", "Pembayaran Berhasil! Struk dicetak.")
self.tampil_struk(order_id, nama, total) self.load_tagihan()
# 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)
def logout(self): def logout(self):
self.frame.destroy() self.frame.destroy()
from main import LoginScreen from main import LoginScreen
LoginScreen(self.parent) LoginScreen(self.parent)

View File

@ -1,7 +1,8 @@
import tkinter as tk import tkinter as tk
from tkinter import messagebox
from PIL import Image, ImageTk from PIL import Image, ImageTk
from database import connect from database import connect
from tkinter import messagebox import datetime
class PembeliMenu: class PembeliMenu:
def __init__(self, parent): def __init__(self, parent):
@ -9,33 +10,38 @@ class PembeliMenu:
self.frame = tk.Frame(parent) self.frame = tk.Frame(parent)
self.frame.pack(fill="both", expand=True) self.frame.pack(fill="both", expand=True)
self.cart = [] # List dictionary: {'nama':, 'harga':, 'jumlah':}
self.images = []
self.cart = [] # Simpan tuple (nama, harga) # Header
self.images = [] # Simpan reference gambar agar tidak dihapus GC tk.Label(self.frame, text="MENU PELANGGAN", font=("Arial", 18, "bold")).pack(pady=10)
# --- Judul Halaman --- # --- INPUT NOMOR MEJA (Fitur Baru) ---
tk.Label(self.frame, text="MENU PEMBELI", font=("Arial", 18, "bold")).pack(pady=10) 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)
# --- Tombol Logout --- # Logout
tk.Button(self.frame, text="Logout", bg="#f9e79f", command=self.logout).pack(pady=5) 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 = tk.Frame(self.frame)
self.menu_frame.pack(pady=10) self.menu_frame.pack(pady=10, fill="both", expand=True)
self.load_menu() # Load menu dari database # Load Menu
self.load_menu()
# --- Daftar Pesanan --- # Listbox Keranjang
tk.Label(self.frame, text="Daftar Pesanan:", font=("Arial", 12, "bold")).pack(pady=5) tk.Label(self.frame, text="Keranjang Pesanan:").pack()
self.listbox = tk.Listbox(self.frame, width=50, height=6) self.listbox = tk.Listbox(self.frame, width=50, height=6)
self.listbox.pack() self.listbox.pack()
# --- Total ---
self.total_lbl = tk.Label(self.frame, text="Total: Rp 0", font=("Arial", 12, "bold")) self.total_lbl = tk.Label(self.frame, text="Total: Rp 0", font=("Arial", 12, "bold"))
self.total_lbl.pack(pady=5) self.total_lbl.pack(pady=5)
# --- Tombol Checkout --- tk.Button(self.frame, text="PESAN SEKARANG", bg="#d1e7dd", command=self.checkout).pack(pady=10)
tk.Button(self.frame, text="Checkout", bg="#d1e7dd", command=self.checkout).pack(pady=5)
def load_menu(self): def load_menu(self):
db = connect() db = connect()
@ -44,48 +50,74 @@ class PembeliMenu:
data = cur.fetchall() data = cur.fetchall()
db.close() db.close()
row_frame = None
for i, (nama, harga, gambar) in enumerate(data): for i, (nama, harga, gambar) in enumerate(data):
f = tk.Frame(self.menu_frame, bd=2, relief="ridge") if i % 3 == 0:
f.grid(row=i//3, column=i%3, padx=10, pady=10) 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: 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) photo = ImageTk.PhotoImage(img)
self.images.append(photo) self.images.append(photo)
tk.Label(f, image=photo).pack() tk.Label(f, image=photo).pack()
except FileNotFoundError: except:
tk.Label(f, text="No Image").pack() tk.Label(f, text="[No Image]").pack()
tk.Label(f, text=nama).pack() tk.Label(f, text=nama, font=("Arial",10,"bold")).pack()
tk.Label(f, text=f"Rp {harga:,}").pack() tk.Label(f, text=f"Rp {harga:,.0f}").pack()
tk.Button(f, text="Pesan", bg="#cfe2ff", tk.Button(f, text="Tambah", command=lambda n=nama, h=harga: self.add_to_cart(n, h)).pack()
command=lambda n=nama, h=harga: self.add(n, h)).pack(pady=3)
def add(self, nama, harga): def add_to_cart(self, nama, harga):
self.cart.append((nama, harga)) self.cart.append({'nama': nama, 'harga': harga})
self.listbox.insert(tk.END, f"{nama} - Rp {harga:,}") self.refresh_cart()
total = sum(h for _, h in self.cart)
self.total_lbl.config(text=f"Total: Rp {total:,}") 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): def checkout(self):
if not self.cart: meja = self.entry_meja.get()
messagebox.showwarning("Pesan Kosong", "Belum ada pesanan!") if not meja:
messagebox.showwarning("Peringatan", "Isi nomor meja dulu!")
return 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() db = connect()
cur = db.cursor() 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.commit()
db.close() db.close()
messagebox.showinfo("Sukses", "Pesanan dikirim ke kasir") messagebox.showinfo("Berhasil", "Pesanan terkirim ke Dapur/Waiter!")
self.cart.clear() self.cart.clear()
self.listbox.delete(0, tk.END) self.refresh_cart()
self.total_lbl.config(text="Total: Rp 0") self.entry_meja.delete(0, tk.END)
def logout(self): def logout(self):
self.frame.destroy() self.frame.destroy()
from main import LoginScreen from main import LoginScreen
LoginScreen(self.parent) LoginScreen(self.parent)

View File

@ -1,4 +1,6 @@
import tkinter as tk import tkinter as tk
from tkinter import messagebox
from database import connect
class WaiterDashboard: class WaiterDashboard:
def __init__(self, parent): def __init__(self, parent):
@ -6,10 +8,60 @@ class WaiterDashboard:
self.frame = tk.Frame(parent) self.frame = tk.Frame(parent)
self.frame.pack(fill="both", expand=True) 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="DASHBOARD WAITER (Dapur)", font=("Arial", 18, "bold")).pack(pady=10)
tk.Label(self.frame, text="(Input pesanan manual)").pack()
tk.Button(self.frame, text="Logout", command=self.logout).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)
# 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): def logout(self):
self.frame.destroy() self.frame.destroy()