Update Waiter & Menu

This commit is contained in:
Jevinca Marvella 2025-12-10 11:31:17 +07:00
parent 988ada5393
commit 251a9e37ae
4 changed files with 101 additions and 67 deletions

View File

@ -1,2 +1,2 @@
id,transaksi_id,menu_id,qty,harga_satuan,subtotal_item
1,1,1,1,20000.0,20000.0

1 id transaksi_id menu_id qty harga_satuan subtotal_item
2 1 1 1 1 20000.0 20000.0

159
main.py
View File

@ -1083,7 +1083,7 @@ class App:
right.pack(side='right', fill='both', padx=6, pady=6)
# === PANEL KIRI: Daftar Menu dengan Card ===
ttk.Label(left, text="Daftar Menu", font=("Arial", 13, "bold")).pack(pady=6)
ttk.Label(left, text="Daftar Menu", font=("Arial", 12, "bold")).pack(pady=4)
# Filter search
search_frame = ttk.Frame(left)
@ -1094,8 +1094,8 @@ class App:
ttk.Button(search_frame, text="Cari", command=self.reload_order_menu_cards).pack(side='left', padx=3)
ttk.Button(search_frame, text="Reset", command=self.reset_order_search).pack(side='left', padx=3)
# Scrollable frame untuk cards
canvas = tk.Canvas(left, bg='white')
# Scrollable frame untuk cards (DENGAN BACKGROUND PUTIH)
canvas = tk.Canvas(left, bg='#f5f5f5', height=450, highlightthickness=0)
scrollbar = ttk.Scrollbar(left, orient="vertical", command=canvas.yview)
self.menu_cards_frame = ttk.Frame(canvas)
@ -1116,18 +1116,18 @@ class App:
canvas.bind_all("<MouseWheel>", _on_mousewheel)
# === PANEL KANAN: Keranjang ===
ttk.Label(right, text="Keranjang Belanja", font=("Arial", 13, "bold")).pack(pady=6)
ttk.Label(right, text="Keranjang Belanja", font=("Arial", 12, "bold")).pack(pady=4)
# Treeview cart
cart_cols = ("Menu", "Qty", "Harga", "Subtotal")
self.cart_tree = ttk.Treeview(right, columns=cart_cols, show='headings', height=12)
self.cart_tree = ttk.Treeview(right, columns=cart_cols, show='headings', height=8)
for c in cart_cols:
self.cart_tree.heading(c, text=c)
if c == "Menu":
self.cart_tree.column(c, width=150)
else:
self.cart_tree.column(c, width=70)
self.cart_tree.pack(fill='both', expand=True)
self.cart_tree.pack(fill='x', pady=4)
# Tombol hapus item atau kosongkan cart
cart_btn_frame = ttk.Frame(right)
@ -1136,32 +1136,49 @@ class App:
ttk.Button(cart_btn_frame, text="Kosongkan", command=self.clear_cart).pack(side='left', padx=3)
# Info total
self.cart_subtotal_label = ttk.Label(right, text="Subtotal: Rp 0", font=("Arial", 10))
self.cart_subtotal_label.pack(pady=2)
self.cart_discount_label = ttk.Label(right, text="Diskon Item: Rp 0", font=("Arial", 10))
self.cart_discount_label.pack(pady=2)
self.cart_promo_label = ttk.Label(right, text="Diskon Promo: Rp 0", font=("Arial", 10))
self.cart_promo_label.pack(pady=2)
self.cart_total_label = ttk.Label(right, text="TOTAL: Rp 0", font=("Arial", 12, "bold"))
self.cart_total_label.pack(pady=4)
total_frame = ttk.Frame(right)
total_frame.pack(fill='x', pady=4)
# Input nomor meja dan promo
self.cart_subtotal_label = ttk.Label(total_frame, text="Subtotal: Rp 0", font=("Arial", 9))
self.cart_subtotal_label.pack()
self.cart_discount_label = ttk.Label(total_frame, text="Diskon Item: Rp 0", font=("Arial", 9))
self.cart_discount_label.pack()
self.cart_promo_label = ttk.Label(total_frame, text="Diskon Promo: Rp 0", font=("Arial", 9))
self.cart_promo_label.pack()
self.cart_total_label = ttk.Label(total_frame, text="TOTAL: Rp 0", font=("Arial", 11, "bold"))
self.cart_total_label.pack(pady=2)
# Input nomor meja dan promo (LAYOUT RAPI)
checkout_frame = ttk.Frame(right)
checkout_frame.pack(pady=6)
ttk.Label(checkout_frame, text="No. Meja:").grid(row=0, column=0, sticky='e', padx=3, pady=3)
checkout_frame.pack(fill='x', pady=6, padx=10)
# Row 0: No. Meja
ttk.Label(checkout_frame, text="No. Meja:", font=("Arial", 9)).grid(row=0, column=0, sticky='w', padx=3, pady=3)
self.order_meja_var = tk.StringVar()
ttk.Entry(checkout_frame, textvariable=self.order_meja_var, width=15).grid(row=0, column=1, pady=3)
ttk.Entry(checkout_frame, textvariable=self.order_meja_var, width=20).grid(row=0, column=1, columnspan=2, pady=3, sticky='ew')
ttk.Label(checkout_frame, text="Kode Promo:").grid(row=1, column=0, sticky='e', padx=3, pady=3)
# Row 1: Kode Promo
ttk.Label(checkout_frame, text="Kode Promo:", font=("Arial", 9)).grid(row=1, column=0, sticky='w', padx=3, pady=3)
self.order_promo_var = tk.StringVar()
ttk.Entry(checkout_frame, textvariable=self.order_promo_var, width=15).grid(row=1, column=1, pady=3)
ttk.Button(checkout_frame, text="Terapkan", command=self.update_cart_display).grid(row=1, column=2, padx=3)
ttk.Entry(checkout_frame, textvariable=self.order_promo_var, width=12).grid(row=1, column=1, pady=3, sticky='ew')
ttk.Button(checkout_frame, text="Terapkan", command=self.update_cart_display, width=10).grid(row=1, column=2, padx=3, sticky='e')
# Tombol checkout
ttk.Button(right, text="🛒 CHECKOUT", command=self.checkout_order, style="Accent.TButton").pack(pady=8)
# Configure columns
checkout_frame.columnconfigure(1, weight=1)
# Tombol checkout (PASTI KELIHATAN)
checkout_btn_frame = ttk.Frame(right)
checkout_btn_frame.pack(fill='x', pady=10, padx=20)
ttk.Button(
checkout_btn_frame,
text="🛒 CHECKOUT PESANAN",
command=self.checkout_order,
width=30
).pack()
# Init cart data
self.cart_items = [] # List of dict: {'menu_id': int, 'qty': int}
self.cart_items = []
# Load menu cards
self.reload_order_menu_cards()
@ -1187,8 +1204,15 @@ class App:
for menu_data in results:
mid, nama, kategori, harga, stok, foto, tersedia, item_disc = menu_data
# Create card frame
card = tk.Frame(self.menu_cards_frame, relief='ridge', borderwidth=2, bg='white', padx=10, pady=10)
# Create card frame (DENGAN BACKGROUND PUTIH + BORDER)
card = tk.Frame(
self.menu_cards_frame,
relief='solid',
borderwidth=1,
bg='white',
padx=10,
pady=10
)
card.grid(row=row, column=col, padx=8, pady=8, sticky='nsew')
# Gambar
@ -1198,14 +1222,13 @@ class App:
img = img.resize((150, 100), Image.Resampling.LANCZOS)
photo = ImageTk.PhotoImage(img)
# Simpan reference agar tidak di-garbage collect
img_label = tk.Label(card, image=photo, bg='white')
img_label.image = photo
img_label.pack()
except:
tk.Label(card, text="[No Image]", bg='lightgray', width=20, height=6).pack()
tk.Label(card, text="[No Image]", bg='#e0e0e0', width=20, height=6).pack()
else:
tk.Label(card, text="[No Image]", bg='lightgray', width=20, height=6).pack()
tk.Label(card, text="[No Image]", bg='#e0e0e0', width=20, height=6).pack()
# Nama menu
tk.Label(card, text=nama, font=("Arial", 11, "bold"), bg='white', wraplength=150).pack(pady=(5, 2))
@ -1217,6 +1240,8 @@ class App:
harga_text = f"Rp {harga:,.0f}"
if item_disc > 0:
harga_text += f" (-{item_disc}%)"
tk.Label(card, text=harga_text, font=("Arial", 10, "bold"), fg='#4CAF50', bg='white').pack(pady=2)
else:
tk.Label(card, text=harga_text, font=("Arial", 10, "bold"), fg='green', bg='white').pack(pady=2)
# Stok info
@ -1237,6 +1262,8 @@ class App:
bg='#FF5722',
fg='white',
width=3,
borderwidth=0,
cursor='hand2',
command=lambda m=mid: self.decrease_from_card(m)
).pack(side='left', padx=2)
@ -1255,6 +1282,8 @@ class App:
bg='#4CAF50',
fg='white',
width=3,
borderwidth=0,
cursor='hand2',
command=lambda m=mid, s=stok: self.increase_from_card(m, s)
).pack(side='left', padx=2)
else:
@ -1266,12 +1295,14 @@ class App:
bg='#4CAF50',
fg='white',
width=12,
borderwidth=0,
cursor='hand2',
command=lambda m=mid, s=stok: self.increase_from_card(m, s)
).pack()
# Next column
col += 1
if col >= 2: # 2 cards per row
if col >= 2:
col = 0
row += 1
@ -1420,7 +1451,7 @@ class App:
self.order_meja_var.set("")
self.order_promo_var.set("")
self.update_cart_display()
self.reload_order_menu() # Refresh stok
self.reload_order_menu_cards() # Refresh stok
else:
messagebox.showerror("Error", f"Gagal menyimpan pesanan: {result}")
@ -1438,26 +1469,26 @@ class App:
# Header
header = ttk.Frame(parent)
header.pack(fill='x', padx=10, pady=8)
ttk.Label(header, text="Dashboard Waiter - Kelola Pesanan", font=("Arial", 14, "bold")).pack(side='left')
header.pack(fill='x', padx=10, pady=6)
ttk.Label(header, text="Dashboard Waiter - Kelola Pesanan", font=("Arial", 13, "bold")).pack(side='left')
ttk.Button(header, text="🔄 Refresh", command=self.reload_waiter_orders).pack(side='right', padx=6)
# Filter status
filter_frame = ttk.Frame(parent)
filter_frame.pack(fill='x', padx=10, pady=6)
filter_frame.pack(fill='x', padx=10, pady=4)
ttk.Label(filter_frame, text="Filter Status:").pack(side='left', padx=6)
ttk.Button(filter_frame, text="Semua", command=lambda: self.reload_waiter_orders(None)).pack(side='left', padx=3)
ttk.Button(filter_frame, text="Pending", command=lambda: self.reload_waiter_orders('pending')).pack(side='left', padx=3)
ttk.Button(filter_frame, text="Menunggu", command=lambda: self.reload_waiter_orders('menunggu')).pack(side='left', padx=3)
ttk.Button(filter_frame, text="Diproses", command=lambda: self.reload_waiter_orders('diproses')).pack(side='left', padx=3)
ttk.Button(filter_frame, text="Selesai", command=lambda: self.reload_waiter_orders('selesai')).pack(side='left', padx=3)
ttk.Button(filter_frame, text="Semua", command=lambda: self.reload_waiter_orders(None), width=8).pack(side='left', padx=2)
ttk.Button(filter_frame, text="Pending", command=lambda: self.reload_waiter_orders('pending'), width=8).pack(side='left', padx=2)
ttk.Button(filter_frame, text="Menunggu", command=lambda: self.reload_waiter_orders('menunggu'), width=10).pack(side='left', padx=2)
ttk.Button(filter_frame, text="Diproses", command=lambda: self.reload_waiter_orders('diproses'), width=8).pack(side='left', padx=2)
ttk.Button(filter_frame, text="Selesai", command=lambda: self.reload_waiter_orders('selesai'), width=8).pack(side='left', padx=2)
# Treeview pesanan
# Treeview pesanan (LEBIH PENDEK)
tree_frame = ttk.Frame(parent)
tree_frame.pack(fill='x', padx=10, pady=6)
tree_frame.pack(fill='x', padx=10, pady=4)
cols = ("ID", "User ID", "No.Meja", "Total", "Status", "Promo", "Tanggal")
self.waiter_tree = ttk.Treeview(tree_frame, columns=cols, show='headings', height=10)
self.waiter_tree = ttk.Treeview(tree_frame, columns=cols, show='headings', height=8)
self.waiter_tree.heading("ID", text="ID")
self.waiter_tree.heading("User ID", text="User ID")
@ -1485,53 +1516,53 @@ class App:
# Bind event saat pilih pesanan
self.waiter_tree.bind("<<TreeviewSelect>>", self.on_waiter_select)
# Detail pesanan dengan SCROLLBAR
detail_frame = ttk.LabelFrame(parent, text="📋 Detail Pesanan Terpilih", padding=10)
detail_frame.pack(fill='both', expand=True, padx=10, pady=6)
# Detail pesanan (LEBIH PENDEK - height=6 aja)
detail_frame = ttk.LabelFrame(parent, text="📋 Detail Pesanan", padding=8)
detail_frame.pack(fill='x', padx=10, pady=4)
# Frame untuk text + scrollbar
text_frame = ttk.Frame(detail_frame)
text_frame.pack(fill='both', expand=True)
self.waiter_detail_text = tk.Text(text_frame, height=8, width=100, font=("Courier New", 9), wrap='word')
self.waiter_detail_text = tk.Text(text_frame, height=6, width=100, font=("Courier New", 8), wrap='word')
detail_scroll = ttk.Scrollbar(text_frame, orient='vertical', command=self.waiter_detail_text.yview)
self.waiter_detail_text.configure(yscrollcommand=detail_scroll.set)
self.waiter_detail_text.pack(side='left', fill='both', expand=True)
detail_scroll.pack(side='right', fill='y')
# Tombol aksi - PASTI KELIHATAN
action_frame = ttk.LabelFrame(parent, text="🎯 Ubah Status Pesanan", padding=15)
action_frame.pack(fill='x', padx=10, pady=10)
# TOMBOL AKSI - PASTI KELIHATAN (TIDAK PAKAI expand=True)
action_frame = ttk.LabelFrame(parent, text="🎯 Ubah Status Pesanan", padding=12)
action_frame.pack(fill='x', padx=10, pady=8)
# Grid 2x2 untuk 4 tombol
ttk.Button(
action_frame,
text="✅ Terima Pesanan (Pending → Menunggu)",
text="✅ Terima (Pending → Menunggu)",
command=lambda: self.update_order_status('menunggu'),
width=40
).grid(row=0, column=0, padx=5, pady=5, sticky='ew')
width=35
).grid(row=0, column=0, padx=4, pady=4, sticky='ew')
ttk.Button(
action_frame,
text="🍳 Proses Pesanan (Menunggu → Diproses)",
text="🍳 Proses (Menunggu → Diproses)",
command=lambda: self.update_order_status('diproses'),
width=40
).grid(row=0, column=1, padx=5, pady=5, sticky='ew')
width=35
).grid(row=0, column=1, padx=4, pady=4, sticky='ew')
ttk.Button(
action_frame,
text="🍽️ Selesai Disajikan (Diproses → Selesai)",
text="🍽️ Selesai (Diproses → Selesai)",
command=lambda: self.update_order_status('selesai'),
width=40
).grid(row=1, column=0, padx=5, pady=5, sticky='ew')
width=35
).grid(row=1, column=0, padx=4, pady=4, sticky='ew')
ttk.Button(
action_frame,
text="💰 Selesai Dilayani (Selesai → Dibayar)",
text="💰 Dibayar (Selesai → Dibayar)",
command=lambda: self.update_order_status('dibayar'),
width=40
).grid(row=1, column=1, padx=5, pady=5, sticky='ew')
width=35
).grid(row=1, column=1, padx=4, pady=4, sticky='ew')
# Buat kolom responsive
action_frame.columnconfigure(0, weight=1)
@ -1651,7 +1682,7 @@ class App:
return
# Konfirmasi
if not messagebox.askyesno("Konfirmasi Ubah Status",
if not messagebox.askyesno("Konfirmasi",
f"Ubah status pesanan #{transaksi_id}\n\n"
f"Dari: {current_status.upper()}\n"
f"Ke: {new_status.upper()}\n\n"
@ -1664,11 +1695,13 @@ class App:
if success:
messagebox.showinfo("✅ Berhasil", f"Status berhasil diubah menjadi '{new_status.upper()}'")
self.reload_waiter_orders()
# Auto select row yang sama setelah reload
# Auto select row yang sama
for item_id in self.waiter_tree.get_children():
if self.waiter_tree.item(item_id)['values'][0] == transaksi_id:
self.waiter_tree.selection_set(item_id)
self.waiter_tree.see(item_id)
# Trigger event untuk reload detail
self.on_waiter_select(None)
break
else:
messagebox.showerror("❌ Gagal", "Gagal mengubah status pesanan")

View File

@ -1,5 +1,5 @@
id,nama,kategori,harga,stok,foto,tersedia,item_discount_pct
1,Americano,Minuman,20000,6,,1,0
1,Americano,Minuman,20000,5,,1,0
2,Latte,Minuman,25000,1,,1,10
3,Banana Cake,Dessert,30000,0,,0,0
4,Nasi Goreng,Makanan,35000,0,,0,0

1 id nama kategori harga stok foto tersedia item_discount_pct
2 1 Americano Minuman 20000 6 5 1 0
3 2 Latte Minuman 25000 1 1 10
4 3 Banana Cake Dessert 30000 0 0 0
5 4 Nasi Goreng Makanan 35000 0 0 0

View File

@ -1 +1,2 @@
id,user_id,nomor_meja,total,status,promo_code,subtotal,item_discount,promo_discount,tanggal
1,4,5,20000.0,dibayar,,20000.0,0.0,0.0,2025-12-10 11:26:40

1 id user_id nomor_meja total status promo_code subtotal item_discount promo_discount tanggal
2 1 4 5 20000.0 dibayar 20000.0 0.0 0.0 2025-12-10 11:26:40