import tkinter as tk from tkinter import messagebox from database import connect from datetime import datetime import qrcode from PIL import ImageTk class KasirPage: def __init__(self, parent, controller=None): self.parent = parent self.frame = tk.Frame(parent) self.frame.pack(fill="both", expand=True) # ===================== # JUDUL # ===================== tk.Label( self.frame, text="KASIR - PEMBAYARAN", font=("Arial", 18, "bold") ).pack(pady=10) tk.Button( self.frame, text="Logout", bg="#f9e79f", command=self.logout ).pack(pady=5) tk.Button( self.frame, text="Refresh", command=self.load_tagihan ).pack(pady=3) # ===================== # LIST TAGIHAN # ===================== tk.Label( self.frame, text="Daftar Tagihan (Status: Disajikan)", font=("Arial", 12) ).pack(pady=5) self.listbox = tk.Listbox(self.frame, width=65, height=10) self.listbox.pack(pady=5) # ===================== # METODE PEMBAYARAN # ===================== metode_frame = tk.Frame(self.frame) metode_frame.pack(pady=5) tk.Label(metode_frame, text="Metode Pembayaran:").pack(side=tk.LEFT) self.metode = tk.StringVar(value="Cash") tk.OptionMenu( metode_frame, self.metode, "Cash", "QRIS", "E-Wallet" ).pack(side=tk.LEFT, padx=5) # ===================== # INPUT CASH # ===================== cash_frame = tk.Frame(self.frame) cash_frame.pack(pady=5) tk.Label(cash_frame, text="Uang Diterima (Cash):").pack(side=tk.LEFT) self.uang_entry = tk.Entry(cash_frame, width=15) self.uang_entry.pack(side=tk.LEFT, padx=5) # ===================== # HITUNG KEMBALIAN # ===================== def hitung_kembalian(event=None): try: # 1. Ambil transaksi yang sedang dipilih (Total tagihan) idx = self.listbox.curselection() if idx: teks_item = self.listbox.get(idx).split(" ") total = int(teks_item[len(teks_item)-1].replace(",","")) uang_diterima = int(self.uang_entry.get()) # 3. Hitung dan update label kembalian = uang_diterima - total self.kembalian_label.config(text=f"Rp {kembalian:,.0f}") except ValueError: # Jika input bukan angka atau kosong, atur kembalian jadi 0 self.kembalian_label.config(text="Rp 0") except IndexError: # Jika transaksi tidak dipilih self.kembalian_label.config(text="Rp 0") self.uang_entry.bind("", hitung_kembalian) # ===================== # UANG KEMBALIAN (BARU) # ===================== kembalian_frame = tk.Frame(self.frame) kembalian_frame.pack(pady=5) tk.Label(kembalian_frame, text="Uang Kembalian:").pack(side=tk.LEFT) # ⭐️ Label untuk menampilkan kembalian self.kembalian_label = tk.Label(kembalian_frame, text="Rp 0") self.kembalian_label.pack(side=tk.LEFT, padx=5) # ===================== # BUTTON BAYAR # ===================== tk.Button( self.frame, text="Proses Pembayaran", bg="#d1e7dd", width=25, command=self.bayar ).pack(pady=10) self.transaksi_data = [] self.load_tagihan() # ===================== # LOAD TAGIHAN # ===================== def load_tagihan(self): self.listbox.delete(0, tk.END) self.transaksi_data = [] db = connect() cur = db.cursor() cur.execute(""" SELECT id, meja_id, total FROM transaksi WHERE status='Disajikan' """) rows = cur.fetchall() db.close() for row in rows: t_id, meja, total = row self.listbox.insert( tk.END, f"Meja {meja} | ID {t_id} | Total Rp {total:,.0f}" ) # 🔽 AMBIL DETAIL MENU db = connect() cur = db.cursor() cur.execute(""" SELECT menu_nama, jumlah FROM detail_transaksi WHERE transaksi_id=? """, (t_id,)) items = cur.fetchall() db.close() for nama, qty in items: self.listbox.insert( tk.END, f" • {nama} x{qty}" ) self.listbox.insert(tk.END, "-" * 50) self.transaksi_data.append(row) # ===================== # BAYAR # ===================== def bayar(self): idx = self.listbox.curselection() if not idx: messagebox.showwarning("Pilih", "Pilih tagihan yang akan dibayar!") return idx = self.listbox.curselection() if idx: teks_item = self.listbox.get(idx).split(" ") total = int(teks_item[len(teks_item)-1].replace(",","")) meja = int(teks_item[1]) t_id = int(teks_item[4]) metode = self.metode.get() if metode == "QRIS": self.tampilkan_qr(t_id, meja, total) elif metode == "E-Wallet": self.konfirmasi_ewallet(t_id, meja, total) else: # CASH try: uang = int(self.uang_entry.get()) except: messagebox.showwarning("Error", "Masukkan uang cash!") return if uang < total: messagebox.showwarning( "Kurang", f"Uang kurang!\nTotal: Rp {total:,.0f}" ) return kembalian = uang - total self.selesaikan_pembayaran( t_id, meja, total, metode, uang, kembalian ) # ===================== # QRIS (CLOSE WINDOW = LUNAS) # ===================== def tampilkan_qr(self, t_id, meja, total): win = tk.Toplevel(self.frame) win.title("QRIS Payment") win.geometry("320x420") tk.Label( win, text="SCAN QR UNTUK BAYAR", font=("Arial", 12, "bold") ).pack(pady=10) qr_data = f""" QRIS-DUMMY Cafe Python Transaksi: {t_id} Meja: {meja} Total: {total} """ qr = qrcode.make(qr_data) qr_img = ImageTk.PhotoImage(qr) lbl = tk.Label(win, image=qr_img) lbl.image = qr_img lbl.pack(pady=10) tk.Label( win, text=f"Total: Rp {total:,.0f}", font=("Arial", 11) ).pack(pady=5) def selesai_qris(): self.selesaikan_pembayaran(t_id, meja, total, "QRIS") win.destroy() # ❌ WINDOW DITUTUP = TRANSAKSI BERHASIL win.protocol("WM_DELETE_WINDOW", selesai_qris) tk.Button( win, text="Konfirmasi Pembayaran", bg="#d1e7dd", width=25, command=selesai_qris ).pack(pady=15) # ===================== # E-WALLET # ===================== def konfirmasi_ewallet(self, t_id, meja, total): confirm = messagebox.askyesno( "E-Wallet Payment", f""" Bayar menggunakan E-Wallet? Meja : {meja} Total : Rp {total:,.0f} Lanjutkan pembayaran? """ ) if confirm: self.selesaikan_pembayaran(t_id, meja, total, "E-Wallet") def selesaikan_pembayaran(self, t_id, meja, total, metode, uang=None, kembalian=None): db = connect() cur = db.cursor() try: cur.execute( """ UPDATE transaksi SET status='Lunas', tanggal = DATETIME('now') WHERE id=? """, (t_id,) ) db.commit() # ⭐️ PASTIKAN COMMIT DILAKUKAN tanggal_sekarang = datetime.now().strftime("%Y-%m-%d %H:%M:%S") sql_query = """ INSERT INTO transaksi (tanggal, total, meja_id, status, metode) VALUES (?, ?, ?, ?, ?) """ data_transaksi = (tanggal_sekarang, total, meja, "Lunas", metode) cur.execute(sql_query, data_transaksi) db.commit() # Tambahkan print debug untuk konfirmasi print(f"DEBUG: Transaksi ID {t_id} berhasil diupdate menjadi Lunas.") except Exception as e: # Jika ada error database print(f"ERROR: Gagal update status transaksi: {e}") messagebox.showerror("DB Error", "Gagal memperbarui status transaksi.") finally: db.close() struk_tambahan = "" if metode == "Cash" and uang is not None and kembalian is not None: struk_tambahan = f""" Uang Diterima: Rp {uang:,.0f} Kembalian : Rp {kembalian:,.0f}""" messagebox.showinfo( "Struk Pembayaran", f""" ======= STRUK ======= ID Transaksi : {t_id} Meja : {meja} Total : Rp {total:,.0f} Metode : {metode}{struk_tambahan} Status : Lunas ==================== Terima kasih 🙏 """ ) self.load_tagihan() def logout(self): self.frame.destroy() from main import LoginScreen LoginScreen(self.parent)