|
|
|
|
@ -638,16 +638,129 @@ def apply_discounts_and_promo(cart_items, promo_code=None):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# === FUNGSI FAVORITE ===
|
|
|
|
|
|
|
|
|
|
def favorite_update(user_id, menu_id):
|
|
|
|
|
"""Update atau tambah favorite count untuk user tertentu"""
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
rows = read_all(FAVORITE_CSV)
|
|
|
|
|
found = False
|
|
|
|
|
|
|
|
|
|
for r in rows:
|
|
|
|
|
if r.get("user_id") == str(user_id) and r.get("menu_id") == str(menu_id):
|
|
|
|
|
try:
|
|
|
|
|
count = int(r.get("order_count") or 0)
|
|
|
|
|
except:
|
|
|
|
|
count = 0
|
|
|
|
|
r["order_count"] = str(count + 1)
|
|
|
|
|
r["last_ordered"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
found = True
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if not found:
|
|
|
|
|
rows.append({
|
|
|
|
|
"user_id": str(user_id),
|
|
|
|
|
"menu_id": str(menu_id),
|
|
|
|
|
"order_count": "1",
|
|
|
|
|
"last_ordered": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
write_all(FAVORITE_CSV, ["user_id", "menu_id", "order_count", "last_ordered"], rows)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def favorite_list(user_id, limit=5):
|
|
|
|
|
"""Ambil menu favorit user, sorted by order_count descending"""
|
|
|
|
|
rows = read_all(FAVORITE_CSV)
|
|
|
|
|
out = []
|
|
|
|
|
|
|
|
|
|
for r in rows:
|
|
|
|
|
if r.get("user_id") == str(user_id):
|
|
|
|
|
try:
|
|
|
|
|
mid = int(r.get("menu_id") or 0)
|
|
|
|
|
except:
|
|
|
|
|
mid = r.get("menu_id")
|
|
|
|
|
try:
|
|
|
|
|
count = int(r.get("order_count") or 0)
|
|
|
|
|
except:
|
|
|
|
|
count = 0
|
|
|
|
|
|
|
|
|
|
last_ordered = r.get("last_ordered")
|
|
|
|
|
out.append((mid, count, last_ordered))
|
|
|
|
|
|
|
|
|
|
out.sort(key=lambda x: x[1], reverse=True)
|
|
|
|
|
|
|
|
|
|
if limit:
|
|
|
|
|
out = out[:limit]
|
|
|
|
|
|
|
|
|
|
return out
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# === FUNGSI PEMBAYARAN ===
|
|
|
|
|
|
|
|
|
|
def pembayaran_add(transaksi_id, metode_pembayaran, jumlah_bayar, status_pembayaran='sukses', struk=''):
|
|
|
|
|
"""Simpan data pembayaran baru"""
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
rows = read_all(PEMBAYARAN_CSV)
|
|
|
|
|
new_id = next_int_id(rows, "id")
|
|
|
|
|
tanggal_bayar = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
|
|
|
|
|
rows.append({
|
|
|
|
|
"id": new_id,
|
|
|
|
|
"transaksi_id": str(transaksi_id),
|
|
|
|
|
"metode_pembayaran": metode_pembayaran,
|
|
|
|
|
"jumlah_bayar": str(float(jumlah_bayar)),
|
|
|
|
|
"status_pembayaran": status_pembayaran,
|
|
|
|
|
"tanggal_bayar": tanggal_bayar,
|
|
|
|
|
"struk": struk
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
write_all(PEMBAYARAN_CSV, ["id", "transaksi_id", "metode_pembayaran", "jumlah_bayar", "status_pembayaran", "tanggal_bayar", "struk"], rows)
|
|
|
|
|
return new_id
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pembayaran_get_by_transaksi(transaksi_id):
|
|
|
|
|
"""Ambil data pembayaran berdasarkan transaksi_id"""
|
|
|
|
|
rows = read_all(PEMBAYARAN_CSV)
|
|
|
|
|
for r in rows:
|
|
|
|
|
if r.get("transaksi_id") == str(transaksi_id):
|
|
|
|
|
try:
|
|
|
|
|
pid = int(r.get("id") or 0)
|
|
|
|
|
except:
|
|
|
|
|
pid = r.get("id")
|
|
|
|
|
try:
|
|
|
|
|
jumlah = float(r.get("jumlah_bayar") or 0.0)
|
|
|
|
|
except:
|
|
|
|
|
jumlah = 0.0
|
|
|
|
|
|
|
|
|
|
return (pid, r.get("metode_pembayaran"), jumlah, r.get("status_pembayaran"), r.get("tanggal_bayar"), r.get("struk"))
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# === FUNGSI MEJA ===
|
|
|
|
|
|
|
|
|
|
def meja_update_status(nomor_meja, new_status, transaksi_id=""):
|
|
|
|
|
"""Update status meja (kosong/terisi) dan link ke transaksi"""
|
|
|
|
|
rows = read_all(MEJA_CSV)
|
|
|
|
|
found = False
|
|
|
|
|
|
|
|
|
|
for r in rows:
|
|
|
|
|
if r.get("nomor_meja") == str(nomor_meja):
|
|
|
|
|
r["status"] = new_status
|
|
|
|
|
r["transaksi_id"] = str(transaksi_id) if transaksi_id else ""
|
|
|
|
|
found = True
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if found:
|
|
|
|
|
write_all(MEJA_CSV, ["nomor_meja", "status", "transaksi_id"], rows)
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def meja_tutup(nomor_meja):
|
|
|
|
|
"""Tutup meja (set ke kosong)"""
|
|
|
|
|
return meja_update_status(nomor_meja, "kosong", "")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Wilayah dikuasai UI
|
|
|
|
|
@ -2119,7 +2232,150 @@ def favorite_all(limit=10):
|
|
|
|
|
return out
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# FITUR PEMBAYARAN
|
|
|
|
|
|
|
|
|
|
# WILAYAH DIKUASAI PEMBAYARAN & MEJA
|
|
|
|
|
|
|
|
|
|
# === FUNGSI PEMBAYARAN ===
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pembayaran_add(transaksi_id, metode_pembayaran, jumlah_bayar, status_pembayaran='sukses', struk=''):
|
|
|
|
|
"""Simpan data pembayaran baru"""
|
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
|
rows = read_all(PEMBAYARAN_CSV)
|
|
|
|
|
new_id = next_int_id(rows, "id")
|
|
|
|
|
tanggal_bayar = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
|
|
|
|
|
rows.append({
|
|
|
|
|
"id": new_id,
|
|
|
|
|
"transaksi_id": str(transaksi_id),
|
|
|
|
|
"metode_pembayaran": metode_pembayaran,
|
|
|
|
|
"jumlah_bayar": str(float(jumlah_bayar)),
|
|
|
|
|
"status_pembayaran": status_pembayaran,
|
|
|
|
|
"tanggal_bayar": tanggal_bayar,
|
|
|
|
|
"struk": struk
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
write_all(PEMBAYARAN_CSV, ["id", "transaksi_id", "metode_pembayaran", "jumlah_bayar", "status_pembayaran", "tanggal_bayar", "struk"], rows)
|
|
|
|
|
return new_id
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pembayaran_get_by_transaksi(transaksi_id):
|
|
|
|
|
"""Ambil data pembayaran berdasarkan transaksi_id"""
|
|
|
|
|
rows = read_all(PEMBAYARAN_CSV)
|
|
|
|
|
for r in rows:
|
|
|
|
|
if r.get("transaksi_id") == str(transaksi_id):
|
|
|
|
|
try:
|
|
|
|
|
pid = int(r.get("id") or 0)
|
|
|
|
|
except:
|
|
|
|
|
pid = r.get("id")
|
|
|
|
|
try:
|
|
|
|
|
jumlah = float(r.get("jumlah_bayar") or 0.0)
|
|
|
|
|
except:
|
|
|
|
|
jumlah = 0.0
|
|
|
|
|
|
|
|
|
|
return (pid, r.get("metode_pembayaran"), jumlah, r.get("status_pembayaran"), r.get("tanggal_bayar"), r.get("struk"))
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def pembayaran_list(status=None, metode=None):
|
|
|
|
|
"""Ambil semua pembayaran dengan filter opsional"""
|
|
|
|
|
rows = read_all(PEMBAYARAN_CSV)
|
|
|
|
|
out = []
|
|
|
|
|
|
|
|
|
|
for r in rows:
|
|
|
|
|
if status and r.get("status_pembayaran") != status:
|
|
|
|
|
continue
|
|
|
|
|
if metode and r.get("metode_pembayaran") != metode:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
pid = int(r.get("id") or 0)
|
|
|
|
|
except:
|
|
|
|
|
pid = r.get("id")
|
|
|
|
|
try:
|
|
|
|
|
tid = int(r.get("transaksi_id") or 0)
|
|
|
|
|
except:
|
|
|
|
|
tid = r.get("transaksi_id")
|
|
|
|
|
try:
|
|
|
|
|
jumlah = float(r.get("jumlah_bayar") or 0.0)
|
|
|
|
|
except:
|
|
|
|
|
jumlah = 0.0
|
|
|
|
|
|
|
|
|
|
out.append((pid, tid, r.get("metode_pembayaran"), jumlah, r.get("status_pembayaran"), r.get("tanggal_bayar")))
|
|
|
|
|
|
|
|
|
|
out.sort(key=lambda x: int(x[0]), reverse=True)
|
|
|
|
|
return out
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# === FUNGSI MEJA ===
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def meja_list(status=None):
|
|
|
|
|
"""Ambil daftar meja dengan filter status opsional"""
|
|
|
|
|
rows = read_all(MEJA_CSV)
|
|
|
|
|
out = []
|
|
|
|
|
|
|
|
|
|
for r in rows:
|
|
|
|
|
if status and r.get("status") != status:
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
nomor = int(r.get("nomor_meja") or 0)
|
|
|
|
|
except:
|
|
|
|
|
nomor = r.get("nomor_meja")
|
|
|
|
|
|
|
|
|
|
transaksi_id = r.get("transaksi_id") or ""
|
|
|
|
|
|
|
|
|
|
out.append((nomor, r.get("status"), transaksi_id))
|
|
|
|
|
|
|
|
|
|
out.sort(key=lambda x: int(x[0]) if isinstance(x[0], int) else 0)
|
|
|
|
|
return out
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def meja_get(nomor_meja):
|
|
|
|
|
"""Ambil data meja berdasarkan nomor"""
|
|
|
|
|
rows = read_all(MEJA_CSV)
|
|
|
|
|
for r in rows:
|
|
|
|
|
if r.get("nomor_meja") == str(nomor_meja):
|
|
|
|
|
try:
|
|
|
|
|
nomor = int(r.get("nomor_meja") or 0)
|
|
|
|
|
except:
|
|
|
|
|
nomor = r.get("nomor_meja")
|
|
|
|
|
|
|
|
|
|
transaksi_id = r.get("transaksi_id") or ""
|
|
|
|
|
return (nomor, r.get("status"), transaksi_id)
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def meja_update_status(nomor_meja, new_status, transaksi_id=""):
|
|
|
|
|
"""Update status meja (kosong/terisi) dan link ke transaksi"""
|
|
|
|
|
rows = read_all(MEJA_CSV)
|
|
|
|
|
found = False
|
|
|
|
|
|
|
|
|
|
for r in rows:
|
|
|
|
|
if r.get("nomor_meja") == str(nomor_meja):
|
|
|
|
|
r["status"] = new_status
|
|
|
|
|
r["transaksi_id"] = str(transaksi_id) if transaksi_id else ""
|
|
|
|
|
found = True
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if found:
|
|
|
|
|
write_all(MEJA_CSV, ["nomor_meja", "status", "transaksi_id"], rows)
|
|
|
|
|
return True
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def meja_tutup(nomor_meja):
|
|
|
|
|
"""Tutup meja (set ke kosong)"""
|
|
|
|
|
return meja_update_status(nomor_meja, "kosong", "")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def meja_buka(nomor_meja, transaksi_id):
|
|
|
|
|
"""Buka meja (set ke terisi dengan transaksi_id)"""
|
|
|
|
|
return meja_update_status(nomor_meja, "terisi", transaksi_id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def build_payment_tab(self, parent):
|
|
|
|
|
"""Tab pembayaran untuk kasir & admin"""
|
|
|
|
|
@ -2132,18 +2388,25 @@ def favorite_all(limit=10):
|
|
|
|
|
ttk.Label(header, text="💰 Pembayaran Transaksi", font=("Arial", 14, "bold")).pack(side='left')
|
|
|
|
|
ttk.Button(header, text="🔄 Refresh", command=self.reload_payment_orders).pack(side='right', padx=6)
|
|
|
|
|
|
|
|
|
|
# Split 2 panel: kiri = daftar transaksi, kanan = form pembayaran
|
|
|
|
|
left = ttk.LabelFrame(parent, text="📋 Transaksi Siap Dibayar (Status: Selesai)", padding=10)
|
|
|
|
|
left.pack(side='left', fill='both', expand=True, padx=10, pady=6)
|
|
|
|
|
# Container utama
|
|
|
|
|
main_container = ttk.Frame(parent)
|
|
|
|
|
main_container.pack(fill='both', expand=True, padx=10, pady=6)
|
|
|
|
|
|
|
|
|
|
right = ttk.LabelFrame(parent, text="💳 Form Pembayaran", padding=10)
|
|
|
|
|
right.pack(side='right', fill='both', expand=True, padx=10, pady=6)
|
|
|
|
|
# === PANEL KIRI: Daftar Transaksi ===
|
|
|
|
|
left = ttk.LabelFrame(main_container, text="📋 Transaksi Siap Dibayar (Status: Selesai)", padding=10)
|
|
|
|
|
left.pack(side='left', fill='both', expand=True, padx=(0, 5))
|
|
|
|
|
|
|
|
|
|
# === PANEL KIRI: Daftar Transaksi Selesai ===
|
|
|
|
|
# Treeview transaksi dengan scrollbar
|
|
|
|
|
tree_frame = ttk.Frame(left)
|
|
|
|
|
tree_frame.pack(fill='both', expand=True)
|
|
|
|
|
|
|
|
|
|
tree_scroll = ttk.Scrollbar(tree_frame, orient='vertical')
|
|
|
|
|
tree_scroll.pack(side='right', fill='y')
|
|
|
|
|
|
|
|
|
|
# Treeview transaksi
|
|
|
|
|
cols = ("ID", "Meja", "Total", "Status", "Tanggal")
|
|
|
|
|
self.payment_tree = ttk.Treeview(left, columns=cols, show='headings', height=12)
|
|
|
|
|
self.payment_tree = ttk.Treeview(tree_frame, columns=cols, show='headings', height=10, yscrollcommand=tree_scroll.set)
|
|
|
|
|
|
|
|
|
|
tree_scroll.config(command=self.payment_tree.yview)
|
|
|
|
|
|
|
|
|
|
self.payment_tree.heading("ID", text="ID")
|
|
|
|
|
self.payment_tree.heading("Meja", text="Meja")
|
|
|
|
|
@ -2155,18 +2418,18 @@ def favorite_all(limit=10):
|
|
|
|
|
self.payment_tree.column("Meja", width=60)
|
|
|
|
|
self.payment_tree.column("Total", width=100)
|
|
|
|
|
self.payment_tree.column("Status", width=80)
|
|
|
|
|
self.payment_tree.column("Tanggal", width=140)
|
|
|
|
|
self.payment_tree.column("Tanggal", width=120)
|
|
|
|
|
|
|
|
|
|
self.payment_tree.pack(fill='both', expand=True, pady=6)
|
|
|
|
|
|
|
|
|
|
# Bind event
|
|
|
|
|
self.payment_tree.pack(side='left', fill='both', expand=True)
|
|
|
|
|
self.payment_tree.bind("<<TreeviewSelect>>", self.on_payment_select)
|
|
|
|
|
|
|
|
|
|
# Detail transaksi
|
|
|
|
|
detail_frame = ttk.Frame(left)
|
|
|
|
|
detail_frame.pack(fill='x', pady=6)
|
|
|
|
|
detail_frame.pack(fill='x', pady=(10, 0))
|
|
|
|
|
|
|
|
|
|
self.payment_detail_text = tk.Text(detail_frame, height=8, font=("Courier New", 8), wrap='word')
|
|
|
|
|
ttk.Label(detail_frame, text="Detail Transaksi:", font=("Arial", 9, "bold")).pack(anchor='w')
|
|
|
|
|
|
|
|
|
|
self.payment_detail_text = tk.Text(detail_frame, height=6, font=("Courier New", 8), wrap='word')
|
|
|
|
|
detail_scroll = ttk.Scrollbar(detail_frame, orient='vertical', command=self.payment_detail_text.yview)
|
|
|
|
|
self.payment_detail_text.configure(yscrollcommand=detail_scroll.set)
|
|
|
|
|
|
|
|
|
|
@ -2174,10 +2437,50 @@ def favorite_all(limit=10):
|
|
|
|
|
detail_scroll.pack(side='right', fill='y')
|
|
|
|
|
|
|
|
|
|
# === PANEL KANAN: Form Pembayaran ===
|
|
|
|
|
right_outer = ttk.LabelFrame(main_container, text="💳 Form Pembayaran", padding=5)
|
|
|
|
|
right_outer.pack(side='right', fill='both', expand=True, padx=(5, 0))
|
|
|
|
|
|
|
|
|
|
# Info transaksi terpilih
|
|
|
|
|
# Frame wrapper untuk canvas
|
|
|
|
|
wrapper = ttk.Frame(right_outer)
|
|
|
|
|
wrapper.pack(fill='both', expand=True)
|
|
|
|
|
|
|
|
|
|
# Scrollbar
|
|
|
|
|
scrollbar = ttk.Scrollbar(wrapper, orient='vertical')
|
|
|
|
|
scrollbar.pack(side='right', fill='y')
|
|
|
|
|
|
|
|
|
|
# Canvas dengan HEIGHT FIXED
|
|
|
|
|
canvas = tk.Canvas(wrapper, yscrollcommand=scrollbar.set, highlightthickness=0, height=450)
|
|
|
|
|
canvas.pack(side='left', fill='both', expand=True)
|
|
|
|
|
|
|
|
|
|
scrollbar.config(command=canvas.yview)
|
|
|
|
|
|
|
|
|
|
# Frame konten
|
|
|
|
|
right = ttk.Frame(canvas)
|
|
|
|
|
canvas_window = canvas.create_window((0, 0), window=right, anchor='nw')
|
|
|
|
|
|
|
|
|
|
# Update scroll region
|
|
|
|
|
def configure_scroll(event):
|
|
|
|
|
canvas.configure(scrollregion=canvas.bbox('all'))
|
|
|
|
|
|
|
|
|
|
right.bind('<Configure>', configure_scroll)
|
|
|
|
|
|
|
|
|
|
# Update width
|
|
|
|
|
def configure_canvas(event):
|
|
|
|
|
canvas.itemconfig(canvas_window, width=event.width)
|
|
|
|
|
|
|
|
|
|
canvas.bind('<Configure>', configure_canvas)
|
|
|
|
|
|
|
|
|
|
# Mouse wheel
|
|
|
|
|
def on_mousewheel(event):
|
|
|
|
|
canvas.yview_scroll(-1 * int(event.delta / 120), "units")
|
|
|
|
|
|
|
|
|
|
canvas.bind_all('<MouseWheel>', on_mousewheel)
|
|
|
|
|
|
|
|
|
|
# === ISI FORM ===
|
|
|
|
|
|
|
|
|
|
# Info transaksi
|
|
|
|
|
info_frame = ttk.Frame(right)
|
|
|
|
|
info_frame.pack(fill='x', pady=10)
|
|
|
|
|
info_frame.pack(fill='x', pady=15, padx=15)
|
|
|
|
|
|
|
|
|
|
self.selected_transaksi_label = ttk.Label(info_frame, text="Belum ada transaksi dipilih", font=("Arial", 10, "bold"), foreground='red')
|
|
|
|
|
self.selected_transaksi_label.pack()
|
|
|
|
|
@ -2185,31 +2488,39 @@ def favorite_all(limit=10):
|
|
|
|
|
self.selected_total_label = ttk.Label(info_frame, text="Total: Rp 0", font=("Arial", 12, "bold"), foreground='green')
|
|
|
|
|
self.selected_total_label.pack(pady=4)
|
|
|
|
|
|
|
|
|
|
ttk.Separator(right, orient='horizontal').pack(fill='x', pady=10)
|
|
|
|
|
ttk.Separator(right, orient='horizontal').pack(fill='x', pady=15, padx=15)
|
|
|
|
|
|
|
|
|
|
# Pilih metode pembayaran
|
|
|
|
|
# Metode pembayaran
|
|
|
|
|
method_frame = ttk.Frame(right)
|
|
|
|
|
method_frame.pack(fill='x', pady=10)
|
|
|
|
|
method_frame.pack(fill='x', pady=10, padx=15)
|
|
|
|
|
|
|
|
|
|
ttk.Label(method_frame, text="💳 Pilih Metode Pembayaran:", font=("Arial", 10, "bold")).pack(anchor='w', pady=4)
|
|
|
|
|
ttk.Label(method_frame, text="💳 Pilih Metode Pembayaran:", font=("Arial", 10, "bold")).pack(anchor='w', pady=6)
|
|
|
|
|
|
|
|
|
|
self.payment_method_var = tk.StringVar(value='cash')
|
|
|
|
|
|
|
|
|
|
ttk.Radiobutton(method_frame, text="💵 Cash", variable=self.payment_method_var, value='cash', command=self.on_payment_method_change).pack(anchor='w', pady=2)
|
|
|
|
|
ttk.Radiobutton(method_frame, text="📱 QRIS", variable=self.payment_method_var, value='qris', command=self.on_payment_method_change).pack(anchor='w', pady=2)
|
|
|
|
|
ttk.Radiobutton(method_frame, text="💳 E-Wallet (GoPay/OVO/Dana)", variable=self.payment_method_var, value='ewallet', command=self.on_payment_method_change).pack(anchor='w', pady=2)
|
|
|
|
|
ttk.Radiobutton(method_frame, text="💵 Cash", variable=self.payment_method_var, value='cash', command=self.on_payment_method_change).pack(anchor='w', pady=3)
|
|
|
|
|
ttk.Radiobutton(method_frame, text="📱 QRIS", variable=self.payment_method_var, value='qris', command=self.on_payment_method_change).pack(anchor='w', pady=3)
|
|
|
|
|
ttk.Radiobutton(method_frame, text="💳 E-Wallet (GoPay/OVO/Dana)", variable=self.payment_method_var, value='ewallet', command=self.on_payment_method_change).pack(anchor='w', pady=3)
|
|
|
|
|
|
|
|
|
|
ttk.Separator(right, orient='horizontal').pack(fill='x', pady=10)
|
|
|
|
|
ttk.Separator(right, orient='horizontal').pack(fill='x', pady=15, padx=15)
|
|
|
|
|
|
|
|
|
|
# Frame dinamis untuk input (berganti sesuai metode)
|
|
|
|
|
# Frame input dinamis
|
|
|
|
|
self.payment_input_frame = ttk.Frame(right)
|
|
|
|
|
self.payment_input_frame.pack(fill='both', expand=True, pady=10)
|
|
|
|
|
self.payment_input_frame.pack(fill='x', pady=10, padx=15)
|
|
|
|
|
|
|
|
|
|
# Init cash input (default)
|
|
|
|
|
self.build_cash_input()
|
|
|
|
|
|
|
|
|
|
# Tombol proses pembayaran
|
|
|
|
|
ttk.Button(right, text="✅ PROSES PEMBAYARAN", command=self.process_payment, style="Accent.TButton").pack(pady=15, ipadx=20, ipady=10)
|
|
|
|
|
ttk.Separator(right, orient='horizontal').pack(fill='x', pady=15, padx=15)
|
|
|
|
|
|
|
|
|
|
# Tombol
|
|
|
|
|
btn_frame = ttk.Frame(right)
|
|
|
|
|
btn_frame.pack(fill='x', pady=20, padx=15)
|
|
|
|
|
|
|
|
|
|
ttk.Button(btn_frame, text="✅ PROSES PEMBAYARAN", command=self.process_payment, style="Accent.TButton").pack(ipadx=30, ipady=10)
|
|
|
|
|
|
|
|
|
|
# PENTING: Tambah banyak space di bawah biar scrollbar muncul
|
|
|
|
|
for i in range(20):
|
|
|
|
|
ttk.Label(right, text="").pack()
|
|
|
|
|
|
|
|
|
|
# Load data
|
|
|
|
|
self.reload_payment_orders()
|
|
|
|
|
@ -2349,6 +2660,7 @@ def favorite_all(limit=10):
|
|
|
|
|
except:
|
|
|
|
|
self.cash_change_label.config(text="Kembalian: Rp 0", foreground='gray')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def build_qris_input(self):
|
|
|
|
|
"""Form input untuk pembayaran QRIS (simulasi QR Code)"""
|
|
|
|
|
ttk.Label(self.payment_input_frame, text="📱 Pembayaran QRIS", font=("Arial", 10, "bold")).pack(pady=6)
|
|
|
|
|
@ -2624,7 +2936,6 @@ def print_struk_simulation(self, struk):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Done
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
init_db_csv()
|
|
|
|
|
|