import tkinter as tk from tkinter import messagebox, simpledialog from PIL import Image, ImageTk import os from database import connect class PembeliMenu(tk.Frame): def __init__(self, parent, controller): super().__init__(parent) self.controller = controller self.keranjang = [] # List untuk simpan belanjaan sementara self.image_refs = [] # Supaya gambar tidak hilang # --- Layout Utama: Kiri (Menu) & Kanan (Keranjang) --- # 1. Frame Kiri (Daftar Menu) self.left_frame = tk.Frame(self) self.left_frame.pack(side="left", fill="both", expand=True) # Header Kiri header = tk.Frame(self.left_frame, bg="#2c3e50", height=50) header.pack(fill="x") tk.Label(header, text="DAFTAR MENU", font=("Arial", 14, "bold"), fg="white", bg="#2c3e50").pack(pady=10) # Canvas untuk Scroll Menu self.canvas = tk.Canvas(self.left_frame) self.scrollbar = tk.Scrollbar(self.left_frame, orient="vertical", command=self.canvas.yview) self.scrollable_frame = tk.Frame(self.canvas) self.scrollable_frame.bind("", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all"))) self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw") self.canvas.configure(yscrollcommand=self.scrollbar.set) self.canvas.pack(side="left", fill="both", expand=True) self.scrollbar.pack(side="right", fill="y") # 2. Frame Kanan (Keranjang Belanja) self.right_frame = tk.Frame(self, bg="#ecf0f1", width=300) self.right_frame.pack(side="right", fill="y") self.right_frame.pack_propagate(False) # Agar lebar tetap 300px tk.Label(self.right_frame, text="KERANJANG SAYA", font=("Arial", 12, "bold"), bg="#bdc3c7", pady=10).pack(fill="x") # Listbox Keranjang self.cart_listbox = tk.Listbox(self.right_frame, font=("Arial", 10)) self.cart_listbox.pack(fill="both", expand=True, padx=10, pady=10) # Label Total Harga self.total_label = tk.Label(self.right_frame, text="Total: Rp 0", font=("Arial", 14, "bold"), bg="#ecf0f1", fg="#e74c3c") self.total_label.pack(pady=10) # Tombol Aksi tk.Button(self.right_frame, text="Hapus Item Terpilih", bg="#e67e22", fg="white", command=self.hapus_item).pack(fill="x", padx=10, pady=5) tk.Button(self.right_frame, text="CHECKOUT / BAYAR", bg="#27ae60", fg="white", font=("Arial", 10, "bold"), height=2, command=self.checkout).pack(fill="x", padx=10, pady=20) tk.Button(self.right_frame, text="Kembali / Logout", command=lambda: controller.show_frame("LoginPage")).pack(pady=5) def update_data(self): """Dipanggil saat halaman dibuka""" self.load_menu() self.keranjang = [] # Reset keranjang tiap login baru self.update_keranjang_ui() def load_menu(self): # Bersihkan area menu for widget in self.scrollable_frame.winfo_children(): widget.destroy() self.image_refs.clear() db = connect() cur = db.cursor() cur.execute("SELECT * FROM menu") items = cur.fetchall() db.close() columns = 3 for index, item in enumerate(items): self.create_card(item, index, columns) def create_card(self, item, index, columns): id_menu, nama, kategori, harga, stok, file_gambar = item row = index // columns col = index % columns card = tk.Frame(self.scrollable_frame, bd=2, relief="groove", bg="white") card.grid(row=row, column=col, padx=5, pady=5, sticky="nsew") # Load Gambar path = os.path.join("aset", file_gambar) try: img = Image.open(path).resize((120, 80), Image.Resampling.LANCZOS) photo = ImageTk.PhotoImage(img) self.image_refs.append(photo) tk.Label(card, image=photo, bg="white").pack(pady=5) except: tk.Label(card, text="[No Image]", bg="#eee", height=4).pack(pady=5) tk.Label(card, text=nama, font=("Arial", 10, "bold"), bg="white").pack() tk.Label(card, text=f"Rp {int(harga):,}", fg="green", bg="white").pack() # Tombol Tambah state = "normal" if stok > 0 else "disabled" text_btn = "Tambah" if stok > 0 else "Habis" tk.Button(card, text=text_btn, bg="#3498db", fg="white", state=state, command=lambda: self.tambah_ke_keranjang(item)).pack(pady=5, padx=5, fill="x") def tambah_ke_keranjang(self, item): # item = (id, nama, kategori, harga, stok, gambar) self.keranjang.append(item) self.update_keranjang_ui() def update_keranjang_ui(self): self.cart_listbox.delete(0, tk.END) total = 0 for item in self.keranjang: nama = item[1] harga = item[3] self.cart_listbox.insert(tk.END, f"{nama} - Rp {int(harga):,}") total += harga self.total_label.config(text=f"Total: Rp {int(total):,}") def hapus_item(self): selected = self.cart_listbox.curselection() if not selected: return index = selected[0] del self.keranjang[index] self.update_keranjang_ui() def checkout(self): if not self.keranjang: messagebox.showwarning("Kosong", "Keranjang masih kosong!") return nama_pelanggan = simpledialog.askstring("Input", "Masukkan Nama Pelanggan:") if not nama_pelanggan: return total_harga = sum(item[3] for item in self.keranjang) # Simpan ke Database db = connect() cur = db.cursor() try: # 1. Simpan Transaksi Utama cur.execute(""" INSERT INTO transaksi (nama_pelanggan, total, status) VALUES (?, ?, 'Pending') """, (nama_pelanggan, total_harga)) transaksi_id = cur.lastrowid # 2. Simpan Detail Transaksi (Looping item di keranjang) for item in self.keranjang: menu_id = item[0] harga = item[3] # Masukkan ke detail cur.execute(""" INSERT INTO detail_transaksi (transaksi_id, menu_id, jumlah, subtotal) VALUES (?, ?, 1, ?) """, (transaksi_id, menu_id, harga)) # Kurangi Stok Menu cur.execute("UPDATE menu SET stok = stok - 1 WHERE id = ?", (menu_id,)) db.commit() messagebox.showinfo("Berhasil", "Pesanan berhasil dibuat! Silakan bayar di kasir.") # Reset self.keranjang = [] self.update_keranjang_ui() self.load_menu() # Reload menu untuk update stok visual except Exception as e: db.rollback() messagebox.showerror("Error", f"Gagal Checkout: {e}") finally: db.close()