Загрузка данных
import sys
import pymysql
import os
from datetime import datetime
from PyQt6 import uic
from PyQt6.QtWidgets import *
from PyQt6.QtGui import QPixmap
from PyQt6.QtCore import Qt
ROLE_GUEST = "Гость"
ROLE_CLIENT = "Клиент"
ROLE_MANAGER = "Менеджер"
ROLE_ADMIN = "Администратор"
def get_connection():
try:
connection = pymysql.connect(
host="localhost",
user="root",
password="root",
database="building_materials",
cursorclass=pymysql.cursors.DictCursor
)
return connection
except Exception as e:
QMessageBox.critical(None, "Ошибка", f"Не удалось подключиться к БД:\n{e}")
sys.exit(1)
class LoginWindow(QMainWindow):
def __init__(self):
super().__init__()
try:
uic.loadUi("login.ui", self)
self.loginButton.clicked.connect(self.login)
self.guestButton.clicked.connect(self.guest_enter)
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка загрузки интерфейса:\n{e}")
def login(self):
try:
login = self.loginEdit.text()
password = self.passwordEdit.text()
if not login or not password:
QMessageBox.warning(self, "Ошибка", "Введите логин и пароль")
return
connection = get_connection()
cursor = connection.cursor()
sql = """
SELECT users.full_name,
roles.role_name
FROM users
JOIN roles ON users.role_id = roles.role_id
WHERE login = %s \
AND password = %s \
"""
cursor.execute(sql, (login, password))
user = cursor.fetchone()
cursor.close()
connection.close()
if user:
full_name = user["full_name"]
role = user["role_name"]
self.products = ProductsWindow(role, full_name, login)
self.products.show()
self.close()
else:
QMessageBox.warning(self, "Ошибка", "Неверный логин или пароль")
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка при входе:\n{e}")
def guest_enter(self):
self.products = ProductsWindow(ROLE_GUEST, "Гость", None)
self.products.show()
self.close()
class ProductEditWindow(QMainWindow):
def __init__(self, parent=None, product_id=None):
super().__init__()
self.parent = parent
self.product_id = product_id
self.image_path = None
try:
uic.loadUi("product_edit.ui", self)
self.saveButton.clicked.connect(self.save)
self.cancelButton.clicked.connect(self.close)
self.loadImageButton.clicked.connect(self.load_image)
if product_id:
self.setWindowTitle("Редактирование товара")
self.load_product()
else:
self.setWindowTitle("Добавление товара")
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка загрузки интерфейса:\n{e}")
def load_image(self):
file_path, _ = QFileDialog.getOpenFileName(
self, "Выберите фото", "", "Images (*.png *.jpg *.jpeg *.bmp)"
)
if file_path:
self.image_path = file_path
pixmap = QPixmap(file_path)
if not pixmap.isNull():
self.imageLabel.setPixmap(pixmap.scaled(200, 200, Qt.AspectRatioMode.KeepAspectRatio))
def load_product(self):
try:
connection = get_connection()
cursor = connection.cursor()
sql = """
SELECT product_name, \
category_id, \
description, \
manufacturer_id,
supplier_id, \
price, \
unit, \
discount, \
stock_quantity, \
image_path
FROM products \
WHERE product_id = %s \
"""
cursor.execute(sql, (self.product_id,))
product = cursor.fetchone()
if product:
self.nameEdit.setText(product["product_name"])
self.descEdit.setPlainText(product["description"] or "")
self.priceEdit.setText(str(product["price"]))
self.unitEdit.setText(product["unit"])
self.discountEdit.setText(str(product["discount"]))
self.stockEdit.setText(str(product["stock_quantity"]))
cursor.execute("SELECT category_id, category_name FROM categories")
categories = cursor.fetchall()
self.categoryBox.clear()
for cat in categories:
self.categoryBox.addItem(cat["category_name"], cat["category_id"])
if cat["category_id"] == product["category_id"]:
self.categoryBox.setCurrentIndex(self.categoryBox.count() - 1)
cursor.execute("SELECT manufacturer_id, manufacturer_name FROM manufacturers")
manufacturers = cursor.fetchall()
self.manufacturerBox.clear()
for man in manufacturers:
self.manufacturerBox.addItem(man["manufacturer_name"], man["manufacturer_id"])
if man["manufacturer_id"] == product["manufacturer_id"]:
self.manufacturerBox.setCurrentIndex(self.manufacturerBox.count() - 1)
cursor.execute("SELECT supplier_id, supplier_name FROM suppliers")
suppliers = cursor.fetchall()
self.supplierBox.clear()
for sup in suppliers:
self.supplierBox.addItem(sup["supplier_name"], sup["supplier_id"])
if sup["supplier_id"] == product["supplier_id"]:
self.supplierBox.setCurrentIndex(self.supplierBox.count() - 1)
if product["image_path"] and os.path.exists(product["image_path"]):
self.image_path = product["image_path"]
pixmap = QPixmap(product["image_path"])
self.imageLabel.setPixmap(pixmap.scaled(200, 200, Qt.AspectRatioMode.KeepAspectRatio))
cursor.close()
connection.close()
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка загрузки товара:\n{e}")
def save(self):
try:
if not self.nameEdit.text():
QMessageBox.warning(self, "Ошибка", "Введите название товара")
return
if not self.priceEdit.text():
QMessageBox.warning(self, "Ошибка", "Введите цену")
return
connection = get_connection()
cursor = connection.cursor()
category_id = self.categoryBox.currentData()
manufacturer_id = self.manufacturerBox.currentData()
supplier_id = self.supplierBox.currentData()
if self.product_id:
sql = """
UPDATE products \
SET product_name=%s, \
category_id=%s, \
description=%s, \
manufacturer_id=%s, \
supplier_id=%s, \
price=%s, \
unit=%s, \
discount=%s, \
stock_quantity=%s, \
image_path=%s
WHERE product_id = %s \
"""
params = (
self.nameEdit.text(), category_id, self.descEdit.toPlainText(),
manufacturer_id, supplier_id, float(self.priceEdit.text()),
self.unitEdit.text(), int(self.discountEdit.text() or 0),
int(self.stockEdit.text() or 0), self.image_path, self.product_id
)
else:
sql = """
INSERT INTO products (product_name, category_id, description,
manufacturer_id, supplier_id, price, unit, discount, stock_quantity, \
image_path)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s) \
"""
params = (
self.nameEdit.text(), category_id, self.descEdit.toPlainText(),
manufacturer_id, supplier_id, float(self.priceEdit.text()),
self.unitEdit.text(), int(self.discountEdit.text() or 0),
int(self.stockEdit.text() or 0), self.image_path
)
cursor.execute(sql, params)
connection.commit()
cursor.close()
connection.close()
QMessageBox.information(self, "Успех", "Товар сохранён")
if self.parent:
self.parent.load_products()
self.close()
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка сохранения товара:\n{e}")
class OrderEditWindow(QMainWindow):
def __init__(self, parent=None, order_id=None):
super().__init__()
self.parent = parent
self.order_id = order_id
try:
uic.loadUi("order_edit.ui", self)
self.saveButton.clicked.connect(self.save)
self.cancelButton.clicked.connect(self.close)
if order_id:
self.setWindowTitle("Редактирование заказа")
self.load_order()
else:
self.setWindowTitle("Добавление заказа")
self.load_clients()
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка загрузки интерфейса:\n{e}")
def load_clients(self):
try:
connection = get_connection()
cursor = connection.cursor()
cursor.execute("SELECT user_id, full_name FROM users")
clients = cursor.fetchall()
self.clientBox.clear()
for client in clients:
self.clientBox.addItem(client["full_name"], client["user_id"])
cursor.close()
connection.close()
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка загрузки клиентов:\n{e}")
def load_order(self):
try:
connection = get_connection()
cursor = connection.cursor()
sql = "SELECT order_id, order_date, delivery_date, pickup_address, client_id, code, status FROM orders WHERE order_id=%s"
cursor.execute(sql, (self.order_id,))
order = cursor.fetchone()
if order:
self.load_clients()
self.dateEdit.setDate(datetime.strptime(str(order["order_date"]), "%Y-%m-%d").date())
self.deliveryDateEdit.setDate(datetime.strptime(str(order["delivery_date"]), "%Y-%m-%d").date())
self.addressEdit.setText(order["pickup_address"])
self.codeEdit.setText(order["code"])
self.statusEdit.setText(order["status"])
for i in range(self.clientBox.count()):
if self.clientBox.itemData(i) == order["client_id"]:
self.clientBox.setCurrentIndex(i)
break
cursor.close()
connection.close()
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка загрузки заказа:\n{e}")
def save(self):
try:
connection = get_connection()
cursor = connection.cursor()
if self.order_id:
sql = """
UPDATE orders \
SET order_date=%s, \
delivery_date=%s, \
pickup_address=%s, \
client_id=%s, \
code=%s, \
status=%s
WHERE order_id = %s \
"""
params = (
self.dateEdit.date().toPyDate(), self.deliveryDateEdit.date().toPyDate(),
self.addressEdit.text(), self.clientBox.currentData(),
self.codeEdit.text(), self.statusEdit.text(), self.order_id
)
else:
sql = """
INSERT INTO orders (order_date, delivery_date, pickup_address, client_id, code, status)
VALUES (%s, %s, %s, %s, %s, %s) \
"""
params = (
self.dateEdit.date().toPyDate(), self.deliveryDateEdit.date().toPyDate(),
self.addressEdit.text(), self.clientBox.currentData(),
self.codeEdit.text(), self.statusEdit.text()
)
cursor.execute(sql, params)
connection.commit()
cursor.close()
connection.close()
QMessageBox.information(self, "Успех", "Заказ сохранён")
if self.parent:
self.parent.load_orders()
self.close()
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка сохранения заказа:\n{e}")
class OrdersWindow(QMainWindow):
def __init__(self, role):
super().__init__()
self.role = role
try:
uic.loadUi("orders.ui", self)
self.backButton.clicked.connect(self.go_back)
self.load_orders()
if self.role == ROLE_ADMIN:
self.addButton.setVisible(True)
self.editButton.setVisible(True)
self.deleteButton.setVisible(True)
self.addButton.clicked.connect(self.add_order)
self.editButton.clicked.connect(self.edit_order)
self.deleteButton.clicked.connect(self.delete_order)
else:
self.addButton.setVisible(False)
self.editButton.setVisible(False)
self.deleteButton.setVisible(False)
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка загрузки интерфейса:\n{e}")
def go_back(self):
self.close()
def load_orders(self):
try:
connection = get_connection()
cursor = connection.cursor()
sql = """
SELECT order_id, \
code, \
order_date, \
delivery_date, \
status
FROM orders \
"""
cursor.execute(sql)
orders = cursor.fetchall()
cursor.close()
connection.close()
self.ordersList.clear()
for order in orders:
text = (
f"Заказ № {order['order_id']} | "
f"Дата заказа: {order['order_date']} | "
f"Дата доставки: {order['delivery_date']} | "
f"Код: {order['code']} | "
f"Статус: {order['status']}"
)
self.ordersList.addItem(text)
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка загрузки заказов:\n{e}")
def add_order(self):
self.order_edit = OrderEditWindow(self)
self.order_edit.show()
def edit_order(self):
current_item = self.ordersList.currentItem()
if not current_item:
QMessageBox.warning(self, "Ошибка", "Выберите заказ для редактирования")
return
text = current_item.text()
order_id = int(text.split("№")[1].split("|")[0].strip())
self.order_edit = OrderEditWindow(self, order_id)
self.order_edit.show()
def delete_order(self):
current_item = self.ordersList.currentItem()
if not current_item:
QMessageBox.warning(self, "Ошибка", "Выберите заказ для удаления")
return
reply = QMessageBox.question(self, "Подтверждение", "Удалить заказ?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
if reply == QMessageBox.StandardButton.Yes:
try:
text = current_item.text()
order_id = int(text.split("№")[1].split("|")[0].strip())
connection = get_connection()
cursor = connection.cursor()
cursor.execute("DELETE FROM order_items WHERE order_id=%s", (order_id,))
cursor.execute("DELETE FROM orders WHERE order_id=%s", (order_id,))
connection.commit()
cursor.close()
connection.close()
QMessageBox.information(self, "Успех", "Заказ удалён")
self.load_orders()
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка удаления заказа:\n{e}")
class ProductsWindow(QMainWindow):
def __init__(self, role, full_name, login):
super().__init__()
try:
uic.loadUi("products.ui", self)
self.searchEdit.setVisible(False)
self.filterBox.setVisible(False)
self.sortBox.setVisible(False)
self.ordersButton.setVisible(False)
self.addButton.setVisible(False)
self.editButton.setVisible(False)
self.deleteButton.setVisible(False)
self.role = role
self.full_name = full_name
self.login = login
self.labelUser.setText(full_name)
self.container = QWidget()
self.scrollArea.setWidget(self.container)
self.scrollArea.setWidgetResizable(True)
self.verticalLayout = QVBoxLayout(self.container)
self.load_suppliers()
self.load_products()
self.setup_role()
self.backButton.clicked.connect(self.go_back)
self.ordersButton.clicked.connect(self.open_orders)
self.addButton.clicked.connect(self.add_product)
self.editButton.clicked.connect(self.edit_product)
self.deleteButton.clicked.connect(self.delete_product)
self.searchEdit.textChanged.connect(self.load_products)
self.filterBox.currentTextChanged.connect(self.load_products)
self.sortBox.currentTextChanged.connect(self.load_products)
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка загрузки интерфейса:\n{e}")
def load_products(self):
try:
for i in reversed(range(self.verticalLayout.count())):
widget = self.verticalLayout.itemAt(i).widget()
if widget:
widget.setParent(None)
search = self.searchEdit.text()
supplier = self.filterBox.currentText()
sort = self.sortBox.currentText()
sql = """
SELECT p.product_id, \
p.product_name, \
c.category_name, \
p.description, \
m.manufacturer_name, \
s.supplier_name, \
p.price, \
p.unit, \
p.discount, \
p.stock_quantity, \
p.image_path
FROM products p
JOIN categories c ON p.category_id = c.category_id
JOIN manufacturers m ON p.manufacturer_id = m.manufacturer_id
JOIN suppliers s ON p.supplier_id = s.supplier_id
WHERE (p.product_name LIKE %s
OR c.category_name LIKE %s
OR m.manufacturer_name LIKE %s
OR s.supplier_name LIKE %s) \
"""
params = [
f"%{search}%",
f"%{search}%",
f"%{search}%",
f"%{search}%"
]
if supplier != "Все поставщики":
sql += " AND s.supplier_name=%s"
params.append(supplier)
if sort == "По возрастанию":
sql += " ORDER BY p.stock_quantity ASC"
elif sort == "По убыванию":
sql += " ORDER BY p.stock_quantity DESC"
connection = get_connection()
cursor = connection.cursor()
cursor.execute(sql, params)
products = cursor.fetchall()
cursor.close()
connection.close()
for product in products:
card = self.create_product_card(product)
self.verticalLayout.addWidget(card)
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка загрузки товаров:\n{e}")
def create_product_card(self, product):
card = QWidget()
card.setProperty("product_data", product)
card.setCursor(Qt.CursorShape.PointingHandCursor)
card_layout = QHBoxLayout(card)
image_label = QLabel()
image_label.setFixedSize(120, 120)
if product["image_path"]:
pixmap = QPixmap(product["image_path"])
if not pixmap.isNull():
image_label.setPixmap(pixmap.scaled(120, 120, Qt.AspectRatioMode.KeepAspectRatio))
else:
image_label.setText("Нет фото")
image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
else:
image_label.setText("Нет фото")
image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
info_text = (
f"ID: {product['product_id']}\n"
f"Категория: {product['category_name']}\n"
f"Название: {product['product_name']}\n"
f"Описание: {product['description']}\n"
f"Производитель: {product['manufacturer_name']}\n"
f"Поставщик: {product['supplier_name']}\n"
f"Цена: {product['price']} руб.\n"
f"Единица измерения: {product['unit']}\n"
f"Количество: {product['stock_quantity']}"
)
info_label = QLabel(info_text)
info_label.setWordWrap(True)
discount_label = QLabel(str(product["discount"]) + "%")
card_layout.addWidget(image_label)
card_layout.addWidget(info_label)
card_layout.addWidget(discount_label)
card.setStyleSheet("QWidget {border: 1px solid black; margin: 5px;}")
discount_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
return card
def setup_role(self):
if self.role == ROLE_GUEST:
self.labelUser.setText("Вы вошли как Гость")
elif self.role == ROLE_CLIENT:
self.labelUser.setText(self.full_name)
elif self.role == ROLE_MANAGER:
self.labelUser.setText(f"{self.full_name} (Менеджер)")
self.enable_manager_features()
elif self.role == ROLE_ADMIN:
self.labelUser.setText(f"{self.full_name} (Админ)")
self.enable_manager_features()
self.enable_admin_features()
def enable_manager_features(self):
self.searchEdit.setVisible(True)
self.filterBox.setVisible(True)
self.sortBox.setVisible(True)
self.ordersButton.setVisible(True)
def enable_admin_features(self):
self.addButton.setVisible(True)
self.editButton.setVisible(True)
self.deleteButton.setVisible(True)
def go_back(self):
self.login = LoginWindow()
self.login.show()
self.close()
def open_orders(self):
self.orders_window = OrdersWindow(self.role)
self.orders_window.show()
def load_suppliers(self):
try:
connection = get_connection()
cursor = connection.cursor()
sql = "SELECT supplier_name FROM suppliers"
cursor.execute(sql)
suppliers = cursor.fetchall()
cursor.close()
connection.close()
self.filterBox.clear()
self.filterBox.addItem("Все поставщики")
for supplier in suppliers:
self.filterBox.addItem(supplier["supplier_name"])
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка загрузки поставщиков:\n{e}")
def add_product(self):
self.product_edit = ProductEditWindow(self)
self.product_edit.show()
def edit_product(self):
for i in range(self.verticalLayout.count()):
widget = self.verticalLayout.itemAt(i).widget()
if widget:
product_data = widget.property("product_data")
if product_data:
self.product_edit = ProductEditWindow(self, product_data["product_id"])
self.product_edit.show()
return
QMessageBox.warning(self, "Ошибка", "Нажмите на карточку товара для редактирования")
def delete_product(self):
for i in range(self.verticalLayout.count()):
widget = self.verticalLayout.itemAt(i).widget()
if widget:
product_data = widget.property("product_data")
if product_data:
reply = QMessageBox.question(self, "Подтверждение", "Удалить товар?",
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
if reply == QMessageBox.StandardButton.Yes:
try:
connection = get_connection()
cursor = connection.cursor()
cursor.execute("DELETE FROM order_items WHERE product_id=%s", (product_data["product_id"],))
cursor.execute("DELETE FROM products WHERE product_id=%s", (product_data["product_id"],))
connection.commit()
cursor.close()
connection.close()
QMessageBox.information(self, "Успех", "Товар удалён")
self.load_products()
except Exception as e:
QMessageBox.critical(self, "Ошибка", f"Ошибка удаления товара:\n{e}")
return
QMessageBox.warning(self, "Ошибка", "Нажмите на карточку товара для удаления")
app = QApplication(sys.argv)
window = LoginWindow()
window.show()
sys.exit(app.exec())