Python-Menu/project/pembeli_menu.py

177 lines
6.9 KiB
Python

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("<Configure>", 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()