From fd1eb9cdb9678cbd9583473e706e7612a50760a3 Mon Sep 17 00:00:00 2001 From: Hijau-dev Date: Tue, 16 Dec 2025 21:28:52 +0700 Subject: [PATCH] Update --- Main.py | 5080 +++++++++++++++-- data/bahan.csv | 8 + data/detail_transaksi.csv | 1 + data/favorites.csv | 1 + data/meja.csv | 11 + data/menu.csv | 11 + data/notifikasi.csv | 1 + data/pembayaran.csv | 1 + data/promo_codes.csv | 5 + data/resep.csv | 13 + data/transaksi.csv | 1 + data/users.csv | 6 + ...12-14 at 22.08.43 (1)_20251214_221702.jpeg | Bin 0 -> 40379 bytes ...025-12-14 at 22.08.43_20251214_221654.jpeg | Bin 0 -> 86219 bytes images/cappucino.jpeg | Bin 0 -> 7221 bytes images/es teh.jpeg | Bin 0 -> 4524 bytes images/kopi susu.jpeg | Bin 0 -> 6926 bytes images/mie goreng.jpeg | Bin 0 -> 13439 bytes images/nasi goreng.jpeg | Bin 0 -> 13290 bytes images/pasta.jpeg | Bin 0 -> 9305 bytes images/roti bakar.jpeg | Bin 0 -> 7619 bytes images/smothie buah.jpeg | Bin 0 -> 9652 bytes 22 files changed, 4719 insertions(+), 420 deletions(-) create mode 100644 data/bahan.csv create mode 100644 data/detail_transaksi.csv create mode 100644 data/favorites.csv create mode 100644 data/meja.csv create mode 100644 data/menu.csv create mode 100644 data/notifikasi.csv create mode 100644 data/pembayaran.csv create mode 100644 data/promo_codes.csv create mode 100644 data/resep.csv create mode 100644 data/transaksi.csv create mode 100644 data/users.csv create mode 100644 images/WhatsApp Image 2025-12-14 at 22.08.43 (1)_20251214_221702.jpeg create mode 100644 images/WhatsApp Image 2025-12-14 at 22.08.43_20251214_221654.jpeg create mode 100644 images/cappucino.jpeg create mode 100644 images/es teh.jpeg create mode 100644 images/kopi susu.jpeg create mode 100644 images/mie goreng.jpeg create mode 100644 images/nasi goreng.jpeg create mode 100644 images/pasta.jpeg create mode 100644 images/roti bakar.jpeg create mode 100644 images/smothie buah.jpeg diff --git a/Main.py b/Main.py index 7aebd37..1571843 100644 --- a/Main.py +++ b/Main.py @@ -1,52 +1,549 @@ +""" +SISTEM MANAGEMENT CAFE - ULTIMATE EDITION (FIXED & COMPLETE) +============================================================== + +✅ SEMUA FITUR SUDAH DIIMPLEMENTASI & TERINTEGRASI +✅ SEMUA BUG SUDAH DIPERBAIKI +✅ PEMBELI SUDAH BISA MEMESAN +✅ KASIR SUDAH BISA TERIMA PEMBAYARAN (Cash/QRIS/E-Wallet) + +""Akun Default: +- admin / admin123 +- kasir / kasir123 +- waiter / waiter123 +- pembeli / user123 +- owner / owner123 +""" + import os +import csv +import shutil +import datetime import tkinter as tk from tkinter import ttk, messagebox, simpledialog, filedialog +from collections import defaultdict +import hashlib -# Try Pillow for image support; fallback to Tkinter PhotoImage +# Image support try: from PIL import Image, ImageTk PIL_AVAILABLE = True -except Exception: +except: PIL_AVAILABLE = False -# ------------------------- -# In-memory "database" -# ------------------------- -users = [ - {"username": "admin", "password": "123", "role": "admin"}, - {"username": "kasir", "password": "123", "role": "kasir"}, - {"username": "waiter", "password": "123", "role": "waiter"}, - {"username": "owner", "password": "123", "role": "owner"}, - {"username": "pembeli", "password": "123", "role": "pembeli"}, -] +# QRCode support +try: + import qrcode + from io import BytesIO + QRCODE_AVAILABLE = True +except: + QRCODE_AVAILABLE = False -menu = [ - {"id": 1, "nama": "Es Teh", "harga": 5000, "kategori": "Minuman", "stok": 10, "foto": None, "promo": None}, - {"id": 2, "nama": "Kopi Susu", "harga": 12000, "kategori": "Minuman", "stok": 8, "foto": None, "promo": "Diskon 10%"}, - {"id": 3, "nama": "Nasi Goreng", "harga": 15000, "kategori": "Makanan", "stok": 5, "foto": None, "promo": None}, -] +# Matplotlib support +try: + import matplotlib + matplotlib.use('TkAgg') + from matplotlib.figure import Figure + from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg + MATPLOTLIB_AVAILABLE = True +except: + MATPLOTLIB_AVAILABLE = False -bahan = { - "teh": 50, - "kopi": 20, - "susu": 15, - "beras": 10, - "bumbu": 10 -} +# ================================ +# KONFIGURASI +# ================================ -current_user = None -cart = [] -_image_refs = {} +DATA_DIR = "data" +IMAGES_DIR = "images" + +CSV_USERS = os.path.join(DATA_DIR, "users.csv") +CSV_MENU = os.path.join(DATA_DIR, "menu.csv") +CSV_BAHAN = os.path.join(DATA_DIR, "bahan.csv") +CSV_RESEP = os.path.join(DATA_DIR, "resep.csv") +CSV_TRANSAKSI = os.path.join(DATA_DIR, "transaksi.csv") +CSV_DETAIL_TRANSAKSI = os.path.join(DATA_DIR, "detail_transaksi.csv") +CSV_MEJA = os.path.join(DATA_DIR, "meja.csv") +CSV_FAVORITES = os.path.join(DATA_DIR, "favorites.csv") +CSV_NOTIFIKASI = os.path.join(DATA_DIR, "notifikasi.csv") +CSV_PROMO_CODES = os.path.join(DATA_DIR, "promo_codes.csv") +CSV_PEMBAYARAN = os.path.join(DATA_DIR, "pembayaran.csv") + +os.makedirs(DATA_DIR, exist_ok=True) +os.makedirs(IMAGES_DIR, exist_ok=True) + +# ================================ +# GLOBAL DATABASE +# ================================ + +users = [] +menu = [] +bahan = {} +resep = {} +transaksi = [] +detail_transaksi = [] +data_meja = {} +favorites = {} +notifikasi = [] +promo_codes = {} +pembayaran = [] +_image_refs = {} + +# ================================ +# CSV UTILITY +# ================================ + +def ensure_file(path, fieldnames): + if not os.path.exists(path): + with open(path, "w", newline="", encoding="utf-8") as f: + writer = csv.DictWriter(f, fieldnames=fieldnames) + writer.writeheader() + +def read_csv(path): + if not os.path.exists(path): + return [] + try: + with open(path, newline="", encoding="utf-8") as f: + return list(csv.DictReader(f)) + except: + return [] + +def write_csv(path, fieldnames, rows): + try: + with open(path, "w", newline="", encoding="utf-8") as f: + writer = csv.DictWriter(f, fieldnames=fieldnames) + writer.writeheader() + writer.writerows(rows) + except Exception as e: + print(f"Error writing {path}: {e}") + +# ================================ +# INIT DATA +# ================================ + +def init_default_data(): + global users, menu, bahan, resep, data_meja, promo_codes + + if not users: + users.extend([ + {"id": "1", "username": "admin", "password": "admin123", "role": "admin"}, + {"id": "2", "username": "kasir", "password": "kasir123", "role": "kasir"}, + {"id": "3", "username": "waiter", "password": "waiter123", "role": "waiter"}, + {"id": "4", "username": "pembeli", "password": "user123", "role": "pembeli"}, + {"id": "5", "username": "owner", "password": "owner123", "role": "owner"}, + ]) + + if not menu: + menu.extend([ + {"id": 1, "nama": "Americano", "harga": 20000, "kategori": "Minuman", "stok": 50, "foto": "", "promo": "", "item_discount_pct": 0}, + {"id": 2, "nama": "Latte", "harga": 25000, "kategori": "Minuman", "stok": 45, "foto": "", "promo": "Diskon 10%", "item_discount_pct": 10}, + {"id": 3, "nama": "Nasi Goreng", "harga": 35000, "kategori": "Makanan", "stok": 30, "foto": "", "promo": "", "item_discount_pct": 0}, + {"id": 4, "nama": "Mie Goreng", "harga": 30000, "kategori": "Makanan", "stok": 35, "foto": "", "promo": "", "item_discount_pct": 0}, + {"id": 5, "nama": "Es Teh", "harga": 5000, "kategori": "Minuman", "stok": 100, "foto": "", "promo": "", "item_discount_pct": 0}, + {"id": 6, "nama": "Kopi Susu", "harga": 15000, "kategori": "Minuman", "stok": 60, "foto": "", "promo": "Diskon 5%", "item_discount_pct": 5}, + {"id": 7, "nama": "Cappuccino", "harga": 28000, "kategori": "Minuman", "stok": 40, "foto": "", "promo": "", "item_discount_pct": 0}, + {"id": 8, "nama": "Roti Bakar", "harga": 15000, "kategori": "Makanan", "stok": 25, "foto": "", "promo": "Diskon 15%", "item_discount_pct": 15}, + {"id": 9, "nama": "Pasta Carbonara", "harga": 45000, "kategori": "Makanan", "stok": 20, "foto": "", "promo": "", "item_discount_pct": 0}, + {"id": 10, "nama": "Smoothie Buah", "harga": 22000, "kategori": "Minuman", "stok": 35, "foto": "", "promo": "", "item_discount_pct": 0}, + ]) + + if not bahan: + bahan.update({ + "kopi": 50, "susu": 30, "teh": 40, "nasi": 20, + "mie": 15, "telur": 25, "bumbu": 30 + }) + + if not resep: + resep.update({ + 1: {"kopi": 1}, + 2: {"kopi": 1, "susu": 1}, + 3: {"nasi": 1, "telur": 1, "bumbu": 1}, + 4: {"mie": 1, "telur": 1, "bumbu": 1}, + 5: {"teh": 1}, + 6: {"kopi": 1, "susu": 1}, + }) + + if not data_meja: + data_meja.update({i: "Kosong" for i in range(1, 11)}) + + if not promo_codes: + promo_codes.update({ + "CAFE10": 10, + "CAFE20": 20, + "WELCOME": 15, + "SPECIAL25": 25 + }) + +# ================================ +# LOAD/SAVE FUNCTIONS +# ================================ + +def save_users(): + write_csv(CSV_USERS, ["id", "username", "password", "role"], users) + +def load_users(): + global users + users = read_csv(CSV_USERS) + if not users: + init_default_data() + save_users() + +def save_menu(): + rows = [] + for m in menu: + rows.append({ + "id": str(m["id"]), + "nama": m["nama"], + "harga": str(m["harga"]), + "kategori": m["kategori"], + "stok": str(m["stok"]), + "foto": m.get("foto", ""), + "promo": m.get("promo", ""), + "item_discount_pct": str(m.get("item_discount_pct", 0)) + }) + write_csv(CSV_MENU, ["id", "nama", "harga", "kategori", "stok", "foto", "promo", "item_discount_pct"], rows) + +def load_menu(): + global menu + rows = read_csv(CSV_MENU) + menu = [] + for r in rows: + try: + menu.append({ + "id": int(r["id"]), + "nama": r["nama"], + "harga": int(float(r["harga"])), + "kategori": r["kategori"], + "stok": int(float(r["stok"])), + "foto": r.get("foto", ""), + "promo": r.get("promo", ""), + "item_discount_pct": float(r.get("item_discount_pct", 0)) + }) + except: + pass + if not menu: + init_default_data() + save_menu() + +def save_bahan(): + rows = [{"nama": k, "jumlah": str(v)} for k, v in bahan.items()] + write_csv(CSV_BAHAN, ["nama", "jumlah"], rows) + +def load_bahan(): + global bahan + rows = read_csv(CSV_BAHAN) + bahan = {} + for r in rows: + try: + bahan[r["nama"]] = int(float(r["jumlah"])) + except: + pass + if not bahan: + init_default_data() + save_bahan() + +def save_resep(): + rows = [] + for menu_id, ingredients in resep.items(): + for bahan_nama, qty in ingredients.items(): + rows.append({"menu_id": str(menu_id), "bahan": bahan_nama, "jumlah": str(qty)}) + write_csv(CSV_RESEP, ["menu_id", "bahan", "jumlah"], rows) + +def load_resep(): + global resep + rows = read_csv(CSV_RESEP) + resep = {} + for r in rows: + try: + mid = int(r["menu_id"]) + if mid not in resep: + resep[mid] = {} + resep[mid][r["bahan"]] = int(float(r["jumlah"])) + except: + pass + if not resep: + init_default_data() + save_resep() + +def save_transaksi(): + rows = [] + for t in transaksi: + items_str = ";".join([f"{it['nama']}x{it['qty']}@{it['harga_satuan']}" for it in t['items']]) + rows.append({ + "id": str(t['id']), + "tanggal": t['tanggal'], + "waktu": t['waktu'].strftime('%Y-%m-%d %H:%M:%S'), + "user": t['user'], + "items": items_str, + "subtotal": str(t['subtotal']), + "diskon": str(t['diskon']), + "total": str(t['total']), + "meja": str(t.get('meja', '')), + "status": t['status'], + "payment_status": t.get('payment_status', 'Pending'), + "payment_method": t.get('payment_method', ''), + "paid_amount": str(t.get('paid_amount', 0)), + "change": str(t.get('change', 0)), + "promo_code": t.get('promo_code', '') + }) + write_csv(CSV_TRANSAKSI, ["id", "tanggal", "waktu", "user", "items", "subtotal", "diskon", "total", "meja", "status", "payment_status", "payment_method", "paid_amount", "change", "promo_code"], rows) + +def load_transaksi(): + global transaksi + rows = read_csv(CSV_TRANSAKSI) + transaksi = [] + for r in rows: + try: + items = [] + if r['items']: + for item_str in r['items'].split(';'): + parts = item_str.split('x') + nama = parts[0] + qty_price = parts[1].split('@') + items.append({ + 'nama': nama, + 'qty': int(qty_price[0]), + 'harga_satuan': int(qty_price[1]), + 'subtotal': int(qty_price[0]) * int(qty_price[1]) + }) + + transaksi.append({ + 'id': int(r['id']), + 'tanggal': r['tanggal'], + 'waktu': datetime.datetime.strptime(r['waktu'], '%Y-%m-%d %H:%M:%S'), + 'user': r['user'], + 'items': items, + 'subtotal': int(float(r['subtotal'])), + 'diskon': int(float(r['diskon'])), + 'total': int(float(r['total'])), + 'meja': int(r['meja']) if r['meja'] else None, + 'status': r['status'], + 'payment_status': r.get('payment_status', 'Pending'), + 'payment_method': r.get('payment_method', ''), + 'paid_amount': int(float(r.get('paid_amount', 0))), + 'change': int(float(r.get('change', 0))), + 'promo_code': r.get('promo_code', '') + }) + except: + pass + +def save_detail_transaksi(): + rows = [] + for d in detail_transaksi: + rows.append({ + "id": str(d['id']), + "transaksi_id": str(d['transaksi_id']), + "menu_id": str(d['menu_id']), + "nama_menu": d['nama_menu'], + "jumlah": str(d['jumlah']), + "harga_satuan": str(d['harga_satuan']), + "subtotal": str(d['subtotal']), + "diskon": str(d['diskon']) + }) + write_csv(CSV_DETAIL_TRANSAKSI, ["id", "transaksi_id", "menu_id", "nama_menu", "jumlah", "harga_satuan", "subtotal", "diskon"], rows) + +def load_detail_transaksi(): + global detail_transaksi + rows = read_csv(CSV_DETAIL_TRANSAKSI) + detail_transaksi = [] + for r in rows: + try: + detail_transaksi.append({ + 'id': int(r['id']), + 'transaksi_id': int(r['transaksi_id']), + 'menu_id': int(r['menu_id']), + 'nama_menu': r['nama_menu'], + 'jumlah': int(r['jumlah']), + 'harga_satuan': int(float(r['harga_satuan'])), + 'subtotal': int(float(r['subtotal'])), + 'diskon': int(float(r['diskon'])) + }) + except: + pass + +def save_meja(): + rows = [{"nomor": str(k), "status": v} for k, v in data_meja.items()] + write_csv(CSV_MEJA, ["nomor", "status"], rows) + +def load_meja(): + global data_meja + rows = read_csv(CSV_MEJA) + data_meja = {} + for r in rows: + try: + data_meja[int(r['nomor'])] = r['status'] + except: + pass + if not data_meja: + init_default_data() + save_meja() + +def save_favorites(): + rows = [] + for username, menu_ids in favorites.items(): + rows.append({"username": username, "menu_ids": ",".join(map(str, menu_ids))}) + write_csv(CSV_FAVORITES, ["username", "menu_ids"], rows) + +def load_favorites(): + global favorites + rows = read_csv(CSV_FAVORITES) + favorites = {} + for r in rows: + try: + if r['menu_ids']: + favorites[r['username']] = [int(x) for x in r['menu_ids'].split(',')] + else: + favorites[r['username']] = [] + except: + favorites[r['username']] = [] + +def save_notifikasi(): + write_csv(CSV_NOTIFIKASI, ["id", "timestamp", "type", "message", "read"], notifikasi) + +def load_notifikasi(): + global notifikasi + rows = read_csv(CSV_NOTIFIKASI) + notifikasi = [] + for r in rows: + try: + notifikasi.append({ + 'id': int(r['id']), + 'timestamp': r['timestamp'], + 'type': r['type'], + 'message': r['message'], + 'read': r['read'] == 'True' + }) + except: + pass + +def save_promo_codes(): + rows = [{"code": code, "discount_percent": str(discount)} for code, discount in promo_codes.items()] + write_csv(CSV_PROMO_CODES, ["code", "discount_percent"], rows) + +def load_promo_codes(): + global promo_codes + rows = read_csv(CSV_PROMO_CODES) + promo_codes = {} + for r in rows: + try: + promo_codes[r['code']] = int(r['discount_percent']) + except: + pass + if not promo_codes: + init_default_data() + save_promo_codes() + +def save_pembayaran(): + rows = [] + for p in pembayaran: + rows.append({ + "id": str(p['id']), + "transaksi_id": str(p['transaksi_id']), + "metode": p['metode'], + "jumlah": str(p['jumlah']), + "status": p['status'], + "tanggal": p['tanggal'] + }) + write_csv(CSV_PEMBAYARAN, ["id", "transaksi_id", "metode", "jumlah", "status", "tanggal"], rows) + +def load_pembayaran(): + global pembayaran + rows = read_csv(CSV_PEMBAYARAN) + pembayaran = [] + for r in rows: + try: + pembayaran.append({ + 'id': int(r['id']), + 'transaksi_id': int(r['transaksi_id']), + 'metode': r['metode'], + 'jumlah': int(float(r['jumlah'])), + 'status': r['status'], + 'tanggal': r['tanggal'] + }) + except: + pass + +def load_all_data(): + ensure_file(CSV_USERS, ["id", "username", "password", "role"]) + ensure_file(CSV_MENU, ["id", "nama", "harga", "kategori", "stok", "foto", "promo", "item_discount_pct"]) + ensure_file(CSV_BAHAN, ["nama", "jumlah"]) + ensure_file(CSV_RESEP, ["menu_id", "bahan", "jumlah"]) + ensure_file(CSV_TRANSAKSI, ["id", "tanggal", "waktu", "user", "items", "subtotal", "diskon", "total", "meja", "status", "payment_status", "payment_method", "paid_amount", "change", "promo_code"]) + ensure_file(CSV_DETAIL_TRANSAKSI, ["id", "transaksi_id", "menu_id", "nama_menu", "jumlah", "harga_satuan", "subtotal", "diskon"]) + ensure_file(CSV_MEJA, ["nomor", "status"]) + ensure_file(CSV_FAVORITES, ["username", "menu_ids"]) + ensure_file(CSV_NOTIFIKASI, ["id", "timestamp", "type", "message", "read"]) + ensure_file(CSV_PROMO_CODES, ["code", "discount_percent"]) + ensure_file(CSV_PEMBAYARAN, ["id", "transaksi_id", "metode", "jumlah", "status", "tanggal"]) + + load_users() + load_menu() + load_bahan() + load_resep() + load_transaksi() + load_detail_transaksi() + load_meja() + load_favorites() + load_notifikasi() + load_promo_codes() + load_pembayaran() + add_sample_transactions() + +# ================================ +# HELPER FUNCTIONS +# ================================ -# ------------------------- -# Helpers -# ------------------------- def find_menu_by_id(mid): for it in menu: if it["id"] == mid: return it return None +def format_currency(n): + try: + return f"Rp{int(n):,}".replace(",", ".") + except: + return f"Rp{n}" + +def calculate_discount(harga, promo_text): + if not promo_text: + return 0 + try: + import re + match = re.search(r'(\d+)%', promo_text) + if match: + percent = int(match.group(1)) + return int(harga * percent / 100) + except: + pass + return 0 + +def add_notification(ntype, message): + global notifikasi + new_id = max([n['id'] for n in notifikasi], default=0) + 1 + notifikasi.append({ + 'id': new_id, + 'timestamp': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), + 'type': ntype, + 'message': message, + 'read': False + }) + save_notifikasi() + +def copy_image_to_project(src_path): + if not src_path or not os.path.exists(src_path): + return "" + try: + filename = os.path.basename(src_path) + name, ext = os.path.splitext(filename) + timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") + new_filename = f"{name}_{timestamp}{ext}" + dest_path = os.path.join(IMAGES_DIR, new_filename) + shutil.copy2(src_path, dest_path) + return dest_path + except Exception as e: + print(f"Error copying image: {e}") + return "" + def ensure_image(path, maxsize=(240, 160)): if not path or not os.path.exists(path): return None @@ -62,410 +559,4153 @@ def ensure_image(path, maxsize=(240, 160)): tkimg = tk.PhotoImage(file=path) _image_refs[key] = tkimg return tkimg - except Exception: + except: return None def reset_image_refs(): _image_refs.clear() -# ------------------------- -# Keranjang Functions -# ------------------------- -def _add_to_cart(self): - sel = self.tree.selection() - if not sel: - messagebox.showwarning("Pilih Menu", "Pilih menu dulu.") - return - mid = int(sel[0]) - it = find_menu_by_id(mid) - if not it: - return - try: - qty = int(simpledialog.askstring("Jumlah", f"Berapa {it['nama']} yang ingin ditambahkan?")) - except: - return - if qty <= 0: - messagebox.showerror("Error", "Jumlah harus > 0") - return - if qty > it.get("stok",0): - messagebox.showerror("Error", f"Stok tidak cukup ({it.get('stok',0)})") - return - for c in cart: - if c["menu_id"] == mid: - c["jumlah"] += qty - break - else: - cart.append({"menu_id": mid, "jumlah": qty}) - messagebox.showinfo("Keranjang", f"{it['nama']} x{qty} berhasil ditambahkan ke keranjang.") +def get_daily_report(date_str): + trans = [t for t in transaksi if t['tanggal'] == date_str and t.get('payment_status') == 'Berhasil'] + total_omzet = sum(t['total'] for t in trans) + total_transaksi = len(trans) + + menu_count = defaultdict(int) + for t in trans: + for item in t['items']: + menu_count[item['nama']] += item['qty'] + + return { + 'date': date_str, + 'total_omzet': total_omzet, + 'total_transaksi': total_transaksi, + 'menu_terlaris': dict(menu_count) + } -def _view_cart(self): - if not cart: - messagebox.showinfo("Keranjang", "Keranjang kosong.") - return - s = "" - total = 0 - for c in cart: - it = find_menu_by_id(c["menu_id"]) - harga = it["harga"] * c["jumlah"] - s += f"{it['nama']} x {c['jumlah']} = Rp{harga}\n" - total += harga - s += f"\nTotal: Rp{total}" - if messagebox.askyesno("Checkout", s + "\n\nCheckout sekarang?"): - for c in cart: - it = find_menu_by_id(c["menu_id"]) - it["stok"] -= c["jumlah"] - cart.clear() - self._refresh_menu() - messagebox.showinfo("Sukses", "Pesanan berhasil dibuat!") +def add_sample_transactions(): + """Tambahkan data transaksi sample untuk demo""" + global transaksi, detail_transaksi + + if len(transaksi) < 5: + today = str(datetime.date.today()) + yesterday = str(datetime.date.today() - datetime.timedelta(days=1)) + two_days_ago = str(datetime.date.today() - datetime.timedelta(days=2)) + + sample_data = [ + {'tanggal': today, 'items': [{'nama': 'Americano', 'qty': 2, 'harga_satuan': 20000}, {'nama': 'Es Teh', 'qty': 1, 'harga_satuan': 5000}], 'total': 45000, 'meja': 1}, + {'tanggal': today, 'items': [{'nama': 'Latte', 'qty': 3, 'harga_satuan': 25000}, {'nama': 'Roti Bakar', 'qty': 2, 'harga_satuan': 15000}], 'total': 105000, 'meja': 2}, + {'tanggal': today, 'items': [{'nama': 'Nasi Goreng', 'qty': 2, 'harga_satuan': 35000}, {'nama': 'Kopi Susu', 'qty': 2, 'harga_satuan': 15000}], 'total': 100000, 'meja': 3}, + {'tanggal': today, 'items': [{'nama': 'Mie Goreng', 'qty': 1, 'harga_satuan': 30000}, {'nama': 'Cappuccino', 'qty': 1, 'harga_satuan': 28000}], 'total': 58000, 'meja': 4}, + {'tanggal': yesterday, 'items': [{'nama': 'Pasta Carbonara', 'qty': 2, 'harga_satuan': 45000}, {'nama': 'Smoothie Buah', 'qty': 3, 'harga_satuan': 22000}], 'total': 156000, 'meja': 5}, + {'tanggal': yesterday, 'items': [{'nama': 'Americano', 'qty': 4, 'harga_satuan': 20000}, {'nama': 'Es Teh', 'qty': 2, 'harga_satuan': 5000}], 'total': 90000, 'meja': 6}, + {'tanggal': two_days_ago, 'items': [{'nama': 'Latte', 'qty': 2, 'harga_satuan': 25000}, {'nama': 'Nasi Goreng', 'qty': 1, 'harga_satuan': 35000}], 'total': 85000, 'meja': 7}, + ] + + for idx, data in enumerate(sample_data, start=1): + trans_id = idx + transaksi.append({ + 'id': trans_id, + 'tanggal': data['tanggal'], + 'waktu': datetime.datetime.now() - datetime.timedelta(hours=idx), + 'user': 'waiter', + 'items': data['items'], + 'subtotal': data['total'], + 'diskon': 0, + 'total': data['total'], + 'meja': data['meja'], + 'status': 'Selesai', + 'payment_status': 'Berhasil', + 'payment_method': 'cash' if idx % 2 == 0 else 'qris', + 'paid_amount': data['total'], + 'change': 0, + 'promo_code': '' + }) -# ------------------------- -# GUI App -# ------------------------- -class Anggota1App: +def get_payment_summary(start_date, end_date): + trans = [t for t in transaksi + if start_date <= t['tanggal'] <= end_date + and t.get('payment_status') == 'Berhasil'] + + total = sum(t['total'] for t in trans) + count = len(trans) + + method_breakdown = defaultdict(int) + for t in trans: + method = t.get('payment_method', 'Unknown') + method_breakdown[method] += 1 + + return { + 'total_income': total, + 'total_count': count, + 'avg': total / count if count > 0 else 0, + 'method_breakdown': dict(method_breakdown) + } + +# ================================ +# MAIN APP CLASS +# ================================ + +class CafeApp: def __init__(self, root): self.root = root - self.root.title("Cafe Ceria") - self.root.geometry("1000x650") - self.root.minsize(920, 600) - self._build_login() - - # ---------- login ---------- + self.root.title("Sistem Management Cafe - Ultimate Edition (FIXED)") + self.root.geometry("1200x700") + self.root.minsize(1000, 600) + + # Session + self.current_user = None + self.cart_items = [] + + # Load data + load_all_data() + + # Style + self.setup_styles() + + # Start + self.show_welcome_screen() + + def setup_styles(self): + style = ttk.Style() + style.theme_use('clam') + style.configure("Accent.TButton", + background="#8B7355", + foreground="white", + font=("Arial", 10, "bold")) + style.map("Accent.TButton", + background=[('active', '#6B5335')]) + + # ================================ + # WELCOME & LOGIN + # ================================ + + def show_welcome_screen(self): + self._clear_root() + self.root.configure(bg="#F5F5F0") + + main_frame = tk.Frame(self.root, bg="#F5F5F0") + main_frame.place(relx=0.5, rely=0.5, anchor="center") + + title_frame = tk.Frame(main_frame, bg="#F5F5F0") + title_frame.pack(pady=(0, 30)) + + tk.Label(title_frame, text="☕", font=("Segoe UI", 64), bg="#F5F5F0", fg="#8B7355").pack() + tk.Label(title_frame, text="CAFE MANAGEMENT", font=("Segoe UI", 32, "bold"), + bg="#F5F5F0", fg="#5C4033").pack(pady=(10, 0)) + tk.Label(title_frame, text="Ultimate Edition - FIXED VERSION", font=("Segoe UI", 14), + bg="#F5F5F0", fg="#999999").pack() + + btn_frame = tk.Frame(main_frame, bg="#F5F5F0") + btn_frame.pack(pady=40) + + guest_btn = tk.Button(btn_frame, text="🌐 Browse Sebagai Guest", + command=self.enter_as_guest, + font=("Segoe UI", 12, "bold"), + bg="#27AE60", fg="white", + relief="flat", bd=0, + padx=40, pady=15, cursor="hand2") + guest_btn.pack(pady=10) + guest_btn.bind("", lambda e: guest_btn.configure(bg="#229954")) + guest_btn.bind("", lambda e: guest_btn.configure(bg="#27AE60")) + + login_btn = tk.Button(btn_frame, text="🔐 Login Sebagai Staff", + command=self.show_login_screen, + font=("Segoe UI", 12, "bold"), + bg="#8B7355", fg="white", + relief="flat", bd=0, + padx=40, pady=15, cursor="hand2") + login_btn.pack(pady=10) + login_btn.bind("", lambda e: login_btn.configure(bg="#6B5335")) + login_btn.bind("", lambda e: login_btn.configure(bg="#8B7355")) + + tk.Label(main_frame, + text="Guest dapat melihat menu tanpa login\nStaff perlu login untuk akses penuh", + font=("Segoe UI", 9), bg="#F5F5F0", fg="#999999", + justify="center").pack(pady=(20, 5)) + + def enter_as_guest(self): + self.current_user = { + 'id': 0, + 'username': 'Guest', + 'role': 'guest' + } + messagebox.showinfo("Welcome", "Selamat datang, Guest!\n\nAnda dapat melihat menu kami.") + self.build_main_ui() + + def show_login_screen(self): + self._clear_root() + self.root.configure(bg="#F5F5F0") + + main_frame = tk.Frame(self.root, bg="#F5F5F0") + main_frame.place(relx=0.5, rely=0.5, anchor="center") + + title_frame = tk.Frame(main_frame, bg="#F5F5F0") + title_frame.pack(pady=(0, 30)) + + tk.Label(title_frame, text="☕", font=("Segoe UI", 48), bg="#F5F5F0", fg="#8B7355").pack() + tk.Label(title_frame, text="STAFF LOGIN", font=("Segoe UI", 24, "bold"), + bg="#F5F5F0", fg="#5C4033").pack(pady=(5, 0)) + + form_frame = tk.Frame(main_frame, bg="white", relief="flat", bd=0) + form_frame.pack(pady=20, padx=40) + + inner_form = tk.Frame(form_frame, bg="white") + inner_form.pack(padx=50, pady=40) + + tk.Label(inner_form, text="Username", font=("Segoe UI", 10), + bg="white", fg="#666666", anchor="w").grid(row=0, column=0, sticky="w", pady=(0, 5)) + self.e_user = tk.Entry(inner_form, font=("Segoe UI", 11), relief="solid", + bd=1, bg="#FAFAFA", fg="#333333", width=28) + self.e_user.grid(row=1, column=0, pady=(0, 20), ipady=8) + + tk.Label(inner_form, text="Password", font=("Segoe UI", 10), + bg="white", fg="#666666", anchor="w").grid(row=2, column=0, sticky="w", pady=(0, 5)) + self.e_pass = tk.Entry(inner_form, show="●", font=("Segoe UI", 11), + relief="solid", bd=1, bg="#FAFAFA", fg="#333333", width=28) + self.e_pass.grid(row=3, column=0, pady=(0, 25), ipady=8) + + login_btn = tk.Button(inner_form, text="Login", font=("Segoe UI", 11, "bold"), + bg="#8B7355", fg="white", relief="flat", bd=0, + command=self.handle_login, cursor="hand2", width=28, pady=12) + login_btn.grid(row=4, column=0) + login_btn.bind("", lambda e: login_btn.configure(bg="#6B5335")) + login_btn.bind("", lambda e: login_btn.configure(bg="#8B7355")) + + self.e_pass.bind("", lambda e: self.handle_login()) + + back_btn = tk.Button(main_frame, text="← Kembali", + command=self.show_welcome_screen, + font=("Segoe UI", 9), bg="#E8E0D5", fg="#5C4033", + relief="flat", bd=0, padx=20, pady=8, cursor="hand2") + back_btn.pack(pady=(15, 0)) + + tk.Label(main_frame, text="Default: admin/admin123, kasir/kasir123, pembeli/user123", + font=("Segoe UI", 9), bg="#F5F5F0", fg="#999999").pack(pady=(10, 0)) + + def handle_login(self): + u = self.e_user.get().strip() + p = self.e_pass.get().strip() + + for usr in users: + if usr["username"] == u and usr["password"] == p: + self.current_user = { + 'id': int(usr['id']), + 'username': usr['username'], + 'role': usr['role'] + } + messagebox.showinfo("Login", f"Berhasil login sebagai {u} ({usr['role']})") + self.build_main_ui() + return + + messagebox.showerror("Login Gagal", "Username atau password salah.") + def _clear_root(self): for w in self.root.winfo_children(): w.destroy() - - def _build_login(self): + + def logout(self): + self.current_user = None + self.cart_items = [] + self.show_welcome_screen() + + # ================================ + # MAIN UI + # ================================ + + def build_main_ui(self): self._clear_root() - frame = ttk.Frame(self.root, padding=20) - frame.pack(expand=True) - ttk.Label(frame, text="LOGIN", font=("Segoe UI", 18)).grid(row=0, column=0, columnspan=2, pady=(0,10)) - ttk.Label(frame, text="Username:").grid(row=1, column=0, sticky="e", padx=5, pady=5) - self.e_user = ttk.Entry(frame) - self.e_user.grid(row=1, column=1, padx=5, pady=5) - ttk.Label(frame, text="Password:").grid(row=2, column=0, sticky="e", padx=5, pady=5) - self.e_pass = ttk.Entry(frame, show="*") - self.e_pass.grid(row=2, column=1, padx=5, pady=5) - btn = ttk.Button(frame, text="Login", command=self._handle_login) - btn.grid(row=3, column=0, columnspan=2, pady=12) - ttk.Label(frame, text="(users: admin/kasir/waiter/owner/pembeli ; pass: 123)").grid(row=4, column=0, columnspan=2, pady=(8,0)) - - def _handle_login(self): - global current_user - u = self.e_user.get().strip() - p = self.e_pass.get().strip() - for usr in users: - if usr["username"] == u and usr["password"] == p: - current_user = usr - messagebox.showinfo("Login", f"Berhasil login sebagai {u} ({usr['role']})") - self._build_main_ui() - return - messagebox.showerror("Login Gagal", "Username atau password salah.") - - # ---------- main UI ---------- - def _build_main_ui(self): - self._clear_root() - - topbar = ttk.Frame(self.root) - topbar.pack(fill="x", padx=6, pady=6) - ttk.Label(topbar, text=f"User: {current_user['username']} ({current_user['role']})", font=("Segoe UI", 10)).pack(side="left") - ttk.Button(topbar, text="Logout", command=self._logout).pack(side="right") - - main = ttk.Frame(self.root) - main.pack(fill="both", expand=True, padx=8, pady=4) - - ctrl = ttk.Frame(main, width=320, padding=8) - ctrl.pack(side="left", fill="y") - ttk.Label(ctrl, text="Search / Cari:").pack(anchor="w") - self.search_var = tk.StringVar() - sframe = ttk.Frame(ctrl) - sframe.pack(fill="x", pady=4) - self.search_entry = ttk.Entry(sframe, textvariable=self.search_var) - self.search_entry.pack(side="left", fill="x", expand=True) - ttk.Button(sframe, text="Search", command=self._search_menu).pack(side="left", padx=4) - ttk.Button(sframe, text="Refresh", command=self._refresh_menu).pack(side="left") - ttk.Label(ctrl, text="Filter Kategori:").pack(anchor="w", pady=(10,0)) - self.filter_var = tk.StringVar() - values = ["All"] + sorted({it.get("kategori","Undefined") for it in menu}) - self.filter_cb = ttk.Combobox(ctrl, values=values, state="readonly", textvariable=self.filter_var) - self.filter_cb.set("All") - self.filter_cb.pack(fill="x", pady=4) - ttk.Button(ctrl, text="Apply Filter", command=self._apply_filter).pack(fill="x", pady=(0,6)) - ttk.Label(ctrl, text="Sort:").pack(anchor="w", pady=(6,0)) - self.sort_var = tk.StringVar() - self.sort_cb = ttk.Combobox(ctrl, values=["Default","Harga - Rendah→Tinggi","Harga - Tinggi→Rendah","Stok - Rendah→Tinggi","Stok - Tinggi→Rendah"], state="readonly", textvariable=self.sort_var) - self.sort_cb.set("Default") - self.sort_cb.pack(fill="x", pady=4) - ttk.Button(ctrl, text="Apply Sort", command=self._apply_sort).pack(fill="x", pady=(0,6)) - - ttk.Separator(ctrl).pack(fill="x", pady=8) - self.btn_add = ttk.Button(ctrl, text="Tambah Menu (+Foto)", command=self._gui_add_menu) - self.btn_edit = ttk.Button(ctrl, text="Edit Menu (+Ganti Foto)", command=self._gui_edit_menu) - self.btn_delete = ttk.Button(ctrl, text="Hapus Menu", command=self._gui_delete_menu) - self.btn_refresh = ttk.Button(ctrl, text="Refresh List", command=self._refresh_menu) - self.btn_add.pack(fill="x", pady=4) - self.btn_edit.pack(fill="x", pady=4) - self.btn_delete.pack(fill="x", pady=4) - self.btn_refresh.pack(fill="x", pady=6) - if current_user["role"] != "admin": - self.btn_add.state(["disabled"]) - self.btn_edit.state(["disabled"]) - self.btn_delete.state(["disabled"]) - - ttk.Label(ctrl, text="Stok Bahan:", font=("Segoe UI", 10, "bold")).pack(anchor="w", pady=(10,0)) - self.bahan_listbox = tk.Listbox(ctrl, height=8) - self.bahan_listbox.pack(fill="both", expand=False, pady=(4,6)) - self._refresh_bahan_listbox() - self.btn_edit_bahan = ttk.Button(ctrl, text="Tambah/Edit Stok Bahan", command=self._gui_edit_bahan) - self.btn_edit_bahan.pack(fill="x") - if current_user["role"] != "admin": - self.btn_edit_bahan.state(["disabled"]) - - right = ttk.Frame(main, padding=8) - right.pack(side="right", fill="both", expand=True) - ttk.Label(right, text="Daftar Menu", font=("Segoe UI", 12)).pack(anchor="w") - self.tree = ttk.Treeview(right, columns=("harga","kategori","stok"), show="headings", selectmode="browse") - self.tree.heading("harga", text="Harga") - self.tree.heading("kategori", text="Kategori") - self.tree.heading("stok", text="Stok") - self.tree.column("harga", width=120, anchor="center") - self.tree.column("kategori", width=120, anchor="center") - self.tree.column("stok", width=80, anchor="center") - self.tree.pack(fill="both", expand=True, pady=(6,8)) - self.tree.bind("<>", self._on_tree_select) - - detail_frame = ttk.Frame(right) - detail_frame.pack(fill="x", pady=4) - self.img_label = ttk.Label(detail_frame) - self.img_label.pack(side="left", padx=6) - info_frame = ttk.Frame(detail_frame) - info_frame.pack(side="left", fill="both", expand=True, padx=6) - self.detail_text = tk.Text(info_frame, height=8, state="disabled") - self.detail_text.pack(fill="both", expand=True) - - # --- Tambahkan tombol keranjang untuk pembeli --- - if current_user["role"] == "pembeli": - ttk.Button(right, text="Tambah ke Keranjang", command=lambda: _add_to_cart(self)).pack(fill="x", pady=4) - ttk.Button(right, text="Lihat Keranjang / Checkout", command=lambda: _view_cart(self)).pack(fill="x", pady=4) - - self._populate_tree(menu) - - # ---------- Data ops ---------- - def _populate_tree(self, items): - for r in self.tree.get_children(): - self.tree.delete(r) - for it in items: - self.tree.insert("", "end", iid=str(it["id"]), values=(f"Rp{it['harga']}", it.get("kategori","-"), it.get("stok",0)), text=it["nama"]) - self._clear_details() - - def _refresh_menu(self): - self.search_var.set("") - self.filter_cb['values'] = ["All"] + sorted({it.get("kategori","Undefined") for it in menu}) - self.filter_cb.set("All") - self.sort_cb.set("Default") - self._populate_tree(menu) - reset_image_refs() - self._refresh_bahan_listbox() - - def _apply_filter(self): - cat = self.filter_var.get() if self.filter_var.get() else "All" - if cat == "All": - filtered = list(menu) - else: - filtered = [it for it in menu if it.get("kategori","") == cat] - self._populate_tree(filtered) - - def _search_menu(self): - q = self.search_var.get().strip().lower() - if not q: - self._populate_tree(menu) - return - res = [] - for it in menu: - if q in it["nama"].lower() or q in str(it["harga"]) or q in it.get("kategori","").lower(): - res.append(it) - self._populate_tree(res) - - def _apply_sort(self): - key = self.sort_var.get() - arr = list(menu) - if key == "Harga - Rendah→Tinggi": - arr.sort(key=lambda x: x["harga"]) - elif key == "Harga - Tinggi→Rendah": - arr.sort(key=lambda x: -x["harga"]) - elif key == "Stok - Rendah→Tinggi": - arr.sort(key=lambda x: x.get("stok",0)) - elif key == "Stok - Tinggi→Rendah": - arr.sort(key=lambda x: -x.get("stok",0)) - self._populate_tree(arr) - - def _clear_details(self): - self.detail_text.config(state="normal") - self.detail_text.delete("1.0", tk.END) - self.detail_text.config(state="disabled") - self.img_label.config(image="", text="(No Image)") - self.img_label.image = None - - def _on_tree_select(self, evt): - sel = self.tree.selection() - if not sel: - return - mid = int(sel[0]) - it = find_menu_by_id(mid) - if not it: return - self.detail_text.config(state="normal") - self.detail_text.delete("1.0", tk.END) - s = f"ID: {it['id']}\nNama: {it['nama']}\nHarga: Rp{it['harga']}\nKategori: {it.get('kategori','-')}\nStok: {it.get('stok',0)}\nFoto: {os.path.basename(it['foto']) if it.get('foto') else 'Tidak ada'}\n" - self.detail_text.insert(tk.END, s) - self.detail_text.config(state="disabled") - img = ensure_image(it.get('foto')) - if img: - self.img_label.config(image=img, text="") - self.img_label.image = img - else: - self.img_label.config(image="", text="(No Image)") - self.img_label.image = None - - # ---------- CRUD Menu ---------- - def _gui_add_menu(self): - if current_user["role"] != "admin": - messagebox.showerror("Akses", "Hanya admin bisa menambah menu.") - return - dialog = AddEditDialog(self.root, title="Tambah Menu") - self.root.wait_window(dialog.top) - if dialog.result is None: - return - nama, harga, stok, kategori, foto_path = dialog.result - try: - harga = int(harga); stok = int(stok) - except: - messagebox.showerror("Error", "Harga & Stok harus angka.") - return - new_id = menu[-1]["id"] + 1 if menu else 1 - menu.append({"id": new_id, "nama": nama, "harga": harga, "kategori": kategori, "stok": stok, "foto": foto_path}) - messagebox.showinfo("Sukses", "Menu ditambahkan.") - self._refresh_menu() - - def _gui_edit_menu(self): - if current_user["role"] != "admin": - messagebox.showerror("Akses", "Hanya admin bisa edit menu.") - return - sel = self.tree.selection() - if not sel: - messagebox.showwarning("Pilih", "Pilih menu untuk diedit.") - return - mid = int(sel[0]) - it = find_menu_by_id(mid) - if not it: - messagebox.showerror("Error", "Menu tidak ditemukan.") - return - dialog = AddEditDialog(self.root, title="Edit Menu", existing=it) - self.root.wait_window(dialog.top) - if dialog.result is None: - return - nama, harga, stok, kategori, foto_path = dialog.result - try: - harga = int(harga); stok = int(stok) - except: - messagebox.showerror("Error", "Harga & Stok harus angka.") - return - it.update({"nama": nama, "harga": harga, "kategori": kategori, "stok": stok, "foto": foto_path}) - messagebox.showinfo("Sukses", "Menu diperbarui.") - self._refresh_menu() - - def _gui_delete_menu(self): - if current_user["role"] != "admin": - messagebox.showerror("Akses", "Hanya admin bisa hapus menu.") - return - sel = self.tree.selection() - if not sel: - messagebox.showwarning("Pilih", "Pilih menu untuk dihapus.") - return - mid = int(sel[0]) - it = find_menu_by_id(mid) - if not it: - messagebox.showerror("Error", "Menu tidak ditemukan.") - return - if messagebox.askyesno("Hapus", f"Yakin ingin hapus {it['nama']}?"): - menu.remove(it) - self._refresh_menu() - - # ---------- Bahan ---------- - def _refresh_bahan_listbox(self): - self.bahan_listbox.delete(0, tk.END) - for k,v in bahan.items(): - self.bahan_listbox.insert(tk.END, f"{k}: {v}") - - def _gui_edit_bahan(self): - if current_user["role"] != "admin": - messagebox.showerror("Akses", "Hanya admin bisa edit stok bahan.") - return - k = simpledialog.askstring("Bahan", "Nama bahan:") - if not k: - return - try: - v = int(simpledialog.askstring("Stok", "Jumlah:")) - except: - return - bahan[k] = v - self._refresh_bahan_listbox() - - def _logout(self): - global current_user - current_user = None - self._build_login() - -# ---------- Dialog ---------- -class AddEditDialog: - def __init__(self, parent, title="Tambah/Edit", existing=None): - self.top = tk.Toplevel(parent) - self.top.title(title) - self.result = None - self.existing = existing - ttk.Label(self.top, text="Nama:").grid(row=0, column=0, sticky="e", padx=5, pady=4) - self.e_nama = ttk.Entry(self.top) - self.e_nama.grid(row=0, column=1, padx=5, pady=4) - ttk.Label(self.top, text="Harga:").grid(row=1, column=0, sticky="e", padx=5, pady=4) - self.e_harga = ttk.Entry(self.top) - self.e_harga.grid(row=1, column=1, padx=5, pady=4) - ttk.Label(self.top, text="Stok:").grid(row=2, column=0, sticky="e", padx=5, pady=4) - self.e_stok = ttk.Entry(self.top) - self.e_stok.grid(row=2, column=1, padx=5, pady=4) - ttk.Label(self.top, text="Kategori:").grid(row=3, column=0, sticky="e", padx=5, pady=4) - self.e_kategori = ttk.Entry(self.top) - self.e_kategori.grid(row=3, column=1, padx=5, pady=4) - ttk.Label(self.top, text="Foto:").grid(row=4, column=0, sticky="e", padx=5, pady=4) - self.foto_path = tk.StringVar() - self.e_foto = ttk.Entry(self.top, textvariable=self.foto_path) - self.e_foto.grid(row=4, column=1, padx=5, pady=4) - ttk.Button(self.top, text="Browse", command=self._browse_file).grid(row=4, column=2, padx=4, pady=4) - ttk.Button(self.top, text="OK", command=self._ok).grid(row=5, column=0, pady=8) - ttk.Button(self.top, text="Cancel", command=self.top.destroy).grid(row=5, column=1) - if existing: - self.e_nama.insert(0, existing["nama"]) - self.e_harga.insert(0, str(existing["harga"])) - self.e_stok.insert(0, str(existing.get("stok",0))) - self.e_kategori.insert(0, existing.get("kategori","")) - self.foto_path.set(existing.get("foto","")) - - def _browse_file(self): - path = filedialog.askopenfilename(filetypes=[("Image files","*.png *.jpg *.jpeg *.gif")]) - if path: - self.foto_path.set(path) - - def _ok(self): - self.result = ( - self.e_nama.get(), - self.e_harga.get(), - self.e_stok.get(), - self.e_kategori.get(), - self.foto_path.get() + self.root.configure(bg="#F5F5F0") + + # Top bar + topbar = tk.Frame(self.root, bg="#5C4033", height=60) + topbar.pack(fill="x") + topbar.pack_propagate(False) + + left_header = tk.Frame(topbar, bg="#5C4033") + left_header.pack(side="left", padx=20, pady=10) + tk.Label(left_header, text="☕ CAFE MANAGEMENT", font=("Segoe UI", 14, "bold"), + bg="#5C4033", fg="white").pack(side="left") + + role_text = self.current_user['role'].upper() if self.current_user['role'] != 'guest' else 'GUEST MODE' + tk.Label(left_header, text=f" | {self.current_user['username']} ({role_text})", + font=("Segoe UI", 10), bg="#5C4033", fg="#D4AF77").pack(side="left") + + right_header = tk.Frame(topbar, bg="#5C4033") + right_header.pack(side="right", padx=20, pady=10) + + # Notifikasi button (untuk staff saja) + if self.current_user['role'] != 'guest': + unread = len([n for n in notifikasi if not n['read']]) + notif_text = f"🔔 ({unread})" if unread > 0 else "🔔" + notif_btn = tk.Button(right_header, text=notif_text, + command=self.open_notifikasi_window, + font=("Arial", 9), bg="#6B5335", fg="white", + relief="flat", bd=0, padx=15, pady=8, cursor="hand2") + notif_btn.pack(side="right", padx=3) + + # Logout button + logout_btn = tk.Button(right_header, text="🚪 Logout", command=self.logout, + font=("Arial", 9), bg="#A0522D", fg="white", + relief="flat", bd=0, padx=15, pady=8, cursor="hand2") + logout_btn.pack(side="right", padx=3) + + # Main content + main = ttk.Notebook(self.root) + main.pack(fill='both', expand=True, padx=10, pady=10) + + # Build tabs based on role + if self.current_user['role'] == 'guest': + self.build_guest_tabs(main) + elif self.current_user['role'] == 'pembeli': + self.build_pembeli_tabs(main) + elif self.current_user['role'] == 'kasir': + self.build_kasir_tabs(main) + elif self.current_user['role'] == 'waiter': + self.build_waiter_tabs(main) + elif self.current_user['role'] == 'owner': + self.build_owner_tabs(main) + elif self.current_user['role'] == 'admin': + self.build_admin_tabs(main) + + # ================================ + # TAB BUILDERS + # ================================ + + def build_guest_tabs(self, notebook): + tab_menu = ttk.Frame(notebook) + notebook.add(tab_menu, text="📖 Lihat Menu") + self.build_menu_browse_tab(tab_menu, guest_mode=True) + + def build_pembeli_tabs(self, notebook): + tab_menu = ttk.Frame(notebook) + tab_order = ttk.Frame(notebook) + tab_fav = ttk.Frame(notebook) + + notebook.add(tab_menu, text="📖 Menu") + notebook.add(tab_order, text="🛒 Order") + notebook.add(tab_fav, text="⭐ Favorit") + + self.build_menu_browse_tab(tab_menu) + self.build_order_tab(tab_order) + self.build_favorite_tab(tab_fav) + + def build_kasir_tabs(self, notebook): + tab_payment = ttk.Frame(notebook) + tab_riwayat = ttk.Frame(notebook) + + notebook.add(tab_payment, text="💰 Pembayaran") + notebook.add(tab_riwayat, text="📜 Riwayat") + + self.build_payment_tab(tab_payment) + self.build_riwayat_tab(tab_riwayat) + + def build_waiter_tabs(self, notebook): + tab_pesanan = ttk.Frame(notebook) + tab_meja = ttk.Frame(notebook) + + notebook.add(tab_pesanan, text="🍽️ Pesanan") + notebook.add(tab_meja, text="🪑 Meja") + + self.build_waiter_pesanan_tab(tab_pesanan) + self.build_meja_tab(tab_meja) + + def build_owner_tabs(self, notebook): + tab_laporan = ttk.Frame(notebook) + tab_riwayat = ttk.Frame(notebook) + + notebook.add(tab_laporan, text="📊 Laporan") + notebook.add(tab_riwayat, text="📜 Riwayat") + + self.build_laporan_tab(tab_laporan) + self.build_riwayat_tab(tab_riwayat) + + def build_admin_tabs(self, notebook): + tab_menu_manage = ttk.Frame(notebook) + tab_bahan = ttk.Frame(notebook) + tab_promo = ttk.Frame(notebook) + tab_user = ttk.Frame(notebook) + tab_laporan = ttk.Frame(notebook) + + notebook.add(tab_menu_manage, text="⚙️ Kelola Menu") + notebook.add(tab_bahan, text="📦 Stok Bahan") + notebook.add(tab_promo, text="🎁 Promo") + notebook.add(tab_user, text="👥 User") + notebook.add(tab_laporan, text="📊 Laporan") + + self.build_menu_manage_tab(tab_menu_manage) + self.build_bahan_tab(tab_bahan) + self.build_promo_tab(tab_promo) + self.build_user_tab(tab_user) + self.build_laporan_tab(tab_laporan) + + # ================================ + # TAB: MENU BROWSE + # ================================ + + def build_menu_browse_tab(self, parent, guest_mode=False): + for w in parent.winfo_children(): + w.destroy() + + header = tk.Frame(parent, bg="#F5F5F0") + header.pack(fill="x", padx=15, pady=10) + + tk.Label(header, text="🍽️ Menu Cafe", font=("Arial", 18, "bold"), + bg="#F5F5F0", fg="#5C4033").pack(side="left") + + if guest_mode: + info = tk.Label(header, + text="ℹ️ Mode Guest - Login untuk memesan", + font=("Arial", 10), bg="#FFF3CD", fg="#856404", + padx=10, pady=5) + info.pack(side="right") + + search_frame = tk.Frame(parent, bg="white", relief="solid", bd=1) + search_frame.pack(fill="x", padx=15, pady=5) + + inner_search = tk.Frame(search_frame, bg="white") + inner_search.pack(padx=10, pady=8) + + tk.Label(inner_search, text="🔍 Cari:", font=("Arial", 9), + bg="white").pack(side="left", padx=5) + + self.menu_search_var = tk.StringVar() + tk.Entry(inner_search, textvariable=self.menu_search_var, + font=("Arial", 10), width=25).pack(side="left", padx=5) + + tk.Button(inner_search, text="Cari", command=self.refresh_menu_browse, + font=("Arial", 9), bg="#8B7355", fg="white", + relief="flat", padx=15, pady=5).pack(side="left", padx=5) + + tk.Label(inner_search, text="📂 Kategori:", font=("Arial", 9), + bg="white").pack(side="left", padx=(15, 5)) + + self.menu_filter_var = tk.StringVar(value="Semua") + categories = ["Semua"] + sorted(set(m['kategori'] for m in menu)) + filter_cb = ttk.Combobox(inner_search, textvariable=self.menu_filter_var, + values=categories, state="readonly", width=15) + filter_cb.pack(side="left", padx=5) + filter_cb.bind("<>", lambda e: self.refresh_menu_browse()) + + container = tk.Frame(parent, bg="white") + container.pack(fill="both", expand=True, padx=15, pady=5) + + canvas = tk.Canvas(container, bg="white", highlightthickness=0) + scrollbar = ttk.Scrollbar(container, orient="vertical", command=canvas.yview) + self.menu_browse_frame = tk.Frame(canvas, bg="white") + + canvas.configure(yscrollcommand=scrollbar.set) + scrollbar.pack(side="right", fill="y") + canvas.pack(side="left", fill="both", expand=True) + + canvas_window = canvas.create_window((0, 0), window=self.menu_browse_frame, anchor="nw") + + def configure_scroll(event): + canvas.configure(scrollregion=canvas.bbox("all")) + + self.menu_browse_frame.bind("", configure_scroll) + + def configure_canvas(event): + canvas.itemconfig(canvas_window, width=event.width) + + canvas.bind("", configure_canvas) + + def on_mousewheel(event): + canvas.yview_scroll(-1 * int(event.delta / 120), "units") + + canvas.bind_all("", on_mousewheel) + + self.refresh_menu_browse() + + def refresh_menu_browse(self): + for widget in self.menu_browse_frame.winfo_children(): + widget.destroy() + + search = self.menu_search_var.get().lower() if hasattr(self, 'menu_search_var') else "" + kategori = self.menu_filter_var.get() if hasattr(self, 'menu_filter_var') else "Semua" + + filtered = [] + for m in menu: + if search and search not in m['nama'].lower(): + continue + if kategori != "Semua" and m['kategori'] != kategori: + continue + filtered.append(m) + + cols = 3 + row = 0 + col = 0 + + for m in filtered: + card = tk.Frame(self.menu_browse_frame, bg="white", relief="solid", + bd=1, highlightthickness=2, highlightbackground="#E0E0E0") + card.grid(row=row, column=col, padx=15, pady=15, sticky="nsew") + + img_frame = tk.Frame(card, bg="#F5F5F5", width=220, height=180) + img_frame.pack(fill="x", padx=10, pady=(10, 5)) + img_frame.pack_propagate(False) + + foto = m.get('foto') + if foto and os.path.exists(foto): + img = ensure_image(foto, maxsize=(200, 160)) + if img: + img_label = tk.Label(img_frame, image=img, bg="#F5F5F5") + img_label.image = img + img_label.pack(expand=True) + else: + tk.Label(img_frame, text="🍽️\nNo Image", font=("Arial", 16), + bg="#F5F5F5", fg="#CCCCCC").pack(expand=True) + else: + tk.Label(img_frame, text="🍽️\nNo Image", font=("Arial", 16), + bg="#F5F5F5", fg="#CCCCCC").pack(expand=True) + + info_frame = tk.Frame(card, bg="white") + info_frame.pack(fill="x", padx=15, pady=10) + + tk.Label(info_frame, text=m['nama'], font=("Arial", 13, "bold"), + bg="white", fg="#5C4033", anchor="w").pack(fill="x") + + tk.Label(info_frame, text=f"📂 {m['kategori']}", + font=("Arial", 9), bg="white", fg="#999999", + anchor="w").pack(fill="x", pady=(3, 5)) + + price_frame = tk.Frame(info_frame, bg="white") + price_frame.pack(fill="x", pady=(0, 5)) + + harga = m['harga'] + promo = m.get('promo', '') + + if promo: + diskon = calculate_discount(harga, promo) + harga_after = harga - diskon + tk.Label(price_frame, text=format_currency(harga), + font=("Arial", 10), bg="white", fg="#999999", + anchor="w").pack(side="left") + tk.Label(price_frame, text=" → ", font=("Arial", 10), + bg="white", fg="#999999").pack(side="left") + tk.Label(price_frame, text=format_currency(harga_after), + font=("Arial", 12, "bold"), bg="white", fg="#D2691E", + anchor="w").pack(side="left") + tk.Label(info_frame, text=f"🎁 {promo}", + font=("Arial", 9), bg="white", fg="#D2691E", + anchor="w").pack(fill="x") + else: + tk.Label(price_frame, text=format_currency(harga), + font=("Arial", 13, "bold"), bg="white", fg="#8B7355", + anchor="w").pack(side="left") + + stok = m.get('stok', 0) + stock_color = "#E74C3C" if stok < 5 else "#27AE60" + tk.Label(info_frame, text=f"📦 Stok: {stok}", + font=("Arial", 9), bg="white", fg=stock_color, + anchor="w").pack(fill="x", pady=(3, 0)) + + col += 1 + if col >= cols: + col = 0 + row += 1 + + # ================================ + # TAB: ORDER (FIXED & INTEGRATED) + # ================================ + + def build_order_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + left = ttk.Frame(parent, width=600) + right = ttk.Frame(parent, width=380) + left.pack(side='left', fill='both', expand=True, padx=6, pady=6) + right.pack(side='right', fill='both', padx=6, pady=6) + + tk.Label(left, text="🍽️ Daftar Menu", font=("Arial", 12, "bold")).pack(pady=4) + + search_frame = ttk.Frame(left) + search_frame.pack(fill='x', pady=4) + tk.Label(search_frame, text="🔍 Cari:").pack(side='left', padx=3) + self.order_search_var = tk.StringVar() + ttk.Entry(search_frame, textvariable=self.order_search_var, width=25).pack(side='left', padx=3) + ttk.Button(search_frame, text="Cari", command=self.reload_order_menu_cards).pack(side='left', padx=3) + ttk.Button(search_frame, text="Reset", command=self.reset_order_search).pack(side='left', padx=3) + + canvas = tk.Canvas(left, bg='#f5f5f5', height=450, highlightthickness=0) + scrollbar = ttk.Scrollbar(left, orient="vertical", command=canvas.yview) + self.menu_cards_frame = ttk.Frame(canvas) + + self.menu_cards_frame.bind( + "", + lambda e: canvas.configure(scrollregion=canvas.bbox("all")) ) - self.top.destroy() + + canvas.create_window((0, 0), window=self.menu_cards_frame, anchor="nw") + canvas.configure(yscrollcommand=scrollbar.set) + + canvas.pack(side="left", fill="both", expand=True) + scrollbar.pack(side="right", fill="y") + + def _on_mousewheel(event): + canvas.yview_scroll(int(-1*(event.delta/120)), "units") + canvas.bind_all("", _on_mousewheel) + + tk.Label(right, text="🛒 Keranjang Belanja", font=("Arial", 12, "bold")).pack(pady=4) + + cart_cols = ("Menu", "Qty", "Harga", "Subtotal") + self.cart_tree = ttk.Treeview(right, columns=cart_cols, show='headings', height=8) + for c in cart_cols: + self.cart_tree.heading(c, text=c) + if c == "Menu": + self.cart_tree.column(c, width=150) + else: + self.cart_tree.column(c, width=70) + self.cart_tree.pack(fill='x', pady=4) + + cart_btn_frame = ttk.Frame(right) + cart_btn_frame.pack(pady=4) + ttk.Button(cart_btn_frame, text="🗑️ Hapus Item", command=self.remove_cart_item).pack(side='left', padx=3) + ttk.Button(cart_btn_frame, text="🗑️ Kosongkan", command=self.clear_cart).pack(side='left', padx=3) + + total_frame = ttk.Frame(right) + total_frame.pack(fill='x', pady=4) + + self.cart_subtotal_label = ttk.Label(total_frame, text="Subtotal: Rp 0", font=("Arial", 9)) + self.cart_subtotal_label.pack() + self.cart_discount_label = ttk.Label(total_frame, text="Diskon Item: Rp 0", font=("Arial", 9)) + self.cart_discount_label.pack() + self.cart_promo_label = ttk.Label(total_frame, text="Diskon Promo: Rp 0", font=("Arial", 9)) + self.cart_promo_label.pack() + self.cart_total_label = ttk.Label(total_frame, text="TOTAL: Rp 0", font=("Arial", 11, "bold")) + self.cart_total_label.pack(pady=2) + + checkout_frame = ttk.Frame(right) + checkout_frame.pack(fill='x', pady=6, padx=10) + + ttk.Label(checkout_frame, text="No. Meja:", font=("Arial", 9)).grid(row=0, column=0, sticky='w', padx=3, pady=3) + self.order_meja_var = tk.StringVar() + meja_entry = ttk.Entry(checkout_frame, textvariable=self.order_meja_var, width=20) + meja_entry.grid(row=0, column=1, pady=3, sticky='ew') + + ttk.Label(checkout_frame, text="Kode Promo:", font=("Arial", 9)).grid(row=1, column=0, sticky='w', padx=3, pady=3) + self.order_promo_var = tk.StringVar() + ttk.Entry(checkout_frame, textvariable=self.order_promo_var, width=12).grid(row=1, column=1, pady=3, sticky='ew') + ttk.Button(checkout_frame, text="Terapkan", command=self.update_cart_display, width=10).grid(row=1, column=2, padx=3, sticky='e') + + checkout_frame.columnconfigure(1, weight=1) + + checkout_btn_frame = ttk.Frame(right) + checkout_btn_frame.pack(fill='x', pady=10, padx=20) + + ttk.Button( + checkout_btn_frame, + text="🛒 CHECKOUT PESANAN", + command=self.checkout_order, + width=30 + ).pack() + + self.cart_items = [] + self.reload_order_menu_cards() + + def reload_order_menu_cards(self): + for widget in self.menu_cards_frame.winfo_children(): + widget.destroy() + + search = self.order_search_var.get().strip() or None + results = [m for m in menu if m.get('stok', 0) > 0] + + if search: + results = [m for m in results if search.lower() in m['nama'].lower()] + + cart_dict = {} + for cart_item in self.cart_items: + cart_dict[cart_item['menu_id']] = cart_item['qty'] + + row = 0 + col = 0 + for m in results: + mid = m['id'] + nama = m['nama'] + kategori = m['kategori'] + harga = m['harga'] + stok = m['stok'] + foto = m.get('foto') + item_disc = m.get('item_discount_pct', 0) + promo = m.get('promo', '') + + card = tk.Frame( + self.menu_cards_frame, + relief='solid', + borderwidth=1, + bg='white', + padx=10, + pady=10 + ) + card.grid(row=row, column=col, padx=8, pady=8, sticky='nsew') + + if foto and os.path.exists(foto): + try: + if PIL_AVAILABLE: + img = Image.open(foto) + img = img.resize((150, 100), Image.Resampling.LANCZOS) + photo = ImageTk.PhotoImage(img) + + img_label = tk.Label(card, image=photo, bg='white') + img_label.image = photo + img_label.pack() + else: + tk.Label(card, text="[No Image]", bg='#e0e0e0', width=20, height=6).pack() + except: + tk.Label(card, text="[No Image]", bg='#e0e0e0', width=20, height=6).pack() + else: + tk.Label(card, text="[No Image]", bg='#e0e0e0', width=20, height=6).pack() + + tk.Label(card, text=nama, font=("Arial", 11, "bold"), bg='white', wraplength=150).pack(pady=(5, 2)) + tk.Label(card, text=kategori, font=("Arial", 9), fg='gray', bg='white').pack() + + harga_text = f"Rp {harga:,}" + if item_disc > 0: + harga_after = harga - (harga * item_disc / 100) + harga_text = f"Rp {harga:,} → Rp {int(harga_after):,}" + tk.Label(card, text=harga_text, font=("Arial", 9, "bold"), fg='#E67E22', bg='white').pack(pady=2) + if promo: + tk.Label(card, text=f"🎁 {promo}", font=("Arial", 8), fg='#D35400', bg='white').pack() + else: + tk.Label(card, text=harga_text, font=("Arial", 10, "bold"), fg='green', bg='white').pack(pady=2) + + tk.Label(card, text=f"📦 Stok: {stok}", font=("Arial", 8), fg='blue', bg='white').pack(pady=2) + + qty_in_cart = cart_dict.get(mid, 0) + + btn_frame = tk.Frame(card, bg='white') + btn_frame.pack(pady=5) + + if qty_in_cart > 0: + tk.Button( + btn_frame, + text="➖", + font=("Arial", 12, "bold"), + bg='#E74C3C', + fg='white', + width=3, + borderwidth=0, + cursor='hand2', + command=lambda m=mid: self.decrease_from_card(m) + ).pack(side='left', padx=2) + + tk.Label( + btn_frame, + text=str(qty_in_cart), + font=("Arial", 12, "bold"), + bg='white', + width=3 + ).pack(side='left', padx=5) + + tk.Button( + btn_frame, + text="➕", + font=("Arial", 12, "bold"), + bg='#27AE60', + fg='white', + width=3, + borderwidth=0, + cursor='hand2', + command=lambda m=mid, s=stok: self.increase_from_card(m, s) + ).pack(side='left', padx=2) + else: + tk.Button( + btn_frame, + text="➕ Tambah", + font=("Arial", 10, "bold"), + bg='#27AE60', + fg='white', + width=12, + borderwidth=0, + cursor='hand2', + command=lambda m=mid, s=stok: self.increase_from_card(m, s) + ).pack() + + col += 1 + if col >= 2: + col = 0 + row += 1 + + def reset_order_search(self): + self.order_search_var.set("") + self.reload_order_menu_cards() + + def increase_from_card(self, menu_id, stok): + current_qty = 0 + cart_item_found = None + for cart_item in self.cart_items: + if cart_item['menu_id'] == menu_id: + current_qty = cart_item['qty'] + cart_item_found = cart_item + break + + if current_qty >= stok: + messagebox.showwarning("Stok Habis", f"Stok hanya tersisa {stok}") + return + + if cart_item_found: + cart_item_found['qty'] += 1 + else: + self.cart_items.append({'menu_id': menu_id, 'qty': 1}) + + self.reload_order_menu_cards() + self.update_cart_display() + + def decrease_from_card(self, menu_id): + for i, cart_item in enumerate(self.cart_items): + if cart_item['menu_id'] == menu_id: + cart_item['qty'] -= 1 + + if cart_item['qty'] <= 0: + del self.cart_items[i] + + self.reload_order_menu_cards() + self.update_cart_display() + return + + def update_cart_display(self): + for r in self.cart_tree.get_children(): + self.cart_tree.delete(r) + + if not self.cart_items: + self.cart_subtotal_label.config(text="Subtotal: Rp 0") + self.cart_discount_label.config(text="Diskon Item: Rp 0") + self.cart_promo_label.config(text="Diskon Promo: Rp 0") + self.cart_total_label.config(text="TOTAL: Rp 0") + return + + subtotal = 0 + item_discount_total = 0 + + for cart_item in self.cart_items: + menu_data = find_menu_by_id(cart_item['menu_id']) + if not menu_data: + continue + + harga = menu_data['harga'] + qty = cart_item['qty'] + item_disc_pct = menu_data.get('item_discount_pct', 0) + + line_subtotal = harga * qty + subtotal += line_subtotal + + if item_disc_pct > 0: + item_discount = int(line_subtotal * item_disc_pct / 100) + item_discount_total += item_discount + + self.cart_tree.insert("", tk.END, values=( + menu_data['nama'], + qty, + f"{harga:,}", + f"{line_subtotal:,}" + )) + + promo_code = self.order_promo_var.get().strip().upper() + promo_discount = 0 + + if promo_code and promo_code in promo_codes: + discount_pct = promo_codes[promo_code] + promo_discount = int((subtotal - item_discount_total) * discount_pct / 100) + + total = subtotal - item_discount_total - promo_discount + + self.cart_subtotal_label.config(text=f"Subtotal: Rp {subtotal:,}") + self.cart_discount_label.config(text=f"Diskon Item: Rp {item_discount_total:,}") + self.cart_promo_label.config(text=f"Diskon Promo: Rp {promo_discount:,}") + self.cart_total_label.config(text=f"TOTAL: Rp {total:,}") + + def remove_cart_item(self): + sel = self.cart_tree.selection() + if not sel: + messagebox.showwarning("Pilih Item", "Pilih item di keranjang") + return + + idx = self.cart_tree.index(sel) + if idx >= len(self.cart_items): + return + + del self.cart_items[idx] + self.reload_order_menu_cards() + self.update_cart_display() + + def clear_cart(self): + if not self.cart_items: + return + + if messagebox.askyesno("Konfirmasi", "Kosongkan keranjang?"): + self.cart_items = [] + self.reload_order_menu_cards() + self.update_cart_display() + + def checkout_order(self): + if not self.cart_items: + messagebox.showwarning("Keranjang Kosong", "Tambahkan item terlebih dahulu") + return + + nomor_meja = self.order_meja_var.get().strip() + if not nomor_meja: + messagebox.showwarning("Input Error", "Masukkan nomor meja") + return + + try: + nomor_meja = int(nomor_meja) + except: + messagebox.showerror("Input Error", "Nomor meja harus angka") + return + + if nomor_meja < 1 or nomor_meja > 10: + messagebox.showerror("Invalid", "Nomor meja harus 1-10") + return + + promo_code = self.order_promo_var.get().strip().upper() or None + + if promo_code and promo_code not in promo_codes: + messagebox.showwarning("Promo Invalid", "Kode promo tidak ditemukan") + return + + # Cek stok bahan + kurang_bahan = [] + for cart_item in self.cart_items: + mid = cart_item['menu_id'] + qty = cart_item['qty'] + + if mid in resep: + for bahan_nama, need in resep[mid].items(): + if bahan.get(bahan_nama, 0) < need * qty: + kurang_bahan.append((bahan_nama, bahan.get(bahan_nama, 0), need * qty)) + + if kurang_bahan: + msg = "❌ Stok bahan tidak cukup untuk pesanan:\n\n" + for bn, avail, need in kurang_bahan: + msg += f"• {bn}: tersedia {avail}, dibutuhkan {need}\n" + messagebox.showerror("Stok Bahan Kurang", msg) + add_notification("warning", f"Stok bahan kurang untuk pesanan dari {self.current_user['username']}") + return + + # Hitung total + subtotal = 0 + item_discount_total = 0 + items_for_trans = [] + + for cart_item in self.cart_items: + menu_data = find_menu_by_id(cart_item['menu_id']) + if not menu_data: + continue + + qty = cart_item['qty'] + harga = menu_data['harga'] + item_disc_pct = menu_data.get('item_discount_pct', 0) + + line_subtotal = harga * qty + subtotal += line_subtotal + + if item_disc_pct > 0: + item_discount = int(line_subtotal * item_disc_pct / 100) + item_discount_total += item_discount + + menu_data['stok'] -= qty + if menu_data['stok'] < 0: + menu_data['stok'] = 0 + + if menu_data['stok'] < 5: + add_notification("warning", f"Stok {menu_data['nama']} tinggal {menu_data['stok']}") + + if menu_data['id'] in resep: + for bahan_nama, kebutuhan in resep[menu_data['id']].items(): + if bahan_nama in bahan: + bahan[bahan_nama] -= kebutuhan * qty + if bahan[bahan_nama] < 0: + bahan[bahan_nama] = 0 + if bahan[bahan_nama] < 10: + add_notification("warning", f"Stok bahan {bahan_nama} tinggal {bahan[bahan_nama]}") + + items_for_trans.append({ + 'menu_id': menu_data['id'], + 'nama': menu_data['nama'], + 'qty': qty, + 'harga_satuan': harga, + 'subtotal': line_subtotal + }) + + promo_discount = 0 + if promo_code: + discount_pct = promo_codes[promo_code] + promo_discount = int((subtotal - item_discount_total) * discount_pct / 100) + + total = subtotal - item_discount_total - promo_discount + + new_trans_id = max([t['id'] for t in transaksi], default=0) + 1 + + transaksi.append({ + 'id': new_trans_id, + 'tanggal': str(datetime.date.today()), + 'waktu': datetime.datetime.now(), + 'user': self.current_user['username'], + 'items': items_for_trans, + 'subtotal': subtotal, + 'diskon': item_discount_total + promo_discount, + 'total': total, + 'meja': nomor_meja, + 'status': 'Baru', + 'payment_status': 'Pending', + 'payment_method': None, + 'paid_amount': 0, + 'change': 0, + 'promo_code': promo_code or '' + }) + + detail_id = max([d['id'] for d in detail_transaksi], default=0) + 1 + for item in items_for_trans: + detail_transaksi.append({ + 'id': detail_id, + 'transaksi_id': new_trans_id, + 'menu_id': item['menu_id'], + 'nama_menu': item['nama'], + 'jumlah': item['qty'], + 'harga_satuan': item['harga_satuan'], + 'subtotal': item['subtotal'], + 'diskon': 0 + }) + detail_id += 1 + + data_meja[nomor_meja] = "Terisi" + + add_notification("info", f"Pesanan baru dari {self.current_user['username']} - Total: Rp {total:,}") + + save_menu() + save_bahan() + save_transaksi() + save_detail_transaksi() + save_meja() + + self.cart_items = [] + self.order_promo_var.set("") + self.reload_order_menu_cards() + self.update_cart_display() + + messagebox.showinfo("✅ Sukses", + f"Pesanan berhasil dibuat!\n\n" + f"ID Transaksi: #{new_trans_id}\n" + f"Total: Rp {total:,}\n\n" + f"Silakan lakukan pembayaran di kasir.") + + # ================================ + # TAB: PAYMENT (FIXED & INTEGRATED) + # ================================ + + def build_payment_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + header = ttk.Frame(parent) + header.pack(fill='x', padx=10, pady=8) + + 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) + + search_frame = ttk.LabelFrame(parent, text="🔍 Cari Transaksi by Nomor Meja", padding=10) + search_frame.pack(fill='x', padx=10, pady=6) + + search_inner = ttk.Frame(search_frame) + search_inner.pack() + + ttk.Label(search_inner, text="Nomor Meja:", font=("Arial", 9)).grid(row=0, column=0, padx=5) + self.search_meja_var = tk.StringVar() + ttk.Entry(search_inner, textvariable=self.search_meja_var, width=15).grid(row=0, column=1, padx=5) + ttk.Button(search_inner, text="🔍 Cari Tagihan", + command=self.search_by_meja).grid(row=0, column=2, padx=5) + ttk.Button(search_inner, text="🔄 Tampilkan Semua", + command=self.reload_payment_orders).grid(row=0, column=3, padx=5) + + summary_frame = ttk.LabelFrame(parent, text="📊 TOTAL PERHITUNGAN - Penjualan Hari Ini", padding=12) + summary_frame.pack(fill='x', padx=10, pady=6) + + summary_inner = ttk.Frame(summary_frame) + summary_inner.pack() + + today = str(datetime.date.today()) + today_report = get_daily_report(today) + + ttk.Label(summary_inner, text="Total Transaksi Hari Ini:", + font=("Arial", 11, "bold")).grid(row=0, column=0, sticky='w', padx=10, pady=5) + ttk.Label(summary_inner, text=str(today_report['total_transaksi']), + font=("Arial", 12, "bold"), foreground='blue').grid(row=0, column=1, sticky='w', padx=10, pady=5) + + ttk.Label(summary_inner, text="Total Pendapatan Hari Ini:", + font=("Arial", 11, "bold")).grid(row=1, column=0, sticky='w', padx=10, pady=5) + ttk.Label(summary_inner, text=format_currency(today_report['total_omzet']), + font=("Arial", 12, "bold"), foreground='green').grid(row=1, column=1, sticky='w', padx=10, pady=5) + + pending_total = sum(t['total'] for t in transaksi if t.get('payment_status') == 'Pending' and t['tanggal'] == today) + ttk.Label(summary_inner, text="Total Tagihan Pending:", + font=("Arial", 11, "bold")).grid(row=2, column=0, sticky='w', padx=10, pady=5) + ttk.Label(summary_inner, text=format_currency(pending_total), + font=("Arial", 12, "bold"), foreground='orange').grid(row=2, column=1, sticky='w', padx=10, pady=5) + + # Breakdown QRIS vs CASH + today_berhasil = [t for t in transaksi if t['tanggal'] == today and t.get('payment_status') == 'Berhasil'] + qris_total = sum(t['total'] for t in today_berhasil if t.get('payment_method', '').lower() == 'qris') + cash_total = sum(t['total'] for t in today_berhasil if t.get('payment_method', '').lower() == 'cash') + qris_count = len([t for t in today_berhasil if t.get('payment_method', '').lower() == 'qris']) + cash_count = len([t for t in today_berhasil if t.get('payment_method', '').lower() == 'cash']) + + ttk.Separator(summary_inner, orient='horizontal').grid(row=3, column=0, columnspan=2, sticky='ew', padx=10, pady=8) + + ttk.Label(summary_inner, text="📱 QRIS:", + font=("Arial", 10, "bold"), foreground='#FF6B6B').grid(row=4, column=0, sticky='w', padx=10, pady=3) + ttk.Label(summary_inner, text=f"{format_currency(qris_total)} ({qris_count}x)", + font=("Arial", 10, "bold"), foreground='#FF6B6B').grid(row=4, column=1, sticky='w', padx=10, pady=3) + + ttk.Label(summary_inner, text="💵 CASH:", + font=("Arial", 10, "bold"), foreground='#4CAF50').grid(row=5, column=0, sticky='w', padx=10, pady=3) + ttk.Label(summary_inner, text=f"{format_currency(cash_total)} ({cash_count}x)", + font=("Arial", 10, "bold"), foreground='#4CAF50').grid(row=5, column=1, sticky='w', padx=10, pady=3) + + main_container = ttk.Frame(parent) + main_container.pack(fill='both', expand=True, padx=10, pady=6) + + left = ttk.LabelFrame(main_container, text="📋 Daftar Transaksi Belum Dibayar", padding=5) + left.pack(side='left', fill='both', expand=True, padx=(0, 5)) + + tree_scroll = ttk.Scrollbar(left, orient='vertical') + tree_scroll.pack(side='right', fill='y') + + cols = ("ID", "Meja", "Total", "Status", "Tanggal") + self.payment_tree = ttk.Treeview( + left, + columns=cols, + show='headings', + height=8, + 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") + self.payment_tree.heading("Total", text="Total") + self.payment_tree.heading("Status", text="Status") + self.payment_tree.heading("Tanggal", text="Tanggal") + + self.payment_tree.column("ID", width=50) + 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=120) + + self.payment_tree.pack(side='left', fill='both', expand=True) + self.payment_tree.bind("<>", self.on_payment_select) + + detail_label = ttk.Label(left, text="📄 Detail Transaksi", font=("Arial", 10, "bold")) + detail_label.pack(anchor='w', pady=(10, 5)) + + detail_frame = ttk.Frame(left) + detail_frame.pack(fill='both', expand=True) + + detail_scroll = ttk.Scrollbar(detail_frame, orient='vertical') + detail_scroll.pack(side='right', fill='y') + + self.payment_detail_text = tk.Text(detail_frame, height=10, font=("Courier New", 9), + wrap='word', yscrollcommand=detail_scroll.set) + detail_scroll.config(command=self.payment_detail_text.yview) + self.payment_detail_text.pack(side='left', fill='both', expand=True) + + right = ttk.LabelFrame(main_container, text="💳 Form Pembayaran", padding=10) + right.pack(side='right', fill='both', expand=True, padx=(5, 0)) + + self.selected_transaksi_label = ttk.Label( + right, + text="❌ Belum ada transaksi dipilih", + font=("Arial", 10, "bold"), + foreground='red' + ) + self.selected_transaksi_label.pack(pady=5) + + self.selected_total_label = ttk.Label( + right, + text="Total: Rp 0", + font=("Arial", 14, "bold"), + foreground='green' + ) + self.selected_total_label.pack(pady=5) + + ttk.Separator(right, orient='horizontal').pack(fill='x', pady=10) + + method_label = ttk.Label(right, text="💳 Pilih Metode Pembayaran:", + font=("Arial", 10, "bold")) + method_label.pack(anchor='w', pady=5) + + self.payment_method_var = tk.StringVar(value='cash') + + method_frame = ttk.Frame(right) + method_frame.pack(fill='x', pady=5) + + 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", + variable=self.payment_method_var, value='ewallet', + command=self.on_payment_method_change).pack(anchor='w', pady=2) + + ttk.Separator(right, orient='horizontal').pack(fill='x', pady=10) + + # Container untuk payment input + button + payment_container = tk.Frame(right, bg='white') + payment_container.pack(fill='both', expand=True, pady=5) + + # Canvas dengan scrollbar untuk payment input (max height 250px) + self.payment_canvas = tk.Canvas(payment_container, bg='white', highlightthickness=0, height=250) + scrollbar = ttk.Scrollbar(payment_container, orient='vertical', command=self.payment_canvas.yview) + self.payment_input_frame = tk.Frame(self.payment_canvas, bg='white', relief='solid', bd=1) + + self.payment_input_frame.bind( + "", + lambda e: self.payment_canvas.configure(scrollregion=self.payment_canvas.bbox("all")) + ) + + self.payment_canvas.create_window((0, 0), window=self.payment_input_frame, anchor='nw') + self.payment_canvas.configure(yscrollcommand=scrollbar.set) + + self.payment_canvas.pack(fill='both', expand=False, padx=2, pady=5, side='left') + scrollbar.pack(fill='y', side='right', pady=5) + + # Mouse wheel scrolling + def _on_mousewheel(event): + self.payment_canvas.yview_scroll(int(-1*(event.delta/120)), "units") + self.payment_canvas.bind_all("", _on_mousewheel) + + self.build_cash_input() + + # Separator + ttk.Separator(payment_container, orient='horizontal').pack(fill='x', pady=8) + + # Button PROSES PEMBAYARAN + self.process_btn = tk.Button( + payment_container, + text="✅ PROSES PEMBAYARAN", + command=self.process_payment, + state='disabled', + font=("Arial", 11, "bold"), + bg='#4CAF50', + fg='white', + relief='raised', + bd=2, + padx=15, + pady=10, + cursor='hand2' + ) + self.process_btn.pack(fill='x', padx=5, pady=10) + + self.reload_payment_orders() + + def reload_payment_orders(self): + for r in self.payment_tree.get_children(): + self.payment_tree.delete(r) + + for t in transaksi: + if t.get('payment_status') == 'Pending': + self.payment_tree.insert("", tk.END, values=( + t['id'], + t.get('meja', '-'), + format_currency(t['total']), + t['status'], + t['tanggal'] + )) + + def search_by_meja(self): + nomor_meja = self.search_meja_var.get().strip() + + if not nomor_meja: + messagebox.showwarning("Input Error", "Masukkan nomor meja") + return + + try: + nomor_meja = int(nomor_meja) + except: + messagebox.showerror("Input Error", "Nomor meja harus angka") + return + + if nomor_meja < 1 or nomor_meja > 10: + messagebox.showwarning("Invalid", "Nomor meja harus 1-10") + return + + for r in self.payment_tree.get_children(): + self.payment_tree.delete(r) + + found = False + for t in transaksi: + if t.get('meja') == nomor_meja and t.get('payment_status') == 'Pending': + self.payment_tree.insert("", tk.END, values=( + t['id'], + t.get('meja', '-'), + format_currency(t['total']), + t['status'], + t['tanggal'] + )) + found = True + + if not found: + messagebox.showinfo("Tidak Ditemukan", + f"❌ Tidak ada tagihan aktif untuk Meja {nomor_meja}") + self.reload_payment_orders() + + def on_payment_select(self, event): + sel = self.payment_tree.selection() + if not sel: + return + + item = self.payment_tree.item(sel)['values'] + transaksi_id = item[0] + + t = None + for trans in transaksi: + if trans['id'] == transaksi_id: + t = trans + break + + if not t: + return + + self.selected_transaksi_label.config( + text=f"✅ Transaksi #{t['id']} - Meja {t.get('meja', '-')}", + foreground='green' + ) + self.selected_total_label.config(text=f"Total: {format_currency(t['total'])}") + + self.process_btn.config(state='normal') + + detail_text = f"═══════════════════════════════════════\n" + detail_text += f"TRANSAKSI #{t['id']}\n" + detail_text += f"═══════════════════════════════════════\n\n" + detail_text += f"Tanggal : {t['tanggal']}\n" + detail_text += f"User : {t['user']}\n" + detail_text += f"Meja : {t.get('meja', '-')}\n" + detail_text += f"Status : {t['status']}\n\n" + detail_text += f"───────────────────────────────────────\n" + detail_text += f"ITEM PESANAN:\n" + detail_text += f"───────────────────────────────────────\n" + + for item in t['items']: + detail_text += f"• {item['nama']}\n" + detail_text += f" {item['qty']} x {format_currency(item['harga_satuan'])} = {format_currency(item['subtotal'])}\n\n" + + detail_text += f"───────────────────────────────────────\n" + detail_text += f"Subtotal : {format_currency(t['subtotal'])}\n" + detail_text += f"Diskon : {format_currency(t['diskon'])}\n" + detail_text += f"───────────────────────────────────────\n" + detail_text += f"TOTAL : {format_currency(t['total'])}\n" + detail_text += f"═══════════════════════════════════════\n" + + self.payment_detail_text.delete('1.0', tk.END) + self.payment_detail_text.insert('1.0', detail_text) + + self.selected_payment_transaksi = t + + def on_payment_method_change(self): + for widget in self.payment_input_frame.winfo_children(): + widget.destroy() + + method = self.payment_method_var.get() + + if method == 'cash': + self.build_cash_input() + elif method == 'qris': + self.build_qris_input() + elif method == 'ewallet': + self.build_ewallet_input() + + def build_cash_input(self): + ttk.Label(self.payment_input_frame, text="💵 PEMBAYARAN CASH", + font=("Arial", 11, "bold"), background='white').pack(pady=8) + + ttk.Label(self.payment_input_frame, text="Jumlah Bayar:", font=("Arial", 9), + background='white').pack(anchor='w', padx=10, pady=(5, 2)) + + self.cash_amount_var = tk.StringVar() + cash_entry = ttk.Entry(self.payment_input_frame, textvariable=self.cash_amount_var, + font=("Arial", 11), width=25) + cash_entry.pack(pady=5, padx=10) + + self.cash_change_label = ttk.Label(self.payment_input_frame, text="Kembalian: Rp 0", + font=("Arial", 10, "bold"), foreground='blue', + background='white') + self.cash_change_label.pack(pady=8, padx=10) + + def calculate_change(*args): + if not hasattr(self, 'selected_payment_transaksi'): + return + + try: + paid = int(self.cash_amount_var.get()) + total = self.selected_payment_transaksi['total'] + change = paid - total + + if change >= 0: + self.cash_change_label.config( + text=f"Kembalian: {format_currency(change)}", + foreground='green' + ) + else: + self.cash_change_label.config( + text=f"Kurang: {format_currency(abs(change))}", + foreground='red' + ) + except: + self.cash_change_label.config(text="Kembalian: Rp 0", foreground='blue') + + self.cash_amount_var.trace('w', calculate_change) + + def build_qris_input(self): + ttk.Label(self.payment_input_frame, text="📱 PEMBAYARAN QRIS", + font=("Arial", 9, "bold"), background='white').pack(pady=2) + + if not hasattr(self, 'selected_payment_transaksi'): + ttk.Label(self.payment_input_frame, text="Pilih transaksi", + foreground='red', background='white', font=("Arial", 8)).pack() + return + + t = self.selected_payment_transaksi + + if QRCODE_AVAILABLE: + ttk.Label(self.payment_input_frame, text="📲 Scan QR Code:", + font=("Arial", 8), background='white').pack(pady=1) + + qr_data = f"CAFE-TRX-{t['id']}-{t['total']}" + + try: + qr = qrcode.QRCode(version=1, box_size=4, border=1) + qr.add_data(qr_data) + qr.make(fit=True) + + img = qr.make_image(fill_color="black", back_color="white") + + buffer = BytesIO() + img.save(buffer, format='PNG') + buffer.seek(0) + + if PIL_AVAILABLE: + qr_img = Image.open(buffer) + qr_img = qr_img.resize((120, 120)) + qr_photo = ImageTk.PhotoImage(qr_img) + + qr_label = tk.Label(self.payment_input_frame, image=qr_photo, bg='white') + qr_label.image = qr_photo + qr_label.pack(pady=2) + + ttk.Label(self.payment_input_frame, + text=f"Total: Rp {t['total']:,}".replace(",", "."), + font=("Arial", 8, "bold"), background='white', foreground='green').pack(pady=1) + + except Exception as e: + ttk.Label(self.payment_input_frame, + text=f"Error: {str(e)[:20]}", + foreground='red', font=("Arial", 8), background='white').pack() + else: + ttk.Label(self.payment_input_frame, + text="qrcode tidak tersedia", + foreground='red', font=("Arial", 8), background='white').pack() + + def build_ewallet_input(self): + ttk.Label(self.payment_input_frame, text="💳 PEMBAYARAN E-WALLET", + font=("Arial", 10, "bold"), background='white').pack(pady=3) + + ttk.Label(self.payment_input_frame, text="Pilih E-Wallet:", font=("Arial", 8), + background='white').pack(anchor='w', padx=5, pady=(3, 2)) + + self.ewallet_type_var = tk.StringVar(value='gopay') + + wallets = [ + ('GoPay', 'gopay'), + ('OVO', 'ovo'), + ('DANA', 'dana'), + ('ShopeePay', 'shopeepay') + ] + + wallet_frame = tk.Frame(self.payment_input_frame, bg='white') + wallet_frame.pack(fill='x', padx=5, pady=2) + + for label, value in wallets: + ttk.Radiobutton(wallet_frame, text=f"💰 {label}", + variable=self.ewallet_type_var, value=value).pack(anchor='w', pady=2) + + if hasattr(self, 'selected_payment_transaksi'): + t = self.selected_payment_transaksi + ttk.Label(self.payment_input_frame, + text=f"Total Bayar: {format_currency(t['total'])}", + font=("Arial", 10, "bold"), + foreground='green', background='white').pack(pady=10) + + def process_payment(self): + if not hasattr(self, 'selected_payment_transaksi'): + messagebox.showwarning("Error", "Pilih transaksi terlebih dahulu") + return + + t = self.selected_payment_transaksi + method = self.payment_method_var.get() + + if method == 'cash': + try: + paid = int(self.cash_amount_var.get()) + except: + messagebox.showerror("Input Error", "Masukkan jumlah pembayaran yang valid") + return + + if paid < t['total']: + messagebox.showerror("Pembayaran Kurang", + f"Pembayaran kurang!\nTotal: {format_currency(t['total'])}\nBayar: {format_currency(paid)}") + return + + change = paid - t['total'] + + t['payment_status'] = 'Berhasil' + t['payment_method'] = 'Cash' + t['paid_amount'] = paid + t['change'] = change + t['status'] = 'Selesai' + + if t.get('meja'): + data_meja[t['meja']] = 'Kosong' + + payment_id = max([p['id'] for p in pembayaran], default=0) + 1 + pembayaran.append({ + 'id': payment_id, + 'transaksi_id': t['id'], + 'metode': 'Cash', + 'jumlah': t['total'], + 'status': 'Berhasil', + 'tanggal': str(datetime.date.today()) + }) + + save_transaksi() + save_meja() + save_pembayaran() + + add_notification("success", f"Pembayaran Cash #{t['id']} berhasil - Total: {format_currency(t['total'])}") + + messagebox.showinfo("✅ Pembayaran Berhasil", + f"Transaksi #{t['id']}\n\n" + f"Metode: Cash\n" + f"Total: {format_currency(t['total'])}\n" + f"Bayar: {format_currency(paid)}\n" + f"Kembalian: {format_currency(change)}") + + self.reload_payment_orders() + self.selected_transaksi_label.config(text="❌ Belum ada transaksi dipilih", foreground='red') + self.selected_total_label.config(text="Total: Rp 0") + self.payment_detail_text.delete('1.0', tk.END) + self.process_btn.config(state='disabled') + self.cash_amount_var.set("") + + elif method == 'qris': + confirm = messagebox.askyesno("Konfirmasi QRIS", + f"Apakah pembayaran QRIS sebesar {format_currency(t['total'])} sudah diterima?") + + if not confirm: + return + + t['payment_status'] = 'Berhasil' + t['payment_method'] = 'QRIS' + t['paid_amount'] = t['total'] + t['change'] = 0 + t['status'] = 'Selesai' + + if t.get('meja'): + data_meja[t['meja']] = 'Kosong' + + payment_id = max([p['id'] for p in pembayaran], default=0) + 1 + pembayaran.append({ + 'id': payment_id, + 'transaksi_id': t['id'], + 'metode': 'QRIS', + 'jumlah': t['total'], + 'status': 'Berhasil', + 'tanggal': str(datetime.date.today()) + }) + + save_transaksi() + save_meja() + save_pembayaran() + + add_notification("success", f"Pembayaran QRIS #{t['id']} berhasil - Total: {format_currency(t['total'])}") + + messagebox.showinfo("✅ Pembayaran Berhasil", + f"Transaksi #{t['id']}\n\n" + f"Metode: QRIS\n" + f"Total: {format_currency(t['total'])}") + + self.reload_payment_orders() + self.selected_transaksi_label.config(text="❌ Belum ada transaksi dipilih", foreground='red') + self.selected_total_label.config(text="Total: Rp 0") + self.payment_detail_text.delete('1.0', tk.END) + self.process_btn.config(state='disabled') + + elif method == 'ewallet': + wallet_type = self.ewallet_type_var.get() + wallet_names = { + 'gopay': 'GoPay', + 'ovo': 'OVO', + 'dana': 'DANA', + 'shopeepay': 'ShopeePay' + } + wallet_name = wallet_names.get(wallet_type, 'E-Wallet') + + confirm = messagebox.askyesno("Konfirmasi E-Wallet", + f"Apakah pembayaran {wallet_name} sebesar {format_currency(t['total'])} sudah diterima?") + + if not confirm: + return + + t['payment_status'] = 'Berhasil' + t['payment_method'] = wallet_name + t['paid_amount'] = t['total'] + t['change'] = 0 + t['status'] = 'Selesai' + + if t.get('meja'): + data_meja[t['meja']] = 'Kosong' + + payment_id = max([p['id'] for p in pembayaran], default=0) + 1 + pembayaran.append({ + 'id': payment_id, + 'transaksi_id': t['id'], + 'metode': wallet_name, + 'jumlah': t['total'], + 'status': 'Berhasil', + 'tanggal': str(datetime.date.today()) + }) + + save_transaksi() + save_meja() + save_pembayaran() + + add_notification("success", f"Pembayaran {wallet_name} #{t['id']} berhasil - Total: {format_currency(t['total'])}") + + messagebox.showinfo("✅ Pembayaran Berhasil", + f"Transaksi #{t['id']}\n\n" + f"Metode: {wallet_name}\n" + f"Total: {format_currency(t['total'])}") + + self.reload_payment_orders() + self.selected_transaksi_label.config(text="❌ Belum ada transaksi dipilih", foreground='red') + self.selected_total_label.config(text="Total: Rp 0") + self.payment_detail_text.delete('1.0', tk.END) + self.process_btn.config(state='disabled') + + # ================================ + # TAB: FAVORITE + # ================================ + + def build_favorite_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + header = tk.Frame(parent, bg="#F5F5F0") + header.pack(fill="x", padx=15, pady=10) + + tk.Label(header, text="⭐ Menu Favorit Saya", font=("Arial", 18, "bold"), + bg="#F5F5F0", fg="#5C4033").pack(side="left") + + ttk.Button(header, text="🔄 Refresh", + command=lambda: self.build_favorite_tab(parent)).pack(side="right") + + username = self.current_user['username'] + user_favs = favorites.get(username, []) + + if not user_favs: + empty_frame = tk.Frame(parent, bg="white") + empty_frame.pack(fill="both", expand=True, padx=20, pady=20) + + tk.Label(empty_frame, text="⭐", font=("Arial", 64), + bg="white", fg="#CCCCCC").pack(pady=(50, 20)) + tk.Label(empty_frame, text="Belum ada menu favorit", + font=("Arial", 16), bg="white", fg="#999999").pack() + tk.Label(empty_frame, text="Tandai menu favorit Anda dari tab Menu", + font=("Arial", 11), bg="white", fg="#CCCCCC").pack(pady=10) + return + + container = tk.Frame(parent, bg="white") + container.pack(fill="both", expand=True, padx=15, pady=5) + + canvas = tk.Canvas(container, bg="white", highlightthickness=0) + scrollbar = ttk.Scrollbar(container, orient="vertical", command=canvas.yview) + fav_frame = tk.Frame(canvas, bg="white") + + canvas.configure(yscrollcommand=scrollbar.set) + scrollbar.pack(side="right", fill="y") + canvas.pack(side="left", fill="both", expand=True) + + canvas_window = canvas.create_window((0, 0), window=fav_frame, anchor="nw") + + fav_frame.bind("", lambda e: canvas.configure(scrollregion=canvas.bbox("all"))) + canvas.bind("", lambda e: canvas.itemconfig(canvas_window, width=e.width)) + canvas.bind_all("", lambda e: canvas.yview_scroll(-1 * int(e.delta / 120), "units")) + + row = 0 + col = 0 + + for fav_id in user_favs: + m = find_menu_by_id(fav_id) + if not m: + continue + + card = tk.Frame(fav_frame, bg="white", relief="solid", + bd=1, highlightthickness=2, highlightbackground="#FFD700") + card.grid(row=row, column=col, padx=15, pady=15, sticky="nsew") + + img_frame = tk.Frame(card, bg="#F5F5F5", width=220, height=180) + img_frame.pack(fill="x", padx=10, pady=(10, 5)) + img_frame.pack_propagate(False) + + foto = m.get('foto') + if foto and os.path.exists(foto): + img = ensure_image(foto, maxsize=(200, 160)) + if img: + img_label = tk.Label(img_frame, image=img, bg="#F5F5F5") + img_label.image = img + img_label.pack(expand=True) + else: + tk.Label(img_frame, text="⭐\nFavorite", font=("Arial", 16), + bg="#F5F5F5", fg="#FFD700").pack(expand=True) + else: + tk.Label(img_frame, text="⭐\nFavorite", font=("Arial", 16), + bg="#F5F5F5", fg="#FFD700").pack(expand=True) + + info_frame = tk.Frame(card, bg="white") + info_frame.pack(fill="x", padx=15, pady=10) + + tk.Label(info_frame, text=m['nama'], font=("Arial", 13, "bold"), + bg="white", fg="#5C4033", anchor="w").pack(fill="x") + + tk.Label(info_frame, text=f"📂 {m['kategori']}", + font=("Arial", 9), bg="white", fg="#999999", + anchor="w").pack(fill="x", pady=(3, 5)) + + tk.Label(info_frame, text=format_currency(m['harga']), + font=("Arial", 13, "bold"), bg="white", fg="#8B7355", + anchor="w").pack(fill="x") + + btn_frame = tk.Frame(info_frame, bg="white") + btn_frame.pack(fill="x", pady=(10, 0)) + + tk.Button(btn_frame, text="💔 Hapus dari Favorit", + command=lambda mid=m['id']: self.remove_from_favorites(mid, parent), + font=("Arial", 9), bg="#E74C3C", fg="white", + relief="flat", padx=10, pady=5).pack() + + col += 1 + if col >= 3: + col = 0 + row += 1 + + def remove_from_favorites(self, menu_id, parent): + username = self.current_user['username'] + + if username in favorites and menu_id in favorites[username]: + favorites[username].remove(menu_id) + save_favorites() + messagebox.showinfo("Success", "Menu dihapus dari favorit") + self.build_favorite_tab(parent) + + # ================================ + # TAB: RIWAYAT + # ================================ + + def build_riwayat_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + header = ttk.Frame(parent) + header.pack(fill='x', padx=10, pady=8) + + ttk.Label(header, text="📜 Riwayat Transaksi", + font=("Arial", 14, "bold")).pack(side='left') + + ttk.Button(header, text="🔄 Refresh", + command=lambda: self.build_riwayat_tab(parent)).pack(side='right', padx=5) + + filter_frame = ttk.LabelFrame(parent, text="🔍 Filter Riwayat", padding=10) + filter_frame.pack(fill='x', padx=10, pady=5) + + filter_inner = ttk.Frame(filter_frame) + filter_inner.pack() + + ttk.Label(filter_inner, text="Status:").grid(row=0, column=0, padx=5) + self.riwayat_status_var = tk.StringVar(value="Semua") + status_cb = ttk.Combobox(filter_inner, textvariable=self.riwayat_status_var, + values=["Semua", "Pending", "Berhasil", "Batal"], + state="readonly", width=15) + status_cb.grid(row=0, column=1, padx=5) + + ttk.Label(filter_inner, text="Tanggal:").grid(row=0, column=2, padx=5) + self.riwayat_date_var = tk.StringVar(value=str(datetime.date.today())) + ttk.Entry(filter_inner, textvariable=self.riwayat_date_var, width=15).grid(row=0, column=3, padx=5) + + ttk.Button(filter_inner, text="🔍 Tampilkan", + command=lambda: self.refresh_riwayat_tree()).grid(row=0, column=4, padx=5) + ttk.Button(filter_inner, text="🔄 Reset", + command=self.reset_riwayat_filter).grid(row=0, column=5, padx=5) + + tree_frame = ttk.Frame(parent) + tree_frame.pack(fill='both', expand=True, padx=10, pady=5) + + tree_scroll = ttk.Scrollbar(tree_frame, orient='vertical') + tree_scroll.pack(side='right', fill='y') + + cols = ("ID", "Tanggal", "User", "Total", "Metode", "Status", "Meja") + self.riwayat_tree = ttk.Treeview( + tree_frame, + columns=cols, + show='headings', + height=12, + yscrollcommand=tree_scroll.set + ) + + tree_scroll.config(command=self.riwayat_tree.yview) + + for c in cols: + self.riwayat_tree.heading(c, text=c) + if c == "ID": + self.riwayat_tree.column(c, width=50) + elif c == "Total": + self.riwayat_tree.column(c, width=100) + elif c == "Meja": + self.riwayat_tree.column(c, width=60) + else: + self.riwayat_tree.column(c, width=100) + + self.riwayat_tree.pack(side='left', fill='both', expand=True) + self.riwayat_tree.bind("", self.show_riwayat_detail) + + detail_frame = ttk.LabelFrame(parent, text="📄 Detail Transaksi", padding=10) + detail_frame.pack(fill='x', padx=10, pady=5) + + self.riwayat_detail_text = tk.Text(detail_frame, height=8, font=("Courier New", 9), + wrap='word', state='disabled') + self.riwayat_detail_text.pack(fill='x') + + self.refresh_riwayat_tree() + + def refresh_riwayat_tree(self): + for r in self.riwayat_tree.get_children(): + self.riwayat_tree.delete(r) + + status_filter = self.riwayat_status_var.get() + date_filter = self.riwayat_date_var.get().strip() + + for t in reversed(transaksi): + payment_status = t.get('payment_status', 'Pending') + + if status_filter != "Semua" and payment_status != status_filter: + continue + + if date_filter and t['tanggal'] != date_filter: + continue + + self.riwayat_tree.insert("", tk.END, values=( + t['id'], + t['tanggal'], + t['user'], + format_currency(t['total']), + t.get('payment_method', '-'), + payment_status, + t.get('meja', '-') + )) + + def reset_riwayat_filter(self): + self.riwayat_status_var.set("Semua") + self.riwayat_date_var.set(str(datetime.date.today())) + self.refresh_riwayat_tree() + + def show_riwayat_detail(self, event): + sel = self.riwayat_tree.selection() + if not sel: + return + + item = self.riwayat_tree.item(sel)['values'] + transaksi_id = item[0] + + t = None + for trans in transaksi: + if trans['id'] == transaksi_id: + t = trans + break + + if not t: + return + + detail_text = f"═══════════════════════════════════════\n" + detail_text += f"DETAIL TRANSAKSI #{t['id']}\n" + detail_text += f"═══════════════════════════════════════\n\n" + detail_text += f"Tanggal : {t['tanggal']}\n" + detail_text += f"Waktu : {t['waktu'].strftime('%H:%M:%S')}\n" + detail_text += f"User : {t['user']}\n" + detail_text += f"Meja : {t.get('meja', '-')}\n" + detail_text += f"Status Pesanan : {t['status']}\n" + detail_text += f"Status Bayar : {t.get('payment_status', 'Pending')}\n" + detail_text += f"Metode Bayar : {t.get('payment_method', '-')}\n\n" + detail_text += f"───────────────────────────────────────\n" + detail_text += f"ITEM:\n" + detail_text += f"───────────────────────────────────────\n" + + for item in t['items']: + detail_text += f"• {item['nama']}\n" + detail_text += f" {item['qty']} x {format_currency(item['harga_satuan'])} = {format_currency(item['subtotal'])}\n\n" + + detail_text += f"───────────────────────────────────────\n" + detail_text += f"Subtotal : {format_currency(t['subtotal'])}\n" + detail_text += f"Diskon : {format_currency(t['diskon'])}\n" + + if t.get('promo_code'): + detail_text += f"Promo Code : {t['promo_code']}\n" + + detail_text += f"───────────────────────────────────────\n" + detail_text += f"TOTAL : {format_currency(t['total'])}\n" + + if t.get('payment_method') == 'Cash': + detail_text += f"Bayar : {format_currency(t.get('paid_amount', 0))}\n" + detail_text += f"Kembalian : {format_currency(t.get('change', 0))}\n" + + detail_text += f"═══════════════════════════════════════\n" + + self.riwayat_detail_text.config(state='normal') + self.riwayat_detail_text.delete('1.0', tk.END) + self.riwayat_detail_text.insert('1.0', detail_text) + self.riwayat_detail_text.config(state='disabled') + + # ================================ + # TAB: MEJA + # ================================ + + def build_meja_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + header = ttk.Frame(parent) + header.pack(fill='x', padx=10, pady=8) + + ttk.Label(header, text="🪑 Manajemen Meja", + font=("Arial", 14, "bold")).pack(side='left') + + ttk.Button(header, text="🔄 Refresh", + command=lambda: self.build_meja_tab(parent)).pack(side='right', padx=5) + + # Summary + summary_frame = ttk.LabelFrame(parent, text="📊 Status Meja", padding=10) + summary_frame.pack(fill='x', padx=10, pady=5) + + summary_inner = ttk.Frame(summary_frame) + summary_inner.pack() + + kosong = len([m for m in data_meja.values() if m == "Kosong"]) + terisi = len([m for m in data_meja.values() if m == "Terisi"]) + + ttk.Label(summary_inner, text="✅ Meja Kosong:", + font=("Arial", 10)).grid(row=0, column=0, sticky='w', padx=10, pady=3) + ttk.Label(summary_inner, text=str(kosong), + font=("Arial", 10, "bold"), foreground='green').grid(row=0, column=1, sticky='w', padx=10, pady=3) + + ttk.Label(summary_inner, text="🔴 Meja Terisi:", + font=("Arial", 10)).grid(row=1, column=0, sticky='w', padx=10, pady=3) + ttk.Label(summary_inner, text=str(terisi), + font=("Arial", 10, "bold"), foreground='red').grid(row=1, column=1, sticky='w', padx=10, pady=3) + + # Grid Meja + meja_frame = ttk.LabelFrame(parent, text="🗺️ Layout Meja", padding=15) + meja_frame.pack(fill='both', expand=True, padx=10, pady=5) + + grid_frame = tk.Frame(meja_frame, bg='white') + grid_frame.pack(expand=True) + + # Buat grid 2x5 untuk 10 meja + for i in range(1, 11): + status = data_meja.get(i, "Kosong") + + if status == "Kosong": + bg_color = "#D4EDDA" + fg_color = "#155724" + icon = "✅" + else: + bg_color = "#F8D7DA" + fg_color = "#721C24" + icon = "🔴" + + # Hitung posisi grid + row = (i - 1) // 5 + col = (i - 1) % 5 + + # Frame untuk setiap meja + meja_card = tk.Frame(grid_frame, bg=bg_color, relief='solid', bd=2, + width=120, height=100) + meja_card.grid(row=row, column=col, padx=10, pady=10) + meja_card.pack_propagate(False) + + # Konten meja + tk.Label(meja_card, text=icon, font=("Arial", 20), + bg=bg_color).pack(pady=(10, 5)) + tk.Label(meja_card, text=f"Meja {i}", font=("Arial", 11, "bold"), + bg=bg_color, fg=fg_color).pack() + tk.Label(meja_card, text=status, font=("Arial", 9), + bg=bg_color, fg=fg_color).pack(pady=(2, 5)) + + # Button aksi + if status == "Terisi": + btn = tk.Button(meja_card, text="🧹 Kosongkan", + command=lambda m=i: self.kosongkan_meja(m, parent), + font=("Arial", 8), bg='#FFC107', fg='black', + relief='flat', padx=8, pady=3, cursor='hand2') + btn.pack(pady=3) + else: + btn = tk.Button(meja_card, text="🔒 Tandai Terisi", + command=lambda m=i: self.tandai_terisi_meja(m, parent), + font=("Arial", 8), bg='#007BFF', fg='white', + relief='flat', padx=8, pady=3, cursor='hand2') + btn.pack(pady=3) + + # Info footer + info_frame = ttk.Frame(parent) + info_frame.pack(fill='x', padx=10, pady=(5, 10)) + + ttk.Label(info_frame, + text="💡 Tips: Meja otomatis terisi saat pembeli checkout, dan kosong saat pembayaran selesai", + font=("Arial", 9), foreground='gray').pack() + + def kosongkan_meja(self, nomor_meja, parent): + confirm = messagebox.askyesno("Konfirmasi", + f"Kosongkan Meja {nomor_meja}?\n\n" + f"Pastikan tamu sudah selesai dan pembayaran telah lunas.") + + if not confirm: + return + + data_meja[nomor_meja] = "Kosong" + save_meja() + add_notification("info", f"Meja {nomor_meja} dikosongkan oleh {self.current_user['username']}") + messagebox.showinfo("Success", f"Meja {nomor_meja} berhasil dikosongkan") + self.build_meja_tab(parent) + + def tandai_terisi_meja(self, nomor_meja, parent): + confirm = messagebox.askyesno("Konfirmasi", + f"Tandai Meja {nomor_meja} terisi?\n\n" + f"Gunakan fitur ini jika ada tamu tanpa order sistem.") + + if not confirm: + return + + data_meja[nomor_meja] = "Terisi" + save_meja() + add_notification("info", f"Meja {nomor_meja} ditandai terisi oleh {self.current_user['username']}") + messagebox.showinfo("Success", f"Meja {nomor_meja} berhasil ditandai terisi") + self.build_meja_tab(parent) + + # ================================ + # TAB: USER MANAGEMENT + # ================================ + + def build_user_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + header = ttk.Frame(parent) + header.pack(fill='x', padx=10, pady=8) + + ttk.Label(header, text="👥 Kelola User", + font=("Arial", 14, "bold")).pack(side='left') + + ttk.Button(header, text="➕ Tambah User", + command=self.add_user_dialog).pack(side='right', padx=5) + ttk.Button(header, text="🔄 Refresh", + command=lambda: self.build_user_tab(parent)).pack(side='right', padx=5) + + tree_frame = ttk.Frame(parent) + tree_frame.pack(fill='both', expand=True, padx=10, pady=5) + + tree_scroll = ttk.Scrollbar(tree_frame, orient='vertical') + tree_scroll.pack(side='right', fill='y') + + cols = ("ID", "Username", "Role", "Status") + self.user_tree = ttk.Treeview( + tree_frame, + columns=cols, + show='headings', + height=15, + yscrollcommand=tree_scroll.set + ) + + tree_scroll.config(command=self.user_tree.yview) + + for c in cols: + self.user_tree.heading(c, text=c) + if c == "ID": + self.user_tree.column(c, width=50) + else: + self.user_tree.column(c, width=150) + + self.user_tree.pack(side='left', fill='both', expand=True) + + for u in users: + self.user_tree.insert("", tk.END, values=( + u['id'], + u['username'], + u['role'], + "✅ Aktif" + )) + + action_frame = ttk.Frame(parent) + action_frame.pack(fill='x', padx=10, pady=10) + + ttk.Button(action_frame, text="✏️ Edit", + command=self.edit_user_dialog, + width=20).pack(side='left', padx=5) + ttk.Button(action_frame, text="🔒 Reset Password", + command=self.reset_user_password, + width=20).pack(side='left', padx=5) + ttk.Button(action_frame, text="🗑️ Hapus", + command=self.delete_user, + width=20).pack(side='left', padx=5) + + def add_user_dialog(self): + dialog = tk.Toplevel(self.root) + dialog.title("➕ Tambah User Baru") + dialog.geometry("400x300") + dialog.resizable(False, False) + + frame = ttk.Frame(dialog, padding=20) + frame.pack(fill='both', expand=True) + + ttk.Label(frame, text="Username:").grid(row=0, column=0, sticky='w', pady=10) + username_entry = ttk.Entry(frame, width=25) + username_entry.grid(row=0, column=1, pady=10) + + ttk.Label(frame, text="Password:").grid(row=1, column=0, sticky='w', pady=10) + password_entry = ttk.Entry(frame, show="●", width=25) + password_entry.grid(row=1, column=1, pady=10) + + ttk.Label(frame, text="Role:").grid(row=2, column=0, sticky='w', pady=10) + role_var = tk.StringVar(value="pembeli") + role_cb = ttk.Combobox(frame, textvariable=role_var, + values=["admin", "kasir", "waiter", "pembeli", "owner"], + state="readonly", width=23) + role_cb.grid(row=2, column=1, pady=10) + + def save_user(): + username = username_entry.get().strip() + password = password_entry.get().strip() + role = role_var.get() + + if not username or not password: + messagebox.showwarning("Input Error", "Username dan password harus diisi") + return + + for u in users: + if u['username'] == username: + messagebox.showwarning("Sudah Ada", f"Username '{username}' sudah digunakan") + return + + new_id = max([int(u['id']) for u in users], default=0) + 1 + + users.append({ + 'id': str(new_id), + 'username': username, + 'password': password, + 'role': role + }) + + save_users() + add_notification("success", f"User '{username}' berhasil ditambahkan") + messagebox.showinfo("Success", f"User '{username}' berhasil ditambahkan") + dialog.destroy() + self.build_user_tab(self.user_tree.master.master) + + ttk.Button(frame, text="💾 Simpan", command=save_user).grid(row=3, column=0, columnspan=2, pady=20) + + def edit_user_dialog(self): + sel = self.user_tree.selection() + if not sel: + messagebox.showwarning("Pilih User", "Pilih user yang akan diedit") + return + + item = self.user_tree.item(sel)['values'] + user_id = str(item[0]) + + user = None + for u in users: + if u['id'] == user_id: + user = u + break + + if not user: + return + + dialog = tk.Toplevel(self.root) + dialog.title(f"✏️ Edit User: {user['username']}") + dialog.geometry("400x250") + dialog.resizable(False, False) + + frame = ttk.Frame(dialog, padding=20) + frame.pack(fill='both', expand=True) + + ttk.Label(frame, text="Username:").grid(row=0, column=0, sticky='w', pady=10) + username_entry = ttk.Entry(frame, width=25) + username_entry.insert(0, user['username']) + username_entry.grid(row=0, column=1, pady=10) + + ttk.Label(frame, text="Role:").grid(row=1, column=0, sticky='w', pady=10) + role_var = tk.StringVar(value=user['role']) + role_cb = ttk.Combobox(frame, textvariable=role_var, + values=["admin", "kasir", "waiter", "pembeli", "owner"], + state="readonly", width=23) + role_cb.grid(row=1, column=1, pady=10) + + def update_user(): + new_username = username_entry.get().strip() + + if not new_username: + messagebox.showwarning("Input Error", "Username harus diisi") + return + + for u in users: + if u['username'] == new_username and u['id'] != user_id: + messagebox.showwarning("Sudah Ada", f"Username '{new_username}' sudah digunakan") + return + + user['username'] = new_username + user['role'] = role_var.get() + + save_users() + add_notification("info", f"User '{new_username}' berhasil diupdate") + messagebox.showinfo("Success", "User berhasil diupdate") + dialog.destroy() + self.build_user_tab(self.user_tree.master.master) + + ttk.Button(frame, text="💾 Update", command=update_user).grid(row=2, column=0, columnspan=2, pady=20) + + def reset_user_password(self): + sel = self.user_tree.selection() + if not sel: + messagebox.showwarning("Pilih User", "Pilih user untuk reset password") + return + + item = self.user_tree.item(sel)['values'] + user_id = str(item[0]) + + user = None + for u in users: + if u['id'] == user_id: + user = u + break + + if not user: + return + + new_password = simpledialog.askstring("Reset Password", + f"Password baru untuk '{user['username']}':", + show='●') + + if new_password: + user['password'] = new_password + save_users() + add_notification("warning", f"Password user '{user['username']}' direset") + messagebox.showinfo("Success", f"Password '{user['username']}' berhasil direset") + + def delete_user(self): + sel = self.user_tree.selection() + if not sel: + messagebox.showwarning("Pilih User", "Pilih user yang akan dihapus") + return + + item = self.user_tree.item(sel)['values'] + user_id = str(item[0]) + + user = None + for u in users: + if u['id'] == user_id: + user = u + break + + if not user: + return + + if user['id'] == str(self.current_user['id']): + messagebox.showwarning("Error", "Tidak bisa menghapus user yang sedang login") + return + + confirm = messagebox.askyesno("Konfirmasi", f"Hapus user '{user['username']}'?") + if not confirm: + return + + users.remove(user) + save_users() + add_notification("warning", f"User '{user['username']}' dihapus") + messagebox.showinfo("Success", f"User '{user['username']}' berhasil dihapus") + self.build_user_tab(self.user_tree.master.master) + + + # ================================ + # TAB: WAITER PESANAN (FIXED) + # ================================ + + def build_waiter_pesanan_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + header = ttk.Frame(parent) + header.pack(fill='x', padx=10, pady=8) + + ttk.Label(header, text="🍽️ Daftar Pesanan", + font=("Arial", 14, "bold")).pack(side='left') + + ttk.Button(header, text="🔄 Refresh", + command=lambda: self.build_waiter_pesanan_tab(parent)).pack(side='right', padx=5) + + info_frame = ttk.Frame(parent) + info_frame.pack(fill='x', padx=10, pady=5) + + pending_count = len([t for t in transaksi if t['status'] == 'Baru']) + proses_count = len([t for t in transaksi if t['status'] == 'Diproses']) + + ttk.Label(info_frame, text=f"📋 Pesanan Baru: {pending_count}", + font=("Arial", 10), foreground='red').pack(side='left', padx=20) + ttk.Label(info_frame, text=f"⏳ Sedang Diproses: {proses_count}", + font=("Arial", 10), foreground='orange').pack(side='left', padx=20) + + tree_frame = ttk.Frame(parent) + tree_frame.pack(fill='both', expand=True, padx=10, pady=5) + + tree_scroll = ttk.Scrollbar(tree_frame, orient='vertical') + tree_scroll.pack(side='right', fill='y') + + cols = ("ID", "Tanggal", "User", "Meja", "Total", "Status") + self.pesanan_tree = ttk.Treeview( + tree_frame, + columns=cols, + show='headings', + height=15, + yscrollcommand=tree_scroll.set + ) + + tree_scroll.config(command=self.pesanan_tree.yview) + + for c in cols: + self.pesanan_tree.heading(c, text=c) + if c == "ID": + self.pesanan_tree.column(c, width=50) + elif c == "Meja": + self.pesanan_tree.column(c, width=60) + elif c == "Total": + self.pesanan_tree.column(c, width=100) + else: + self.pesanan_tree.column(c, width=100) + + self.pesanan_tree.pack(side='left', fill='both', expand=True) + + for t in transaksi: + if t.get('payment_status') == 'Berhasil': + continue + + self.pesanan_tree.insert("", tk.END, values=( + t['id'], + t['tanggal'], + t['user'], + t.get('meja', '-'), + format_currency(t['total']), + t['status'] + )) + + action_frame = ttk.Frame(parent) + action_frame.pack(fill='x', padx=10, pady=10) + + ttk.Button(action_frame, text="✅ Proses Pesanan", + command=self.proses_pesanan, + width=20).pack(side='left', padx=5) + ttk.Button(action_frame, text="🍽️ Pesanan Siap", + command=self.siap_pesanan, + width=20).pack(side='left', padx=5) + ttk.Button(action_frame, text="📄 Lihat Detail", + command=self.detail_pesanan, + width=20).pack(side='left', padx=5) + + def proses_pesanan(self): + sel = self.pesanan_tree.selection() + if not sel: + messagebox.showwarning("Pilih Pesanan", "Pilih pesanan yang akan diproses") + return + + item = self.pesanan_tree.item(sel)['values'] + transaksi_id = item[0] + + for t in transaksi: + if t['id'] == transaksi_id: + if t['status'] != 'Baru': + messagebox.showinfo("Info", "Pesanan sudah diproses") + return + + t['status'] = 'Diproses' + save_transaksi() + add_notification("info", f"Pesanan #{t['id']} sedang diproses") + messagebox.showinfo("Success", f"Pesanan #{transaksi_id} sedang diproses") + self.build_waiter_pesanan_tab(self.pesanan_tree.master.master) + return + + def siap_pesanan(self): + sel = self.pesanan_tree.selection() + if not sel: + messagebox.showwarning("Pilih Pesanan", "Pilih pesanan yang sudah siap") + return + + item = self.pesanan_tree.item(sel)['values'] + transaksi_id = item[0] + + for t in transaksi: + if t['id'] == transaksi_id: + if t['status'] == 'Baru': + messagebox.showwarning("Warning", "Proses pesanan terlebih dahulu") + return + + if t['status'] == 'Siap': + messagebox.showinfo("Info", "Pesanan sudah ditandai siap") + return + + t['status'] = 'Siap' + save_transaksi() + add_notification("success", f"Pesanan #{t['id']} siap disajikan") + messagebox.showinfo("Success", f"Pesanan #{transaksi_id} siap disajikan!") + self.build_waiter_pesanan_tab(self.pesanan_tree.master.master) + return + + def detail_pesanan(self): + sel = self.pesanan_tree.selection() + if not sel: + messagebox.showwarning("Pilih Pesanan", "Pilih pesanan untuk melihat detail") + return + + item = self.pesanan_tree.item(sel)['values'] + transaksi_id = item[0] + + for t in transaksi: + if t['id'] == transaksi_id: + detail = f"═══════════════════════════════\n" + detail += f"DETAIL PESANAN #{t['id']}\n" + detail += f"═══════════════════════════════\n\n" + detail += f"Meja: {t.get('meja', '-')}\n" + detail += f"User: {t['user']}\n" + detail += f"Status: {t['status']}\n\n" + detail += f"ITEM PESANAN:\n" + detail += f"───────────────────────────────\n" + + for it in t['items']: + detail += f"• {it['nama']} x{it['qty']}\n" + + detail += f"───────────────────────────────\n" + detail += f"Total: {format_currency(t['total'])}\n" + detail += f"═══════════════════════════════\n" + + messagebox.showinfo(f"Detail Pesanan #{transaksi_id}", detail) + return + + # ================================ + # TAB: KELOLA MENU (Admin) + # ================================ + + def build_menu_manage_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + header = ttk.Frame(parent) + header.pack(fill='x', padx=10, pady=8) + + ttk.Label(header, text="⚙️ Kelola Menu", + font=("Arial", 14, "bold")).pack(side='left') + + ttk.Button(header, text="➕ Tambah Menu", + command=self.add_menu_dialog).pack(side='right', padx=5) + ttk.Button(header, text="🔄 Refresh", + command=lambda: self.build_menu_manage_tab(parent)).pack(side='right', padx=5) + + search_frame = ttk.LabelFrame(parent, text="🔍 Filter Menu", padding=10) + search_frame.pack(fill='x', padx=10, pady=5) + + search_inner = ttk.Frame(search_frame) + search_inner.pack() + + ttk.Label(search_inner, text="Kategori:").grid(row=0, column=0, padx=5) + self.menu_manage_filter_var = tk.StringVar(value="Semua") + categories = ["Semua"] + sorted(set(m['kategori'] for m in menu)) + ttk.Combobox(search_inner, textvariable=self.menu_manage_filter_var, + values=categories, state="readonly", width=15).grid(row=0, column=1, padx=5) + + ttk.Button(search_inner, text="🔍 Filter", + command=lambda: self.refresh_menu_manage_tree()).grid(row=0, column=2, padx=5) + + tree_frame = ttk.Frame(parent) + tree_frame.pack(fill='both', expand=True, padx=10, pady=5) + + tree_scroll = ttk.Scrollbar(tree_frame, orient='vertical') + tree_scroll.pack(side='right', fill='y') + + cols = ("ID", "Nama", "Harga", "Kategori", "Stok", "Promo", "Diskon%") + self.menu_manage_tree = ttk.Treeview( + tree_frame, + columns=cols, + show='headings', + height=12, + yscrollcommand=tree_scroll.set + ) + + tree_scroll.config(command=self.menu_manage_tree.yview) + + for c in cols: + self.menu_manage_tree.heading(c, text=c) + if c == "ID": + self.menu_manage_tree.column(c, width=40) + elif c == "Nama": + self.menu_manage_tree.column(c, width=150) + elif c == "Diskon%": + self.menu_manage_tree.column(c, width=60) + else: + self.menu_manage_tree.column(c, width=100) + + self.menu_manage_tree.pack(side='left', fill='both', expand=True) + + self.refresh_menu_manage_tree() + + action_frame = ttk.Frame(parent) + action_frame.pack(fill='x', padx=10, pady=10) + + ttk.Button(action_frame, text="✏️ Edit Menu", + command=self.edit_menu_dialog, + width=20).pack(side='left', padx=5) + ttk.Button(action_frame, text="📸 Upload Foto", + command=self.upload_menu_photo, + width=20).pack(side='left', padx=5) + ttk.Button(action_frame, text="🗑️ Hapus Menu", + command=self.delete_menu, + width=20).pack(side='left', padx=5) + + def refresh_menu_manage_tree(self): + for r in self.menu_manage_tree.get_children(): + self.menu_manage_tree.delete(r) + + filter_cat = self.menu_manage_filter_var.get() + + for m in menu: + if filter_cat != "Semua" and m['kategori'] != filter_cat: + continue + + self.menu_manage_tree.insert("", tk.END, values=( + m['id'], + m['nama'], + format_currency(m['harga']), + m['kategori'], + m['stok'], + m.get('promo', '-'), + f"{m.get('item_discount_pct', 0)}%" + )) + + def add_menu_dialog(self): + dialog = tk.Toplevel(self.root) + dialog.title("➕ Tambah Menu Baru") + dialog.geometry("450x500") + dialog.resizable(False, False) + + frame = ttk.Frame(dialog, padding=20) + frame.pack(fill='both', expand=True) + + ttk.Label(frame, text="Nama Menu:").grid(row=0, column=0, sticky='w', pady=8) + nama_entry = ttk.Entry(frame, width=30) + nama_entry.grid(row=0, column=1, pady=8) + + ttk.Label(frame, text="Harga:").grid(row=1, column=0, sticky='w', pady=8) + harga_entry = ttk.Entry(frame, width=30) + harga_entry.grid(row=1, column=1, pady=8) + + ttk.Label(frame, text="Kategori:").grid(row=2, column=0, sticky='w', pady=8) + kategori_var = tk.StringVar(value="Minuman") + ttk.Combobox(frame, textvariable=kategori_var, + values=["Minuman", "Makanan", "Snack", "Dessert"], + width=28).grid(row=2, column=1, pady=8) + + ttk.Label(frame, text="Stok Awal:").grid(row=3, column=0, sticky='w', pady=8) + stok_entry = ttk.Entry(frame, width=30) + stok_entry.insert(0, "10") + stok_entry.grid(row=3, column=1, pady=8) + + ttk.Label(frame, text="Promo Text:").grid(row=4, column=0, sticky='w', pady=8) + promo_entry = ttk.Entry(frame, width=30) + promo_entry.grid(row=4, column=1, pady=8) + + ttk.Label(frame, text="Diskon %:").grid(row=5, column=0, sticky='w', pady=8) + discount_entry = ttk.Entry(frame, width=30) + discount_entry.insert(0, "0") + discount_entry.grid(row=5, column=1, pady=8) + + def save_menu(): + nama = nama_entry.get().strip() + + try: + harga = int(harga_entry.get()) + stok = int(stok_entry.get()) + discount = float(discount_entry.get()) + except: + messagebox.showerror("Input Error", "Harga, Stok, dan Diskon harus angka") + return + + if not nama: + messagebox.showwarning("Input Error", "Nama menu harus diisi") + return + + new_id = max([m['id'] for m in menu], default=0) + 1 + + menu.append({ + 'id': new_id, + 'nama': nama, + 'harga': harga, + 'kategori': kategori_var.get(), + 'stok': stok, + 'foto': '', + 'promo': promo_entry.get().strip(), + 'item_discount_pct': discount + }) + + save_menu() + add_notification("success", f"Menu '{nama}' berhasil ditambahkan") + messagebox.showinfo("Success", f"Menu '{nama}' berhasil ditambahkan!") + dialog.destroy() + self.build_menu_manage_tab(self.menu_manage_tree.master.master) + + ttk.Button(frame, text="💾 Simpan", command=save_menu).grid(row=6, column=0, columnspan=2, pady=20) + + def edit_menu_dialog(self): + sel = self.menu_manage_tree.selection() + if not sel: + messagebox.showwarning("Pilih Menu", "Pilih menu yang akan diedit") + return + + item = self.menu_manage_tree.item(sel)['values'] + menu_id = item[0] + + menu_item = find_menu_by_id(menu_id) + if not menu_item: + return + + dialog = tk.Toplevel(self.root) + dialog.title(f"✏️ Edit Menu: {menu_item['nama']}") + dialog.geometry("450x500") + dialog.resizable(False, False) + + frame = ttk.Frame(dialog, padding=20) + frame.pack(fill='both', expand=True) + + ttk.Label(frame, text="Nama Menu:").grid(row=0, column=0, sticky='w', pady=8) + nama_entry = ttk.Entry(frame, width=30) + nama_entry.insert(0, menu_item['nama']) + nama_entry.grid(row=0, column=1, pady=8) + + ttk.Label(frame, text="Harga:").grid(row=1, column=0, sticky='w', pady=8) + harga_entry = ttk.Entry(frame, width=30) + harga_entry.insert(0, str(menu_item['harga'])) + harga_entry.grid(row=1, column=1, pady=8) + + ttk.Label(frame, text="Kategori:").grid(row=2, column=0, sticky='w', pady=8) + kategori_var = tk.StringVar(value=menu_item['kategori']) + ttk.Combobox(frame, textvariable=kategori_var, + values=["Minuman", "Makanan", "Snack", "Dessert"], + width=28).grid(row=2, column=1, pady=8) + + ttk.Label(frame, text="Stok:").grid(row=3, column=0, sticky='w', pady=8) + stok_entry = ttk.Entry(frame, width=30) + stok_entry.insert(0, str(menu_item['stok'])) + stok_entry.grid(row=3, column=1, pady=8) + + ttk.Label(frame, text="Promo Text:").grid(row=4, column=0, sticky='w', pady=8) + promo_entry = ttk.Entry(frame, width=30) + promo_entry.insert(0, menu_item.get('promo', '')) + promo_entry.grid(row=4, column=1, pady=8) + + ttk.Label(frame, text="Diskon %:").grid(row=5, column=0, sticky='w', pady=8) + discount_entry = ttk.Entry(frame, width=30) + discount_entry.insert(0, str(menu_item.get('item_discount_pct', 0))) + discount_entry.grid(row=5, column=1, pady=8) + + def update_menu(): + nama = nama_entry.get().strip() + + try: + harga = int(harga_entry.get()) + stok = int(stok_entry.get()) + discount = float(discount_entry.get()) + except: + messagebox.showerror("Input Error", "Harga, Stok, dan Diskon harus angka") + return + + if not nama: + messagebox.showwarning("Input Error", "Nama menu harus diisi") + return + + menu_item['nama'] = nama + menu_item['harga'] = harga + menu_item['kategori'] = kategori_var.get() + menu_item['stok'] = stok + menu_item['promo'] = promo_entry.get().strip() + menu_item['item_discount_pct'] = discount + + save_menu() + add_notification("info", f"Menu '{nama}' berhasil diupdate") + messagebox.showinfo("Success", "Menu berhasil diupdate!") + dialog.destroy() + self.build_menu_manage_tab(self.menu_manage_tree.master.master) + + ttk.Button(frame, text="💾 Update", command=update_menu).grid(row=6, column=0, columnspan=2, pady=20) + + def upload_menu_photo(self): + sel = self.menu_manage_tree.selection() + if not sel: + messagebox.showwarning("Pilih Menu", "Pilih menu untuk upload foto") + return + + item = self.menu_manage_tree.item(sel)['values'] + menu_id = item[0] + + menu_item = find_menu_by_id(menu_id) + if not menu_item: + return + + file_path = filedialog.askopenfilename( + title="Pilih Foto Menu", + filetypes=[("Image files", "*.jpg *.jpeg *.png *.gif *.bmp")] + ) + + if file_path: + new_path = copy_image_to_project(file_path) + if new_path: + menu_item['foto'] = new_path + save_menu() + messagebox.showinfo("Success", f"Foto berhasil diupload untuk '{menu_item['nama']}'") + self.build_menu_manage_tab(self.menu_manage_tree.master.master) + else: + messagebox.showerror("Error", "Gagal mengcopy foto") + + def delete_menu(self): + sel = self.menu_manage_tree.selection() + if not sel: + messagebox.showwarning("Pilih Menu", "Pilih menu yang akan dihapus") + return + + item = self.menu_manage_tree.item(sel)['values'] + menu_id = item[0] + + menu_item = find_menu_by_id(menu_id) + if not menu_item: + return + + confirm = messagebox.askyesno("Konfirmasi", f"Hapus menu '{menu_item['nama']}'?") + if not confirm: + return + + menu.remove(menu_item) + save_menu() + add_notification("warning", f"Menu '{menu_item['nama']}' dihapus") + messagebox.showinfo("Success", f"Menu '{menu_item['nama']}' berhasil dihapus") + self.build_menu_manage_tab(self.menu_manage_tree.master.master) + + # ================================ + # TAB: STOK BAHAN (Admin) + # ================================ + + def build_bahan_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + header = ttk.Frame(parent) + header.pack(fill='x', padx=10, pady=8) + + ttk.Label(header, text="📦 Kelola Stok Bahan", + font=("Arial", 14, "bold")).pack(side='left') + + ttk.Button(header, text="➕ Tambah Bahan", + command=self.add_bahan_dialog).pack(side='right', padx=5) + ttk.Button(header, text="🔄 Refresh", + command=lambda: self.build_bahan_tab(parent)).pack(side='right', padx=5) + + # Warning frame untuk stok rendah + low_stock = [name for name, qty in bahan.items() if qty < 10] + if low_stock: + warning_frame = ttk.Frame(parent) + warning_frame.pack(fill='x', padx=10, pady=5) + + tk.Label(warning_frame, + text=f"⚠️ PERINGATAN: {len(low_stock)} bahan dengan stok < 10!", + font=("Arial", 10, "bold"), + bg="#FFF3CD", fg="#856404", + padx=10, pady=8).pack(fill='x') + + # Container dengan 2 kolom + container = ttk.Frame(parent) + container.pack(fill='both', expand=True, padx=10, pady=5) + + # LEFT: Daftar Bahan + left_frame = ttk.LabelFrame(container, text="📋 Daftar Bahan Baku", padding=10) + left_frame.pack(side='left', fill='both', expand=True, padx=(0, 5)) + + tree_scroll = ttk.Scrollbar(left_frame, orient='vertical') + tree_scroll.pack(side='right', fill='y') + + cols = ("Nama Bahan", "Jumlah", "Status") + self.bahan_tree = ttk.Treeview( + left_frame, + columns=cols, + show='headings', + height=15, + yscrollcommand=tree_scroll.set + ) + + tree_scroll.config(command=self.bahan_tree.yview) + + self.bahan_tree.heading("Nama Bahan", text="Nama Bahan") + self.bahan_tree.heading("Jumlah", text="Jumlah") + self.bahan_tree.heading("Status", text="Status") + + self.bahan_tree.column("Nama Bahan", width=150) + self.bahan_tree.column("Jumlah", width=80) + self.bahan_tree.column("Status", width=100) + + self.bahan_tree.pack(side='left', fill='both', expand=True) + + for nama, qty in sorted(bahan.items()): + if qty < 10: + status = "🔴 Rendah" + elif qty < 20: + status = "🟡 Sedang" + else: + status = "🟢 Aman" + + self.bahan_tree.insert("", tk.END, values=(nama, qty, status)) + + action_frame = ttk.Frame(left_frame) + action_frame.pack(fill='x', pady=(10, 0)) + + ttk.Button(action_frame, text="➕ Tambah Stok", + command=self.add_stock_dialog, + width=18).pack(side='left', padx=3) + ttk.Button(action_frame, text="➖ Kurangi Stok", + command=self.reduce_stock_dialog, + width=18).pack(side='left', padx=3) + ttk.Button(action_frame, text="🗑️ Hapus Bahan", + command=self.delete_bahan, + width=18).pack(side='left', padx=3) + + # RIGHT: Resep Menu + right_frame = ttk.LabelFrame(container, text="📝 Resep Menu", padding=10) + right_frame.pack(side='right', fill='both', expand=True, padx=(5, 0)) + + ttk.Label(right_frame, text="Pilih Menu:", font=("Arial", 9, "bold")).pack(anchor='w', pady=5) + + menu_names = [f"{m['id']} - {m['nama']}" for m in menu] + self.resep_menu_var = tk.StringVar() + + menu_combo = ttk.Combobox(right_frame, textvariable=self.resep_menu_var, + values=menu_names, state="readonly", width=30) + menu_combo.pack(fill='x', pady=5) + menu_combo.bind("<>", lambda e: self.show_resep()) + + self.resep_text = tk.Text(right_frame, height=12, font=("Arial", 10), + wrap='word', state='disabled') + self.resep_text.pack(fill='both', expand=True, pady=5) + + ttk.Button(right_frame, text="✏️ Edit Resep", + command=self.edit_resep_dialog).pack(fill='x', pady=5) + + def show_resep(self): + selected = self.resep_menu_var.get() + if not selected: + return + + try: + menu_id = int(selected.split(' - ')[0]) + except: + return + + menu_item = find_menu_by_id(menu_id) + if not menu_item: + return + + self.resep_text.config(state='normal') + self.resep_text.delete('1.0', tk.END) + + text = f"═══════════════════════════════\n" + text += f"RESEP: {menu_item['nama']}\n" + text += f"═══════════════════════════════\n\n" + + if menu_id in resep and resep[menu_id]: + text += "Bahan yang dibutuhkan:\n\n" + for bahan_nama, qty in resep[menu_id].items(): + stok_tersedia = bahan.get(bahan_nama, 0) + text += f"• {bahan_nama}: {qty} unit\n" + text += f" (Stok tersedia: {stok_tersedia})\n\n" + else: + text += "❌ Belum ada resep untuk menu ini.\n\n" + text += "Klik 'Edit Resep' untuk menambahkan." + + self.resep_text.insert('1.0', text) + self.resep_text.config(state='disabled') + + def add_bahan_dialog(self): + dialog = tk.Toplevel(self.root) + dialog.title("➕ Tambah Bahan Baru") + dialog.geometry("400x250") + dialog.resizable(False, False) + + frame = ttk.Frame(dialog, padding=20) + frame.pack(fill='both', expand=True) + + ttk.Label(frame, text="Nama Bahan:").grid(row=0, column=0, sticky='w', pady=10) + nama_entry = ttk.Entry(frame, width=25) + nama_entry.grid(row=0, column=1, pady=10) + + ttk.Label(frame, text="Jumlah Awal:").grid(row=1, column=0, sticky='w', pady=10) + jumlah_entry = ttk.Entry(frame, width=25) + jumlah_entry.insert(0, "50") + jumlah_entry.grid(row=1, column=1, pady=10) + + def save_bahan(): + nama = nama_entry.get().strip().lower() + + try: + jumlah = int(jumlah_entry.get()) + except: + messagebox.showerror("Input Error", "Jumlah harus angka") + return + + if not nama: + messagebox.showwarning("Input Error", "Nama bahan harus diisi") + return + + if nama in bahan: + messagebox.showwarning("Sudah Ada", f"Bahan '{nama}' sudah ada") + return + + bahan[nama] = jumlah + save_bahan() + add_notification("success", f"Bahan '{nama}' berhasil ditambahkan") + messagebox.showinfo("Success", f"Bahan '{nama}' berhasil ditambahkan!") + dialog.destroy() + self.build_bahan_tab(self.bahan_tree.master.master.master) + + ttk.Button(frame, text="💾 Simpan", command=save_bahan).grid(row=2, column=0, columnspan=2, pady=20) + + def add_stock_dialog(self): + sel = self.bahan_tree.selection() + if not sel: + messagebox.showwarning("Pilih Bahan", "Pilih bahan untuk menambah stok") + return + + item = self.bahan_tree.item(sel)['values'] + nama_bahan = item[0] + + qty = simpledialog.askinteger("Tambah Stok", + f"Tambah berapa unit untuk '{nama_bahan}'?", + minvalue=1) + + if qty: + bahan[nama_bahan] += qty + save_bahan() + add_notification("info", f"Stok {nama_bahan} ditambah {qty} unit") + messagebox.showinfo("Success", f"Stok '{nama_bahan}' berhasil ditambahkan!") + self.build_bahan_tab(self.bahan_tree.master.master.master) + + def reduce_stock_dialog(self): + sel = self.bahan_tree.selection() + if not sel: + messagebox.showwarning("Pilih Bahan", "Pilih bahan untuk mengurangi stok") + return + + item = self.bahan_tree.item(sel)['values'] + nama_bahan = item[0] + stok_sekarang = bahan.get(nama_bahan, 0) + + qty = simpledialog.askinteger("Kurangi Stok", + f"Kurangi berapa unit dari '{nama_bahan}'?\n(Stok sekarang: {stok_sekarang})", + minvalue=1, maxvalue=stok_sekarang) + + if qty: + bahan[nama_bahan] -= qty + if bahan[nama_bahan] < 0: + bahan[nama_bahan] = 0 + + save_bahan() + add_notification("warning", f"Stok {nama_bahan} dikurangi {qty} unit") + messagebox.showinfo("Success", f"Stok '{nama_bahan}' berhasil dikurangi!") + self.build_bahan_tab(self.bahan_tree.master.master.master) + + def delete_bahan(self): + sel = self.bahan_tree.selection() + if not sel: + messagebox.showwarning("Pilih Bahan", "Pilih bahan yang akan dihapus") + return + + item = self.bahan_tree.item(sel)['values'] + nama_bahan = item[0] + + # Check if used in recipe + used_in = [] + for menu_id, ingredients in resep.items(): + if nama_bahan in ingredients: + menu_item = find_menu_by_id(menu_id) + if menu_item: + used_in.append(menu_item['nama']) + + if used_in: + messagebox.showwarning("Tidak Bisa Dihapus", + f"Bahan '{nama_bahan}' digunakan di resep:\n" + "\n".join(used_in)) + return + + confirm = messagebox.askyesno("Konfirmasi", f"Hapus bahan '{nama_bahan}'?") + if not confirm: + return + + del bahan[nama_bahan] + save_bahan() + add_notification("warning", f"Bahan '{nama_bahan}' dihapus") + messagebox.showinfo("Success", f"Bahan '{nama_bahan}' berhasil dihapus") + self.build_bahan_tab(self.bahan_tree.master.master.master) + + def edit_resep_dialog(self): + selected = self.resep_menu_var.get() + if not selected: + messagebox.showwarning("Pilih Menu", "Pilih menu terlebih dahulu") + return + + try: + menu_id = int(selected.split(' - ')[0]) + except: + return + + menu_item = find_menu_by_id(menu_id) + if not menu_item: + return + + dialog = tk.Toplevel(self.root) + dialog.title(f"✏️ Edit Resep: {menu_item['nama']}") + dialog.geometry("500x500") + dialog.resizable(False, False) + + frame = ttk.Frame(dialog, padding=20) + frame.pack(fill='both', expand=True) + + ttk.Label(frame, text=f"Resep untuk: {menu_item['nama']}", + font=("Arial", 12, "bold")).pack(pady=10) + + # Frame untuk resep entries + resep_frame = ttk.Frame(frame) + resep_frame.pack(fill='both', expand=True, pady=10) + + # Canvas + Scrollbar untuk banyak bahan + canvas = tk.Canvas(resep_frame, height=300) + scrollbar = ttk.Scrollbar(resep_frame, orient="vertical", command=canvas.yview) + scrollable_frame = ttk.Frame(canvas) + + scrollable_frame.bind( + "", + lambda e: canvas.configure(scrollregion=canvas.bbox("all")) + ) + + canvas.create_window((0, 0), window=scrollable_frame, anchor="nw") + canvas.configure(yscrollcommand=scrollbar.set) + + canvas.pack(side="left", fill="both", expand=True) + scrollbar.pack(side="right", fill="y") + + # Get current recipe + current_resep = resep.get(menu_id, {}) + + # Buat entry untuk setiap bahan yang ada + entries = {} + row = 0 + + for bahan_nama in sorted(bahan.keys()): + ttk.Label(scrollable_frame, text=f"{bahan_nama}:").grid(row=row, column=0, sticky='w', padx=5, pady=5) + + qty_entry = ttk.Entry(scrollable_frame, width=10) + qty_entry.insert(0, str(current_resep.get(bahan_nama, 0))) + qty_entry.grid(row=row, column=1, padx=5, pady=5) + + ttk.Label(scrollable_frame, text="unit").grid(row=row, column=2, sticky='w', padx=5, pady=5) + + entries[bahan_nama] = qty_entry + row += 1 + + def save_resep(): + new_resep = {} + + for bahan_nama, entry in entries.items(): + try: + qty = int(entry.get()) + if qty > 0: + new_resep[bahan_nama] = qty + except: + pass + + if not new_resep: + confirm = messagebox.askyesno("Konfirmasi", "Resep kosong. Hapus resep untuk menu ini?") + if confirm and menu_id in resep: + del resep[menu_id] + else: + resep[menu_id] = new_resep + + save_resep() + add_notification("info", f"Resep '{menu_item['nama']}' berhasil diupdate") + messagebox.showinfo("Success", "Resep berhasil disimpan!") + dialog.destroy() + self.show_resep() + + ttk.Button(frame, text="💾 Simpan Resep", command=save_resep).pack(pady=10) + + # ================================ + # TAB: PROMO (Admin) + # ================================ + + def build_promo_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + header = ttk.Frame(parent) + header.pack(fill='x', padx=10, pady=8) + + ttk.Label(header, text="🎁 Kelola Kode Promo", + font=("Arial", 14, "bold")).pack(side='left') + + ttk.Button(header, text="➕ Tambah Promo", + command=self.add_promo_dialog).pack(side='right', padx=5) + ttk.Button(header, text="🔄 Refresh", + command=lambda: self.build_promo_tab(parent)).pack(side='right', padx=5) + + info_frame = ttk.Frame(parent) + info_frame.pack(fill='x', padx=10, pady=5) + + tk.Label(info_frame, + text=f"📊 Total Kode Promo Aktif: {len(promo_codes)}", + font=("Arial", 10, "bold"), + bg="#E3F2FD", fg="#1565C0", + padx=15, pady=8).pack(fill='x') + + # Promo Code List + list_frame = ttk.LabelFrame(parent, text="📋 Daftar Kode Promo", padding=10) + list_frame.pack(fill='both', expand=True, padx=10, pady=5) + + tree_scroll = ttk.Scrollbar(list_frame, orient='vertical') + tree_scroll.pack(side='right', fill='y') + + cols = ("Kode Promo", "Diskon %", "Status") + self.promo_tree = ttk.Treeview( + list_frame, + columns=cols, + show='headings', + height=12, + yscrollcommand=tree_scroll.set + ) + + tree_scroll.config(command=self.promo_tree.yview) + + self.promo_tree.heading("Kode Promo", text="Kode Promo") + self.promo_tree.heading("Diskon %", text="Diskon %") + self.promo_tree.heading("Status", text="Status") + + self.promo_tree.column("Kode Promo", width=200) + self.promo_tree.column("Diskon %", width=100) + self.promo_tree.column("Status", width=150) + + self.promo_tree.pack(side='left', fill='both', expand=True) + + for code, discount in sorted(promo_codes.items()): + self.promo_tree.insert("", tk.END, values=( + code, + f"{discount}%", + "✅ Aktif" + )) + + # Action buttons + action_frame = ttk.Frame(list_frame) + action_frame.pack(fill='x', pady=(10, 0)) + + ttk.Button(action_frame, text="✏️ Edit Promo", + command=self.edit_promo_dialog, + width=20).pack(side='left', padx=5) + ttk.Button(action_frame, text="🗑️ Hapus Promo", + command=self.delete_promo, + width=20).pack(side='left', padx=5) + ttk.Button(action_frame, text="📋 Salin Kode", + command=self.copy_promo_code, + width=20).pack(side='left', padx=5) + + # Info box + info_box = ttk.LabelFrame(parent, text="ℹ️ Informasi", padding=10) + info_box.pack(fill='x', padx=10, pady=5) + + info_text = """ +- Kode promo dapat digunakan oleh pembeli saat checkout +- Diskon promo diterapkan setelah diskon item +- Kode promo tidak case-sensitive (CAFE10 = cafe10) +- Gunakan kode yang mudah diingat untuk pelanggan + """ + + ttk.Label(info_box, text=info_text, font=("Arial", 9), + foreground='#666666', justify='left').pack(anchor='w') + + def add_promo_dialog(self): + dialog = tk.Toplevel(self.root) + dialog.title("➕ Tambah Kode Promo Baru") + dialog.geometry("450x300") + dialog.resizable(False, False) + + frame = ttk.Frame(dialog, padding=20) + frame.pack(fill='both', expand=True) + + ttk.Label(frame, text="Kode Promo:", font=("Arial", 10, "bold")).grid(row=0, column=0, sticky='w', pady=10) + ttk.Label(frame, text="(Huruf kapital, tanpa spasi)").grid(row=1, column=0, sticky='w', pady=(0, 10)) + code_entry = ttk.Entry(frame, width=30, font=("Arial", 11)) + code_entry.grid(row=0, column=1, rowspan=2, pady=10, padx=10) + + ttk.Label(frame, text="Diskon (%):", font=("Arial", 10, "bold")).grid(row=2, column=0, sticky='w', pady=10) + discount_entry = ttk.Entry(frame, width=30) + discount_entry.grid(row=2, column=1, pady=10, padx=10) + + ttk.Label(frame, text="Contoh: CAFE10, DISKON20, WELCOME15", + font=("Arial", 9), foreground='gray').grid(row=3, column=0, columnspan=2, pady=5) + + def save_promo(): + code = code_entry.get().strip().upper() + + try: + discount = int(discount_entry.get()) + except: + messagebox.showerror("Input Error", "Diskon harus angka") + return + + if not code: + messagebox.showwarning("Input Error", "Kode promo harus diisi") + return + + if ' ' in code: + messagebox.showwarning("Input Error", "Kode promo tidak boleh mengandung spasi") + return + + if discount < 1 or discount > 100: + messagebox.showwarning("Input Error", "Diskon harus antara 1-100%") + return + + if code in promo_codes: + messagebox.showwarning("Sudah Ada", f"Kode promo '{code}' sudah ada") + return + + promo_codes[code] = discount + save_promo_codes() + add_notification("success", f"Kode promo '{code}' berhasil ditambahkan") + messagebox.showinfo("Success", f"✅ Kode promo '{code}' berhasil dibuat!\n\nDiskon: {discount}%") + dialog.destroy() + self.build_promo_tab(self.promo_tree.master.master) + + ttk.Button(frame, text="💾 Simpan Promo", command=save_promo).grid(row=4, column=0, columnspan=2, pady=20) + + def edit_promo_dialog(self): + sel = self.promo_tree.selection() + if not sel: + messagebox.showwarning("Pilih Promo", "Pilih kode promo yang akan diedit") + return + + item = self.promo_tree.item(sel)['values'] + code = item[0] + current_discount = promo_codes.get(code, 0) + + dialog = tk.Toplevel(self.root) + dialog.title(f"✏️ Edit Kode Promo: {code}") + dialog.geometry("450x250") + dialog.resizable(False, False) + + frame = ttk.Frame(dialog, padding=20) + frame.pack(fill='both', expand=True) + + ttk.Label(frame, text="Kode Promo:", font=("Arial", 10, "bold")).grid(row=0, column=0, sticky='w', pady=10) + code_label = ttk.Label(frame, text=code, font=("Arial", 12, "bold"), foreground='#1565C0') + code_label.grid(row=0, column=1, pady=10, padx=10, sticky='w') + + ttk.Label(frame, text="Diskon Baru (%):", font=("Arial", 10, "bold")).grid(row=1, column=0, sticky='w', pady=10) + discount_entry = ttk.Entry(frame, width=30) + discount_entry.insert(0, str(current_discount)) + discount_entry.grid(row=1, column=1, pady=10, padx=10) + + def update_promo(): + try: + discount = int(discount_entry.get()) + except: + messagebox.showerror("Input Error", "Diskon harus angka") + return + + if discount < 1 or discount > 100: + messagebox.showwarning("Input Error", "Diskon harus antara 1-100%") + return + + promo_codes[code] = discount + save_promo_codes() + add_notification("info", f"Kode promo '{code}' diupdate menjadi {discount}%") + messagebox.showinfo("Success", f"✅ Kode promo '{code}' berhasil diupdate!") + dialog.destroy() + self.build_promo_tab(self.promo_tree.master.master) + + ttk.Button(frame, text="💾 Update", command=update_promo).grid(row=2, column=0, columnspan=2, pady=20) + + def delete_promo(self): + sel = self.promo_tree.selection() + if not sel: + messagebox.showwarning("Pilih Promo", "Pilih kode promo yang akan dihapus") + return + + item = self.promo_tree.item(sel)['values'] + code = item[0] + + confirm = messagebox.askyesno("Konfirmasi", f"Hapus kode promo '{code}'?") + if not confirm: + return + + del promo_codes[code] + save_promo_codes() + add_notification("warning", f"Kode promo '{code}' dihapus") + messagebox.showinfo("Success", f"Kode promo '{code}' berhasil dihapus") + self.build_promo_tab(self.promo_tree.master.master) + + def copy_promo_code(self): + sel = self.promo_tree.selection() + if not sel: + messagebox.showwarning("Pilih Promo", "Pilih kode promo yang akan disalin") + return + + item = self.promo_tree.item(sel)['values'] + code = item[0] + + self.root.clipboard_clear() + self.root.clipboard_append(code) + messagebox.showinfo("Tersalin", f"✅ Kode promo '{code}' berhasil disalin ke clipboard!") + + # ================================ + # TAB: LAPORAN (Owner/Admin) + # ================================ + + def build_laporan_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + header = ttk.Frame(parent) + header.pack(fill='x', padx=10, pady=8) + + ttk.Label(header, text="📊 Laporan & Analisis", + font=("Arial", 14, "bold")).pack(side='left') + + ttk.Button(header, text="🔄 Refresh", + command=lambda: self.build_laporan_tab(parent)).pack(side='right', padx=5) + ttk.Button(header, text="📥 Export Excel", + command=self.export_laporan_excel).pack(side='right', padx=5) + + # Period selector + period_frame = ttk.LabelFrame(parent, text="📅 Pilih Periode Laporan", padding=10) + period_frame.pack(fill='x', padx=10, pady=5) + + period_inner = ttk.Frame(period_frame) + period_inner.pack() + + ttk.Label(period_inner, text="Dari:").grid(row=0, column=0, padx=5) + self.laporan_start_date = tk.StringVar(value=str(datetime.date.today())) + ttk.Entry(period_inner, textvariable=self.laporan_start_date, width=15).grid(row=0, column=1, padx=5) + + ttk.Label(period_inner, text="Sampai:").grid(row=0, column=2, padx=5) + self.laporan_end_date = tk.StringVar(value=str(datetime.date.today())) + ttk.Entry(period_inner, textvariable=self.laporan_end_date, width=15).grid(row=0, column=3, padx=5) + + ttk.Button(period_inner, text="📊 Tampilkan", + command=self.refresh_laporan).grid(row=0, column=4, padx=10) + + # Quick filters + quick_frame = ttk.Frame(period_frame) + quick_frame.pack(pady=5) + + ttk.Button(quick_frame, text="📅 Hari Ini", + command=lambda: self.set_period_today()).pack(side='left', padx=3) + ttk.Button(quick_frame, text="📆 Minggu Ini", + command=lambda: self.set_period_week()).pack(side='left', padx=3) + ttk.Button(quick_frame, text="📊 Bulan Ini", + command=lambda: self.set_period_month()).pack(side='left', padx=3) + + # Main container with tabs + notebook = ttk.Notebook(parent) + notebook.pack(fill='both', expand=True, padx=10, pady=5) + + # Tab 1: Dashboard + tab_dashboard = ttk.Frame(notebook) + notebook.add(tab_dashboard, text="📊 Dashboard") + self.build_dashboard_tab(tab_dashboard) + + # Tab 2: Detail Transaksi + tab_detail = ttk.Frame(notebook) + notebook.add(tab_detail, text="📋 Detail Transaksi") + self.build_detail_transaksi_tab(tab_detail) + + # Tab 3: Menu Analytics + tab_menu = ttk.Frame(notebook) + notebook.add(tab_menu, text="🍽️ Analisis Menu") + self.build_menu_analytics_tab(tab_menu) + + # Tab 4: Payment Analytics + tab_payment = ttk.Frame(notebook) + notebook.add(tab_payment, text="💳 Analisis Pembayaran") + self.build_payment_analytics_tab(tab_payment) + + def set_period_today(self): + today = str(datetime.date.today()) + self.laporan_start_date.set(today) + self.laporan_end_date.set(today) + self.refresh_laporan() + + def set_period_week(self): + today = datetime.date.today() + start = today - datetime.timedelta(days=today.weekday()) + self.laporan_start_date.set(str(start)) + self.laporan_end_date.set(str(today)) + self.refresh_laporan() + + def set_period_month(self): + today = datetime.date.today() + start = today.replace(day=1) + self.laporan_start_date.set(str(start)) + self.laporan_end_date.set(str(today)) + self.refresh_laporan() + + def refresh_laporan(self): + # Rebuild all tabs + notebook = None + for widget in self.root.winfo_children(): + if isinstance(widget, ttk.Notebook): + for tab in widget.winfo_children(): + if isinstance(tab, ttk.Notebook): + notebook = tab + break + + if notebook: + for i, tab in enumerate(notebook.winfo_children()): + if i == 0: + self.build_dashboard_tab(tab) + elif i == 1: + self.build_detail_transaksi_tab(tab) + elif i == 2: + self.build_menu_analytics_tab(tab) + elif i == 3: + self.build_payment_analytics_tab(tab) + + def get_filtered_transactions(self): + start_date = self.laporan_start_date.get() + end_date = self.laporan_end_date.get() + + return [t for t in transaksi + if start_date <= t['tanggal'] <= end_date + and t.get('payment_status') == 'Berhasil'] + + def build_dashboard_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + trans = self.get_filtered_transactions() + + # Summary Cards + summary_frame = ttk.Frame(parent) + summary_frame.pack(fill='x', padx=10, pady=10) + + # Card 1: Total Pendapatan + card1 = tk.Frame(summary_frame, bg='#4CAF50', relief='solid', bd=1) + card1.pack(side='left', fill='both', expand=True, padx=5) + + total_income = sum(t['total'] for t in trans) + + tk.Label(card1, text="💰", font=("Arial", 32), bg='#4CAF50', fg='white').pack(pady=(15, 5)) + tk.Label(card1, text="Total Pendapatan", font=("Arial", 11), bg='#4CAF50', fg='white').pack() + tk.Label(card1, text=format_currency(total_income), + font=("Arial", 18, "bold"), bg='#4CAF50', fg='white').pack(pady=(5, 15)) + + # Card 2: Total Transaksi + card2 = tk.Frame(summary_frame, bg='#2196F3', relief='solid', bd=1) + card2.pack(side='left', fill='both', expand=True, padx=5) + + tk.Label(card2, text="📋", font=("Arial", 32), bg='#2196F3', fg='white').pack(pady=(15, 5)) + tk.Label(card2, text="Total Transaksi", font=("Arial", 11), bg='#2196F3', fg='white').pack() + tk.Label(card2, text=str(len(trans)), + font=("Arial", 18, "bold"), bg='#2196F3', fg='white').pack(pady=(5, 15)) + + # Card 3: Rata-rata + card3 = tk.Frame(summary_frame, bg='#FF9800', relief='solid', bd=1) + card3.pack(side='left', fill='both', expand=True, padx=5) + + avg_trans = total_income // len(trans) if trans else 0 + + tk.Label(card3, text="📊", font=("Arial", 32), bg='#FF9800', fg='white').pack(pady=(15, 5)) + tk.Label(card3, text="Rata-rata/Transaksi", font=("Arial", 11), bg='#FF9800', fg='white').pack() + tk.Label(card3, text=format_currency(avg_trans), + font=("Arial", 18, "bold"), bg='#FF9800', fg='white').pack(pady=(5, 15)) + + # Card 4: Menu Terjual + card4 = tk.Frame(summary_frame, bg='#9C27B0', relief='solid', bd=1) + card4.pack(side='left', fill='both', expand=True, padx=5) + + total_items = sum(sum(item['qty'] for item in t['items']) for t in trans) + + tk.Label(card4, text="🍽️", font=("Arial", 32), bg='#9C27B0', fg='white').pack(pady=(15, 5)) + tk.Label(card4, text="Total Item Terjual", font=("Arial", 11), bg='#9C27B0', fg='white').pack() + tk.Label(card4, text=str(total_items), + font=("Arial", 18, "bold"), bg='#9C27B0', fg='white').pack(pady=(5, 15)) + + # Chart Section + chart_frame = ttk.LabelFrame(parent, text="📈 Grafik Penjualan", padding=10) + chart_frame.pack(fill='both', expand=True, padx=10, pady=5) + + if MATPLOTLIB_AVAILABLE and trans: + self.create_sales_chart(chart_frame, trans) + else: + tk.Label(chart_frame, + text="📊 Chart membutuhkan matplotlib\nInstall: pip install matplotlib", + font=("Arial", 12), fg='gray').pack(pady=50) + + # Top Menu Section + top_frame = ttk.LabelFrame(parent, text="🏆 Top 5 Menu Terlaris", padding=10) + top_frame.pack(fill='x', padx=10, pady=5) + + menu_sales = defaultdict(int) + for t in trans: + for item in t['items']: + menu_sales[item['nama']] += item['qty'] + + top_menu = sorted(menu_sales.items(), key=lambda x: x[1], reverse=True)[:5] + + if top_menu: + for i, (nama, qty) in enumerate(top_menu, 1): + rank_frame = tk.Frame(top_frame, bg='white', relief='solid', bd=1) + rank_frame.pack(fill='x', pady=3) + + medal = ['🥇', '🥈', '🥉', '4️⃣', '5️⃣'][i-1] + + tk.Label(rank_frame, text=f"{medal} {nama}", + font=("Arial", 11, "bold"), bg='white', anchor='w').pack(side='left', padx=10, pady=8) + tk.Label(rank_frame, text=f"{qty} terjual", + font=("Arial", 10), bg='white', fg='green', anchor='e').pack(side='right', padx=10, pady=8) + else: + tk.Label(top_frame, text="Belum ada data", fg='gray').pack(pady=10) + + def create_sales_chart(self, parent, transactions): + """Buat multiple charts untuk visualisasi data penjualan""" + if not MATPLOTLIB_AVAILABLE or not transactions: + tk.Label(parent, text="📊 Chart data tidak tersedia", fg='gray').pack(pady=20) + return + + today = str(datetime.date.today()) + + fig = Figure(figsize=(16, 10), dpi=80) + + # Chart 1: Daily Sales (Bar Chart) + ax1 = fig.add_subplot(3, 3, 1) + daily_sales = defaultdict(int) + for t in transactions: + daily_sales[t['tanggal']] += t['total'] + + dates = sorted(daily_sales.keys()) + sales = [daily_sales[d] for d in dates] + ax1.bar(dates, sales, color='#4CAF50', alpha=0.8) + ax1.set_title('📊 Penjualan Harian', fontweight='bold', fontsize=10) + ax1.set_ylabel('Pendapatan (Rp)', fontsize=9) + ax1.tick_params(axis='x', rotation=45) + ax1.grid(True, alpha=0.3, axis='y') + + # Chart 2: Payment Methods (Pie Chart) + ax2 = fig.add_subplot(3, 3, 2) + payment_methods = defaultdict(int) + for t in transactions: + method = t.get('payment_method', 'Unknown') + payment_methods[method] += t['total'] + + colors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#FFA726'] + ax2.pie(payment_methods.values(), labels=payment_methods.keys(), autopct='%1.1f%%', + colors=colors[:len(payment_methods)], startangle=90) + ax2.set_title('💳 Metode Pembayaran (Total)', fontweight='bold', fontsize=10) + + # Chart 3: Top 5 Menu (Bar Chart Horizontal) + ax3 = fig.add_subplot(3, 3, 3) + menu_sales = defaultdict(int) + for t in transactions: + for item in t['items']: + menu_sales[item['nama']] += item['qty'] + + top_menus = dict(sorted(menu_sales.items(), key=lambda x: x[1], reverse=True)[:5]) + if top_menus: + ax3.barh(list(top_menus.keys()), list(top_menus.values()), color='#FFA726', alpha=0.8) + ax3.set_title('🍽️ Menu Top 5', fontweight='bold', fontsize=10) + ax3.set_xlabel('Jumlah Terjual', fontsize=9) + + # Chart 4: Cumulative Revenue + ax4 = fig.add_subplot(3, 3, 4) + cumulative = 0 + cum_values = [] + for d in dates: + cumulative += daily_sales[d] + cum_values.append(cumulative) + + ax4.plot(dates, cum_values, marker='o', linewidth=2, markersize=6, color='#2196F3') + ax4.fill_between(range(len(dates)), cum_values, alpha=0.3, color='#2196F3') + ax4.set_title('📈 Kumulatif Pendapatan', fontweight='bold', fontsize=10) + ax4.set_ylabel('Total (Rp)', fontsize=9) + ax4.tick_params(axis='x', rotation=45) + ax4.grid(True, alpha=0.3) + + # Chart 5: Transaction Count per Day + ax5 = fig.add_subplot(3, 3, 5) + daily_count = defaultdict(int) + for t in transactions: + daily_count[t['tanggal']] += 1 + + counts = [daily_count[d] for d in dates] + ax5.bar(dates, counts, color='#9C27B0', alpha=0.8) + ax5.set_title('📊 Jumlah Transaksi per Hari', fontweight='bold', fontsize=10) + ax5.set_ylabel('Jumlah Transaksi', fontsize=9) + ax5.tick_params(axis='x', rotation=45) + ax5.grid(True, alpha=0.3, axis='y') + + # Chart 6: Average Transaction Value + ax6 = fig.add_subplot(3, 3, 6) + daily_avg = [] + for d in dates: + trans_on_day = [t['total'] for t in transactions if t['tanggal'] == d] + avg = sum(trans_on_day) / len(trans_on_day) if trans_on_day else 0 + daily_avg.append(avg) + + ax6.plot(dates, daily_avg, marker='s', linewidth=2, markersize=5, color='#4CAF50') + ax6.set_title('💵 Rata-rata Transaksi', fontweight='bold', fontsize=10) + ax6.set_ylabel('Nilai Rata-rata (Rp)', fontsize=9) + ax6.tick_params(axis='x', rotation=45) + ax6.grid(True, alpha=0.3) + + # Chart 7: Hari Ini - Pendapatan QRIS vs CASH (Pie Chart) + ax7 = fig.add_subplot(3, 3, 7) + today_trans = [t for t in transactions if t['tanggal'] == today] + qris_cash = defaultdict(int) + for t in today_trans: + method = t.get('payment_method', 'Unknown') + if method: + method_lower = method.lower() + if method_lower == 'qris': + qris_cash['QRIS'] += t['total'] + elif method_lower == 'cash': + qris_cash['CASH'] += t['total'] + else: + qris_cash[method] += t['total'] + + if qris_cash and sum(qris_cash.values()) > 0: + colors_qris = ['#FF6B6B', '#4CAF50', '#2196F3', '#FFA726'] + labels_pie = [f"{k}: Rp {int(v):,}" for k, v in qris_cash.items()] + ax7.pie(qris_cash.values(), labels=labels_pie, + autopct='%1.1f%%', colors=colors_qris[:len(qris_cash)], startangle=90) + ax7.set_title(f'💳 Pendapatan Hari Ini ({today})', fontweight='bold', fontsize=10) + else: + ax7.text(0.5, 0.5, 'Tidak ada transaksi hari ini', ha='center', va='center', fontsize=10) + ax7.set_title(f'💳 Pendapatan Hari Ini ({today})', fontweight='bold', fontsize=10) + + # Chart 8: Hari Ini - Jumlah Transaksi QRIS vs CASH (Bar Chart) + ax8 = fig.add_subplot(3, 3, 8) + qris_cash_count = defaultdict(int) + for t in today_trans: + method = t.get('payment_method', 'Unknown') + if method: + method_lower = method.lower() + if method_lower == 'qris': + qris_cash_count['QRIS'] += 1 + elif method_lower == 'cash': + qris_cash_count['CASH'] += 1 + else: + qris_cash_count[method] += 1 + + if qris_cash_count and len(today_trans) > 0: + methods = list(qris_cash_count.keys()) + counts_qris = list(qris_cash_count.values()) + colors_bar = ['#FF6B6B', '#4CAF50', '#2196F3', '#FFA726'] + ax8.bar(methods, counts_qris, color=colors_bar[:len(methods)], alpha=0.8) + ax8.set_title('📊 Jumlah Transaksi Hari Ini', fontweight='bold', fontsize=10) + ax8.set_ylabel('Jumlah Transaksi', fontsize=9) + ax8.grid(True, alpha=0.3, axis='y') + else: + ax8.text(0.5, 0.5, 'Tidak ada transaksi hari ini', ha='center', va='center', fontsize=10) + ax8.set_title('📊 Jumlah Transaksi Hari Ini', fontweight='bold', fontsize=10) + + # Chart 9: Hari Ini - Rata-rata per Metode (Bar Chart) + ax9 = fig.add_subplot(3, 3, 9) + qris_cash_avg = defaultdict(lambda: {'total': 0, 'count': 0}) + for t in today_trans: + method = t.get('payment_method', 'Unknown') + if method: + method_lower = method.lower() + if method_lower == 'qris': + qris_cash_avg['QRIS']['total'] += t['total'] + qris_cash_avg['QRIS']['count'] += 1 + elif method_lower == 'cash': + qris_cash_avg['CASH']['total'] += t['total'] + qris_cash_avg['CASH']['count'] += 1 + else: + qris_cash_avg[method]['total'] += t['total'] + qris_cash_avg[method]['count'] += 1 + + if qris_cash_avg and len(today_trans) > 0: + methods_avg = list(qris_cash_avg.keys()) + avg_values = [qris_cash_avg[m]['total'] / qris_cash_avg[m]['count'] if qris_cash_avg[m]['count'] > 0 else 0 for m in methods_avg] + colors_bar = ['#FF6B6B', '#4CAF50', '#2196F3', '#FFA726'] + ax9.bar(methods_avg, avg_values, color=colors_bar[:len(methods_avg)], alpha=0.8) + ax9.set_title('💵 Rata-rata per Metode Hari Ini', fontweight='bold', fontsize=10) + ax9.set_ylabel('Nilai Rata-rata (Rp)', fontsize=9) + ax9.grid(True, alpha=0.3, axis='y') + else: + ax9.text(0.5, 0.5, 'Tidak ada transaksi hari ini', ha='center', va='center', fontsize=10) + ax9.set_title('💵 Rata-rata per Metode Hari Ini', fontweight='bold', fontsize=10) + + fig.tight_layout() + + canvas = FigureCanvasTkAgg(fig, master=parent) + canvas.draw() + canvas.get_tk_widget().pack(fill='both', expand=True) + + def build_detail_transaksi_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + trans = self.get_filtered_transactions() + + info_frame = ttk.Frame(parent) + info_frame.pack(fill='x', padx=10, pady=5) + + ttk.Label(info_frame, text=f"📋 Menampilkan {len(trans)} transaksi", + font=("Arial", 10, "bold")).pack(side='left') + + tree_frame = ttk.Frame(parent) + tree_frame.pack(fill='both', expand=True, padx=10, pady=5) + + tree_scroll_y = ttk.Scrollbar(tree_frame, orient='vertical') + tree_scroll_y.pack(side='right', fill='y') + + tree_scroll_x = ttk.Scrollbar(tree_frame, orient='horizontal') + tree_scroll_x.pack(side='bottom', fill='x') + + cols = ("ID", "Tanggal", "Waktu", "User", "Meja", "Items", "Subtotal", "Diskon", "Total", "Metode", "Promo") + detail_tree = ttk.Treeview( + tree_frame, + columns=cols, + show='headings', + height=15, + yscrollcommand=tree_scroll_y.set, + xscrollcommand=tree_scroll_x.set + ) + + tree_scroll_y.config(command=detail_tree.yview) + tree_scroll_x.config(command=detail_tree.xview) + + for c in cols: + detail_tree.heading(c, text=c) + if c in ["ID", "Meja"]: + detail_tree.column(c, width=50) + elif c in ["Subtotal", "Diskon", "Total"]: + detail_tree.column(c, width=100) + elif c == "Items": + detail_tree.column(c, width=200) + else: + detail_tree.column(c, width=100) + + detail_tree.pack(side='left', fill='both', expand=True) + + for t in reversed(trans): + items_str = ", ".join([f"{it['nama']}({it['qty']})" for it in t['items']]) + + detail_tree.insert("", tk.END, values=( + t['id'], + t['tanggal'], + t['waktu'].strftime('%H:%M'), + t['user'], + t.get('meja', '-'), + items_str, + format_currency(t['subtotal']), + format_currency(t['diskon']), + format_currency(t['total']), + t.get('payment_method', '-'), + t.get('promo_code', '-') + )) + + def build_menu_analytics_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + trans = self.get_filtered_transactions() + + # Calculate menu statistics + menu_stats = defaultdict(lambda: {'qty': 0, 'revenue': 0}) + + for t in trans: + for item in t['items']: + menu_stats[item['nama']]['qty'] += item['qty'] + menu_stats[item['nama']]['revenue'] += item['subtotal'] + + # Sort by quantity + sorted_menu = sorted(menu_stats.items(), key=lambda x: x[1]['qty'], reverse=True) + + # Summary + summary_frame = ttk.LabelFrame(parent, text="📊 Ringkasan Menu", padding=10) + summary_frame.pack(fill='x', padx=10, pady=5) + + summary_inner = ttk.Frame(summary_frame) + summary_inner.pack() + + total_menu_sold = sum(s['qty'] for s in menu_stats.values()) + total_menu_revenue = sum(s['revenue'] for s in menu_stats.values()) + + ttk.Label(summary_inner, text="Total Menu Berbeda Terjual:").grid(row=0, column=0, sticky='w', padx=10, pady=3) + ttk.Label(summary_inner, text=str(len(menu_stats)), font=("Arial", 10, "bold")).grid(row=0, column=1, sticky='w', padx=10, pady=3) + + ttk.Label(summary_inner, text="Total Item Terjual:").grid(row=1, column=0, sticky='w', padx=10, pady=3) + ttk.Label(summary_inner, text=str(total_menu_sold), font=("Arial", 10, "bold")).grid(row=1, column=1, sticky='w', padx=10, pady=3) + + ttk.Label(summary_inner, text="Total Pendapatan dari Menu:").grid(row=2, column=0, sticky='w', padx=10, pady=3) + ttk.Label(summary_inner, text=format_currency(total_menu_revenue), + font=("Arial", 10, "bold"), foreground='green').grid(row=2, column=1, sticky='w', padx=10, pady=3) + + # Chart + if MATPLOTLIB_AVAILABLE and sorted_menu: + chart_frame = ttk.LabelFrame(parent, text="📊 Top 10 Menu", padding=10) + chart_frame.pack(fill='both', expand=True, padx=10, pady=5) + + top_10 = sorted_menu[:10] + names = [m[0] for m in top_10] + qtys = [m[1]['qty'] for m in top_10] + + fig = Figure(figsize=(8, 5), dpi=80) + ax = fig.add_subplot(111) + + bars = ax.bar(names, qtys, color='#4CAF50') + ax.set_ylabel('Jumlah Terjual', fontsize=10) + ax.set_title('Top 10 Menu Terlaris', fontsize=12, fontweight='bold') + ax.grid(axis='y', alpha=0.3) + ax.tick_params(axis='x', rotation=45) + + # Add value labels + for bar in bars: + height = bar.get_height() + ax.text(bar.get_x() + bar.get_width()/2., height, + f'{int(height)}', ha='center', va='bottom', fontsize=9) + + fig.tight_layout() + + canvas = FigureCanvasTkAgg(fig, chart_frame) + canvas.draw() + canvas.get_tk_widget().pack(fill='both', expand=True) + + # Detail table + table_frame = ttk.LabelFrame(parent, text="📋 Detail Semua Menu", padding=10) + table_frame.pack(fill='both', expand=True, padx=10, pady=5) + + tree_scroll = ttk.Scrollbar(table_frame, orient='vertical') + tree_scroll.pack(side='right', fill='y') + + cols = ("Rank", "Nama Menu", "Qty Terjual", "Pendapatan", "% dari Total") + menu_tree = ttk.Treeview( + table_frame, + columns=cols, + show='headings', + height=10, + yscrollcommand=tree_scroll.set + ) + + tree_scroll.config(command=menu_tree.yview) + + for c in cols: + menu_tree.heading(c, text=c) + if c == "Rank": + menu_tree.column(c, width=50) + elif c == "Nama Menu": + menu_tree.column(c, width=200) + else: + menu_tree.column(c, width=120) + + menu_tree.pack(side='left', fill='both', expand=True) + + for rank, (nama, stats) in enumerate(sorted_menu, 1): + pct = (stats['revenue'] / total_menu_revenue * 100) if total_menu_revenue > 0 else 0 + + menu_tree.insert("", tk.END, values=( + rank, + nama, + stats['qty'], + format_currency(stats['revenue']), + f"{pct:.1f}%" + )) + + def build_payment_analytics_tab(self, parent): + for w in parent.winfo_children(): + w.destroy() + + trans = self.get_filtered_transactions() + + # Calculate payment statistics + payment_stats = defaultdict(lambda: {'count': 0, 'total': 0}) + + for t in trans: + method = t.get('payment_method', 'Unknown') + payment_stats[method]['count'] += 1 + payment_stats[method]['total'] += t['total'] + + # Summary cards + summary_frame = ttk.Frame(parent) + summary_frame.pack(fill='x', padx=10, pady=10) + + for method, stats in sorted(payment_stats.items()): + card = tk.Frame(summary_frame, bg='#2196F3', relief='solid', bd=1) + card.pack(side='left', fill='both', expand=True, padx=5) + + icon_map = {'Cash': '💵', 'QRIS': '📱', 'GoPay': '💳', 'OVO': '💳', 'DANA': '💳', 'ShopeePay': '💳'} + icon = icon_map.get(method, '💳') + + tk.Label(card, text=icon, font=("Arial", 28), bg='#2196F3', fg='white').pack(pady=(10, 5)) + tk.Label(card, text=method, font=("Arial", 11, "bold"), bg='#2196F3', fg='white').pack() + tk.Label(card, text=f"{stats['count']} transaksi", + font=("Arial", 9), bg='#2196F3', fg='white').pack(pady=(2, 0)) + tk.Label(card, text=format_currency(stats['total']), + font=("Arial", 14, "bold"), bg='#2196F3', fg='white').pack(pady=(5, 10)) + + # Pie chart + if MATPLOTLIB_AVAILABLE and payment_stats: + chart_frame = ttk.LabelFrame(parent, text="📊 Distribusi Metode Pembayaran", padding=10) + chart_frame.pack(fill='both', expand=True, padx=10, pady=5) + + methods = list(payment_stats.keys()) + counts = [payment_stats[m]['count'] for m in methods] + + fig = Figure(figsize=(10, 5), dpi=80) + + # Pie chart for count + ax1 = fig.add_subplot(121) + colors = ['#4CAF50', '#2196F3', '#FF9800', '#9C27B0', '#F44336'] + wedges, texts, autotexts = ax1.pie(counts, labels=methods, autopct='%1.1f%%', + colors=colors[:len(methods)], startangle=90) + for text in texts: + text.set_fontsize(10) + for autotext in autotexts: + autotext.set_color('white') + autotext.set_fontsize(9) + autotext.set_fontweight('bold') + ax1.set_title('Berdasarkan Jumlah Transaksi', fontsize=11, fontweight='bold') + + # Bar chart for revenue + ax2 = fig.add_subplot(122) + revenues = [payment_stats[m]['total'] for m in methods] + bars = ax2.bar(methods, revenues, color=colors[:len(methods)]) + ax2.set_ylabel('Pendapatan (Rp)', fontsize=10) + ax2.set_title('Berdasarkan Pendapatan', fontsize=11, fontweight='bold') + ax2.tick_params(axis='x', rotation=45) + ax2.yaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, p: f'{int(x/1000)}k')) + ax2.grid(axis='y', alpha=0.3) + + # Add value labels on bars + for bar in bars: + height = bar.get_height() + ax2.text(bar.get_x() + bar.get_width()/2., height, + f'{int(height/1000)}k', + ha='center', va='bottom', fontsize=9) + + fig.tight_layout() + + canvas = FigureCanvasTkAgg(fig, chart_frame) + canvas.draw() + canvas.get_tk_widget().pack(fill='both', expand=True) + + # Detail table + table_frame = ttk.LabelFrame(parent, text="📋 Detail Pembayaran", padding=10) + table_frame.pack(fill='x', padx=10, pady=5) + + cols = ("Metode", "Jumlah Trans", "Total Pendapatan", "Rata-rata", "% dari Total") + payment_tree = ttk.Treeview( + table_frame, + columns=cols, + show='headings', + height=6 + ) + + for c in cols: + payment_tree.heading(c, text=c) + payment_tree.column(c, width=150) + + payment_tree.pack(fill='x') + + total_revenue = sum(s['total'] for s in payment_stats.values()) + + for method, stats in sorted(payment_stats.items(), key=lambda x: x[1]['total'], reverse=True): + avg = stats['total'] // stats['count'] if stats['count'] > 0 else 0 + pct = (stats['total'] / total_revenue * 100) if total_revenue > 0 else 0 + + payment_tree.insert("", tk.END, values=( + method, + stats['count'], + format_currency(stats['total']), + format_currency(avg), + f"{pct:.1f}%" + )) + + def export_laporan_excel(self): + try: + trans = self.get_filtered_transactions() + + if not trans: + messagebox.showwarning("Tidak Ada Data", "Tidak ada transaksi untuk periode ini") + return + + filename = filedialog.asksaveasfilename( + defaultextension=".csv", + filetypes=[("CSV files", "*.csv"), ("All files", "*.*")], + initialfile=f"laporan_{self.laporan_start_date.get()}_to_{self.laporan_end_date.get()}.csv" + ) + + if filename: + with open(filename, 'w', newline='', encoding='utf-8') as f: + fieldnames = ["ID", "Tanggal", "Waktu", "User", "Meja", "Items", + "Subtotal", "Diskon", "Total", "Metode", "Promo"] + writer = csv.DictWriter(f, fieldnames=fieldnames) + writer.writeheader() + + for t in trans: + items_str = "; ".join([f"{it['nama']} x{it['qty']}" for it in t['items']]) + + writer.writerow({ + "ID": t['id'], + "Tanggal": t['tanggal'], + "Waktu": t['waktu'].strftime('%H:%M:%S'), + "User": t['user'], + "Meja": t.get('meja', '-'), + "Items": items_str, + "Subtotal": t['subtotal'], + "Diskon": t['diskon'], + "Total": t['total'], + "Metode": t.get('payment_method', '-'), + "Promo": t.get('promo_code', '-') + }) + + messagebox.showinfo("Success", f"✅ Laporan berhasil di-export ke:\n{filename}") + + except Exception as e: + messagebox.showerror("Export Error", f"Gagal export laporan:\n{str(e)}") + + # ================================ + # NOTIFIKASI + # ================================ + + def open_notifikasi_window(self): + notif_win = tk.Toplevel(self.root) + notif_win.title("🔔 Notifikasi") + notif_win.geometry("600x500") + + header = ttk.Frame(notif_win) + header.pack(fill='x', padx=10, pady=10) + + ttk.Label(header, text="🔔 Notifikasi", + font=("Arial", 14, "bold")).pack(side='left') + + ttk.Button(header, text="✅ Tandai Semua Dibaca", + command=lambda: self.mark_all_read(notif_win)).pack(side='right', padx=5) + ttk.Button(header, text="🗑️ Hapus Semua", + command=lambda: self.clear_all_notifications(notif_win)).pack(side='right', padx=5) + + list_frame = ttk.Frame(notif_win) + list_frame.pack(fill='both', expand=True, padx=10, pady=5) + + canvas = tk.Canvas(list_frame, bg='white') + scrollbar = ttk.Scrollbar(list_frame, orient='vertical', command=canvas.yview) + notif_container = ttk.Frame(canvas) + + canvas.configure(yscrollcommand=scrollbar.set) + scrollbar.pack(side='right', fill='y') + canvas.pack(side='left', fill='both', expand=True) + + canvas.create_window((0, 0), window=notif_container, anchor='nw') + notif_container.bind('', lambda e: canvas.configure(scrollregion=canvas.bbox('all'))) + + if not notifikasi: + ttk.Label(notif_container, text="📭 Tidak ada notifikasi", + font=("Arial", 12), foreground='gray').pack(pady=50) + else: + for n in reversed(notifikasi): + self.create_notif_card(notif_container, n, notif_win) + + def create_notif_card(self, parent, notif, window): + bg_color = "#F8F9FA" if notif['read'] else "#E3F2FD" + + card = tk.Frame(parent, bg=bg_color, relief='solid', bd=1) + card.pack(fill='x', padx=5, pady=5) + + inner = tk.Frame(card, bg=bg_color) + inner.pack(fill='x', padx=10, pady=8) + + icon_map = { + 'success': '✅', + 'info': 'ℹ️', + 'warning': '⚠️', + 'error': '❌' + } + icon = icon_map.get(notif['type'], '📌') + + tk.Label(inner, text=icon, font=("Arial", 16), bg=bg_color).pack(side='left', padx=(0, 10)) + + text_frame = tk.Frame(inner, bg=bg_color) + text_frame.pack(side='left', fill='x', expand=True) + + tk.Label(text_frame, text=notif['message'], font=("Arial", 10), + bg=bg_color, anchor='w', wraplength=450).pack(fill='x') + tk.Label(text_frame, text=notif['timestamp'], font=("Arial", 8), + bg=bg_color, fg='gray', anchor='w').pack(fill='x') + + if not notif['read']: + tk.Button(inner, text="✓", font=("Arial", 10), bg='#4CAF50', fg='white', + relief='flat', padx=10, pady=2, + command=lambda: self.mark_as_read(notif['id'], window)).pack(side='right') + + def mark_as_read(self, notif_id, window): + for n in notifikasi: + if n['id'] == notif_id: + n['read'] = True + break + save_notifikasi() + self.open_notifikasi_window() + window.destroy() + self.build_main_ui() + + def mark_all_read(self, window): + for n in notifikasi: + n['read'] = True + save_notifikasi() + messagebox.showinfo("Success", "Semua notifikasi ditandai sudah dibaca") + self.open_notifikasi_window() + window.destroy() + self.build_main_ui() + + def clear_all_notifications(self, window): + confirm = messagebox.askyesno("Konfirmasi", "Hapus semua notifikasi?") + if confirm: + notifikasi.clear() + save_notifikasi() + messagebox.showinfo("Success", "Semua notifikasi dihapus") + window.destroy() + self.build_main_ui() + +# ================================ +# MAIN +# ================================ -# ------------------------- -# Main -# ------------------------- if __name__ == "__main__": root = tk.Tk() - app = Anggota1App(root) - root.mainloop() + app = CafeApp(root) + root.mainloop() \ No newline at end of file diff --git a/data/bahan.csv b/data/bahan.csv new file mode 100644 index 0000000..e02ca3c --- /dev/null +++ b/data/bahan.csv @@ -0,0 +1,8 @@ +nama,jumlah +kopi,50 +susu,30 +teh,40 +nasi,20 +mie,15 +telur,25 +bumbu,30 diff --git a/data/detail_transaksi.csv b/data/detail_transaksi.csv new file mode 100644 index 0000000..82c96eb --- /dev/null +++ b/data/detail_transaksi.csv @@ -0,0 +1 @@ +id,transaksi_id,menu_id,nama_menu,jumlah,harga_satuan,subtotal,diskon diff --git a/data/favorites.csv b/data/favorites.csv new file mode 100644 index 0000000..fbd9e29 --- /dev/null +++ b/data/favorites.csv @@ -0,0 +1 @@ +username,menu_ids diff --git a/data/meja.csv b/data/meja.csv new file mode 100644 index 0000000..95e0389 --- /dev/null +++ b/data/meja.csv @@ -0,0 +1,11 @@ +nomor,status +1,Kosong +2,Kosong +3,Kosong +4,Kosong +5,Kosong +6,Kosong +7,Kosong +8,Kosong +9,Kosong +10,Kosong diff --git a/data/menu.csv b/data/menu.csv new file mode 100644 index 0000000..1322aee --- /dev/null +++ b/data/menu.csv @@ -0,0 +1,11 @@ +id,nama,harga,kategori,stok,foto,promo,item_discount_pct +1,Americano,20000,Minuman,50,,,0 +2,Latte,25000,Minuman,45,,Diskon 10%,10 +3,Nasi Goreng,35000,Makanan,30,,,0 +4,Mie Goreng,30000,Makanan,35,,,0 +5,Es Teh,5000,Minuman,100,,,0 +6,Kopi Susu,15000,Minuman,60,,Diskon 5%,5 +7,Cappuccino,28000,Minuman,40,,,0 +8,Roti Bakar,15000,Makanan,25,,Diskon 15%,15 +9,Pasta Carbonara,45000,Makanan,20,,,0 +10,Smoothie Buah,22000,Minuman,35,,,0 diff --git a/data/notifikasi.csv b/data/notifikasi.csv new file mode 100644 index 0000000..c734ca4 --- /dev/null +++ b/data/notifikasi.csv @@ -0,0 +1 @@ +id,timestamp,type,message,read diff --git a/data/pembayaran.csv b/data/pembayaran.csv new file mode 100644 index 0000000..7e9eca3 --- /dev/null +++ b/data/pembayaran.csv @@ -0,0 +1 @@ +id,transaksi_id,metode,jumlah,status,tanggal diff --git a/data/promo_codes.csv b/data/promo_codes.csv new file mode 100644 index 0000000..8128eeb --- /dev/null +++ b/data/promo_codes.csv @@ -0,0 +1,5 @@ +code,discount_percent +CAFE10,10 +CAFE20,20 +WELCOME,15 +SPECIAL25,25 diff --git a/data/resep.csv b/data/resep.csv new file mode 100644 index 0000000..f250a52 --- /dev/null +++ b/data/resep.csv @@ -0,0 +1,13 @@ +menu_id,bahan,jumlah +1,kopi,1 +2,kopi,1 +2,susu,1 +3,nasi,1 +3,telur,1 +3,bumbu,1 +4,mie,1 +4,telur,1 +4,bumbu,1 +5,teh,1 +6,kopi,1 +6,susu,1 diff --git a/data/transaksi.csv b/data/transaksi.csv new file mode 100644 index 0000000..8e6245c --- /dev/null +++ b/data/transaksi.csv @@ -0,0 +1 @@ +id,tanggal,waktu,user,items,subtotal,diskon,total,meja,status,payment_status,payment_method,paid_amount,change,promo_code diff --git a/data/users.csv b/data/users.csv new file mode 100644 index 0000000..c36286d --- /dev/null +++ b/data/users.csv @@ -0,0 +1,6 @@ +id,username,password,role +1,admin,admin123,admin +2,kasir,kasir123,kasir +3,waiter,waiter123,waiter +4,pembeli,user123,pembeli +5,owner,owner123,owner diff --git a/images/WhatsApp Image 2025-12-14 at 22.08.43 (1)_20251214_221702.jpeg b/images/WhatsApp Image 2025-12-14 at 22.08.43 (1)_20251214_221702.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..35687cc74a4188979612be51ccb4a16e469fb7c6 GIT binary patch literal 40379 zcmbrlbwFFqw>BEA1&X^<65L%{q=f{x0L7&ZPLbkLq_nsPf?IJZ@}k8l#hu_*DDD(@ z`O^3N&bjBi_s=_f2guA`YlOAdJoC)#$Jxi<03v01C3yfE8UTQXx&V(0fFQsVRC@a4 zDK_>~+-InZkN^*lfRKWS7D<<#>RM#PJw|21fUb6VGyG|b^!zc01ULh3GhD&4IKj$>&er9bN^R1sxzp9 z$9VuA1{wgJ2!jX!K)-(VKT@baY;)hfNH#RKEvEGS9^M%J)=`)BC(NEo{a7DSf`n2Z zzyStDdK6p!8OS^iA5hmXsVsZaVF#x4GajJjHI>1cKQA|TG+QOcy^$V$m%cOYXOg2TFLvuHMAFBEgz<*STu(ht89e!%Se%ftuVeYFnYPr_oPKpLr!P;$>e|>D z#Q)0JE6Dg(CZ6nCDeXse3Yt=g^U3$6qW|!JYX=;1j>=6P-G7-_&i+R84EPLOP8=#` zEwJT$>70IM*|gUCtIIolI8*Au$+)duFL8?gyjQ_!Bd@S=du~J5W(C2Dfhi~>fsz0J zQtK{emGwPgx$HJGD+B! z%IJjpz;*@tXXo_759{tB{Lf6Vb;F$rq47!Q`j4^yTR+;ONt*kK+aHGIyiFhD%L#4o zacXSG>aCrhl81b9K|9M*dWp6AOYQLAKI3a>Z)Hh0hY|6m!z~SS_-8*#FvLKlrX*%lEeJObMf`5D3 zF;RbZ2T$h*DJH*iywdAyXYeF~MDz7KtRM;^ec6AF0&{3mP=pKgYIuU;YOn0Jtv7ss zaIVmB^%LM3)j^cA^M&)^gmO%P(8S69$=RsUN2yW5UxQ=YoqlSZjvIkC|7l-#s_6Au zqK#TLeN%9;MVSp(}De5F<3R2aIcI_XvH?0o}#%(=fmM6v zorva>Q`krHj@+G%^JBgAT08fTZH$e{dF?XtH3e#R{AB;BK}KA}w`oI)n5qfp5cW^_ zq>y2Ms&Yu0Xr{L6JMc*N+kdUMXNO-*_ia6%T49YtKG*AtcZD`jp0vd#DvV$FCheTh z`(`Wq2_1P#xeiYrO7QsL*^GUvmJMPAY&Kk!xXDiO>Q%zL2Pbs(d~Zw-I`;J_33NlEj5FlW|NGk_8GDH>gELoUw)-X zMRd&-`sBO4@0l2z=vO(|J6-qVIF)s-z4Eb9eY<9+*MC-*HC|aH!8ziup`B&MNcf&^ zuWKSN@5NfILNF|yrOpytcLOo;>h-IBp47Au4WkO%y^$gNuXVcYll(DdQ7QNw)mfrW z-Uk-tDuPB&G>mF8-J8W@ejHI$ZT=Ax)|Op%O0OHOzuPFg;FHc9Gj3(wFIR^(3YD%k zj0EC#b!oGvz74|M<1mC~)|JhPm9QvIYt!t6OyzmHq9TPMd6c`*Naswi*kDBz%YviB z{#1D#%bxDr3oAaWlyve_gGKLKCfxNPJ}La6+>wZNQsnN5XQi5V+1^jpLpYeGhAsa~ zT9q0^b#k+{s>Y|MPB@k5YdIIC#YUmlbc2rDvWT5KuZNqNbduZ7X!%Grh0BpogSDx( z{FLzbO!suU#b0YxHXPU*iHfH;BsN-1{E@6>@r#AQZs2p8b7?=7D?@tFE{6W^>)R%EeDxO&dU za?eze#np-?$z^khQELhtRXrKrGX}Rt!h2OVtPM91yA|Z7iPu;ko9`}eduv9M^;C~W z9dRAv(&fGh>OHe*=Fdvu&x$wZD*P7csp|S|2xb++v{`#~hK4^3;QWdi_@o=IYJa+| z?)E(Gimo3j$^pdPm9|3qf$!ZYju3tQrENhj3D~8rQXn~y(l;N zjZW^7S)GZpA`A8SNN+8D%}5el!ZepF55SYa;fUh=p(bEYb@^PVe=9WOfbP3s-V0YS zL{qJaX^aU$Fpk?-P5dU+P!1;z?{xc1GNGJM<+qNrk1n%2>j%-SaTV)4SS22HBNw%aGSABVPz_@tOGyew7rYgsht2qM zt2>sA&07|b@Qnyb)7xQ)2zL~|*E(a3YxeqRapTXs#A6-%GF!|e$YH8~u4UvU%x$B> zXH>?C(Y~e8<8+`|qJG+pHJO)YFFf*vYf;Q%+OYddodWOObwxbh8TLqp@r^{QbjmV* za#5({B4?U{r2A&0K&0;h&sR)F(Gu@l+(H1%7Qu;7xAXC?*xJ*0IkP00vP>xE;+CpD z!lgdq_{H0Ouv}vCpNTZ?r6N+VK_!ga`W)1ZxsWXCdH(;wcx1QwA z#_f%svK`+Wf zWNmBO!@$9yvs*;LqX=j3eD3t-w#_yxgEIO?DoeN5Szsm`a=KU6F~-Os6lyWW2~+tn zntS4R$dJ)^E8gm8(()ivaCGQ(<=0MXKtsIvdgs#jeAtiX=*GF?D*Ch}E0}HzJQz5( zvGHPeL~L45#J(&!OV_>fDE<+i`SxvKr-qPk$BVLO zcXcLNLtEW6E2VkhG83D0Q_J{eQ>azrV5D+v$#T~XL58G^(#cw7`G(VAG+)+@3~iwV zDKYCO0Gi1whawI>_v?WE_!GruVs`f6@Fm>C&TQ1n!7o&rFOa+fX=c% z^V$CNpM`ANb047z=wz!3vGp(yTc~Z$9LwkJZwaCM{z9{RgWGqHfY*8n*$UF4mU?WV z^erBWBwqnof2UbAeIfuq+Gj)x#uK7LThl5Jk3F%nf$_4gZSL+iZ!>{G;tJD^Mol}Z zf2N03yRHM53C3$>ml;*GYeFYBmt|l3KVJ|JO1YTV?mF=IrDg2kze11rY(!25Mqq!1 zyn$%5rsHxZxW8+;DD?FopIq5Rl8OoT_<$|NgfozSlD}}0-ryT0T82sc5=hY%l+2wy z0$9$Px0cSgrricPtGu!y8!DS?JHNe8Cq~l(@wv-p<=xQILf8SqlkWgO?4M+c7Tde+ zm_#ZsZQeFsOhYq;yI%7UQ)X0&U{3*WJ|Ml)f)`BRm-mtWjQ4iv)4y+jik$XuPJgy6 zpt`f;&5%syvQa26dHar6X+$`8+#H$oX8bhVlV$TC@=u}}mA;&&BLd;E(5je(>iW$I z?IK_ICE=EGG_6=Mo_NlY({Q!0LR0rFx9T0A4EG5(iH3GbgzJR1sC107M*f+<>+G_0 zMrF2Z)7?Yy>B&U=o8TVq!bE&h8s&G6T=ZO7rh}&kAD0>8&ssP|%M7Z*9IxS%AJp8p zvLVS+p=z15EA@q8L?v(Xbqj%V5n98dr6b0M3)s+3IbUg{Y-k>jF)iveuLNVfS7& zwf9`rLEE-zmalmhtEG)?I(f_f6mLuvau#SabyGhbk~2R0RK*%JUMcsj=OAHnl-}Go z$H417=4Z?)rW{VF#O^ojY1MRoZKWWDK@pAQ^pgH-D;E3%9~yS ztqtZyFUC)Nl2n8RMa1->7Vwi*LCg+pmnqiB7q^npdD9Y2LfVb2JO&^|Rvayoe0eEi z{b5Y9WWNTFm?Yzpsfb?#WiCnIv<}^-m4zqWAThf7(PC=ZIA`G z*{gH9?0Zj$K%LHkt;>G7yyZ}<*Y#b>OkQV4_=NaU5oD#Ryj$&k{!(5;?To5jEwBui zbVJ+tEF?(eZK|@(bIUL^JT=jE>!SAPLZ|Qk($_P2l1<&}Nv;)NHwIf7)cuEcz3a9o zTV8nR$Vcfx+0?WAb$uGI#j`49QX_68TU<-(6|1UZrUrc=gNE`UP1bJ|t)`+fRcLBp z7+czc@EkN*7%OIJnw&0bA&>S1YiESs=L5-&`$o-FCCA`yJA16o$(Kn}!%8jRE+2`b z(!CguWWj9!&D&lMJ zWTMhH06PuQ_+L?0Y#7sLDpmmcCk!mW6P+5J4O~GvyYon%;WyKUbBZ3UrI@Fst`-Qk zw2aeV%v!W8nsBvgyYbh``F4Rhcwl}xoe*qPBVaVB&nJBCBopy;y0N)5PGZeomDidj zizeDh2v%JBM2-o-=@hRIsSZAXADw85MKQIykH-LuoF^!XB%kRs2X+o~jzyu8qdpIA zFDEs|YuOUmf@~s(ML~;WMff*m`=T^1C6*$*u|RQ5UxrD80090c znAkdtRXKP7OwGVjpb=&o4endzPgS22KM7+4%BVg)>BnbHDqPB6V0X7t@vae4BEftr zB&RwXC|Q_-&hh*^b2$L#6X0_Xll~$r5gr-k@IsuPd`GV9&$P498>Z(uPJAH!C+8*?;sDA(&$hH`XpG!?p3>M~e)c+BJUOU$D zd?N7+2_{uXVR=kucbY`2f@WEbsP;$>B^ik_4qm(ridaJbZ>9)G@Si~~EnmK2escQ9FBmXHNpAt^n@Z}R4U zL@;9N8wSn`^RD|v7~j_EI{%NzF~h-gN8B(4P~>EK>yr27@_$5J`(%V=%*jR+Cx!cM z|8UYgzgPc+$KQ!3G%AVy=TiZ}_HmEA->;6JnEaIU5HZGpa_;s~2F?JyN5E-weCrbn z`@ee7f}IcC*A&z_$sPg6;<$D`6;=SXN5HGUWmo`P_hotv@5u|E?QPT5FZ{>K6818E z%+S{dRYJLiE2AGdd8ask5y+gbdOe%{WDN%IJ&-Y5J4+-~WNQk?9>Z?RxP^z}yCTE9 z`_xD>@w}rNf4TALPn+)D&}5D8b(u~WCEM(G-<=n0kB#90C@gmE2%82$Q-7WX9}}r< z3gn@qpF^q*f`Bh(fZ+?&Yku+*1MCrk?d^-WVdBThE2KalHOYmgVi0*SMUvGPiU+mX>>S`TP zqg}Zik>@AuuZGXlFcNh*>%4S!EF{6BJ|+@8ZlpIaEhIVbUGZLry>PhQFE8+-3z$-* z3*Z;;ck%=cuKi)b(SPa_Uin3m{16(;=7rfsHfRWMJ_4(gv6t} zF&B3ZK0jnJx9n1@a;XRo%=QkCYgeKj6%Ju8~P{3VY4f432xRgK(y3>Hh z?a-b=+bxynE1xi`%J4Huxf*?$#F6Akdy?9YmyKD=ziq^ut5tF-&cgUKkue|y{YwW{ zvM-^?UBDTM`6J+3a&0r_BW;>rh#NjOXrX#bpVk2KGDCoaU=}oG$C1_k{a(Wt7x;u_bDGnWS`WUYW<& zSol}syRE-<)gt$brzOs+;4W=pHD9x-nEBa0GLaY|dC#uAtDKR$8h&geGWzQ!Z%nqp zS?=j0;7{9W%VopRoC>#Z8S&|xAsAGHupv+Y9u{Ex^8Z)l3& zOAsPf6&L8d9>E{JhW{Ut(?3<@4rRQ8!J;c^bMJfqtoi>(WK{ClRNM6K7q{LYCq>&% zWPIoOe?)3VQ<5tdV%a9h&9pbC1?1!X{<{{*`JHa^YO!{m=sW+YViH>nLf`)?s_B0! z+wsRicj@Vyie+{R`j;4c#*(La!l$Fs1`!uekjER7U|do^p;2yT;dQvM2w}lgE_;{8xV$(2l$Ml}5LQCLQc*Fd_M2 z=$W#5`uT;Js%vsfKZ zq1UV(Dzaz%Qk0axDZV~$>&r^EqxBpsQ_>1db1^{>h>s905tk7>kJM#7@3V9r`#|d2 z=_Vz_QCEmB{u{{XfPVNULfpw0snRgyELd@AwBg)&#a(~yf3ZbT*<+q?Z-5_MCwJfd zt`dyQq(J-r#wPh$>F`I)wF$nVMT43w}h&%}q-aL-u9I<*f z0eQy?%+a3tCCoG77uH?ACszc5dGajl^dE7m!W`AFIj-=4!+{X3D-V~&Rf3Z^`rfLw{E8@O#XVR_p9!^0;?02aixAyL{_>G zEZY~CEHw3<^CRH=C&mUFbjgs{v$?|FVHC%#_U!o-a}tDmZ}ID89b|@AQA8ccd!{;3 zUqe`MLf_sWuX?kF<9la(f4IgVck4wDJf{8hGwhr&uC2Sv{_Cvy+V-+{8Ef}Br6Vf0M!e=4)JM0O=laf0lg#dN%p zIP+f?&1Nbtd#2CocfZw`J%OP->VKn-_c|sBi=8UNlD47#Py9KNepf|Sny%j#r5D`zgud>JcNQ?cIKc@_uyvcZ>j2hp5#r{m41FPXz;% z0haemA=q?gf@{8Czy}Hj1Fx=;;$GqT3g%~vEKVOH5KYdzf!4lR_)QqNPb+0d5kI`BXD1R~6(n*3{CGRQk|nW#rV*lTNHa@pb}0lT6BuaX1Q z61K1hKP^C zYiIRRkau3lC_wDv<(FHZDPH7vUG1)QvMX`}cgCk`4d1;>G2;fxzas_!FX`jf{ka_p z@1Z(_`GX?V6HBd2+73a8Ddl(}gk+wU@SsSodPVaM;Ui#W5KD^;Yn`F+6(`u>{pOw; zDkusP1JKdYFfh=uFwsyL|8GJ=C&nNmVZsCokP4DL=YI{wlGTENUb(~zYrp$Ejslk0 zXy|BYGJqQuMN+>aC}>hFeRvga4)YQAG4JvbV8D(o3cIn%#vxsa4Y{%1p-@RlokBnj z!E&TT4?f{g(caxclOF>i5$rkGFv?m)@sg92oL3Wv%XW-V{6Ueh|pU_e#DQ&MpAGjE8BzN^7S+QeJzC+w(%$h}X0f|YjNtblA zt>uo@4z7z>-;z&gF?UfZM^;V~(3xBLg^pU4XxG^)I}WY#-xgQ3GSM<{Fd#zmYpYb0 zk+v|a9ftg1gaIT@TMVof?mQhKnywZynt;La%$B{^mKzFs2A9;4XC1FKG+5LLrlz&v z`6-zZp(TH86<3{ATpa;PE~jdUJ3;O$Mkbs%9MDE7sjur7lqUg!^KS?&jP(%)wFh+e zNx{vZ5Hs^)fqa9y)(Z8_K8xpvJnT7n&M+A9yudS?Jc|{O1tP4( z=91Wj!N8HMTR@plWxOnhhZ}-dGs!!gU-LFJHMX*=Mef5RKr4IxY44VG&-v4ybM(Dx z_`U4={>XE2zu$7D9m!q&3P%c`_ia=ch<|eH=Ss?iM_Zc`o}^bl0tgfFkxf18(0Z;U z%ROL2FS@tu=r19A^{G-1sc#S*@pSNdl$4czKyAk~Y_RhnF0#5d2RMi_iMibH`L4)t zF{-X%4rM)w^kT=C4M@5qh+ofYOZp=K9g&RHfAunD3a6i*(dbr?GIy$pbb8-We$y#u z1KtF7iCY{g;?~1XXe6A6?QHOx+4}MF%{76WvX&N&0@k^&egCkqTgLJ)0C$08&0)oZ zKUPE-{HjO~X(H(yWwlJzLq)Ib18Q?4h`ReC8Hwq(wZfUezQoZ-Dm7S@ZsCJ&;T#+; zZ-WQDCkOO%uq)kyL#UXV+1%O#C48z^8IQ)rnU6Gh9|1NuN(z{#7Fo;N-oKBmI%>>K zdNnwdg@;v<4k;8CA(E8xzW}#tPC9J2UjaR;^7Q0V-%GLizKn zR-V&89|4E->c6r^fBR?TZX{pRYp7*OICR!-XE1$sV*5TR)N-#{-dTJ0&)aUXc={eX z!9kf_cflwSo=UUrgvV;ytd*xU_Hn1=0GYJL#EQ4oBOsj6Lb$4&G&S}H$fz;4^e5CG#Z<1Ii5bY) zi)Q0!EvK{Jr1ai-J%{alYey|0(=UER+*UW+I~H`1v++ue^Zyjj!wYD>jDSL=Y$BX3 zmnzziI@ZIy+9j7Kn_Yx=7g&_o9U2$XCDm{5komDY|{^(0NYW z91)Py z)lmkPk$$vAcRl%c5mH58Iu_R6(P{ev#osadJ_2qic8gKcJ?v5TF-)*8D+$~EzY(eu z8J4K+rNo{0%E;EETt{d!)`(D9kVFteG~}9ruR}VC?}B8f`MuYXnta^Ruzv?Efr6Tm z@MV?T_-$lS=qV_Is|&ySxV=_0Vw{!yf+Q!Gw1S%5QE;uqV8Zn?o;nMHhlI?s9&hxs zvToG1b&|&;z&5lQlW|~Df8~h}REj+-UW(a1f>Va``8VCLkvw@vMR{m9CPbxQ7P5WG zL1kt$Gnabf)G@)+{JX!W;2{ur`y5`(9Px*9*1~!9W6W$x@hSCj$ZN1O9M9Zjl=^KwVV--+QqETo08?(xa92s_=d>RhMd@Wrye(6eze zWx9`$Px>|sWIUj*h&FI>bzi0oQ94&7$uAnlCu<*antxpKQuF0N$e5WGsOwqq@qOWz zNz4!`iKwxxZDf632X+s1-3zAt(gK2HqxNQ@;nFLm2$N@b6rHrOtF^Jo4PlXW<^@iW z)erO)ACd?hbL1pAFBF8|r?Tq>mfOT9M1#mg;@0xee5EVPi-+re87_iB{ve z3dR!tKb@VcN|Vkk6AAQkkuo(jktdR7fj<>=`q z0$pkFw{=y^XuW=OI5n|_fn|&{3bt~E-G-SbB;5t;=ZZSs?U>9n^RUG96cAg~IQtmD z%(>qmiAoR{g2Ty-q3I<-l0!-M*9E=ys`};(1~9)|bG<&KAuH&RhfbR<$j+Iv!3Uf+3@%cF_yZi2v!NxCE_hp$&WLy#BZ|-r^=Mr1iITGHWiEeK)ts{Y&Is^+; zl6G6W#;w+nS2*%I1J)Y>`XQZtll|Ffpl=qLB%VLu0dQ$# z;v%!bk6Jn4LtQc|7k^HE!d7eEKp|QTCy7-QY_?6Cvo7X0+?nm%);9ojeyJD}ol7Ey zGq%YQ9*&yL?~==tBs4dbJq(&6iR*(RkuSnKoJlE?0@h_=38re>T4Jcqr$=|DF}zkq zl&PA#NhUF~Sk30X1jn+T3?>yDdx64t54wI8ayvS55^o|!x zo<0E4igH)?{5ibv(5H2Z7c@X!>2GutAF&Dsn&}_+v$+!(kZ)P!VAf_6nQH$#GDZH>gWe{!36ONr?X1 z(<_>;iAzqi#ml3H5&Pj(>Oq)<0wQSNzRfJ}>!RA&^+i<=E1ZEU7H5Ny=r^sN`Ub*zP&313+55EBT+Lh-;;unHcPbFuqKSBxS8uM&q{iu_ zDdVk%`9SCynKh1E7Ls$LQ;UT|p`n0s_Wk@vxIc1tlss}^u=>`*0A~5Dg!jt|nJ}-# zuBgItQYzIRv3OhYC}%VkhY-AT=qef@FWG*+E7}y-5OeDFtJ1(;% z`sEoXJF>}gjBaB|3b_A)3V7>-E^lMScnv1~Cq(sE!&lZgl)b4}MZN8RmeMQClu|+_ z_r2z(IUhQAI4N;5`+*Uw*Euz8^N^k7fUd}fGg84$uQLIQlO{oZP9vD)j$id9*q@f{ zW;K=0z?yN7c=hP$w&{Yw9Vnwewc zAd({Y=rr3n0fa4A`*f!95g<2-Sk1eMcNx6tf<|sjYHD#lO?+Z`)V83|Bt>n7gyc3D z%R48X3mO#WTOf=@V;2>*Dxx~FH1ESKgPNT!6S~`7^#kMcr#;SzmAaI`|I>r=&oLSjJ5o%KTdB!hSduKb6s^|8-wqO&?yqK8-0r$5bnmi~B zeBsA}W~q!M++z#HHLoA6(l)9|xq-j^~^UZ4Qi@IWor`;rcfxEhF)E?}U29^v_ zhIiP;d}^o}EgtT&BF)H%j@nS*NK%?xeWBh{ml(b5JZPXEEP*pS6}d1Q6+E!nXl}7l z=^F5%z?VtzO0lYhoas2#SbqIRAbyWZz&)HHU_C0Ri;37-YuB>Bwlb;Ta;A!nZR#i` zpVa{N^3{CwaK2*IxscojKK`xE=jv}06dbrvvPe^3&Cmd6p4Q}_8rwPlCy zyx^288?W4^glLs>ri0{N<~Kf+>Rd5xsZ6m55Cw<2+>`=Xh1?xN_MYkJYG1s&H)jJ% zpZvP{toK2g3n?46stkgVvG=F=N@nX_#6V4Fv1|0xW?+pdh&+~IhT{B$Q7dN}5Z~v9 z959sKB3v+k$dthq6iLDRutPG);Q8SQn=b0Wc8wDmR2Gp_9kC0%FF2Mn78zvE$;oZiftKXRq7o#@!1)Xb z!FRdJ$&EOJLde`#aDn0SxzRMyij%vFMzpRFniv*TFW?Y-GCdSwfeU=ojYFnCx0rKm z8nGFzra*#XPx7FzG)3qjG&Fp{G%LyGw8RkdvvUztBJ&5MiccbQl=(u$WEm9 znF$A=z=t@|Uy2AF3j-Y!g+I{$!jJ!=h)~djNdUzUy?RFm6m-Ut)zk_E!E>sFU~(NU z$m4%e2^HE|;aw{(* z#!ez^DY|DB1wM$;*%kjwS*LBSGYg4|VxA3>Sw?rRF{7Vuj&6rB%zBlu%g<0C4jBD! zeW;3+!11iLpV@6v?sjCusxtE8UDTBZta;L@tI`cLZg2&t`fyO~Cxe3F!fLkYAyGjs z+hO1s0Td2kUe8E~b0K)$Cqv**cPDY>8s}m#5MU71^XhMp$)L|?*t-CQRv6E7S(II z_A+^Ds#Ie4zSOu&0h^)xmK_XICMLl_zRAk+uG-ETyt*t3(4RFLmePm&~$&QhATz95Xot2O3kw{N+SQ~cdr@(ozYjZG7LssB#Jjd zDNbVP4^`MdhE&6vQiV7UVdL^JQ@>|cn@-ju8JpaztJ15h{;R7RUD@H3Wd3Y>L{ZYJ z%vh8EQS8OCr3{Mc{)8F|^P{0V;TUj?PIUa0Xj{6~4jpRz{b0nA{hvNHrGoy|9Ds2G zWbcj&A$});efL6!Ahwg~D9o3J5mOr57yF7;nm}&F%7xXX;K(6)nu+Qz1^Zb^ykOR* z6tne_4Dfk#9;V_e&A+T!=et1(YxWILe2gq3L1-sm;8EmnUz(dP5Mx5SO$_xHlh!2YCZ9YR@g$mxf5)axs@gcueh zpdPq@w>&!VArSQ>YVm_&k=V<1)?2%?ftQrjaN@OfzEy0qF3<_Ds0`a`-ib;$_$tu) zP)=fqMM$VRERPcL&VuT1t16n>5Mz^b*o+Y;=x9~OJe+L9~NwQ|U} zDjv{a?8tW4XRIo%?yLTCjs5_-pgg9!@4k~`>}yyISmb48l==`|Egt@R-=EG{f|t&V zhK^<@_b*@i-yZx|6-wFP=Kc*WA>;r0_J4WLzxA9sdkc7q($%tqk|fy&J7Ysxg3CeA zM13ap)X4Nq$ftu)LCN8-FkMaZ3?VD4f(j{jA}!7jua9wE%DCa)H@K)#sGS!_{Xh+5 z$B%_?K0x3!s>bNT@g{gU9Nv-ywU+pq0HdMPz}(n_%0g@nXU|ZPh}u zEIINOMiwxvxs+2lr$P?p0e^JI4-L=$?HpCEzk z^SaTr26dT8F7oj7ZUNQJ$mjX`^V}vPm` zeV@Bp^$2)(l@Ty6%|-H{ee4xbYpg-w$}h7;5_!zbUWJ#TKoS;-GVkcT9+%;e9(KWy zd}H{q#FqGGBxLwau))?y%|isZIOkwn|m$&=BAT`v7F2{z{S_@0N)-6#vB(@qZJCW_rN z@5^mxR^X0584l@$iRRWGRQxr=cU5$?lIEXQJ!3;)Yo~JOo?xM)>$agJ4nF$nFbDz5 zGi4g2;0?+vMJr9VQ%U%pItGFQG&h%RF60-uR9^1Lk4G1f@h~9l<$C2&$_S|k=nVOf z8=bum!!!tq+PMmq38dXnu3DL6@=RG2@pfhXcCeZjdO(uhmZVZ&JFussR%GD_Nsooy zW;ZI%i^mdQA2%yJ>y-~k;7FiY+H3J+)lWkLTWPoq*(;(X1@E;{W4yotbrUOs!55Tk zEMknKqbk2Ed_F(nd`at;=hQKq)6>89zDb-{q_ST~nqjfeA8vD2Jvf!4pOOvnsW<3+ z``}IM*Q2a(y{&1lj}=Uo+_1rz;N4Q(hp>_3N%ZfT9jIq%AoyzQlhW%poaK$VG9m*5TQ?!TnM^q{z^alg?~SXTn;oRfwhQ{>{2Wa4jE zctczC%v{#fg7jbkHQy`+%!ke|v8b)k*u~R@#e2R(uYelVkp(LjM!dPDGK8Yi%0PAv zbEUZu0RN;Sq$Cqe%Dy$=9#Comd@josvdS1V|;0*U)yEwECyc1*T zCNXkRvYGyl6vsuzn278kfBrnl!+dFwSVH1=o3)NWe0y*U-DN)}9R!iVB~;YPx5M~` z)V!DoJ*;eQx4U#Knn_H;1bj*VFbaDD?=B`5oAx~vX8UPXAL#8E*GJkXw{wyl$wGl~ zc{@44CUKVQA(<;=`l7j+gVd17qP*U0?@fq>LL=3S7bh?GoR>Lv?i&)HDv;1~cq_rrrp(&Xyp7;kMQX3YD_ z{%jD|92UPn75V)UzWm!%k}9vA_m9mZV2(}kOMX&3Y7Szkz_M-8YUP>=wfc}Mk65vS z$lV(Xzu0x?la=Bj|4l3>UI0|$&y;=!XtF;AgTw>|LB8Mz7ax1Hk0M)1zYep_`uL8`1 zmCgKIOTc0Q6grf4KNPp0DjtrU4M@Hi=jnzIq?-3+e{od2qHuz%6E4~fmt6C*d%tb% z&0e9cR$Om){#!E%OZ;7CYYb9`hy2L%N~-;ar`;J`zcjV=5LUcqb}^LdkdjHavSH1? zNr$um#l`5{r8cu-m}@=`AONnhdE7$lK$pT(4#dAV`m5iq-Wk zlnhId)cWOmf9Kjz+arM4%Q!AO0H)GB!C*~FNR|zsY)oNpOylzaqWo;Y4ohThtu<}b^>WhP75 z0C&i$5D5Olf4i^Ltf5$m7Rv1(_4e9>)%-}1)W$%2e`uguMZdob^~S_{h?f!pvESIS zu!BthT;h=kBzb0e?&6xpbWJHhU>?4xbc@TnoPdhPr;AzkA55M0qcY^+9zdCULI^1% zK}%oMJ4RwK+tayxji6rXTcG9dcXzGfa;$8NA+Hsq27eJQKrAc^Ziqg65y#V7$o;5t z1Xqd2*9k?0+Phwx;Kk@h`5J-6Q)*5WlVrYF`)~F@ly763|E$kuhuGi7aL-+cR;R4? z^=_bm$pwXw9oGuwC4(Z+Sc|P|#B_5Di7~s;eJxumdo$D~`z^xbC4DrKLH{mRSfLweta%mE3vX*6F`ZbB;mHJBh_ZZvenXAXpCpoJ$@t4omtX_XPD_iPLlU-%z<;ae- zULEbuj+CJo?G`%b_65hdMenyOgQELFV_K-|FZ}V2RZi&?;_+5mlyf? z;;jl)3=<~`r70Wbf4HydJ+$tv*EU;VZO;K;fPLNbcy-71=BP7k!CmzoJX&O^!)&uF z*Q(wObVzuFopaRKYJOD8MYZfchXcZ_Q+!*GlrOwnF~b)1Qb;(t*RpQEU>;*5N4+{Y zwR7#4Of@$o43dnL=ho;4amoZ8o86(JB)WgsS|j!I9-(lfD^&xj-#ZUO{j_p7Q@N-Y z#S0$hUAFFvSWUNhx%%h4!1>BHhkqM%bH_N+jpj_AKpgF zcfM1@sTTCm?>%$V(*naReq88RiS5e;Kdi_K9Mzfc$jh(>O!K@H{8kilZ;i7Oog}?Q z9x`;tpvoUrU^0MOCx}LHL?HbO-b2WDAXLt`H+X*7fyt=K#s^4uRvrP+j&}CM%Gu~x zpzPg=__k9o<6<&_i~jE!6}acQ5|y)&-tSC4dVBM2u#(1UbvMer0#bf&EiuR2xO~_b zqAf|iT{Wj>R;L$5QZ`RlLO_;8pPKRK`AVYvh{2fzAVqfxpU`!wrQiWfipnMO|gD;|U+D9WI9#Q=Q)vA7K6srfM%I{rJ zC!YqSsp%d8z`oRmcIDw6l2yv8Cf5@P5ivv9Kq#a8cKd+Bz0!T$Dhk$9Yx60Ty6tzz zbtX+OUx)#<3iYf1bl0V72c?;tpV5$huvl%^Iugl61S3#vL-h6%>W+a))4 z<`5AznRANvC?nT$YmY3`o$P&U$UxZ4!Xc4XXO0q)ddLX(S=8#u6LnUWG&K@vp74e3 zp;qR?RC?_!jdbCbG}!A%1i4smHrrm+ct;63^-YHmgB4|gOq7#L8|ClQc|bG)CD%+z zQ-XT?Bj%Nny5vJ7V_lEStoM8LH`G)8q7Qs62^q0jrQvQo5By z&;34&Bo6AT${E7(N5I;I&8N~Y*q^0V zvU!1xDn+deKP3AdZDkGVhucE&+e*gsoqmP@KW%5=#2E<*$&_7fZW9ZfW#N9P<@J)^ z@@JMLZ}wKyKC-QUjN~%2b%DVW%N;?xlTuFJNbAgJQjN=<946i%9!)rEtL{S3GAbb8 z3m-8ovu!ndw*52jT{sV^xvnnr^=Km0Nol#9S(UuY* zp{7tmsG;{>1qDKfpfqVxLy=AZMLGf@gx;%22LY9iAR;w%RGM_9D=H#jp$Pc$z4zl~ zW!*n>@8qtTxpPnU-e(^wW&vv>)_RWobc5Xa7}9?P?oW>59r~@pg|CkJn3j`h4c2U4 zfmo!oKIW~zH}}M2RCNV@Vb#vf_2b{^*jH_g7R&AbmFu4F<{Wo7UMpj9RAZOVo>-6d zB#caC=GP|`Jn7t5{5Hz3BhRO*o5fYs!NlJ3_`FykgXXd4it~Eg&zSV;!tysY!_cWL zDc&;3iEv5&gMH;n4BsRS{EAhtJ+0$E(aR_NY=5e9QvRB?(k-(gELQK zk0{@&54}w+N;moYn-BN;9rqT-6Scs$-q~X8cNOsWA6bjPrOo3$9uv$s(u37aqA$>0 zb?P(c&(h$xVekF}G)ZX8df+D~eo`M90=>r3$tZ{&|HVDw4kIUwywhKeQ)SzjJKat~ zXa7NJoD0FWZ|*AT%jum(=3hm*N##lXaze$pMmLe3+p|kE&-O|jPU-_!N8i`?N7Kny zZL3BzpuKLjJ^ZAdboM39C3o_SXTofeYj}Hy6ID2UWnaaj-Hfz;%c|p5nwOIk2~}3I z4G$6d@ojP5y0-h(Jv(KN?tncXyWe|_$-j%%jP*iz7OmQ?O`>kSXwTq&eRA%7uJG)j zG{uwaUxugP!V_WcQ{xJm7*Qp+%h zPvs5$2fM#-pIcvoB+XH=FOnT3?==bSUK(CEE!t&HOSpgCX>NT1NoOoc0vLSU3odWG zW|?vSW@WJ#{vT2;1}3Gukce^;NlroHzyFsehmbgOGc6b1z*reg5;#3Dvw3Lx|JXG0 zauALZo&sf6R8-J0Z3K>-%4u;yW&odh=&$Qnofrf9`*g1kO%05x6DHAH5xm*7$;oLR zd=iLk{eyhaxd_eNmcK_2P3}^`j>DjUD6#T8o98RtC8+^vw@AUuRc`i=qe{0wMlgjY(SkHWh7P6Si&K=R^p8#<_kJQRW}|MEuU2$wf8~~*4rkKhAqBOg z56kMV(fT^d<)C-KHSf&!ZdBjXFgwqfj;{L6Q+G+Tr=iuU9gV+r63*j#7@G2ve1{VU z8lZxqcUVFFuW6xKxL^7@ziw&&60QtK+*921nqI6pkN(b)H4;jYCh#6Jx|H{TEmBkg zyd|LiN*yE!2Q>s_YVqIf3;hfsh7wR<90Gh(cgIs0z`XI+EI5PO&%@IE6Bvio2-lh3 z;n@EE{+yhkm5jubPTdouK9R?5BusJOe1pOcB^5#6Eg(7jsnpG%H_Q}JdXD8ej zo@UBD)YKu;ff0m#qblbt=K0cH0A$Y zw!QrKFp7G6dk}154iWMG`Db~o-0rN*UD6o0spV{FPt>uNZ|h-(8wDSH}KV1r>cw5Lw(+}Fn>Bea32Qtf33F` zn2x`5qPD<7PC1{CZpj?4vEGwjC_-vDVfN`H}VFafL-z)7^F>4V)1{bL+AI zLpoKs9|eN}z-93atByCD^7^_?Z8z{BLoM`SZwdIna}Q?D}Ln>mi1-{GC*oh@8VA z;%E>|KvVUAA^~3xy*7R^cB$e};1sII6qmf4Hzk>)XuhRpN{qqJBQtw_Oe-fvN)w{3 zX+@B4I01k@%8yivBhp}nz0Kcz)EmhqqFG z5AB&3$jk?(Rh#RiId4`SN>?=?r2ujM0;otUFP({72}S~l-6nfjK|G^GY5>DPGj1#n ztfhiR@*!leDW*m6f2O?q8MtrE7OIe_vhWi`7!$;s0j&T~c$^zO0hh9Ey{Gt%k_JKG zEu;K(qe}wp@{DieGbbCr&2md0oj(;#fT)o$0V%6@#aGB%>;{)*OHhH?)QHOdDs7E{ zPUdN_`UVhuM=|q%3FQ@l^q!LKTH%pd-jR_J4(J=-m-^*HX9)nfmfRP8dK{*Qm7dg- zx>?I+i(gv$_4ojKz4d%E+5`p!hwYs~uybl^Y6gg;g%*bgP=NB1(hgauS!C%;2^(m2 z&Kh?8{E-PEWF-j5#|(pq(XBZyH!2DIHhx z67GtMB|&5iMVmz6HKFy0q%{!Z9aIqBtI_tnr`e)MP)MWO*Bu^&vLa;)m!{N})U}c@ zS`;=iGdF0#h1%+@q{KrP47hwyI}x{Ul9Y%mLGzXle@~*&(vm={yiMDR9CVP5xkfaQ zRu93gfRTR)y4X8Xc)&*TC}6dc6a9l%ZR?vx`qSB$_C*~COA54AUQS?!Wl|lL^0Jnu*^sVls6`RN$m;-tMGwX zP!0nDlyRUeixOsC*@_B+j=nZ^W%z(hoG#lSX0rgCzzTGf){f|`(v_j=eNgm6U=bBy zl-xaWDT|5km#>-?__{MDew@(Ib|-p}cj#FPbNoOC6qQRz<*#TP0N5ijNf|(G6vr@q z1o)1h6Kapf<88IEbh_@IkR*?m_z`@S3&m80Un(?=WLook%|NjEu%s~kRc0X^(xb)K ziVDSHrt9ho+aSipLh_+o=p97ClM+69w3Cc(mMk|CNR$u-JHd4MIybyS z_dY&#wcLrZ8yOdoiv?X!E$H`u>Hi?}l9L0m<5w-?#hcC(n} zhB8FP-}KpT5iedlhm*3+XFhQyT$6o<1mFo0vq=R)xn81W*cclx6?ubX@<{pIa7?e#OdIo6w z9anrQs5nZi6Oz>#D^@M<)$W=fh7P%l8VPAhs6)Q(FO|}WU4OTKmz<43V=o|gcGHn? zveeXX5F{UNvVMI13q#)-i<$ZLT6?hqhMj@gGVw{5o}^YmD?8uy%(@oF+P8}$}C96D@>SxiGcA|fwHBsaP^PVBeE&O&irGA zyy%xzuF_)&AqWb4eL=4KN6c8sKeA79-wRxmBwNJkqL{I7jmgD8)s1O&Mpr1(`XDD{;~r^2S|qFAAdS{*hI@SZJJBExF7S%D!5Q z!CQ-mG(sOMzHPUByl;67Rvho!|8NPE&0#7}qc^=b*t#?_dL&VMl#&sng!2pv9N%F| z?8b8&tfD%1e(*50aQz}my-cVrxm#9H0okHcYS$E445SV0Z;HFSg2~TWI{lQhbkJ_~ z>CMxmfeuT=n%h~&WQ!+{BjEL^=qr;5mW7XOyBgzn`j*TebFvn2(Fb{>{;C_?I`sD2 z-S8$3X`7AfQURuy^#+{;Bo+knOdPFnC5wu{09(h;7ogCi?Ex-?$-6T)L2#;7kuKy| zwElvYLzyP0%-vDDK)22FOqC{G1|AOe9*?OgKKUcBbra|5-D{#B{a|Bd{XBt?TC^j6 zPj^?DgoPAYL^u|Hz;2I}pJVk8zb)NTuHdelv$2iMWfz?`=Wv(CX=xLR|<@(WI zfiQlTG2m1Iy?e=UgSgJE*s4}j+LKgeDay4MLn~*3Z!G4TyaLP~5-ad4b}+z)5@@c^ zGk?O(6~B`6b?tr48R1o|Q5ROJk6S9CIwI8PGOO-q^i@jP8T4~bOYMG?UdY4JmU!#K__? z))LE^8~)%=IM;R0r02K7p+dOiZw-Qx`=8=N7B?Ow^&50uB?7o|n{kvgFjdHj2^%gQ z7PIluKtCd-3vI@yb5L`ZL!$11I%N;ERb~eMqlE6#n&({Gg@p zxAZcXZ=2Lj!cwTdc@;Ou=Uvi+n$%#MX0Pk2tGM{ZIUpNo!yd~!!RZ?NAzpQ(jEU!i zEO(Jq_?J8zl4klljkTX|d1@a+KZOSF|2#C1VHcEgTEeC?>r6A>vCh+Zw`53 zTyYy*|3u__Wnj%_-qY^B$FP57%sw5|gMG`^SwVV#6(|duFC=5Aax%`v!oJ;Yty=L) zNjK_Vw)0LRztY8GPdV0WS5(@CeyIWG3>~|!ZXtgiCWsZfs`Cxt*J;5!PMESRY7v1K z@Ah=9Igs(xjSPKshp6zQ>$D^1u7{;3`73UggHY^`0pnop7Y$V{CJaU?_cj~x$}|Rk z{7PTun!k~hSYLW4cF|rca6ix4<8&&-)x>z3+CtJsd4cfN^x{UsnA6pY_@fJmWZNN+ z?({kh+aHz8S9Z(L<-JXsjjW4nEPm0*4wLf;oyxsGTMu`mGV!`Knh3OkA8yO2MhdFC3B5S^W)RWqV$3x-mQF!g;kZnGD6+wG#xL50guS zEq@^mbd@u&xU!oJI541 zfd|;0?Zi@IT@)_$>+QY7Ts|1{7Q_Be{bKP`B!e>jI}C!9bHK* zoYs|XP3EhX4E6jDxNhJZl_1H$TTu6)p$zNuOQa|adOi=WBNsOC&x*ewtTFQpo8fw4%c;lq<(3OB9B zSuG{`wf4-C!>}2L6H%d;$KaOpA+)^&x(O=ny6bmIuh`#Vq-6A$-P1crpI#ulvQmO~ zdLy7R4EF-Ie`r6QMxrWr8Ufh~D>0o;atbekP#~dG)Lr@zsQPxyOr*-&pK6GQ6pn9o z5tOZ3rptPhur%4i`3fov<__7Ukrjk>mv`XM`-K~1WoJzLl>1IgdZqu!e0zy#%>vh_rCt*w*Gcd9U zt;0WKc8|B*`J^3^C)ECt?G-;t84I}i=J`(M@QxOkbVGPqf#%HO7$bvBaV6tza8 zaWihkb~w~V-%dKL8Q@i9;u>4%=J|<6E7)4_NlPu|6#DqVM>;M!QgSaVMTyYSfTc>8 z!1SAJZIe!RY#;>Bu=ai=Ob1+xgm)(ozT#fMumtKg%MEc=z2&_ot{s_KRu9-RLn8S= z?u9>$V;98&UsKH(c!u&`Ng+FxD(f8LoKs4XG1b$=t!v`pOGg!__7yvti-6a%MLhfr zSLsPOA+P|{0S1oKfkFrRmlkYBvt3-a6ajB05W*F5n_HK~Q3f3!(N6p}s2{PO_X+Ql zeMAQaomRk^SpZz~)7P}a5H>dHEglNh;(uh6T-Mq8mFSdb+~Rz3VJ~NxM;T7$;F(g1 zwIXpkp@^_l1IM9IP$*ZRcIG)upZ#T`2}l27;2PhzstYzvO+Xf6{%#M5+|#-p!^6g_<$nMu&k@K6bk zXV$f}ir82*N;c085Hax()ah&elPC!rF~h3srz~ycG^(dLIoOTQhK6n4aJI{P*m}7F+6^#JPv4-Ute0B@j??$7%hKa7#pH z!<>TW!=bxw_BT0AuG3m*TpWs3uRT7ZQV#Eiw)6cXf@iB_`Coh zDMcmd>KrN$t|vC1aBp4X_`-l)y-Huqv*!%D;P}lEqNi{s9S5ET89YnbKc))$8*RI( z&N#SS5y8yC0ry3_FI**t=yN2EwiyL`y^5_l6tfKfM@FOV>+6X-?T9`2`g}r>!)lu% zDzo%m%bspZf0UcQjS~#dhg8esA;XgbEfa@ib0Jp~JAeoK@LHg{ZXTGKQoHt;stV!5gDWzqs zpDzlG&yJk#(nye`H0+Sck@<1`_Ig=Mt`%SnlZ=)(GhMzdk7h z1b8zu<4{1Y*1vEuX~{`Ng%VUv6r_^l9@c*@k?-DZ4L(b+6thLX!Q7gv2|tCo<^Gqn zusu)J?r;4sp0oS2+}}PrmlwRe$c*!Q&R!D^#z9#PGD%&6KtTJsSiBPU=@-t)TU7~X z@OPM)l?}}T_{X?(0#fwPK1r^EJumu)4&yYx!!Ga_?mC-1a=}*Cxl^^%z)5#-j;JLm zx8vs2cwAP!a(Pk?AuMr5`w=ft;I2O9aLmU?sVC0uXO?@2o2IkUBVZpolLm!65)`%g zk1WpVoHWX~*33d=6vH2)6z#lH(`8>yL1=KdHOqBsEJ}Oz>LyoGNImpesqzNnwvU^! z$=`s#V*3eV@G&)fD9`9>MF#(0PS`QS5?pteZBtGyidN961f87neX{UY9M2}VHuM>j zfH*c}G=iHXacc5Q>KzGDnK|EKUGG$1|IakPZH(%Uad{an1vOPq>A>dW zulLnI}yH*T46XL>*GlGqZIHi=F42P8Clo|%ZJAk8iT6Raqg`O zi##YJ+)BN?h4!z$tj+;7@p#YWdA%NNuWeMK-k+w{t6{CvkiPYajEyV#ogyr;XQtF_ z8Me{Z5(4@Qi)32*%j42DP$=CTYT&CBbR}aDXT!W%8wFH*zm*gigREIUj**D*DDe;V zwdypQUB8Mp#P{tVi~D3>d~(_s-#=lB_E`vj=VAr+BxtODD=zub{siChOA4BDzx|J}= zZ=l}M*7~Kz>v^F1v2Wo*yhk*7iT}umDAEQleG_p-OxQjj4Cg$I1}zE(=SS0h8(n@n zR)04e#Q z2+v^j7Hk_R!AWv+(}5m0qgbp%eK$;|6M248sa@|o`xL{iw^@^!tt-MFFg{i;FD_={u9QL`&l?ejoqSYTo%ax1B_NjYTS&* zT{36pAb5KrASh5rA&m9SrXoC|#d@QM-EM~Ok&p&|XyHw*?YF$dDWdRO3?v6kdO;c( z#7lW}^ADf}kcx?bb1~xTAj_l57VDIpKPd_QW2lQeqB6Ka(wQU#7bE9}8(cC#37NK3 zfPi{I8~4GDhqm@dt;p-8*dl9GXzj&jv5>MXkDq&LVGWU8#?;GDw*?&8oz$~{EA!kulNY(m-@()h5;r&?tvUT5l50tGH4;1Eif>72&h$ny5G zfeK*J$wp+Xl4{h(>Q2h~*g|=gXoE(i6jO7>uZc({`yV7+&455aaf6bQ^3H?Vz=b+U z?RITRrYPVi7Ig$eim#STN_Z$mRy{7WhC?yssOFMk-z04#4P2Ng9ELkx#~+vh1cXMP zpG$beO1G_e?aFIMRK)MY*<1zQQ3zM|!9R-X-wdq0@aKK0BRrC^Tj}x=fC85Rn(OkZ z#h`z%6QNw@iMH(14;vG|3TDP_` zjW?Y}aeNrgu(x|H!AfG1Yznob8)ekJf;gmeI`v^Vh+udJ(L7Cpze((rD468j|9_wV zHT@?eRVRQTWwp#)0>QEWQB%B{Gcucp|4&YlLOlCZkMzwh`+Vn(^Zc()8=;fN)V?Q~kAiT0fw@dFa-`lDg7z@0DhIk8m9MgX%smT*$BpyD@J+%_9OUyXo zd`9xhQ4M3qX^g0ND8pbfBO$7VE+fv)P4>^;^NXP;^_*h^ZCb<<_)qnRs?w;|7&p`h z82V2DpD4S4G(~PP?=^^cF+qIL9)`D7)-*XCdQ`X;iJmxc9dwx|wjBolx#BY39a0vV zuNqGCxOdB5Tnn_*6`bTMXh?c0zhnd)GX^VP=XhuUuS zrt!c{8MN<6&Ey)dvPYdNKY^DPKdwL)P4f zU;5KFz-;HE040Z|hidE$=I7 zatWOfdwqRfn5@Qo<)hJoLo1iE4vAA&2qm<}D2ecZnmt*=pHon@7&W;SJ;Z3}p=y5w z-hw-8=22cyMZ$H^)h-j3L3v`9wU$l4l1il5)-^2Tc(ksAG=x}CG9)BJe02t5u$8Le~V zyKkg#)-%M!*H_OJ_g_|&nr&tr4YzgC@eVU_!jbbb1OLdL4sAphFeND$6nxv7y)ubr zKe~Q59LEjGK* z{MS)OI3Y2SC=C{^+kK9@(5&r5$a4!Gh;^`pA-AvJeb#4AWT%-|7tRuK&@pO}5O`-k zuw};}W(7*2cO4?FQy~Bcu6bEpRZv)<$}QeL46iC^EjzD4B{xL#)3}VNf*fGvB?)7Z zn_@!IOyuNl^aA0zW5hL=qr8^}+!di`1Kqsm^K52^DR244L_<~hXqmC|+Po9z#o~IV zFe|Ci+hbia#(>cIHA_5r)=H#H!TIe8hfFfDp8s(cd7-C=JZbY^r7=A!D$WRxzaeYS z%x2mN2(^r~F?O(Y{s^EW>rb3lCD53s-qJbLSI_K&5lexu2Bhb`h_*xrRAYyFg4VbeMG2DO^2h%&<)Uc0TKr@WBBWf zh{5yh^c9|P&PeZxdHzjq0zd-kkogJ9Q)rMK#+!-)2(T*X{DuVzL!==`v7|M3!mPDW z`BCtP69*-ss!Ke+4q&b~%zirxT$y54IrJsZ>_wlb(IerPPTuEGeD-!jsz(ZB5JY*H z7|1xry`gsc+;UJy0_C%bnAR`u!p?VE!)l-_{EWl*CEpwW<|ed5f68eV#^5N8jP(xO zH92q2QV=lCjl9=ljdXuYY$@EQ@1VoJvk4v9kv7A!K~L%<8sb#Zu3TUTnMiv0PsUn_ zsYSLL{$c5x-mn$9-mf7>k9d5!HAGzFp1hw(dD0^27ai(XRucCX!qP>PZ7#S)mPZD& zTAr#FgLqn^?2^-V_#HBp$*&c{6~&IoX;ot9X-o&%6e07Gf{CUZnP!3cE|~2Edhqm{ zV9L;k_kpaM&KBkcbut@xM4BQCmnPAwGW_9t&94IYj2uB_uxUKvk++0rT5+DvX;)h= z*&I;IeajAv*1bN6=g-FP>I|7(Gx%MrSgtJ2smW~fP?zsoteq~^kUCYJiwhiB9CyHG!`6QTE*66-=`Y(QSSU!e(BV zu*>(=AuO#;;{D4)G^uzHeFsMu|2Fs~@0xLFhK>)SIh_J!Dk1B^5=`&Gu$}9UoJZL_ z5ZlE`Oqt7UQMN*7O^wA^(*%_zaHqRyegkX5KCJ{_3w0>J9$b@9OFxQ5!+{nAWkTpJ z8~;sTr~--s{8Z}EOLLU@uA68j+m_3?SP_g3tnwOFqAWc}7k8Ve3~>`gb{S)nYq{+k zz;ou*kd_DBwAMOr*{R~|4nA-PTn zDu_!BmI%fk9LTkrK=9rma3FMWnh7jL5S>6szyjs10vS)FSK-yH4b;3h1v4dtS-;XW z#q*)Hej*_JU=SzkNSE^uEV0&J5=ZAuJt#}$XuqdlWRrp^5P%WciK0ijLeQp?cfctC z5U^&X?O<=Skt{IW0lJYltEg?C_hHd%3>tQeOLLd8nATS&M39%3>- zEi6tz#I=r@tIUt6YZo5KrUbr>&E6#E6db8}>*CLAzBDi)S(vuQCwGIF-d@B&g_!`P zngaG)zSz3MCi}p*188z~T6bYN|RQxxN!9~OT=`;$p^ zhK}{#u+#|^6?%;+?v6ZOn=hMpfU((_RD7$UO82)}Hcp3ARs?r3n^NzDzTF?+dWWlFRiP z7wJkcO%X%lU53%iT}H7w$ZAA=nOqw^r5G*WHl)F0;$6Q$NH1hWunIg#o^0flz%5+u zWWh?!OVBI!pmudi_*7nQFPmhho4xo#?ZtHus@;bKb|cQ#t#;pJ_(|RAnzKK~{j{($ z9q!|A_hF(&EX7_^$lF|sPq~%`L_w7M^l^?>FvnPD-aJS1X)B)oih`HmgRbk zrof#L#k%hhzBJu6!8O)4aZs!To(JM;_Ow>Io$E_7cCbV%P)o{-fT9vbR^sjxTjpg6 zv8K1(Y^B7}4+^1pe_n4sCF2yI^gnCrUAuIWcul`NOMY$O%T~K!Ge)G|Sl7!GY$-1v z5I(P+S-=|}wE5i7j;yyhG$xpSdJt{$FYi;V!T=15j12Gbw7F%{O$_ftXWq|lTXyPn>VlEP z#jEgAnm;ctx~FB|pDNB8O>30;s!kTc&kF5OhXj+UA_?-W8`V!4M%ru*NCn@T19ti! zrc(2%HMr{1v6beS={nbX3#&um% zYW{Pb^UC%{ZGl}9Jf>74+GrgKs;3Spnez8VJZ1|mlXMSTK8Z2FMVM_L;lz~5y~PH> zwp!1%D8}=tii^ex{``Q1rGYp7sN5DqUDn52Y(WiEh)qAns)tO*O+;TMZgstB{ZKws zTSyQImvOhL2=#B2vugx@-#M<p=zm;=D%H4IG}B{6{8127psJPuV;~m`n{xa$_vP zmB6LdNiqlX@2@Y7wY`W2I&XXn32sTeqp3z@3eK^2)?VD+M#O&CB&*oB0p-%occp$@ zF1l0qg3aMtTq2FFk}j=p#FWeJ2Oe;FONxQr)XWO8Z$+i4Tl>LM*9h-x3q?gfaAxUZ zCLO&yX@Dlm#0Fd>g{aMHr>Vl92PASY-1m z?>inz90w9{obW;l-t4#t&60tn14Wky*wo*X#mB>ixS1fX!4{9U91Zh$L79cIr`}I+ zb7Jo0_UJB?&xG34D!7@s?UY2DxVdaGl(^coEIGru1$uE4zG?NisE&+5;(mgYJ$gm< z{!O@zr6}&e&bPIW+9i|PE`T4ag?8iAs?$#~GWyAwVnr-ImU&|lcOcl}cfYiGH0|r} zfyWs^-{eJ~DOHa3gDMi#Z7Em@Vzttvgj|Snma>Eu?d@wWK%oSSE$1}X9CFey7mANj#&ud@@AW2^hVTHBTC!Sv(D4}?U95|a3b$moKkmL90MQg17r z-;dN1cUJp=icxabWkG7HOK$#@C56ISBQ<+$IKI;piCCe7PMg0;*Kg+v7G7;n5vnZj zeL>$#5kbq__5>0t$SSD+E>y5RG*%9OBAW|sjhpr2Ek0W_3U1leIM)mmld7m2V|1oU z4ccZNBxs=+3jnl0W$aBpFq%D1ZZa%C>p1Q41ohTdw#Oi=4$f|#d}WZezfU}9mds+} zC4BpK{+HU`lpYw7Lsh+T_PYriG zzjL1%;AI{ZGYivcbM2BNH;=zP)rxOc&nDj0Gsb}3?LJi`i^y=8F$ z&hY(F$c~;w-fcDe$&c3(6}c?sUbZENA8>ezHj}wMl@6Ri7<MVso{PK6sLuA@tkVHd=Y!Q!+nNRSE8)9$ zMk>oS$lg^L)mR94#6iL4ZVU~B=(3M$M*TARk!7e2k88?DG<2CRAh z@T8kEN|#Xk9J)@wz9{o4;YDZOhABnx8vG%>$jo|u4HQ>H((tUrokwpZ7yBy++USfQ zk>6*PkrK5W#UQ%Cs7k6kI?PtqI$HCh5vS})3^i-ayiCap6NGykf+8W_z4y)ctrp07 z+CZjDpPCtG%i*yPj{|ic)D~8dhX0KDxydw#Bf+nO0d$^F<7;D0MTuSOX5D=?6#dC_ z1~51|3(muvlg+1#%tdAKA3TM3KctoNv@n&Zq$(r|LF_q=L%uGHCmGtn8$2~qGL(Xz zYl52>B)5kr<1s7o=Lx9yzDHu|{_;lWI2T919uz(E)0;>ehfTXDYtL@ATd0gpei8~Y zHJeyxI@r{jX{O)^yYcuw-l=4PT@o0cwg5Y@Q+ODtF0eKM#>q_F7-V<5COksEke|c zYaL?&HMNZ%3Xd~akq;Toa!gg?9bTg@ zbxALnr7he^abMuIq<)?$zJiJ~3^2jJ32;rtq&`MRh;Y~#Kjq!rkaX`0aYU0|WQ4G3 zJp)vVZJrfVbRE{D|4r^QS95SJ{flOk(x8p^3%ioVvCE&Z!IH9y{@ijuWh(YINR zrjS$+g9?>BRZcFi+)QZ!yUd^Vn0tSkA`T{f5;lqB!?Q zAhwG=fC(F;_KxPKtLYnjp6%pUh^BV)I^i~0j7ztfmP0du0kcW_jDcNs*s*8eJ2RG< z@95;V6uBpgvwQhz1D|XqU5!bcgol!nr_`^a(d2ZDm28A~e1>`IibBm*EvNDmN6T0dn#?o%eQPbcpH|OZmfZ&f zh^xuYs_qVwVN^}g+bi#2cr#qyy~~QC7>h4myg*z-CKLIdLToaJ$k<`JcnP_G? zc4kJTLVR2E`>u?4sYJb+z@+*-b$MG3g({q)rMI2h!LNWRldBI-6GSZU2uF4_b*+>G zbZ_|y2AZcGDvbGCZBTnL{N`Lmm(au|6PqNy|yFL4861*dpmB3qXF*>7cL-SHn& z&IS-R>-~6gaU~ALj|>uKZ8WKR{R8+F$WL<7E(@8z;rNGp9;r86PL&O7$%2D(Xu1`>b07OA^L#j=|g801L^Y0A=&bb#5BL`}pE`T=bWlVSi-EHrw z&-1Mivc{zMvUNtPygbRSx!(s?*Nh7!SIxfn!pjwwoR@yv_ZlFjX3Ae&sOz;OO+^2` zDxg9*NJrb;f6HFQBso~5@1-xC(ifh#L@D;-b>75TdLrIc9Nm0d{H$onyfJq;zQ!_w zM$fg_#&^`iE8KO3Rgv?yW%Zp_N&m^x&T+2L^mGa5Fjo57LrF2AT?!gY<1`)n=l<7- z!RGr|4F!tNAF`ZtjWXbW0zavS}PKkP%GJ!nos_>%z{${TMGr z(PZsr>g|yk*A1%xbX6MHdlOllx6Kn3!Q9*ZU#h!gZ)VK_SvK!~NvG4C`~0>L<(~gBkXR`e)_@|TO(U?(6D=qBFuO+cPvX}M z3&l#d>o`o!_n-a#{grxGr1mU~&s(gf<1?=tUK)+0EeDt?F2Jes zX?1>(pLE$<1~Ei`#GrKgXa4+@PHChBgmu)nQ%Gf98sCn)6A(xy=$ZfhCTiw{oh?n# zX-z@Cg7}w+kzmv6tgai*TOC~Rs~$TKi<`bI^0bh8IB_DSkE{E5BI+eG;LrPjFx13Q1@n)wrnxS4ZHkW1y!~>aZ2n1U$TJ*vmt@e7>%{rb6YwY}Z)A z3o~KXt9{0Q54jR>L{)!3Oi@SPLei`K3OVFee*02ie4H)DJdx4HtE<{9vt5jAC7pBg zypT7NJuXPtlY)A9kHjE)8T=VnUGlOis9e<6;+lxFA4p0ONt7(hRPBG>i#V$opHWO4{2eKm8F#ob zelUJameB@T$xoeWlC`ZUIALnbW?f`wC~3_hWS{dVMaGwz*N0^;9*QIoB)%hio-kwoM@!aLClD8Wd*^0{04dJTG}9{n>P5 zfZnC+(U0}UtpVPGP4$pLb&?uS$dW4ckXfTB+n&t6jZastRX~Xd=Oai|f`SY4d}l2Z zYbjG3Q+DDgY;sk%EKLO38zf%Sh@HhR&^~YrM0f0nrEfp^)W(H=_i_qZe_t|=_f`H0 zO+nnS(;_o^Er2ihlg%zSyP48U z$EC_2OLG*i`a+&(~<*b8STFXHeN~{HCIO-Fn>lj|?Ly$)usbb_X3846>>_uvgN{ zSJEo4zb`#+z^eN2~Qd$I@K#>p$Uf9<50_a>CEhXq~?7&A@! z%CYPX3Y8zzUt#oitk_SQi1$9|dMZ!r;CQ(jKT;ONDcB7*a9iFV0Ab1-Fk~A|91khV zkuQxU2khBE_%VIfiQP4?6-MWFQ_Fj(#O?HUU9Nsz1N!GTVIXm2=va*GMRsi78@&%K z4XIRIY|cY5ZV)tsTrO1j?bh3vV~zeUlMV`S?4gvCk=bG}22tP0=tjn5sz@GM(02R7 z&>oPkJfpZ$#AQ+DJM9{E`)c{|5q&$H`CTKfQsM4LdL4P@-NZ`s!Prt2X0TDK1JUwO zi-CT9=PQfYT`xuMhlP3`SX~Bfd#td{qRg)>+lH`*B8=mv*$q}Zp4ilDpBdvXYm^yu zezW({Z<+lZ9lUenL^PTLaDyq{lqgFLn*}qM=j~kTddYep$+AuuZ4rEfF#_^|ZL-$j zT3V0;xzBGnj5zTSeeLs_vsQJD?Fs&_O0^CeRdb`N_O{usCJorotvg$W&5Pi{2$Wz9 z!L49}r>NN6QktNNW=|@c9)96-Y?3zmQ?54CCI0C}KFY8CC7h$NJc#91*EXyDYY*OA zajO5whRWid07wc~Ft3(eo{mf%bg$}OBd_VfZIg|Z-PBj9{UcKhtrcDBT}FQvpYi72 zz&rWEO~y;ySfY2G!G83zH=WOlz9$@r@cKw-H}c=j^vfdz$}`%!O}(aQ9NS>FY8i%x z?z-ujrX^APHXFEWxsK7T!3BEt)O2P3CqNm$=A%gfE>m*x$rwcA{11(M1PN1!9{~ao zAT3a_))26`7Y_+!MzIOimq+&*Xpahx09D{KDx0odOyYQoKnfme-_OOYT*1s4xj2|0 z*6x^s*#(frnYm|BBh*E~7L{^_UW^7y0@+1H0HrD+@FOe2-%HivQ!JOQ%eane$hyT) z$Os`M8cs-ej(LRKJJe5_8SNJ<9|nFZz5-MT5FnQV#qJAsz%)#gBqu%oxm-YZ2w2etp#W%sbqFyp;~-`3BD6rE;L!5Rlr#ibutSfDhOPk>h>Ui@ zs8Le*I>d3ZTv9+=1cEbg$hTy!K_hFH9(KeA#?bnOiz-UtgvwGh)ly!_Ii6yW#on

l>?Y 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 literal 0 HcmV?d00001 diff --git a/images/WhatsApp Image 2025-12-14 at 22.08.43_20251214_221654.jpeg b/images/WhatsApp Image 2025-12-14 at 22.08.43_20251214_221654.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..d4380f085bdd57815006b231f998fc0705552104 GIT binary patch literal 86219 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

mt4Q^Avht}lfenk#H5l0AkJ9@_kgB~(QH5m$0! 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 z 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 literal 0 HcmV?d00001 diff --git a/images/cappucino.jpeg b/images/cappucino.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..4046123c6f88bf217d3f64eb6a6f5c8e6fa7049d GIT binary patch literal 7221 zcmZu#Wl$VIlU-O~A-D!7xD#M;2o~I(;4Z;g+}#pbbRobZ!QI{69YT-<2rR*aLxLW6 zb@kn!dsEd_^IlEQbpM&^_q_7F1;A61QcbxdQAhCk>C_$;pE~(diClR4mJ)s z9v%fJBNZd(|AV*x5BGo6a~}X79Z-S90z{$%Ambwe@sXZ~02BZKGBWVxk^cb-Di95T zgbaESMe$xlBp?tO6&VEu6$SWG4>ACVk3v9;$|FUniAHDP9>$wYB>lCYm|m+M^xhIO zPx9;R92{Qoa+nMW07Uxl9{eAWkbx+uFA^jEOWyy%e{M!X#s|_8@JMN*5c0ayNn6lA zuK}=L)E62bAOSeQQL962Vb!o4B0u{@>7q|R9K_K^p$A&59FKb zJ!d2N1-6b?dQLWP(ra>_0k})%Yr8!WVXRUOjOpl?$&yj?MYfMDqsJxwzf*rD@CQ|D zU(@p>_&a=WD0{##GiwyQct<~aw6EXlkbS|!T>FbkJLC}SASR;~3@<9yZ8m~hTpLoG0l?_&%{PojWpxR=#GohS2~ z2lgtOi_07E5@B`u3F9+>Cl%zjticm@Xa#F#BX#Sdj}d6pdCo&U?W zE*@ozIb&qVQxX5&DIeOXMz+^_Bu+TLzEOJoaguwpPUg zLlK%GAJ@DfJEg-}5$nbGzI@@m<03|UiI${S2~#1y%(&R6!qFh%TsU|ki(lGk+g3wk+bu_Y_2-dqJfJW9hL(Hu>M z{_9l$KNovd$d3)8AiJ6e!Lx2d8&agIC%bo-S2r-yRq$AWw#e%~5`&noW7B)k;X`J~ zff=r*eSz^I?ulHI+io5Ai(|6c0a$DIn-~6 z)zd-L9sCR^x?8~A!E^X5z%VGE`bSP6Im&O9D>#ZA8eZc=^5#CaVj~?U z{IfkKaPThY1|BLYDf}+>^D|(mWebcc5UPf>rBaOUFA$Me*R;Q6oSng*Hx%nhn^5r& z?v-Pbp!dl8a42YgV{sD3PA=YFNkVef?-clLtBmx9M@Z@~7n|3rrAzG5*kj2vVDK2l znx=-Xnt24YBwn#f=OG5G)a?3C*~gg5%Xa}!ebnsX(z7mL)^?WKrGI# zRA07_CMgBH6F2=xMQYD4Z=Uijx5$P=3px+d z_^X@BX*ScdA*1BkCKhk$kCtIb>N5uS!hx9#(!Y8_zr0PANc_$CUi45t?;WA^mraub zhcA^_G@$-_DHt9AD;cqUwRF&PP`LTs@ZCMN%S1}#K z<)Eoi8VkgiqX&#p|CM0Iy(gM0^H1OLFL~B_WvO;$+eMgMbEO0Bhgp#Gz};d0QR*k)1JDOFEa{dLA8uAzKX#Oys!P2)Ut_Zs~ z4)0|G3DXoo{idS4%msMb0&=+}&R-LHro02aKlifWhQZ7MoNWl2CWDH@TLYglUD;5! zJ(^M>hD0>IvSs$bFtvrvGB=McJJK9%=}NpG@DuabY~UFP?T|yV=OMH>B@Gv{#lIZb zCJi#T!j@3RDH!f2)8L*Ei1)kY%_wn)8Lo!&2CiqP3=zU{ws22L_eGK`K6_);o982< zLwO-;snheuilf>9{qqy#Zy?i>7zN5s0496;>pK_0-(NPs$jslm}Z^M{Jl z=IkYgc&rq6F7j#j#e?vrT8oP*906Y;v2FfB;ekok?y+XXm3rxZwlr_kSm&aQ=A7$PRA*FpGF z?S2eybnAyg6rDSFBWqj*)oPP1g%zP>y}xn2cvuhFE$Xz$ZtNH$;{Wzv3YS7V1R{dK zeE!Sjy$3J9NG%o;n&wd*Y;wyDqkn7){JxyO?#-Fa_Qck~m7KAXkx9n19_+1Z_2xgL zG2X8g3*;+>IP%xj7t@RUMxk_G=V+-x!DTeOK6h2?;`}TZavyBB|27oq$qcAl#}I~| z2n~(X8kF_rN2cnl@Oxg!R;daTN>0ig%|)}#+$bW5(9@(@7ZF=H)(1Kbo=`ZEtIMT| zyN9)PRygg!J9M|%@tbrd&%?q{6jDb#_hjZ;z0#>a@kF}xpR^&zfBLUznrs%?kj5x@-ixA^kgNrE53WVfe6J@N?GSc?LhH@Bl} z_{!%I@jLx9bTf5Zx`%AwtbTK1WdZjsWZsZVaIu%tTBGB4XCoqlWu0&JJGr8HMKm?sv_02>0>Xy1YtSXw+r(k)Fo)z81K1)UaWR za87RtwCZ?_uXYgmRk`$4HTHhYk%%5oJz+3@G{?-ODFoNVsb4Uy$-vydnoRT10wTJX zn!@wCR=NG^ulwbRP`&4VFSirWsz*6>y<|2&rv(bJaNTf07Q@W@hfID4;6!cfGR^HbsFYWkPlY*F``mapRWjZSHn{<>eYYb2eNj^{%-h<_Ry3|E&rxDCzQ)xiO1K1i;ii``lE;J&-} z&h>3xwXlpkD5JSZE7`n*#aOL(wFHWu0~Y7o&#r8;rpIKD|Ml&8Q^dQEZzU265E^ol zKeg&5v#%@DuiYa%^=~GMKhaW&3_8nf8i|rPS7}(J#mD0a+y@MIvuk`$cOhH)-3M*z0jHU)YOYTM)zZIrq5pg?C5BUY59UA|7snt zj?}CCMi@PaenxcIu$lnm=%7qg2Z)HQeg+(AJ{H#&9jP`|=5(G3hNVWFKz9;D{77nA z0(W(|Hg+3y!)``hYb=DADWsutIpAsk=*;9Lq^wK>Z*z0Oz|=f&45aXC3ko>RYjXT{ z&_t~9siFm<&qW3h%UxFsJ`)9H4$L%N3H&wF7>y=nK$i1Joa)fYPAfm2kUwQL!@+95 z0}ge6B=Pz61BbFVb1(f&;f5i2fn$ch<@Y4|v6II$;L6%!4?e%qfj%`}@g1y*CDmeI z1k+M%AOTb~_%C=hc$cYs6r9U02+lLz171=bH8TVjp1i*57z++61j_B@Y*O z>lRxUKSo>b9%3;bDHfnL^z0DM@@H8YHBcW81&hh%rF|^XLn;24PMx!{3DLJOT0!l<$$N(gC`R|&wG;6pAue^e*iXFmp?MUY(x%% z-qWLjTk>~~wnj5(_zP&+EQ8?{t98q|N#v7zIfbBI4K@ALO;DUb1%idVn54NBp=YP- ztqCVt^LE2^--bA{K)S51SuZgcjavkEy(i9e1c<1IXhNFc+Rei^#u+J{-#uXfwyJgQ z?AN{pMf3vR9K&vC`fUhX#jj=tlf0`fwdx=H%fMv}bz3%4=P5#uKQxsQ)w87ybHhv3 zqUe7&%=UUfPu;6Q-PWzu;%O(w7B(7tt=I%Rn8s zQczVuQnV~gfdq90m@8cKX_pm8pTM~8)-7b!Re72}AVS-BlGH=G+`sZ4XghAUb<+N^e-asI&GV!10(_Iwul^9>WmuO?P7-vx&^vi^|X!xFuacdenzi}7UEAo|dv zTh|y-2lE06O;V<)xhIeEelM99|5W{lLR0k+KU`v>g@+?xhh7LN5&rv)Q^c>IhI6ON zDs8>Fb3ED)60XS)II~2{HSI`x0Y*< z(!ZH6X8mL*Lr=8wU;nV@y%l*Qw4Uhd;$jHRv8liosg#t(BEIaZN2+(IC?5#t9)jDo zw#!VKd=_C`>)@(rERiZ;&uJ#K`4mrDi={}`Hw!%H@K;5p9b9p^y0uejAzz*QBYIQM zaLYd8J0b)N&Zsc4Nh=<^F5{T^{V0oFHgKXxTuDPJI)3NFyPiLnvZWv7T%uC>ar&bL zO_`OinC}kR)*kPC+UP)XJW?zCq4%vstavja@+c`AI+^%`RS%Ax2nAS+9I7L*3HNB? zLG>L$@280)=`BO*c3idks;-F|W*{XlhZ_&4{+q#6*3WF?p$TcADhg|_!{Bhw;|N*P zYgU*}sL{tx4aNC&GUan_+V$O_UZ)NC3>e90$8~+m&jZMGD{Yt09IiuQXRWr3O4UagC9ct zHjSyG(FijaQ9rxlo zDOW!6nuSm~n`I>2q;O){Kt#8_DDes=v8MRlADv-UAJk5bWir>wT2G1(1E=7nF{>QH z(|+0eC~phTU1Pafl4s$Scoin6SC5D_;Ry=}*rgAiFk#9kyedyQ@w3OF3J!iUc z?7ecadJ_Ui(hVHH(;^zA5GT=}s;0@>aW#3iT*vnFNu_Q!*e1PNX@{yS2=LiUmi1>@ z$6+`Bzg7`QOzVWA&`lq;`48)+iO8&Df|}2zLfG9^`fppkn!g>E3$tO|pQoN)hkJE1 zIzvheKFtum7G)ZC+2XXuo8HW;{ms*;>s(b`V!~5BM`Jp$x+ivL?g14WVOBVmsu6a3o!{5pohkVYV=>^N% zc37;ap|I&EU+(L}>Y`apNA{Qf34p!w63GX+&L5Nu-ws?R5}Gi7eFe^b+a#?0y5`TQ?(35{%VTsp}COO+G z+)vtn0(}NF`To(50y3N@c|ZE#ug4GHMb)Ywia6;tr-i$fnS~PNktK{IzY5Il^IX!C z^w&#oNORFQw{%ac4ojP@i}sxMKjmLN_~w|W)zSKUR0D0N5m-Mf_9Uv%4QXyYyZ+NA ztW{MIWvR}v1pzRVo?Xy_qAZ`{}HJ7O_(y|<%wcT6Akoj-!5ADQj-o(?#LS0y5 zd^6>8-Yw5Fz~T{M=am49GoA}yU;wB&`%!t%a$G4IwwKebV2wr7bH|? zmbZU#(;NqJaNM63zbb-rH9nFM6GF&OrqcKt2?I(l`RurXb+)$ls;K}z6+~u(ZCtD! z!;E4!6GR0t4-U7JnNdN5s4UHcHON+Yb$F2&6hZ|Gaq@?+-|zFJj1Ws7g)K7mYOu?B z9~Ux-<}0Y4yL3jC`Tfg2*;4wG@>qqnqg^2&DjLEwyW&d-p9M4gQ<{~=+aag$`ZOHZ z7PRYU6H!97uQM!?Aihi|laW$zB+v3UQ^<-}QS$3h^oA`v#&ER&L&E5nPAw1YhQFwz zQy)=74SUY8W&Pq^0{f4%=*R?>maTTVr`^V4R|BEvwW{Ah6h>VeyomCoZ=$bPKN85a z#)6*cvUobYB+m%0ThA4($#I~Az5nuc!tXHqqj&`-z~ZS8Uc*_Ruiv}wM0 z&n9zaIhIO$LninHkZl?GO_;IC&@TBiBc}-g+?nHFROanN=iy`xiz()4@xMwY6;|`X zDz=S$Dr-ZUb179&&pJRyyoHRBicLw>OP^#U2pn(mHI9W{%WtB*OpDk|B{YA@-@b+MI-P@PJMN~n=^`+z%j(hRr}PNNe{nNovz%+gVmY`_a?>V!(PD+k18P-%<_L99?HunIl4RfkX6|o;W%&(@X5k(S&x%$!oMGs(kS4o1oXWE4vjk?FUCEhi=O-F^=sIXdu_K(7h7#cS@MbbCD zD7R8oLyzPHqvlYi?eJ~Kj2($pU8^@lJb}6}YS4K@Tzw-9$^vk9`p(`(&iJvkS+(|r zd+Ae9aD?0tDj_I+!&6i(i3qBt_?J@kQ0uzByhBf;Aw({gr7m6m(s zzq$Sv>W04F@cd>a{O5wWj!7YEQTvq$N4dkDsiL*0`qk%C!4hAyt_JD>y^d@`D`Yih zC!_rlMdbZv68&^g>gE*F(e0&;D=OfADjx} z*{n+nloK`}kV_6miMPgOGTrP#jIo4wDp5@+SRj;rWd42;!2j#IZ}TqyCR1@9>w2x( z9C~5lRN_g2Av^xAd#Y~9Hl2%JLeH)eSzBaEj}7zMHlfaVDrIH=%}@Tr{@;oXDa@Oq zdJ%DSvR3&MGAxHM@zOQaytK!HJ9Xw$Fno=TN5$Tm3lakC%L)uoV@YY+vn@hpYMEXM zcr4Prc^E=Fmcl&9QXO?a#=@FJiw#L{I3GaBDQdk67!e=P_8%z?$n~W}zc&uiU(@Ah X?)uJAE9VPy3T+z4Br8uYe_s7BR&SX= literal 0 HcmV?d00001 diff --git a/images/es teh.jpeg b/images/es teh.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c693e6f8c57ed2f991161b2eeeb69a90e2ce6242 GIT binary patch literal 4524 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

8oDBQ5ua`FfTx6 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 literal 0 HcmV?d00001 diff --git a/images/mie goreng.jpeg b/images/mie goreng.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..43b97d803e6a44a703218132e5def7bd6391207b GIT binary patch literal 13439 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 literal 0 HcmV?d00001 diff --git a/images/pasta.jpeg b/images/pasta.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..97b64786bb1511f29b2e4f20876e53fd84af2eee GIT binary patch literal 9305 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 literal 0 HcmV?d00001 diff --git a/images/roti bakar.jpeg b/images/roti bakar.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..9b1e746a9e105a7cb0a9f8f7cf5a4ffbd9bb5852 GIT binary patch literal 7619 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 literal 0 HcmV?d00001 diff --git a/images/smothie buah.jpeg b/images/smothie buah.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..96f92bc55f7cd6596a1fb3f320aef6f34e42193f GIT binary patch literal 9652 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 Qf?Z98|6D4K0DN2hA7*(N6aWAK literal 0 HcmV?d00001