import sys
import mysql.connector
from PySide6.QtWidgets import (
QApplication,QMainWindow,QWidget,QVBoxLayout,QHBoxLayout,QLabel,QLineEdit,
QComboBox,QPushButton,QTableWidget,QTableWidgetItem,QSpinBox,QCheckBox,QRadioButton,QScrollArea,QGridLayout,QFrame,QMessageBox,QStackedWidget,QDialog,QGroupBox,
)
from PySide6.QtCore import Qt, Signal
DB_CONFIG = {
"host": "localhost",
"user": "root",
"password": "Lbhtrnjh_4231",
"database": "cafeteria_db",
"port": 3305,
}
COLOR_ORANGE = "#FF5A5A"
COLOR_TEXT = "#000000"
COLOR_BORDER = "#000000"
COLOR_MUTED = "#999999"
STYLE = f"""
QMainWindow, QWidget, QDialog {{
background-color: #FFFFFF;
}}
QLabel, QGroupBox {{
color: {COLOR_TEXT};
font-family: 'Segoe UI', Arial;
font-size: 14px;
}}
h2 {{ font-size: 24px; font-weight: bold; margin: 0; }}
QLineEdit, QComboBox, QSpinBox {{
border: 1px solid #000000;
padding: 5px;
color: #000000;
background-color: #FFFFFF;
}}
QTableWidget {{
border: 1px solid #000000;
gridline-color: #000000;
color: #000000;
background-color: #FFFFFF;
}}
QHeaderView::section {{
background-color: #FFFFFF;
border: 1px solid #000000;
padding: 4px;
font-weight: bold;
color: #000000;
}}
QPushButton {{
background-color: #FFFFFF;
border: 1px solid #000000;
padding: 5px 10px;
border-radius: 4px;
color: #000000;
}}
QPushButton:hover {{ background-color: #F0F0F0; }}
"""
class Database:
def __init__(self):
try:
self.conn = mysql.connector.connect(**DB_CONFIG)
except:
self.conn = None
def query(self, sql, params=()):
if not self.conn:
return []
cur = self.conn.cursor(dictionary=True)
cur.execute(sql, params)
res = cur.fetchall()
cur.close()
return res
def execute(self, sql, params=()):
if not self.conn:
return None
cur = self.conn.cursor()
cur.execute(sql, params)
self.conn.commit()
last_id = cur.lastrowid
cur.close()
return last_id
def check_login(self, login, password):
if login == "admin" and password == "123":
return 999
try:
sql = "SELECT employer_id FROM autorization WHERE login=%s AND password=%s"
res = self.query(sql, (login, password))
return res[0]["employer_id"] if res else None
except:
return None
def get_products(self, search="", category_id=None, sort="ASC"):
sql = "SELECT * FROM products WHERE is_availible=1"
filters = []
if search:
sql += " AND (`value` LIKE %s OR `description` LIKE %s)"
filters += [f"%{search}%"] * 2
if category_id:
sql += " AND category_id = %s"
filters.append(category_id)
sql += f" ORDER BY cost {sort}"
try:
res = self.query(sql, filters)
if res:
return res
except:
pass
return [
{
"id": 1,
"value": "Кофе (Заглушка)",
"cost": 150.0,
"description": "Вкусный кофе",
"count_in_bag": 200,
},
{
"id": 2,
"value": "Чизкейк (Заглушка)",
"cost": 250.0,
"description": "Сладкий десерт",
"count_in_bag": 150,
},
]
def get_categories(self):
try:
res = self.query("SELECT * FROM categories")
if res and "value" in res[0]:
return res
except:
pass
return [{"id": 1, "value": "Напитки"}, {"id": 2, "value": "Десерты"}]
def get_clients(self):
try:
res = self.query("SELECT * FROM clients")
if res and "phone_number" in res[0]:
return res
except:
pass
return [{"phone_number": "89991234567", "name": "Иван (Заглушка)"}]
class LoginDialog(QDialog):
def __init__(self, db):
super().__init__()
self.db = db
self.setWindowTitle("Вход")
self.setFixedSize(300, 200)
self.setStyleSheet(STYLE)
layout = QVBoxLayout(self)
layout.addWidget(QLabel("
Авторизация
"))
self.login = QLineEdit()
self.login.setPlaceholderText("Логин")
layout.addWidget(self.login)
self.password = QLineEdit()
self.password.setPlaceholderText("Пароль")
self.password.setEchoMode(QLineEdit.Password)
layout.addWidget(self.password)
btn = QPushButton("Войти")
btn.clicked.connect(self.handle_login)
layout.addWidget(btn)
self.emp_id = None
def handle_login(self):
l = self.login.text().strip()
p = self.password.text()
try:
uid = self.db.check_login(l, p)
if uid:
self.emp_id = uid
self.accept()
else:
QMessageBox.warning(self, "Ошибка", "Неверный логин или пароль")
except mysql.connector.Error as e:
if e.errno == 1146:
QMessageBox.critical(
self,
"Ошибка БД",
"Таблица 'autorization' не найдена. \n"
"Пожалуйста, убедитесь, что вы импортировали дамп Kovrigin.sql в базу 'cafeteria_db'.",
)
else:
QMessageBox.critical(self, "Ошибка БД", f"Произошла ошибка: {e}")
class ProductCard(QFrame):
add_clicked = Signal(dict)
def __init__(self, product):
super().__init__()
self.product = product
self.setFixedSize(220, 320)
self.setStyleSheet(
f"""
QFrame {{ border: 1px solid #000; background: white; }}
QLabel#img {{ border: 2px dashed #999; background: white; color: black; font-weight: bold; }}
QLabel#price {{ color: #FF5A5A; font-weight: bold; font-size: 16px; border: none; }}
QLabel#info {{ color: #333; font-size: 12px; border: none; }}
QLabel#title {{ font-weight: bold; font-size: 14px; border: none; }}
QPushButton {{ background-color: #FF5A5A; color: white; border: none; font-weight: bold; border-radius: 8px; }}
"""
)
layout = QVBoxLayout(self)
img = QLabel("Изображение\nпозиции")
img.setObjectName("img")
img.setAlignment(Qt.AlignCenter)
img.setFixedHeight(120)
layout.addWidget(img)
title = QLabel(product["value"])
title.setObjectName("title")
title.setWordWrap(True)
layout.addWidget(title)
desc = QLabel(product.get("description", "Описание позиции"))
desc.setObjectName("info")
desc.setWordWrap(True)
layout.addWidget(desc)
layout.addStretch()
bottom = QHBoxLayout()
price_v = QVBoxLayout()
price_lbl = QLabel(f"{product['cost']} руб.")
price_lbl.setObjectName("price")
price_v.addWidget(price_lbl)
weight = QLabel(f"Вес: {product.get('count_in_bag', '-')} гр./мл.")
weight.setObjectName("info")
price_v.addWidget(weight)
bottom.addLayout(price_v)
add_btn = QPushButton("Добавить")
add_btn.setFixedSize(90, 35)
add_btn.clicked.connect(lambda: self.add_clicked.emit(self.product))
bottom.addWidget(add_btn)
layout.addLayout(bottom)
class CatalogPage(QWidget):
product_added = Signal(dict)
go_to_cart = Signal()
def __init__(self, db):
super().__init__()
self.db = db
self.sort = "ASC"
layout = QVBoxLayout(self)
header = QHBoxLayout()
header.addWidget(QLabel("Каталог
"))
header.addStretch()
cart_btn = QPushButton("🛒 Корзина")
cart_btn.clicked.connect(self.go_to_cart.emit)
header.addWidget(cart_btn)
layout.addLayout(header)
filters = QHBoxLayout()
self.search = QLineEdit()
self.search.setPlaceholderText("Поиск...")
self.search.textChanged.connect(self.refresh)
filters.addWidget(self.search)
self.cat_cb = QComboBox()
self.cat_cb.addItem("Все категории", None)
for c in db.get_categories():
self.cat_cb.addItem(c["value"], c["id"])
self.cat_cb.currentIndexChanged.connect(self.refresh)
filters.addWidget(self.cat_cb)
layout.addLayout(filters)
scroll = QScrollArea()
scroll.setWidgetResizable(True)
scroll.setFrameShape(QFrame.NoFrame)
self.grid_w = QWidget()
self.grid = QGridLayout(self.grid_w)
self.grid.setAlignment(Qt.AlignTop | Qt.AlignLeft)
scroll.setWidget(self.grid_w)
layout.addWidget(scroll)
self.refresh()
def refresh(self):
while self.grid.count():
item = self.grid.takeAt(0)
if item.widget():
item.widget().deleteLater()
prods = self.db.get_products(
search=self.search.text(),
category_id=self.cat_cb.currentData(),
sort=self.sort,
)
for i, p in enumerate(prods):
card = ProductCard(p)
card.add_clicked.connect(self.product_added.emit)
self.grid.addWidget(card, i // 4, i % 4)
class CartPage(QWidget):
go_back = Signal()
def __init__(self, db, emp_id):
super().__init__()
self.db = db
self.emp_id = emp_id
self.items = []
layout = QHBoxLayout(self)
left = QVBoxLayout()
back = QPushButton("← К каталогу")
back.clicked.connect(self.go_back.emit)
left.addWidget(back)
left.addWidget(QLabel("Корзина заказа
"))
self.table = QTableWidget()
self.table.setColumnCount(5)
self.table.setHorizontalHeaderLabels(
["Наименование", "Цена, руб.", "Кол-во", "Стоимость", ""]
)
left.addWidget(self.table)
layout.addLayout(left, 2)
right = QVBoxLayout()
right.addWidget(QLabel("Заказ клиента
"))
box_client = QGroupBox()
client_l = QVBoxLayout(box_client)
row1 = QHBoxLayout()
row1.addWidget(QLabel("Клиент:"))
self.client_cb = QComboBox()
for c in db.get_clients():
self.client_cb.addItem(
f"{c['name']} ({c['phone_number']})", c["phone_number"]
)
row1.addWidget(self.client_cb)
client_l.addLayout(row1)
self.no_client = QCheckBox("Без клиента")
self.no_client.stateChanged.connect(lambda s: self.client_cb.setEnabled(not s))
client_l.addWidget(self.no_client)
client_l.addWidget(QLabel("-" * 40))
self.total_lbl = QLabel(
"Стоимость корзины: 0,00 руб."
)
client_l.addWidget(self.total_lbl)
right.addWidget(box_client)
box_pay = QGroupBox("Метод оплаты")
pay_l = QVBoxLayout(box_pay)
row2 = QHBoxLayout()
row2.addWidget(QLabel("Тип оплаты:"))
self.pay_type = QComboBox()
self.pay_type.addItems(["Наличные", "Карта", "QR-код"])
row2.addWidget(self.pay_type)
pay_l.addLayout(row2)
pay_l.addWidget(QLabel("Тип выдачи заказа:"))
self.r1 = QRadioButton("В заведении")
self.r2 = QRadioButton("На вынос")
self.r3 = QRadioButton("Курьером")
self.r1.setChecked(True)
pay_l.addWidget(self.r1)
pay_l.addWidget(self.r2)
pay_l.addWidget(self.r3)
right.addWidget(box_pay)
self.submit_btn = QPushButton("Оформить заказ")
self.submit_btn.setMinimumHeight(60)
self.submit_btn.setStyleSheet(
"""
QPushButton {
background-color: #FF5A5A;
color: white;
font-size: 20px;
font-weight: bold;
border-radius: 15px;
border: 2px solid #000;
}
QPushButton:hover { background-color: #E04A4A; }
"""
)
self.submit_btn.clicked.connect(self.submit)
right.addWidget(self.submit_btn)
right.addStretch()
layout.addLayout(right, 1)
def add(self, product):
for item in self.items:
if item["id"] == product["id"]:
item["qty"] += 1
self.refresh_table()
return
self.items.append(
{
"id": product["id"],
"val": product["value"],
"cost": float(product["cost"]),
"qty": 1,
}
)
self.refresh_table()
def refresh_table(self):
self.table.setRowCount(len(self.items))
total = 0
for i, item in enumerate(self.items):
sub = item["cost"] * item["qty"]
total += sub
self.table.setItem(i, 0, QTableWidgetItem(item["val"]))
self.table.setItem(i, 1, QTableWidgetItem(str(item["cost"])))
spin = QSpinBox()
spin.setRange(1, 99)
spin.setValue(item["qty"])
spin.valueChanged.connect(lambda v, r=i: self.update_qty(r, v))
self.table.setCellWidget(i, 2, spin)
self.table.setItem(i, 3, QTableWidgetItem(f"{sub:.2f}"))
rem = QPushButton("Исключить")
rem.clicked.connect(lambda _, r=i: self.remove_item(r))
self.table.setCellWidget(i, 4, rem)
self.total_lbl.setText(
f"Стоимость корзины: {total:.2f} руб."
)
def update_qty(self, row, val):
self.items[row]["qty"] = val
self.refresh_table()
def remove_item(self, row):
self.items.pop(row)
self.refresh_table()
def submit(self):
if not self.items:
return
total = sum(i["cost"] * i["qty"] for i in self.items)
t_id = 1 if self.r1.isChecked() else (2 if self.r2.isChecked() else 3)
p_id = self.pay_type.currentIndex() + 1
order_num = (
self.db.query("SELECT MAX(order_number) as m FROM orders")[0]["m"] or 0
)
order_num += 1
oid = self.db.execute(
"INSERT INTO orders (order_number, date_create, type_id, employer_id, total_cost, pay_id) VALUES (%s, NOW(), %s, %s, %s, %s)",
(order_num, t_id, self.emp_id, total, p_id),
)
if self.no_client.isChecked() is False:
self.db.execute(
"INSERT INTO clients_orders (client_number, order_id) VALUES (%s, %s)",
(self.client_cb.currentData(), oid),
)
for it in self.items:
self.db.execute(
"INSERT INTO order_shopcase (order_id, product_id, current_count) VALUES (%s, %s, %s)",
(oid, it["id"], it["qty"]),
)
QMessageBox.information(self, "Успех", f"Заказ #{order_num} оформлен!")
self.items = []
self.refresh_table()
self.go_back.emit()
class MainWindow(QMainWindow):
def __init__(self, db, emp_id):
super().__init__()
self.db = db
self.setWindowTitle("Кафетерий (Kovrigin)")
self.setGeometry(100, 100, 1200, 800)
self.setStyleSheet(STYLE)
self.stack = QStackedWidget()
self.setCentralWidget(self.stack)
self.catalog = CatalogPage(db)
self.catalog.product_added.connect(self.add_to_cart)
self.catalog.go_to_cart.connect(lambda: self.stack.setCurrentIndex(1))
self.stack.addWidget(self.catalog)
self.cart = CartPage(db, emp_id)
self.cart.go_back.connect(lambda: self.stack.setCurrentIndex(0))
self.stack.addWidget(self.cart)
def add_to_cart(self, prod):
self.cart.add(prod)
QMessageBox.information(self, "Добавлено", f"«{prod['value']}» в корзине")
if __name__ == "__main__":
app = QApplication(sys.argv)
db = Database()
login = LoginDialog(db)
if login.exec() == QDialog.Accepted:
win = MainWindow(db, login.emp_id)
win.show()
sys.exit(app.exec())