diff --git a/main.py b/main.py index 5e9ade0..0f300c9 100644 --- a/main.py +++ b/main.py @@ -698,9 +698,12 @@ class App: self.tab_menu_view = ttk.Frame(main) self.tab_promo = ttk.Frame(main) self.tab_order = ttk.Frame(main) + self.tab_waiter = ttk.Frame(main) main.add(self.tab_order, text="Order Menu") main.add(self.tab_menu_view, text="Menu - View") + if self.session['role'] in ['waiter', 'admin']: + main.add(self.tab_waiter, text="Waiter - Pesanan") if self.session['role'] == 'admin': main.add(self.tab_menu_manage, text="Menu - Manage") main.add(self.tab_promo, text="Promo - Manage") @@ -709,6 +712,8 @@ class App: self.build_menu_view_tab(self.tab_menu_view) self.build_order_tab(self.tab_order) + if self.session['role'] in ['waiter', 'admin']: + self.build_waiter_tab(self.tab_waiter) if self.session['role'] == 'admin': self.build_menu_manage_tab(self.tab_menu_manage) self.build_promo_tab(self.tab_promo) @@ -1408,6 +1413,206 @@ class App: + + + # Wilayah dikuasai Waiter + + + def build_waiter_tab(self, parent): + """Tab untuk waiter mengelola pesanan""" + for w in parent.winfo_children(): + w.destroy() + + # 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') + 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) + 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) + + # Treeview pesanan + cols = ("ID", "User ID", "No.Meja", "Total", "Status", "Promo", "Tanggal") + self.waiter_tree = ttk.Treeview(parent, columns=cols, show='headings', height=12) + + self.waiter_tree.heading("ID", text="ID") + self.waiter_tree.heading("User ID", text="User ID") + self.waiter_tree.heading("No.Meja", text="No.Meja") + self.waiter_tree.heading("Total", text="Total") + self.waiter_tree.heading("Status", text="Status") + self.waiter_tree.heading("Promo", text="Promo") + self.waiter_tree.heading("Tanggal", text="Tanggal") + + self.waiter_tree.column("ID", width=40) + self.waiter_tree.column("User ID", width=60) + self.waiter_tree.column("No.Meja", width=70) + self.waiter_tree.column("Total", width=100) + self.waiter_tree.column("Status", width=90) + self.waiter_tree.column("Promo", width=80) + self.waiter_tree.column("Tanggal", width=140) + + self.waiter_tree.pack(fill='both', expand=True, padx=10, pady=6) + + # Detail pesanan (muncul saat pilih row) + detail_frame = ttk.LabelFrame(parent, text="Detail Pesanan", padding=10) + detail_frame.pack(fill='x', padx=10, pady=6) + + self.waiter_detail_text = tk.Text(detail_frame, height=8, width=80) + self.waiter_detail_text.pack(fill='both', expand=True) + + # Bind event saat pilih pesanan + self.waiter_tree.bind("<>", self.on_waiter_select) + + # Tombol aksi + action_frame = ttk.Frame(parent) + action_frame.pack(pady=10) + + ttk.Button(action_frame, text="✅ Terima Pesanan (Pending → Menunggu)", + command=lambda: self.update_order_status('menunggu'), + width=35).pack(pady=3) + ttk.Button(action_frame, text="🍳 Proses Pesanan (Menunggu → Diproses)", + command=lambda: self.update_order_status('diproses'), + width=35).pack(pady=3) + ttk.Button(action_frame, text="🍽️ Selesai Disajikan (Diproses → Selesai)", + command=lambda: self.update_order_status('selesai'), + width=35).pack(pady=3) + ttk.Button(action_frame, text="💰 Selesai Dilayani (Selesai → Dibayar)", + command=lambda: self.update_order_status('dibayar'), + width=35).pack(pady=3) + + # Load data + self.reload_waiter_orders() + + def reload_waiter_orders(self, status_filter=None): + """Load pesanan untuk waiter""" + # Clear tree + for r in self.waiter_tree.get_children(): + self.waiter_tree.delete(r) + + # Get transaksi + if status_filter: + orders = transaksi_list(status=status_filter) + else: + # Tampilkan semua kecuali yang sudah dibayar + all_orders = transaksi_list() + orders = [o for o in all_orders if o[4] != 'dibayar'] + + # Insert ke tree + for order in orders: + tid, uid, meja, total, status, promo_code, tanggal = order + promo_display = promo_code if promo_code else "-" + self.waiter_tree.insert("", tk.END, values=( + tid, uid, meja, f"Rp {total:,.0f}", status, promo_display, tanggal + )) + + def on_waiter_select(self, event): + """Tampilkan detail pesanan saat dipilih""" + sel = self.waiter_tree.selection() + if not sel: + return + + item = self.waiter_tree.item(sel)['values'] + transaksi_id = item[0] + + # Get detail transaksi + transaksi_data = transaksi_get(transaksi_id) + if not transaksi_data: + return + + tid, uid, meja, total, status, promo_code, subtotal, item_disc, promo_disc, tanggal = transaksi_data + + # Get detail items + detail_items = detail_transaksi_list(transaksi_id) + + # Format detail + detail_text = f"═══════════════════════════════════════════════\n" + detail_text += f"TRANSAKSI ID: {tid}\n" + detail_text += f"═══════════════════════════════════════════════\n\n" + detail_text += f"User ID : {uid}\n" + detail_text += f"Nomor Meja : {meja}\n" + detail_text += f"Status : {status.upper()}\n" + detail_text += f"Tanggal : {tanggal}\n" + detail_text += f"Kode Promo : {promo_code if promo_code else '-'}\n\n" + + detail_text += f"───────────────────────────────────────────────\n" + detail_text += f"ITEM PESANAN:\n" + detail_text += f"───────────────────────────────────────────────\n" + + for detail in detail_items: + did, mid, qty, harga, subtotal_item = detail + + # Get nama menu + menu_data = menu_get(mid) + if menu_data: + _, nama, kategori, _, _, _, _, _ = menu_data + detail_text += f"• {nama} ({kategori})\n" + detail_text += f" {qty} x Rp {harga:,.0f} = Rp {subtotal_item:,.0f}\n\n" + + detail_text += f"───────────────────────────────────────────────\n" + detail_text += f"Subtotal : Rp {subtotal:,.0f}\n" + detail_text += f"Diskon Item : Rp {item_disc:,.0f}\n" + detail_text += f"Diskon Promo : Rp {promo_disc:,.0f}\n" + detail_text += f"───────────────────────────────────────────────\n" + detail_text += f"TOTAL BAYAR : Rp {total:,.0f}\n" + detail_text += f"═══════════════════════════════════════════════\n" + + # Tampilkan di text widget + self.waiter_detail_text.delete('1.0', tk.END) + self.waiter_detail_text.insert('1.0', detail_text) + + def update_order_status(self, new_status): + """Update status pesanan yang dipilih""" + sel = self.waiter_tree.selection() + if not sel: + messagebox.showwarning("Pilih Pesanan", "Pilih pesanan terlebih dahulu") + return + + item = self.waiter_tree.item(sel)['values'] + transaksi_id = item[0] + current_status = item[4] + + # Validasi flow status + valid_transitions = { + 'pending': ['menunggu'], + 'menunggu': ['diproses'], + 'diproses': ['selesai'], + 'selesai': ['dibayar'] + } + + if current_status not in valid_transitions: + messagebox.showerror("Error", f"Status '{current_status}' tidak bisa diubah lagi") + return + + if new_status not in valid_transitions[current_status]: + messagebox.showwarning("Invalid", + f"Tidak bisa ubah dari '{current_status}' ke '{new_status}'.\n" + f"Status berikutnya: {', '.join(valid_transitions[current_status])}") + return + + # Konfirmasi + if not messagebox.askyesno("Konfirmasi", + f"Ubah status pesanan #{transaksi_id}\n" + f"dari '{current_status}' ke '{new_status}'?"): + return + + # Update status + success = transaksi_update_status(transaksi_id, new_status) + + if success: + messagebox.showinfo("Sukses", f"Status diubah menjadi '{new_status}'") + self.reload_waiter_orders() + else: + messagebox.showerror("Error", "Gagal update status") + + diff --git a/menu.csv b/menu.csv index 30cfbe4..eca2796 100644 --- a/menu.csv +++ b/menu.csv @@ -1,5 +1,5 @@ id,nama,kategori,harga,stok,foto,tersedia,item_discount_pct -1,Americano,Minuman,20000,10,,1,0 -2,Latte,Minuman,25000,2,,1,10 -3,Banana Cake,Dessert,30000,1,,1,0 +1,Americano,Minuman,20000,8,,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