"""akun default buat login : - admin / admin123 (role admin) - kasir / kasir123 (role kasir) - waiter / waiter123 (role waiter) - user / user123 (role pembeli) - owner / owner123 (role pemilik) """ import sqlite3 import os import tkinter as tk from tkinter import ttk, messagebox, filedialog from PIL import Image, ImageTk DB_PATH = "cafe_person1.db" IMG_PREVIEW_SIZE = (120, 80) # Baguan Database (ati ati) def init_db(): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute(""" CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE, password TEXT, role TEXT ) """) c.execute(""" CREATE TABLE IF NOT EXISTS menu ( id INTEGER PRIMARY KEY AUTOINCREMENT, nama TEXT NOT NULL, kategori TEXT, harga REAL NOT NULL, stok INTEGER DEFAULT 0, foto TEXT, tersedia INTEGER DEFAULT 1, item_discount_pct REAL DEFAULT 0 -- per item discount percent (like 10 for 10%) ) """) c.execute(""" CREATE TABLE IF NOT EXISTS promo ( code TEXT PRIMARY KEY, type TEXT CHECK(type IN ('percent','fixed')), value REAL, min_total REAL DEFAULT 0 ) """) conn.commit() seed_defaults(conn) return conn def seed_defaults(conn): c = conn.cursor() defaults = [ ('admin','admin123','admin'), ('kasir','kasir123','kasir'), ('waiter','waiter123','waiter'), ('user','user123','pembeli'), ('owner','owner123','pemilik'), ] for u,p,r in defaults: try: c.execute("INSERT INTO users (username,password,role) VALUES (?,?,?)", (u,p,r)) except sqlite3.IntegrityError: pass sample = [ ('Americano','Minuman',20000,10,None,1,0), ('Latte','Minuman',25000,5,None,1,10), ('Banana Cake','Dessert',30000,2,None,1,0), ('Nasi Goreng','Makanan',35000,0,None,0,0), ] for name,kategori,harga,stok,foto,tersedia,disc in sample: c.execute("SELECT id FROM menu WHERE nama=?", (name,)) if c.fetchone() is None: c.execute("""INSERT INTO menu (nama,kategori,harga,stok,foto,tersedia,item_discount_pct) VALUES (?,?,?,?,?,?,?)""", (name,kategori,harga,stok,foto,tersedia,disc)) promos = [ ('CAFE10','percent',10,0), ('HEMAT5000','fixed',5000,20000), ] for code,ptype,val,min_total in promos: try: c.execute("INSERT INTO promo (code,type,value,min_total) VALUES (?,?,?,?)", (code,ptype,val,min_total)) except sqlite3.IntegrityError: pass conn.commit() def authenticate(username, password): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("SELECT id,username,role FROM users WHERE username=? AND password=?", (username,password)) r = c.fetchone() conn.close() if r: return {'id':r[0],'username':r[1],'role':r[2]} return None # Bagian Menu wel def menu_add(nama, kategori, harga, stok, foto, item_discount_pct=0): conn = sqlite3.connect(DB_PATH) c = conn.cursor() tersedia = 1 if stok>0 else 0 c.execute("""INSERT INTO menu (nama,kategori,harga,stok,foto,tersedia,item_discount_pct) VALUES (?,?,?,?,?,?,?)""", (nama,kategori,harga,stok,foto,tersedia,item_discount_pct)) conn.commit() conn.close() def menu_update(menu_id, nama, kategori, harga, stok, foto, item_discount_pct=0): conn = sqlite3.connect(DB_PATH) c = conn.cursor() tersedia = 1 if stok>0 else 0 c.execute("""UPDATE menu SET nama=?,kategori=?,harga=?,stok=?,foto=?,tersedia=?,item_discount_pct=? WHERE id=?""", (nama,kategori,harga,stok,foto,tersedia,item_discount_pct, menu_id)) conn.commit() conn.close() def menu_delete(menu_id): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("DELETE FROM menu WHERE id=?", (menu_id,)) conn.commit() conn.close() def menu_list(kategori=None, available_only=False, search_text=None): conn = sqlite3.connect(DB_PATH) c = conn.cursor() q = "SELECT id,nama,kategori,harga,stok,foto,tersedia,item_discount_pct FROM menu" conditions = [] params = [] if kategori: conditions.append("kategori=?") params.append(kategori) if available_only: conditions.append("tersedia=1") if search_text: conditions.append("(nama LIKE ? OR kategori LIKE ?)") params += [f"%{search_text}%", f"%{search_text}%"] if conditions: q += " WHERE " + " AND ".join(conditions) q += " ORDER BY id ASC" c.execute(q, params) rows = c.fetchall() conn.close() return rows def menu_get(menu_id): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("SELECT id,nama,kategori,harga,stok,foto,tersedia,item_discount_pct FROM menu WHERE id=?", (menu_id,)) r = c.fetchone() conn.close() return r def menu_decrease_stock(menu_id, qty): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("SELECT stok FROM menu WHERE id=?", (menu_id,)) r = c.fetchone() if not r: conn.close() return False, "Menu tidak ditemukan" stok = r[0] if stok < qty: conn.close() return False, "Stok tidak cukup" newstok = stok - qty tersedia = 1 if newstok>0 else 0 c.execute("UPDATE menu SET stok=?, tersedia=? WHERE id=?", (newstok, tersedia, menu_id)) conn.commit() conn.close() return True, newstok # Bagian Promooo def promo_add(code, ptype, value, min_total=0): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("INSERT INTO promo (code,type,value,min_total) VALUES (?,?,?,?)", (code,ptype,value,min_total)) conn.commit() conn.close() def promo_update(code, ptype, value, min_total=0): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("UPDATE promo SET type=?, value=?, min_total=? WHERE code=?", (ptype,value,min_total,code)) conn.commit() conn.close() def promo_delete(code): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("DELETE FROM promo WHERE code=?", (code,)) conn.commit() conn.close() def promo_list(): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("SELECT code,type,value,min_total FROM promo ORDER BY code") rows = c.fetchall() conn.close() return rows def promo_get(code): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute("SELECT code,type,value,min_total FROM promo WHERE code=?", (code,)) r = c.fetchone() conn.close() return r def apply_discounts_and_promo(cart_items, promo_code=None): """ cart_items: list of dicts: [{'menu_id':..,'qty':..}, ...] returns breakdown: subtotal, item_discount_total, promo_code, promo_discount, total - uses item_discount_pct from menu table - promo_code can be percent or fixed, with min_total """ conn = sqlite3.connect(DB_PATH) c = conn.cursor() subtotal = 0.0 item_discount_total = 0.0 for it in cart_items: c.execute("SELECT harga,item_discount_pct FROM menu WHERE id=?", (it['menu_id'],)) r = c.fetchone() if not r: continue price, item_disc_pct = r qty = it.get('qty',1) line = price * qty subtotal += line if item_disc_pct and item_disc_pct > 0: item_discount_total += (price * qty) * (item_disc_pct/100.0) promo_discount = 0.0 promo_applied = None if promo_code: c.execute("SELECT type,value,min_total FROM promo WHERE code=?", (promo_code,)) row = c.fetchone() if row: ptype, val, min_total = row if subtotal >= min_total: if ptype == 'percent': promo_discount = (subtotal - item_discount_total) * (val/100.0) else: promo_discount = val promo_applied = promo_code total = subtotal - item_discount_total - promo_discount if total < 0: total = 0.0 conn.close() return { 'subtotal': round(subtotal,2), 'item_discount': round(item_discount_total,2), 'promo_code': promo_applied, 'promo_discount': round(promo_discount,2), 'total': round(total,2) } # wilayah UI (universitas indonesia) class App: def __init__(self, root): self.root = root self.root.title("Cafe Totoro") self.session = None self.img_cache = {} self.setup_ui() def setup_ui(self): self.root.geometry("1000x650") self.root.resizable(False, False) self.login_frame() # windah batubara # tampilan login dan logout def login_frame(self): for w in self.root.winfo_children(): w.destroy() frame = ttk.Frame(self.root, padding=20) frame.pack(expand=True) ttk.Label(frame, text="LOGIN", font=("Arial", 24)).grid(row=0, column=0, columnspan=2, pady=10) ttk.Label(frame, text="Username:").grid(row=1, column=0, sticky='e', pady=5) self.username_var = tk.StringVar() ttk.Entry(frame, textvariable=self.username_var, width=30).grid(row=1, column=1, pady=5) ttk.Label(frame, text="Password:").grid(row=2, column=0, sticky='e', pady=5) self.password_var = tk.StringVar() ttk.Entry(frame, textvariable=self.password_var, show="*", width=30).grid(row=2, column=1, pady=5) ttk.Button(frame, text="Login", command=self.handle_login).grid(row=3, column=0, columnspan=2, pady=12) def handle_login(self): u = self.username_var.get().strip() p = self.password_var.get().strip() if not u or not p: messagebox.showwarning("Input", "Masukkan username & password") return user = authenticate(u,p) if not user: messagebox.showerror("Gagal", "Username atau password salah") return self.session = user messagebox.showinfo("Sukses", f"Login berhasil sebagai {user['role']}") self.dashboard_frame() def logout(self): self.session = None self.img_cache.clear() self.login_frame()