Compare commits

...
34 Commits
Author SHA1 Message Date
5803025001 f349274710 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-16 15:31:17 +07:00
ofeleoprecio 4c8221971a fixing things 2025-12-16 15:31:14 +07:00
ofeleoprecio 5bd728b1bd fixing things 2025-12-16 15:24:08 +07:00
ofeleoprecio 9053434a83 add new 2025-12-16 15:14:12 +07:00
5803025001 e8edfe939f Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-16 10:53:17 +07:00
5803025001 17bdf516b3 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-16 10:53:14 +07:00
ofeleoprecio 94e45a7aad Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-16 10:29:03 +07:00
5803025001 54c14826c4 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-16 10:28:56 +07:00
5803025001 52233b09be Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 09:16:19 +07:00
5803025001 3ab63e6327 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 09:16:17 +07:00
5803025001 e8bc7113d1 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 09:04:23 +07:00
5803025001 509715f629 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 09:04:20 +07:00
5803025001 c4b6e1fba9 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 08:55:06 +07:00
5803025001 e5c6da3417 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 08:55:02 +07:00
5803025001 92abbb95fa Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 04:23:49 +07:00
5803025001 6e6218f2fa Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 04:23:45 +07:00
5803025001 3dc145beae Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 03:07:38 +07:00
5803025001 78c730f245 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 03:07:32 +07:00
5803025001 984b1ecba5 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 02:56:50 +07:00
5803025001 eaf12c10a4 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 02:56:48 +07:00
5803025001 29f0700324 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 02:36:24 +07:00
5803025001 2a9b7a4edc Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 02:36:20 +07:00
5803025001 787bf561e4 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 02:28:36 +07:00
5803025001 b1a5224a67 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 02:28:33 +07:00
5803025001 a710f36393 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 01:38:33 +07:00
5803025001 67c6169a7e Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 01:38:30 +07:00
5803025001 20386a867a Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 01:29:49 +07:00
5803025001 f62c4904cd Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 01:29:46 +07:00
5803025001 6359376da0 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 01:21:00 +07:00
5803025001 5f55320865 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 01:20:56 +07:00
5803025001 02aa1da64f Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 01:16:34 +07:00
5803025001 db80a043d7 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 01:16:31 +07:00
5803025001 69e133c6e3 Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 01:12:43 +07:00
5803025001 40a0ed8d5b Merge branch 'main' of https://git-eng.ukwms.ac.id/5803025001/Python-Menu 2025-12-15 01:12:40 +07:00
17 changed files with 1076 additions and 155 deletions
+1
View File
@@ -0,0 +1 @@
*.pyc
BIN
View File
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.
+200 -16
View File
@@ -1,40 +1,224 @@
import tkinter as tk import tkinter as tk
from database import connect
from tkinter import messagebox from tkinter import messagebox
from database import connect
class AdminMenu: class AdminMenu:
def __init__(self, root): def __init__(self, root):
self.root = root self.root = root
self.frame = tk.Frame(root) self.frame = tk.Frame(root)
self.frame.pack() self.frame.pack(fill="both", expand=True)
# =====================
# JUDUL
# =====================
tk.Label( tk.Label(
self.frame, self.frame,
text="ADMIN - KELOLA MENU", text="ADMIN - KELOLA MENU",
font=("Arial", 18, "bold") font=("Arial", 18, "bold")
).pack(pady=10) ).pack(pady=15)
self.nama = tk.Entry(self.frame) # =====================
self.harga = tk.Entry(self.frame) # FORM INPUT
self.gambar = tk.Entry(self.frame) # =====================
form = tk.Frame(self.frame)
form.pack(pady=10)
for label, entry in [ tk.Label(form, text="Nama Menu", width=15, anchor="w")\
("Nama Menu", self.nama), .grid(row=0, column=0, pady=5)
("Harga", self.harga), self.nama = tk.Entry(form, width=30)
("Path Gambar", self.gambar) self.nama.grid(row=0, column=1)
]:
tk.Label(self.frame, text=label).pack()
entry.pack()
tk.Button(self.frame, text="Tambah Menu", command=self.tambah).pack(pady=5) tk.Label(form, text="Kategori", width=15, anchor="w")\
.grid(row=1, column=0, pady=5)
self.kategori = tk.StringVar()
tk.OptionMenu(
form,
self.kategori,
"Makanan",
"Minuman",
"Dessert"
).grid(row=1, column=1, sticky="w")
self.kategori.set("Makanan")
tk.Label(form, text="Harga", width=15, anchor="w")\
.grid(row=2, column=0, pady=5)
self.harga = tk.Entry(form, width=30)
self.harga.grid(row=2, column=1)
tk.Label(form, text="Path Gambar", width=15, anchor="w")\
.grid(row=3, column=0, pady=5)
self.gambar = tk.Entry(form, width=30)
self.gambar.grid(row=3, column=1)
# =====================
# BUTTON CRUD
# =====================
btn_frame = tk.Frame(self.frame)
btn_frame.pack(pady=10)
tk.Button(btn_frame, text="Tambah", width=10,
bg="#d1e7dd", command=self.tambah).grid(row=0, column=0, padx=5)
tk.Button(btn_frame, text="Update", width=10,
bg="#cfe2ff", command=self.update).grid(row=0, column=1, padx=5)
tk.Button(btn_frame, text="Hapus", width=10,
bg="#f8d7da", command=self.hapus).grid(row=0, column=2, padx=5)
tk.Button(btn_frame, text="Refresh", width=10,
command=self.load_menu).grid(row=0, column=3, padx=5)
tk.Button(btn_frame, text="Logout", width=10,
command=self.logout).grid(row=0, column=4, padx=5)
# =====================
# FILTER
# =====================
filter_frame = tk.Frame(self.frame)
filter_frame.pack(pady=5)
tk.Label(filter_frame, text="Filter Kategori:").pack(side=tk.LEFT)
self.filter_kategori = tk.StringVar()
tk.OptionMenu(
filter_frame,
self.filter_kategori,
"Semua",
"Makanan",
"Minuman",
"Dessert",
command=self.load_menu
).pack(side=tk.LEFT)
self.filter_kategori.set("Semua")
# =====================
# LIST MENU
# =====================
self.listbox = tk.Listbox(self.frame, width=80, height=10)
self.listbox.pack(pady=10)
self.listbox.bind("<<ListboxSelect>>", self.pilih_menu)
self.menu_data = []
self.load_menu()
# =====================
# LOAD MENU + FILTER
# =====================
def load_menu(self, *_):
self.listbox.delete(0, tk.END)
db = connect()
cur = db.cursor()
if self.filter_kategori.get() == "Semua":
cur.execute("SELECT * FROM menu")
else:
cur.execute(
"SELECT * FROM menu WHERE kategori=?",
(self.filter_kategori.get(),)
)
self.menu_data = cur.fetchall()
db.close()
for m in self.menu_data:
self.listbox.insert(
tk.END,
f"{m[0]:<3} | {m[1]:<20} | {m[2]:<10} | Rp {m[3]:,.0f}"
)
# =====================
# PILIH MENU
# =====================
def pilih_menu(self, event):
idx = self.listbox.curselection()
if not idx:
return
menu = self.menu_data[idx[0]]
self.clear_form()
self.nama.insert(0, menu[1])
self.kategori.set(menu[2])
self.harga.insert(0, menu[3])
self.gambar.insert(0, menu[4])
# =====================
# CRUD
# =====================
def tambah(self): def tambah(self):
if not self.nama.get() or not self.harga.get():
messagebox.showwarning("Error", "Data belum lengkap")
return
db = connect() db = connect()
cur = db.cursor() cur = db.cursor()
cur.execute( cur.execute(
"INSERT INTO menu(nama,harga,gambar) VALUES (?,?,?)", "INSERT INTO menu(nama,kategori,harga,gambar) VALUES (?,?,?,?)",
(self.nama.get(), self.harga.get(), self.gambar.get()) (
self.nama.get(),
self.kategori.get(),
float(self.harga.get()),
self.gambar.get()
)
) )
db.commit() db.commit()
db.close() db.close()
messagebox.showinfo("Sukses", "Menu berhasil ditambahkan") messagebox.showinfo("Sukses", "Menu berhasil ditambahkan")
self.load_menu()
self.clear_form()
def update(self):
idx = self.listbox.curselection()
if not idx:
messagebox.showwarning("Pilih", "Pilih menu dulu")
return
menu_id = self.menu_data[idx[0]][0]
db = connect()
cur = db.cursor()
cur.execute(
"UPDATE menu SET nama=?, kategori=?, harga=?, gambar=? WHERE id=?",
(
self.nama.get(),
self.kategori.get(),
float(self.harga.get()),
self.gambar.get(),
menu_id
)
)
db.commit()
db.close()
messagebox.showinfo("Sukses", "Menu berhasil diupdate")
self.load_menu()
def hapus(self):
idx = self.listbox.curselection()
if not idx:
messagebox.showwarning("Pilih", "Pilih menu dulu")
return
menu_id = self.menu_data[idx[0]][0]
if messagebox.askyesno("Konfirmasi", "Yakin hapus menu ini?"):
db = connect()
cur = db.cursor()
cur.execute("DELETE FROM menu WHERE id=?", (menu_id,))
db.commit()
db.close()
messagebox.showinfo("Sukses", "Menu berhasil dihapus")
self.load_menu()
self.clear_form()
def clear_form(self):
self.nama.delete(0, tk.END)
self.harga.delete(0, tk.END)
self.gambar.delete(0, tk.END)
self.kategori.set("Makanan")
def logout(self):
self.frame.destroy()
from main import LoginScreen
LoginScreen(self.root)
Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

+58 -12
View File
@@ -7,6 +7,9 @@ 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 +19,87 @@ def setup_database():
) )
""") """)
# =====================
# TABEL MENU (ADA KATEGORI)
# =====================
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,
kategori TEXT,
harga REAL, harga REAL,
gambar TEXT gambar TEXT
) )
""") """)
# Jaga-jaga DB lama (tidak error)
try:
cur.execute("ALTER TABLE menu ADD COLUMN kategori TEXT")
except sqlite3.OperationalError:
pass
# =====================
# TABEL TRANSAKSI
# =====================
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,
metode TEXT
) )
""") """)
# =====================
# DETAIL TRANSAKSI
# =====================
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 USER DEFAULT
# =====================
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 (?,?,?)", "INSERT INTO users(username,password,role) VALUES (?,?,?)",
users users
) )
db.commit()
# =====================
# INSERT MENU DEFAULT
# =====================
cur.execute("SELECT COUNT(*) FROM menu")
if cur.fetchone()[0] == 0:
menus = [
('Ayam Goreng', 'Makanan', 20000, 'aset/ayam_goreng.jpg'),
('Bakso', 'Makanan', 15000, 'aset/bakso.jpg'),
('Mie Ayam', 'Makanan', 12000, 'aset/mie_ayam.jpg'),
('Es Teh', 'Minuman', 5000, 'aset/es_teh.jpg'),
('Es Teler', 'Dessert', 15000, 'aset/es_teler.jpg'),
('Jus Jeruk', 'Minuman', 8000, 'aset/jus_jeruk.jpg')
]
cur.executemany(
"INSERT INTO menu (nama, kategori, harga, gambar) VALUES (?,?,?,?)",
menus
)
db.commit()
db.close() db.close()
+311 -38
View File
@@ -1,76 +1,349 @@
import tkinter as tk import tkinter as tk
from tkinter import messagebox from tkinter import messagebox
from database import connect from database import connect
from datetime import datetime
import qrcode
from PIL import ImageTk
class KasirPage: class KasirPage:
def __init__(self, parent, controller): def __init__(self, parent, controller=None):
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) # =====================
# JUDUL
# =====================
tk.Label(
self.frame,
text="KASIR - PEMBAYARAN",
font=("Arial", 18, "bold")
).pack(pady=10)
# Tombol Logout tk.Button(
tk.Button(self.frame, text="Logout", bg="#f9e79f", command=self.logout).pack(pady=5) self.frame,
text="Logout",
bg="#f9e79f",
command=self.logout
).pack(pady=5)
# Listbox untuk menampilkan order tk.Button(
tk.Label(self.frame, text="Daftar Order:", font=("Arial", 12, "bold")).pack(pady=5) self.frame,
self.listbox = tk.Listbox(self.frame, width=50, height=10) text="Refresh",
command=self.load_tagihan
).pack(pady=3)
# =====================
# LIST TAGIHAN
# =====================
tk.Label(
self.frame,
text="Daftar Tagihan (Status: Disajikan)",
font=("Arial", 12)
).pack(pady=5)
self.listbox = tk.Listbox(self.frame, width=65, height=10)
self.listbox.pack(pady=5) self.listbox.pack(pady=5)
# Tombol bayar # =====================
tk.Button(self.frame, text="Bayar", bg="#d1e7dd", command=self.bayar).pack(pady=5) # METODE PEMBAYARAN
# =====================
metode_frame = tk.Frame(self.frame)
metode_frame.pack(pady=5)
self.load_orders() # Load order dari database saat awal tk.Label(metode_frame, text="Metode Pembayaran:").pack(side=tk.LEFT)
def load_orders(self): self.metode = tk.StringVar(value="Cash")
tk.OptionMenu(
metode_frame,
self.metode,
"Cash", "QRIS", "E-Wallet"
).pack(side=tk.LEFT, padx=5)
# =====================
# INPUT CASH
# =====================
cash_frame = tk.Frame(self.frame)
cash_frame.pack(pady=5)
tk.Label(cash_frame, text="Uang Diterima (Cash):").pack(side=tk.LEFT)
self.uang_entry = tk.Entry(cash_frame, width=15)
self.uang_entry.pack(side=tk.LEFT, padx=5)
# =====================
# HITUNG KEMBALIAN
# =====================
def hitung_kembalian(event=None):
try:
# 1. Ambil transaksi yang sedang dipilih (Total tagihan)
idx = self.listbox.curselection()
if idx:
teks_item = self.listbox.get(idx).split(" ")
total = int(teks_item[len(teks_item)-1].replace(",",""))
uang_diterima = int(self.uang_entry.get())
# 3. Hitung dan update label
kembalian = uang_diterima - total
self.kembalian_label.config(text=f"Rp {kembalian:,.0f}")
except ValueError:
# Jika input bukan angka atau kosong, atur kembalian jadi 0
self.kembalian_label.config(text="Rp 0")
except IndexError:
# Jika transaksi tidak dipilih
self.kembalian_label.config(text="Rp 0")
self.uang_entry.bind("<KeyRelease>", hitung_kembalian)
# =====================
# UANG KEMBALIAN (BARU)
# =====================
kembalian_frame = tk.Frame(self.frame)
kembalian_frame.pack(pady=5)
tk.Label(kembalian_frame, text="Uang Kembalian:").pack(side=tk.LEFT)
# ⭐️ Label untuk menampilkan kembalian
self.kembalian_label = tk.Label(kembalian_frame, text="Rp 0")
self.kembalian_label.pack(side=tk.LEFT, padx=5)
# =====================
# BUTTON BAYAR
# =====================
tk.Button(
self.frame,
text="Proses Pembayaran",
bg="#d1e7dd",
width=25,
command=self.bayar
).pack(pady=10)
self.transaksi_data = []
self.load_tagihan()
# =====================
# LOAD TAGIHAN
# =====================
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") cur.execute("""
self.data = cur.fetchall() 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 {t_id} | Total Rp {total:,.0f}"
)
# 🔽 AMBIL DETAIL MENU
db = connect()
cur = db.cursor()
cur.execute("""
SELECT menu_nama, jumlah
FROM detail_transaksi
WHERE transaksi_id=?
""", (t_id,))
items = cur.fetchall()
db.close()
for nama, qty in items:
self.listbox.insert(
tk.END,
f" • {nama} x{qty}"
)
self.listbox.insert(tk.END, "-" * 50)
self.transaksi_data.append(row)
# =====================
# BAYAR
# =====================
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]] idx = self.listbox.curselection()
order_id, nama, total = order if idx:
teks_item = self.listbox.get(idx).split(" ")
total = int(teks_item[len(teks_item)-1].replace(",",""))
meja = int(teks_item[1])
t_id = int(teks_item[4])
metode = self.metode.get()
# Simpan pembayaran di database (opsional, bisa buat tabel pembayaran) if metode == "QRIS":
self.tampilkan_qr(t_id, meja, total)
elif metode == "E-Wallet":
self.konfirmasi_ewallet(t_id, meja, total)
else: # CASH
try:
uang = int(self.uang_entry.get())
except:
messagebox.showwarning("Error", "Masukkan uang cash!")
return
if uang < total:
messagebox.showwarning(
"Kurang",
f"Uang kurang!\nTotal: Rp {total:,.0f}"
)
return
kembalian = uang - total
self.selesaikan_pembayaran(
t_id, meja, total, metode,
uang, kembalian
)
# =====================
# QRIS (CLOSE WINDOW = LUNAS)
# =====================
def tampilkan_qr(self, t_id, meja, total):
win = tk.Toplevel(self.frame)
win.title("QRIS Payment")
win.geometry("320x420")
tk.Label(
win,
text="SCAN QR UNTUK BAYAR",
font=("Arial", 12, "bold")
).pack(pady=10)
qr_data = f"""
QRIS-DUMMY
Cafe Python
Transaksi: {t_id}
Meja: {meja}
Total: {total}
"""
qr = qrcode.make(qr_data)
qr_img = ImageTk.PhotoImage(qr)
lbl = tk.Label(win, image=qr_img)
lbl.image = qr_img
lbl.pack(pady=10)
tk.Label(
win,
text=f"Total: Rp {total:,.0f}",
font=("Arial", 11)
).pack(pady=5)
def selesai_qris():
self.selesaikan_pembayaran(t_id, meja, total, "QRIS")
win.destroy()
# ❌ WINDOW DITUTUP = TRANSAKSI BERHASIL
win.protocol("WM_DELETE_WINDOW", selesai_qris)
tk.Button(
win,
text="Konfirmasi Pembayaran",
bg="#d1e7dd",
width=25,
command=selesai_qris
).pack(pady=15)
# =====================
# E-WALLET
# =====================
def konfirmasi_ewallet(self, t_id, meja, total):
confirm = messagebox.askyesno(
"E-Wallet Payment",
f"""
Bayar menggunakan E-Wallet?
Meja : {meja}
Total : Rp {total:,.0f}
Lanjutkan pembayaran?
"""
)
if confirm:
self.selesaikan_pembayaran(t_id, meja, total, "E-Wallet")
def selesaikan_pembayaran(self, t_id, meja, total, metode, uang=None, kembalian=None):
db = connect() db = connect()
cur = db.cursor() 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 try:
self.tampil_struk(order_id, nama, total) cur.execute(
"""
UPDATE transaksi
SET status='Lunas',
tanggal = DATETIME('now')
WHERE id=?
""",
(t_id,)
)
db.commit() # ⭐️ PASTIKAN COMMIT DILAKUKAN
tanggal_sekarang = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
sql_query = """
INSERT INTO transaksi (tanggal, total, meja_id, status, metode)
VALUES (?, ?, ?, ?, ?)
"""
data_transaksi = (tanggal_sekarang, total, meja, "Lunas", metode)
cur.execute(sql_query, data_transaksi)
db.commit()
# Update listbox # Tambahkan print debug untuk konfirmasi
self.load_orders() print(f"DEBUG: Transaksi ID {t_id} berhasil diupdate menjadi Lunas.")
except Exception as e:
# Jika ada error database
print(f"ERROR: Gagal update status transaksi: {e}")
messagebox.showerror("DB Error", "Gagal memperbarui status transaksi.")
finally:
db.close()
def tampil_struk(self, order_id, nama, total): struk_tambahan = ""
win = tk.Toplevel(self.frame) if metode == "Cash" and uang is not None and kembalian is not None:
win.title("Struk Pembayaran") struk_tambahan = f"""
Uang Diterima: Rp {uang:,.0f}
Kembalian : Rp {kembalian:,.0f}"""
tk.Label(win, text="STRUK PEMBAYARAN", font=("Arial",14,"bold")).pack(pady=5) messagebox.showinfo(
tk.Label(win, text=f"Order ID : {order_id}").pack() "Struk Pembayaran",
tk.Label(win, text=f"Nama Menu: {nama}").pack() f"""
tk.Label(win, text=f"Total : Rp {total:,}").pack() ======= STRUK =======
tk.Label(win, text="Terima kasih 🙏").pack(pady=10) ID Transaksi : {t_id}
tk.Button(win, text="Tutup", command=win.destroy).pack(pady=5) Meja : {meja}
Total : Rp {total:,.0f}
Metode : {metode}{struk_tambahan}
Status : Lunas
====================
Terima kasih 🙏
"""
)
self.load_tagihan()
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
+44 -28
View File
@@ -7,65 +7,81 @@ from admin_menu import AdminMenu
from waiter_dashboard import WaiterDashboard from waiter_dashboard import WaiterDashboard
from tkinter import messagebox from tkinter import messagebox
# --- Login Screen ---
class LoginScreen: class LoginScreen:
def __init__(self, root): def __init__(self, root):
self.root = root self.root = root
self.frame = tk.Frame(root) self.frame = tk.Frame(root)
self.frame.pack(fill="both", expand=True) self.frame.pack(fill="both", expand=True)
tk.Label(self.frame,text="LOGIN SISTEM CAFE", font=("Arial",18,"bold")).pack(pady=20) tk.Label(self.frame, text="SISTEM CAFE", font=("Arial", 24, "bold")).pack(pady=30)
tk.Label(self.frame,text="Username").pack()
self.username_entry = tk.Entry(self.frame)
self.username_entry.pack()
tk.Label(self.frame,text="Password").pack()
self.password_entry = tk.Entry(self.frame, show="*")
self.password_entry.pack(pady=5)
tk.Button(self.frame,text="Login", bg="#cfe2ff", command=self.login).pack(pady=10)
def login(self): # --- Bagian Login Staff ---
frame_login = tk.LabelFrame(self.frame, text="Login Staff (Admin/Kasir/Waiter)", padx=20, pady=20)
frame_login.pack(pady=10)
tk.Label(frame_login, text="Username:").pack(anchor="w")
self.username_entry = tk.Entry(frame_login)
self.username_entry.pack(fill="x", pady=5)
tk.Label(frame_login, text="Password:").pack(anchor="w")
self.password_entry = tk.Entry(frame_login, show="*")
self.password_entry.pack(fill="x", pady=5)
tk.Button(frame_login, text="Login Staff", bg="#cfe2ff", command=self.login_staff).pack(pady=10, fill="x")
# --- Bagian Pelanggan (Tanpa Password) ---
tk.Label(self.frame, text="--- ATAU ---", fg="grey").pack(pady=5)
tk.Button(self.frame,
text="🍽️ MASUK SEBAGAI PELANGGAN",
bg="#d1e7dd", fg="#0f5132", font=("Arial", 12, "bold"),
height=2,
command=self.masuk_pelanggan).pack(pady=10, ipadx=20)
def login_staff(self):
username = self.username_entry.get() username = self.username_entry.get()
password = self.password_entry.get() password = self.password_entry.get()
db = connect() db = connect()
cur = db.cursor() cur = db.cursor()
cur.execute("SELECT role FROM users WHERE username=? AND password=?", (username,password)) cur.execute("SELECT role FROM users WHERE username=? AND password=?", (username, password))
result = cur.fetchone() result = cur.fetchone()
db.close() db.close()
if result: if result:
role = result[0] role = result[0]
self.frame.destroy() self.frame.destroy()
if role=="pembeli":
PembeliMenu(self.root) if role == "kasir":
elif role=="kasir":
KasirPage(self.root, self.root) KasirPage(self.root, self.root)
elif role == "pemilik":
elif role=="pemilik":
PemilikPage(self.root, self.root) PemilikPage(self.root, self.root)
elif role == "admin": elif role == "admin":
AdminMenu(self.root) AdminMenu(self.root)
elif role == "waiter": elif role == "waiter":
WaiterDashboard(self.root) WaiterDashboard(self.root)
elif role == "pembeli":
# Jika ada user iseng login pakai akun pembeli di database
PembeliMenu(self.root)
else: else:
messagebox.showerror("Error","Role tidak dikenali") messagebox.showerror("Error", "Role tidak dikenali")
else: else:
messagebox.showerror("Error","Username / Password salah") messagebox.showerror("Error", "Username / Password salah")
# --- App --- def masuk_pelanggan(self):
# Langsung buka menu tanpa cek password
self.frame.destroy()
PembeliMenu(self.root)
# --- App Class ---
class App(tk.Tk): class App(tk.Tk):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.title("Sistem Cafe") self.title("Sistem Cafe Python")
self.geometry("700x600") self.geometry("800x600")
# --- Run Program --- if __name__ == "__main__":
if __name__=="__main__":
setup_database() setup_database()
app = App() app = App()
LoginScreen(app) LoginScreen(app)
app.mainloop() app.mainloop()
+190 -42
View File
@@ -1,42 +1,116 @@
import tkinter as tk import tkinter as tk
from tkinter import messagebox, ttk
from PIL import Image, ImageTk from PIL import Image, ImageTk
from database import connect import sqlite3
from tkinter import messagebox import datetime
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# ================= DATABASE CONNECT =================
def connect():
return sqlite3.connect("cafe.db")
# ================= PEMBELI MENU =================
class PembeliMenu: class PembeliMenu:
def __init__(self, parent): def __init__(self, parent):
self.parent = parent self.parent = parent
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 = []
self.images = []
self.cart = [] # Simpan tuple (nama, harga) # ================= HEADER =================
self.images = [] # Simpan reference gambar agar tidak dihapus GC header = tk.Frame(self.frame)
header.pack(fill="x", padx=20, pady=10)
# --- Judul Halaman --- tk.Label(
tk.Label(self.frame, text="MENU PEMBELI", font=("Arial", 18, "bold")).pack(pady=10) header,
text="SELAMAT DATANG",
font=("Arial", 18, "bold")
).pack(side="left")
# --- Tombol Logout --- tk.Button(
tk.Button(self.frame, text="Logout", bg="#f9e79f", command=self.logout).pack(pady=5) header,
text="⬅ Kembali",
bg="#f8d7da",
font=("Arial", 10, "bold"),
command=self.logout
).pack(side="right")
# --- Frame Menu ---
self.menu_frame = tk.Frame(self.frame)
self.menu_frame.pack(pady=10)
self.load_menu() # Load menu dari database # ================= INPUT DATA =================
info_frame = tk.Frame(self.frame, bd=2, relief="groove", padx=10, pady=10)
info_frame.pack(pady=5)
# --- Daftar Pesanan --- tk.Label(info_frame, text="Nama Anda:").grid(row=0, column=0, sticky="e")
tk.Label(self.frame, text="Daftar Pesanan:", font=("Arial", 12, "bold")).pack(pady=5) self.entry_nama = tk.Entry(info_frame)
self.listbox = tk.Listbox(self.frame, width=50, height=6) self.entry_nama.grid(row=0, column=1, padx=5)
self.listbox.pack()
# --- Total --- tk.Label(info_frame, text="Pilih Meja:").grid(row=0, column=2, sticky="e")
self.total_lbl = tk.Label(self.frame, text="Total: Rp 0", font=("Arial", 12, "bold")) self.meja_var = tk.StringVar()
self.combo_meja = ttk.Combobox(
info_frame,
textvariable=self.meja_var,
state="readonly",
width=5
)
self.combo_meja.grid(row=0, column=3, padx=5)
tk.Button(info_frame, text="🔄", command=self.refresh_available_tables).grid(row=0, column=4, padx=2)
self.refresh_available_tables()
# ================= CONTENT 2 KOLOM =================
content = tk.Frame(self.frame)
content.pack(fill="both", expand=True, padx=20, pady=10)
content.grid_columnconfigure(0, weight=3)
content.grid_columnconfigure(1, weight=1)
# ================= MENU (KIRI) =================
self.menu_frame = tk.Frame(content)
self.menu_frame.grid(row=0, column=0, sticky="nw")
self.load_menu()
# ================= KERANJANG (KANAN) =================
cart_frame = tk.LabelFrame(
content,
text="Keranjang Pesanan",
font=("Arial", 11, "bold"),
padx=10,
pady=10
)
cart_frame.grid(row=0, column=1, sticky="ne")
self.listbox = tk.Listbox(cart_frame, width=35, height=10, font=("Courier", 10))
self.listbox.pack(pady=5)
tk.Button(cart_frame, text="➖ Kurangi / Hapus Item", fg="red",
command=self.kurangi_item_cart).pack(pady=5)
self.total_lbl = tk.Label(cart_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(cart_frame, text="✅ KIRIM PESANAN", bg="#d1e7dd",
tk.Button(self.frame, text="Checkout", bg="#d1e7dd", command=self.checkout).pack(pady=5) font=("Arial", 11, "bold"), command=self.checkout).pack(pady=10)
# ================= MEJA =================
def refresh_available_tables(self):
total_meja = [str(i) for i in range(1, 11)]
db = connect()
cur = db.cursor()
cur.execute("SELECT DISTINCT meja_id FROM transaksi WHERE status != 'Selesai'")
terisi = [str(row[0]) for row in cur.fetchall()]
db.close()
tersedia = [m for m in total_meja if m not in terisi]
self.combo_meja['values'] = tersedia if tersedia else ["Penuh"]
self.combo_meja.set(tersedia[0] if tersedia else "Penuh")
# ================= MENU =================
def load_menu(self): def load_menu(self):
db = connect() db = connect()
cur = db.cursor() cur = db.cursor()
@@ -44,48 +118,122 @@ class PembeliMenu:
data = cur.fetchall() data = cur.fetchall()
db.close() db.close()
columns = 4
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") row, col = divmod(i, columns)
f.grid(row=i//3, column=i%3, padx=10, pady=10) card = tk.Frame(self.menu_frame, width=180, height=220, bd=2, relief="ridge")
card.grid(row=row, column=col, padx=10, pady=10)
card.grid_propagate(False)
try: try:
img = Image.open(gambar).resize((120, 90)) if not gambar:
raise ValueError("gambar kosong")
# gambar dari DB sudah mengandung 'aset/...'
img_path = os.path.join(BASE_DIR, gambar)
if not os.path.exists(img_path):
raise FileNotFoundError(img_path)
img = Image.open(img_path)
img = img.resize((140, 90), Image.Resampling.LANCZOS)
photo = ImageTk.PhotoImage(img) photo = ImageTk.PhotoImage(img)
self.images.append(photo) self.images.append(photo)
tk.Label(f, image=photo).pack() tk.Label(card, image=photo).pack(pady=5)
except FileNotFoundError:
tk.Label(f, text="No Image").pack()
tk.Label(f, text=nama).pack() except Exception as e:
tk.Label(f, text=f"Rp {harga:,}").pack() print("IMG ERROR:", e)
tk.Button(f, text="Pesan", bg="#cfe2ff", tk.Label(card, text="No Image", height=6).pack()
command=lambda n=nama, h=harga: self.add(n, h)).pack(pady=3)
def add(self, nama, harga):
self.cart.append((nama, harga)) tk.Label(card, text=nama, font=("Arial", 10, "bold"), wraplength=160).pack()
self.listbox.insert(tk.END, f"{nama} - Rp {harga:,}") tk.Label(card, text=f"Rp {harga:,.0f}").pack(pady=2)
total = sum(h for _, h in self.cart)
self.total_lbl.config(text=f"Total: Rp {total:,}") tk.Button(card, text="Tambah", bg="#cfe2ff",
command=lambda n=nama, h=harga: self.add_to_cart(n, h)).pack(pady=5)
# ================= CART =================
def add_to_cart(self, nama, harga):
for item in self.cart:
if item['nama'] == nama:
item['qty'] += 1
item['subtotal'] = item['qty'] * harga
self.refresh_cart()
return
self.cart.append({'nama': nama, 'harga_satuan': harga, 'qty': 1, 'subtotal': harga})
self.refresh_cart()
def kurangi_item_cart(self):
if not self.listbox.curselection(): return
idx = self.listbox.curselection()[0]
item = self.cart[idx]
item['qty'] -= 1
if item['qty'] <= 0:
self.cart.pop(idx)
else:
item['subtotal'] = item['qty'] * item['harga_satuan']
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']} (x{item['qty']}) - Rp {item['subtotal']:,.0f}")
total += item['subtotal']
self.total_lbl.config(text=f"Total: Rp {total:,.0f}")
def checkout(self): def checkout(self):
if not self.cart: if not self.entry_nama.get() or not self.cart:
messagebox.showwarning("Pesan Kosong", "Belum ada pesanan!") messagebox.showwarning("Error", "Data belum lengkap")
return return
total = sum(item['subtotal'] 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️⃣ Simpan transaksi
cur.execute("""
INSERT INTO transaksi (tanggal, total, meja_id, status)
VALUES (?, ?, ?, ?)
""", (tanggal, total, self.combo_meja.get(), "Pending"))
transaksi_id = cur.lastrowid # 🔥 AMBIL ID TRANSAKSI
# 2️⃣ Simpan detail menu
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_satuan'],
item['qty'],
item['subtotal']
))
db.commit() db.commit()
db.close() db.close()
messagebox.showinfo("Sukses", "Pesanan dikirim ke kasir") messagebox.showinfo("Berhasil", "Pesanan berhasil dikirim")
self.cart.clear() self.cart.clear()
self.listbox.delete(0, tk.END) self.refresh_cart()
self.total_lbl.config(text="Total: Rp 0")
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)
# ================= RUN =================
if __name__ == '__main__':
root = tk.Tk()
root.title("Sistem Cafe Python")
root.geometry("1200x700")
PembeliMenu(root)
root.mainloop()
+157 -15
View File
@@ -1,40 +1,182 @@
import tkinter as tk import tkinter as tk
from tkinter import messagebox
from database import connect from database import connect
import matplotlib.pyplot as plt
class PemilikPage: class PemilikPage:
def __init__(self, parent, controller): def __init__(self, parent, controller=None):
self.parent = parent self.parent = parent
self.controller = controller 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="LAPORAN PENJUALAN", font=("Arial", 18, "bold")).pack(pady=10) # =====================
# JUDUL
# =====================
tk.Label(
self.frame,
text="LAPORAN PENJUALAN",
font=("Arial", 18, "bold")
).pack(pady=10)
# Label untuk total penjualan # =====================
self.total_lbl = tk.Label(self.frame, text="Total Penjualan: Rp 0", font=("Arial", 14, "bold")) # FILTER PERIODE
self.total_lbl.pack(pady=5) # =====================
filter_frame = tk.Frame(self.frame)
filter_frame.pack(pady=5)
# Tombol Refresh tk.Label(filter_frame, text="Periode:").pack(side=tk.LEFT)
tk.Button(self.frame, text="Refresh", bg="#cfe2ff", command=self.load).pack(pady=5)
# Tombol Logout self.filter_var = tk.StringVar(value="Harian")
tk.Button(self.frame, text="Logout", bg="#f9e79f", command=self.logout).pack(pady=5) tk.OptionMenu(
filter_frame,
self.filter_var,
"Harian", "Mingguan", "Bulanan"
).pack(side=tk.LEFT, padx=5)
tk.Button(
filter_frame,
text="Refresh",
bg="#cfe2ff",
command=self.load
).pack(side=tk.LEFT, padx=10)
# =====================
# TOTAL
# =====================
self.total_lbl = tk.Label(
self.frame,
text="Total (Harian): Rp 0",
font=("Arial", 14, "bold")
)
self.total_lbl.pack(pady=10)
# =====================
# GRAFIK
# =====================
tk.Button(
self.frame,
text="Tampilkan Grafik",
bg="#d1e7dd",
width=20,
command=self.show_graph
).pack(pady=5)
# =====================
# LOGOUT
# =====================
tk.Button(
self.frame,
text="Logout",
bg="#f9e79f",
command=self.logout
).pack(pady=5)
# Load data awal
self.load() self.load()
# =====================
# LOAD TOTAL (SUM ASLI)
# =====================
def load(self): def load(self):
db = connect() db = connect()
cur = db.cursor() cur = db.cursor()
# Jumlahkan semua total pembayaran dari tabel pembayaran periode = self.filter_var.get()
cur.execute("SELECT SUM(total) FROM pembayaran")
total = cur.fetchone()[0] or 0 if periode == "Harian":
cur.execute("""
SELECT COALESCE(SUM(total), 0)
FROM transaksi
WHERE status='Lunas'
AND datetime(tanggal) >= datetime('now','-1 day')
""")
elif periode == "Mingguan":
cur.execute("""
SELECT COALESCE(SUM(total), 0)
FROM transaksi
WHERE status='Lunas'
AND datetime(tanggal) >= datetime('now','-7 day')
""")
else: # Bulanan
cur.execute("""
SELECT COALESCE(SUM(total), 0)
FROM transaksi
WHERE status='Lunas'
AND strftime('%Y-%m', tanggal) = strftime('%Y-%m','now')
""")
total = cur.fetchone()[0]
db.close() db.close()
self.total_lbl.config(text=f"Total Penjualan: Rp {total:,}") self.total_lbl.config(
text=f"Total ({periode}): Rp {total:,.0f}"
)
# =====================
# GRAFIK (SUM SESUAI TOTAL)
# =====================
def show_graph(self):
plt.close('all')
db = connect()
cur = db.cursor()
periode = self.filter_var.get()
if periode == "Harian":
cur.execute("""
SELECT strftime('%H:%M', tanggal), SUM(total)
FROM transaksi
WHERE status='Lunas'
AND datetime(tanggal) >= datetime('now','-1 day')
GROUP BY strftime('%H', tanggal)
ORDER BY tanggal
""")
elif periode == "Mingguan":
cur.execute("""
SELECT date(tanggal), SUM(total)
FROM transaksi
WHERE status='Lunas'
AND datetime(tanggal) >= datetime('now','-7 day')
GROUP BY date(tanggal)
ORDER BY date(tanggal)
""")
else:
cur.execute("""
SELECT strftime('%Y-%m', tanggal), SUM(total)
FROM transaksi
WHERE status='Lunas'
GROUP BY strftime('%Y-%m', tanggal)
ORDER BY strftime('%Y-%m', tanggal)
""")
data = cur.fetchall()
db.close()
if not data:
messagebox.showinfo("Info", "Belum ada data penjualan")
return
labels = [d[0] for d in data]
totals = [d[1] for d in data]
plt.figure()
plt.plot(labels, totals, marker='o')
plt.title(f"Grafik Penjualan ({periode})")
plt.xlabel("Periode")
plt.ylabel("Total Penjualan")
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# =====================
# LOGOUT
# =====================
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)
+115 -4
View File
@@ -1,15 +1,126 @@
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):
self.parent = parent self.parent = parent
self.frame = tk.Frame(parent) self.frame = tk.Frame(parent)
self.frame.pack(fill="both", expand=True) self.frame.pack(fill="both", expand=True, padx=20, pady=10)
tk.Label(self.frame, text="WAITER", font=("Arial", 20, "bold")).pack(pady=20) # =====================
tk.Label(self.frame, text="(Input pesanan manual)").pack() # HEADER
# =====================
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=10) top_btn = tk.Frame(self.frame)
top_btn.pack(pady=5)
tk.Button(top_btn, text="Refresh Data", bg="#cfe2ff",
width=15, command=self.load_orders).grid(row=0, column=0, padx=5)
tk.Button(top_btn, text="Logout", bg="#f8d7da",
width=10, command=self.logout).grid(row=0, column=1, padx=5)
# =====================
# LIST PESANAN + SCROLL
# =====================
list_frame = tk.Frame(self.frame)
list_frame.pack(pady=10)
scrollbar = tk.Scrollbar(list_frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.listbox = tk.Listbox(
list_frame,
width=90,
height=15,
yscrollcommand=scrollbar.set
)
self.listbox.pack(side=tk.LEFT)
scrollbar.config(command=self.listbox.yview)
# =====================
# BUTTON VALIDASI
# =====================
tk.Button(
self.frame,
text="✔ Pesanan Selesai Disajikan",
bg="#d1e7dd",
font=("Arial", 11, "bold"),
width=30,
command=self.validasi_layanan
).pack(pady=10)
self.order_ids = []
self.load_orders()
# =====================
# LOAD DATA
# =====================
def load_orders(self):
self.listbox.delete(0, tk.END)
self.order_ids = []
db = connect()
cur = db.cursor()
cur.execute(
"SELECT id, meja_id, total FROM transaksi WHERE status='Pending'"
)
rows = cur.fetchall()
for t_id, meja, total in rows:
cur.execute(
"SELECT menu_nama, jumlah FROM detail_transaksi WHERE transaksi_id=?",
(t_id,)
)
details = cur.fetchall()
self.listbox.insert(tk.END, f"Meja {meja} | ID Transaksi: {t_id}")
for menu, qty in details:
self.listbox.insert(tk.END, f" - {menu} x{qty}")
self.listbox.insert(tk.END, f"Total : Rp {total:,.0f}")
self.listbox.insert(tk.END, "-" * 70)
self.order_ids.append(t_id)
db.close()
# =====================
# VALIDASI
# =====================
def validasi_layanan(self):
idx = self.listbox.curselection()
if not idx:
messagebox.showwarning("Pilih", "Pilih pesanan yang sudah disajikan")
return
# Cari ID terdekat ke atas
selected_index = idx[0]
transaksi_index = selected_index // 5
transaksi_id = self.order_ids[transaksi_index]
db = connect()
cur = db.cursor()
cur.execute(
"UPDATE transaksi SET status='Disajikan' WHERE id=?",
(transaksi_id,)
)
db.commit()
db.close()
messagebox.showinfo(
"Sukses",
"Pesanan ditandai selesai.\nKasir bisa memproses pembayaran."
)
self.load_orders()
def logout(self): def logout(self):
self.frame.destroy() self.frame.destroy()