177 lines
6.9 KiB
Python
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() |