Compare commits

...
12 Commits
6 changed files with 209 additions and 40 deletions
+1
View File
@@ -0,0 +1 @@
*.pyc
BIN
View File
Binary file not shown.
+2 -1
View File
@@ -47,7 +47,8 @@ def setup_database():
tanggal TEXT,
total REAL,
meja_id INTEGER,
status TEXT
status TEXT,
metode TEXT
)
""")
+129 -13
View File
@@ -1,11 +1,10 @@
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
@@ -61,6 +60,56 @@ class KasirPage:
"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("<KeyRelease>", 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
# =====================
@@ -94,12 +143,33 @@ class KasirPage:
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
# =====================
@@ -109,15 +179,41 @@ class KasirPage:
messagebox.showwarning("Pilih", "Pilih tagihan yang akan dibayar!")
return
t_id, meja, total = self.transaksi_data[idx[0]]
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:
self.selesaikan_pembayaran(t_id, meja, total, metode)
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)
@@ -188,13 +284,11 @@ Lanjutkan pembayaran?
if confirm:
self.selesaikan_pembayaran(t_id, meja, total, "E-Wallet")
# =====================
# FINAL PEMBAYARAN
# =====================
def selesaikan_pembayaran(self, t_id, meja, total, metode):
def selesaikan_pembayaran(self, t_id, meja, total, metode, uang=None, kembalian=None):
db = connect()
cur = db.cursor()
try:
cur.execute(
"""
UPDATE transaksi
@@ -204,10 +298,35 @@ Lanjutkan pembayaran?
""",
(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"""
@@ -215,7 +334,7 @@ Lanjutkan pembayaran?
ID Transaksi : {t_id}
Meja : {meja}
Total : Rp {total:,.0f}
Metode : {metode}
Metode : {metode}{struk_tambahan}
Status : Lunas
====================
Terima kasih 🙏
@@ -224,9 +343,6 @@ Terima kasih 🙏
self.load_tagihan()
# =====================
# LOGOUT
# =====================
def logout(self):
self.frame.destroy()
from main import LoginScreen
View File
+64 -13
View File
@@ -5,6 +5,8 @@ import sqlite3
import datetime
import os
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# ================= DATABASE CONNECT =================
def connect():
return sqlite3.connect("cafe.db")
@@ -20,11 +22,23 @@ class PembeliMenu:
self.images = []
# ================= HEADER =================
header = tk.Frame(self.frame)
header.pack(fill="x", padx=20, pady=10)
tk.Label(
self.frame,
header,
text="SELAMAT DATANG",
font=("Arial", 18, "bold")
).pack(pady=10)
).pack(side="left")
tk.Button(
header,
text="⬅ Kembali",
bg="#f8d7da",
font=("Arial", 10, "bold"),
command=self.logout
).pack(side="right")
# ================= INPUT DATA =================
info_frame = tk.Frame(self.frame, bd=2, relief="groove", padx=10, pady=10)
@@ -112,17 +126,26 @@ class PembeliMenu:
card.grid_propagate(False)
try:
filename = os.path.basename(gambar) if gambar else None
img_path = os.path.join("aset", filename) if filename else None
if img_path and os.path.exists(img_path):
img = Image.open(img_path).resize((140, 90))
if not gambar:
raise ValueError("gambar kosong")
# gambar dari DB sudah mengandung 'aset/...'
img_path = os.path.join(BASE_DIR, gambar)
if not os.path.exists(img_path):
raise FileNotFoundError(img_path)
img = Image.open(img_path)
img = img.resize((140, 90), Image.Resampling.LANCZOS)
photo = ImageTk.PhotoImage(img)
self.images.append(photo)
tk.Label(card, image=photo).pack(pady=5)
else:
tk.Label(card, text="[No Image]", height=6).pack()
except Exception:
tk.Label(card, text="Error Img", height=6).pack()
except Exception as e:
print("IMG ERROR:", e)
tk.Label(card, text="No Image", height=6).pack()
tk.Label(card, text=nama, font=("Arial", 10, "bold"), wraplength=160).pack()
tk.Label(card, text=f"Rp {harga:,.0f}").pack(pady=2)
@@ -160,18 +183,39 @@ class PembeliMenu:
total += item['subtotal']
self.total_lbl.config(text=f"Total: Rp {total:,.0f}")
# ================= CHECKOUT =================
def checkout(self):
if not self.entry_nama.get() or not self.cart:
messagebox.showwarning("Error", "Data belum lengkap")
return
total = sum(item['subtotal'] for item in self.cart)
tanggal = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
db = connect()
cur = db.cursor()
cur.execute("INSERT INTO transaksi (tanggal, total, meja_id, status) VALUES (?, ?, ?, ?)",
(tanggal, total, self.combo_meja.get(), "Pending"))
# 1️⃣ Simpan transaksi
cur.execute("""
INSERT INTO transaksi (tanggal, total, meja_id, status)
VALUES (?, ?, ?, ?)
""", (tanggal, total, self.combo_meja.get(), "Pending"))
transaksi_id = cur.lastrowid # 🔥 AMBIL ID TRANSAKSI
# 2️⃣ Simpan detail menu
for item in self.cart:
cur.execute("""
INSERT INTO detail_transaksi
(transaksi_id, menu_nama, harga, jumlah, subtotal)
VALUES (?, ?, ?, ?, ?)
""", (
transaksi_id,
item['nama'],
item['harga_satuan'],
item['qty'],
item['subtotal']
))
db.commit()
db.close()
@@ -179,6 +223,13 @@ class PembeliMenu:
self.cart.clear()
self.refresh_cart()
def logout(self):
self.frame.destroy()
from main import LoginScreen
LoginScreen(self.parent)
# ================= RUN =================
if __name__ == '__main__':
root = tk.Tk()