2025-11-26 20:39:24 +07:00

342 lines
10 KiB
Python

"""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()