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