Manager + Client fixes
This commit is contained in:
parent
c0727d7b59
commit
2fff742651
2 changed files with 641 additions and 37 deletions
255
src/db.py
255
src/db.py
|
|
@ -118,31 +118,260 @@ def get_items(*, cursor):
|
|||
|
||||
|
||||
@do_request(autocommit=True)
|
||||
def create_request(item_id: int, user: User, **kwargs):
|
||||
def create_request(item_id: int, quantity: int, user: User,
|
||||
date_from: str = None, date_to: str = None,
|
||||
notes: str = None, *, cursor):
|
||||
"""
|
||||
Создать заявку/заказ
|
||||
Создать новую заявку/заказ
|
||||
|
||||
TODO: Адаптировать под конкретную предметную область
|
||||
Args:
|
||||
item_id: ID элемента (товар, номер, услуга)
|
||||
user: Пользователь создающий заявку
|
||||
**kwargs: Дополнительные параметры (даты, количество, etc.)
|
||||
item_id: ID товара/услуги
|
||||
quantity: Количество
|
||||
user: Объект пользователя
|
||||
date_from: Дата начала (YYYY-MM-DD) или None
|
||||
date_to: Дата окончания (YYYY-MM-DD) или None
|
||||
notes: Дополнительные заметки
|
||||
cursor: Курсор БД (автоматически через декоратор)
|
||||
|
||||
Returns:
|
||||
True если успешно, False если ошибка
|
||||
"""
|
||||
# TODO: Реализовать вашу логику создания заявки
|
||||
pass
|
||||
try:
|
||||
# 1. Проверяем существование товара и его доступность
|
||||
cursor.execute("""
|
||||
SELECT id, name, price, quantity, status
|
||||
FROM items
|
||||
WHERE id = %s;
|
||||
""", (item_id,))
|
||||
|
||||
item = cursor.fetchone()
|
||||
|
||||
if not item:
|
||||
print(f"Error: Item with id={item_id} not found")
|
||||
return False
|
||||
|
||||
item_db_id, item_name, item_price, item_quantity, item_status = item
|
||||
|
||||
# 2. Проверяем статус товара
|
||||
if item_status not in ['available', 'reserved']:
|
||||
print(f"Error: Item '{item_name}' is not available (status: {item_status})")
|
||||
return False
|
||||
|
||||
# 3. Проверяем количество (если товар физический)
|
||||
if item_quantity < quantity:
|
||||
print(f"Error: Insufficient quantity. Available: {item_quantity}, requested: {quantity}")
|
||||
return False
|
||||
|
||||
# 4. Вычисляем total_price
|
||||
total_price = float(item_price) * quantity
|
||||
|
||||
# 5. Создаём заявку
|
||||
cursor.execute("""
|
||||
INSERT INTO requests (user_id, item_id, quantity, date_from, date_to,
|
||||
status, total_price, notes)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||
RETURNING id;
|
||||
""", (user.id, item_id, quantity, date_from, date_to,
|
||||
'pending', total_price, notes))
|
||||
|
||||
request_id = cursor.fetchone()[0]
|
||||
|
||||
print(f"Success: Request #{request_id} created for user {user.name}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error creating request: {e}")
|
||||
return False
|
||||
|
||||
|
||||
@do_request()
|
||||
def get_user_requests(user_id: int, *, cursor):
|
||||
"""
|
||||
Получить заявки/заказы пользователя
|
||||
Получить все заявки пользователя
|
||||
|
||||
TODO: Заменить на вашу логику
|
||||
Args:
|
||||
user_id: ID пользователя
|
||||
|
||||
Returns:
|
||||
List of tuples или None
|
||||
"""
|
||||
cursor.execute("""
|
||||
SELECT *
|
||||
FROM requests
|
||||
WHERE user_id = %s;
|
||||
SELECT
|
||||
r.id,
|
||||
r.created_at,
|
||||
i.name AS item_name,
|
||||
r.quantity,
|
||||
r.total_price,
|
||||
r.date_from,
|
||||
r.date_to,
|
||||
r.status,
|
||||
r.notes
|
||||
FROM requests r
|
||||
JOIN items i ON r.item_id = i.id
|
||||
WHERE r.user_id = %s
|
||||
ORDER BY r.created_at DESC;
|
||||
""", (user_id,))
|
||||
|
||||
return cursor.fetchall()
|
||||
|
||||
|
||||
@do_request(autocommit=True)
|
||||
def update_request_status(request_id: int, new_status: str, *, cursor):
|
||||
"""
|
||||
Обновить статус заявки (для менеджера/администратора)
|
||||
|
||||
Args:
|
||||
request_id: ID заявки
|
||||
new_status: Новый статус ('pending', 'approved', 'rejected', 'completed', 'cancelled')
|
||||
|
||||
Returns:
|
||||
True если успешно, False если ошибка
|
||||
"""
|
||||
valid_statuses = ['pending', 'approved', 'rejected', 'completed', 'cancelled']
|
||||
|
||||
if new_status not in valid_statuses:
|
||||
print(f"Error: Invalid status '{new_status}'. Must be one of: {valid_statuses}")
|
||||
return False
|
||||
|
||||
try:
|
||||
cursor.execute("""
|
||||
UPDATE requests
|
||||
SET status = %s, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = %s;
|
||||
""", (new_status, request_id))
|
||||
|
||||
if cursor.rowcount == 0:
|
||||
print(f"Error: Request #{request_id} not found")
|
||||
return False
|
||||
|
||||
print(f"Success: Request #{request_id} status updated to '{new_status}'")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error updating request status: {e}")
|
||||
return False
|
||||
|
||||
|
||||
@do_request()
|
||||
def get_all_requests(status_filter: str = None, *, cursor):
|
||||
"""
|
||||
Получить все заявки (для администратора/менеджера)
|
||||
|
||||
Args:
|
||||
status_filter: Фильтр по статусу (опционально)
|
||||
|
||||
Returns:
|
||||
List of tuples
|
||||
"""
|
||||
if status_filter:
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
r.id,
|
||||
r.created_at,
|
||||
u.name AS user_name,
|
||||
u.email AS user_email,
|
||||
i.name AS item_name,
|
||||
r.quantity,
|
||||
r.total_price,
|
||||
r.date_from,
|
||||
r.date_to,
|
||||
r.status
|
||||
FROM requests r
|
||||
JOIN users u ON r.user_id = u.id
|
||||
JOIN items i ON r.item_id = i.id
|
||||
WHERE r.status = %s
|
||||
ORDER BY r.created_at DESC;
|
||||
""", (status_filter,))
|
||||
else:
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
r.id,
|
||||
r.created_at,
|
||||
u.name AS user_name,
|
||||
u.email AS user_email,
|
||||
i.name AS item_name,
|
||||
r.quantity,
|
||||
r.total_price,
|
||||
r.date_from,
|
||||
r.date_to,
|
||||
r.status
|
||||
FROM requests r
|
||||
JOIN users u ON r.user_id = u.id
|
||||
JOIN items i ON r.item_id = i.id
|
||||
ORDER BY r.created_at DESC;
|
||||
""")
|
||||
|
||||
return cursor.fetchall()
|
||||
|
||||
|
||||
@do_request()
|
||||
def search_items(search_term: str, *, cursor):
|
||||
"""
|
||||
Поиск товаров по названию или описанию
|
||||
|
||||
Args:
|
||||
search_term: Поисковый запрос
|
||||
|
||||
Returns:
|
||||
List of tuples
|
||||
"""
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
i.id,
|
||||
i.name,
|
||||
i.description,
|
||||
i.price,
|
||||
i.quantity,
|
||||
i.status,
|
||||
c.name AS category_name
|
||||
FROM items i
|
||||
LEFT JOIN categories c ON i.category_id = c.id
|
||||
WHERE i.name ILIKE %s OR i.description ILIKE %s
|
||||
ORDER BY i.name;
|
||||
""", (f'%{search_term}%', f'%{search_term}%'))
|
||||
|
||||
return cursor.fetchall()
|
||||
|
||||
|
||||
@do_request()
|
||||
def get_items_by_category(category_id: int, *, cursor):
|
||||
"""
|
||||
Получить товары по категории
|
||||
|
||||
Args:
|
||||
category_id: ID категории
|
||||
|
||||
Returns:
|
||||
List of tuples
|
||||
"""
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
i.id,
|
||||
i.name,
|
||||
i.description,
|
||||
i.price,
|
||||
i.quantity,
|
||||
i.status
|
||||
FROM items i
|
||||
WHERE i.category_id = %s AND i.status = 'available'
|
||||
ORDER BY i.name;
|
||||
""", (category_id,))
|
||||
|
||||
return cursor.fetchall()
|
||||
|
||||
|
||||
@do_request()
|
||||
def get_all_categories(*, cursor):
|
||||
"""
|
||||
Получить все категории
|
||||
|
||||
Returns:
|
||||
List of tuples (id, name)
|
||||
"""
|
||||
cursor.execute("""
|
||||
SELECT id, name, description
|
||||
FROM categories
|
||||
ORDER BY name;
|
||||
""")
|
||||
|
||||
return cursor.fetchall()
|
||||
423
src/windows.py
423
src/windows.py
|
|
@ -1,5 +1,5 @@
|
|||
import csv
|
||||
from .db import auth, get_items, get_user_requests
|
||||
from .db import auth, get_items, create_request
|
||||
from .objects import User, SignalCode
|
||||
from .utils import TabWidgetCustom
|
||||
from PyQt6.QtWidgets import (
|
||||
|
|
@ -9,12 +9,14 @@ from PyQt6.QtWidgets import (
|
|||
QGroupBox,
|
||||
QFormLayout,
|
||||
QVBoxLayout,
|
||||
QHBoxLayout,
|
||||
QMessageBox,
|
||||
QTabWidget,
|
||||
QMainWindow,
|
||||
QComboBox,
|
||||
QDateEdit,
|
||||
QTableView
|
||||
QTableView,
|
||||
QLabel
|
||||
)
|
||||
from PyQt6.QtGui import QStandardItemModel, QStandardItem
|
||||
from PyQt6.QtSql import QSqlTableModel
|
||||
|
|
@ -146,7 +148,7 @@ class LoginWindow(BaseWindow):
|
|||
|
||||
def _apply_window_settings(self):
|
||||
self.setWindowTitle("Login")
|
||||
self.setFixedSize(300, 200)
|
||||
self.setFixedSize(260, 150)
|
||||
|
||||
|
||||
class AdminWindow(BaseWindow):
|
||||
|
|
@ -210,7 +212,7 @@ class AdminWindow(BaseWindow):
|
|||
date_from = tab.from_date.date().toString("yyyy-MM-dd")
|
||||
date_to = tab.to_date.date().toString("yyyy-MM-dd")
|
||||
|
||||
# TODO: Изменить название поля (checkin/checkout → order_date/delivery_date)
|
||||
# TODO: Изменить название поля (checkin/checkout -> order_date/delivery_date)
|
||||
if hasattr(tab, '_name'):
|
||||
# Пример фильтра
|
||||
tab.model.setFilter(
|
||||
|
|
@ -324,17 +326,343 @@ class ManagerWindow(BaseWindow):
|
|||
"""
|
||||
Панель менеджера
|
||||
|
||||
TODO: Реализовать если требуется в задании
|
||||
Обычно: просмотр данных + поиск/фильтрация (без удаления)
|
||||
Функционал:
|
||||
- Просмотр всех заявок
|
||||
- Фильтрация заявок по статусу
|
||||
- Одобрение/отклонение заявок
|
||||
- Поиск товаров
|
||||
- Просмотр товаров (без редактирования)
|
||||
"""
|
||||
|
||||
def _define_widgets(self):
|
||||
# TODO: Похож на AdminWindow, но с ограниченными правами
|
||||
pass
|
||||
self.root = QWidget()
|
||||
self.tabs = QTabWidget()
|
||||
|
||||
# Таб 1: Управление заявками
|
||||
self._define_requests_tab()
|
||||
|
||||
# Таб 2: Просмотр товаров
|
||||
self._define_items_tab()
|
||||
|
||||
def _define_requests_tab(self):
|
||||
"""Таб управления заявками"""
|
||||
self.requests_widget = QWidget()
|
||||
|
||||
# Фильтр по статусу
|
||||
self.filter_layout = QHBoxLayout()
|
||||
|
||||
self.filter_label = QLabel("Filter by status:")
|
||||
self.status_filter = QComboBox()
|
||||
self.status_filter.addItems([
|
||||
"All",
|
||||
"Pending",
|
||||
"Approved",
|
||||
"Rejected",
|
||||
"Completed",
|
||||
"Cancelled"
|
||||
])
|
||||
|
||||
self.filter_button = QPushButton("Apply Filter")
|
||||
self.refresh_button = QPushButton("Refresh")
|
||||
|
||||
self.filter_layout.addWidget(self.filter_label)
|
||||
self.filter_layout.addWidget(self.status_filter)
|
||||
self.filter_layout.addWidget(self.filter_button)
|
||||
self.filter_layout.addWidget(self.refresh_button)
|
||||
self.filter_layout.addStretch()
|
||||
|
||||
# Таблица заявок
|
||||
self.requests_table = QTableView()
|
||||
self.requests_model = QStandardItemModel()
|
||||
self.requests_model.setHorizontalHeaderLabels([
|
||||
"ID", "Date", "User", "Email", "Item",
|
||||
"Qty", "Price", "From", "To", "Status"
|
||||
])
|
||||
self.requests_table.setModel(self.requests_model)
|
||||
|
||||
# Кнопки управления
|
||||
self.requests_buttons = QHBoxLayout()
|
||||
|
||||
self.approve_button = QPushButton("✓ Approve")
|
||||
self.approve_button.setStyleSheet("background-color: #90EE90;")
|
||||
|
||||
self.reject_button = QPushButton("✗ Reject")
|
||||
self.reject_button.setStyleSheet("background-color: #FFB6C6;")
|
||||
|
||||
self.complete_button = QPushButton("✓ Complete")
|
||||
self.complete_button.setStyleSheet("background-color: #87CEEB;")
|
||||
|
||||
self.view_details_button = QPushButton("View Details")
|
||||
|
||||
self.requests_buttons.addWidget(self.approve_button)
|
||||
self.requests_buttons.addWidget(self.reject_button)
|
||||
self.requests_buttons.addWidget(self.complete_button)
|
||||
self.requests_buttons.addWidget(self.view_details_button)
|
||||
self.requests_buttons.addStretch()
|
||||
|
||||
def _define_items_tab(self):
|
||||
"""Таб просмотра товаров"""
|
||||
self.items_widget = QWidget()
|
||||
|
||||
# Поиск
|
||||
self.search_layout = QHBoxLayout()
|
||||
|
||||
self.search_label = QLabel("Search:")
|
||||
self.search_input = QLineEdit()
|
||||
self.search_input.setPlaceholderText("Enter item name...")
|
||||
self.search_button = QPushButton("Search")
|
||||
self.show_all_button = QPushButton("Show All")
|
||||
|
||||
self.search_layout.addWidget(self.search_label)
|
||||
self.search_layout.addWidget(self.search_input)
|
||||
self.search_layout.addWidget(self.search_button)
|
||||
self.search_layout.addWidget(self.show_all_button)
|
||||
self.search_layout.addStretch()
|
||||
|
||||
# Таблица товаров
|
||||
self.items_table = QTableView()
|
||||
self.items_model = QSqlTableModel(db=self._db)
|
||||
self.items_model.setTable("items")
|
||||
self.items_model.setEditStrategy(QSqlTableModel.EditStrategy.OnManualSubmit)
|
||||
self.items_model.select()
|
||||
self.items_table.setModel(self.items_model)
|
||||
|
||||
# Только для чтения
|
||||
self.items_table.setEditTriggers(QTableView.EditTrigger.NoEditTriggers)
|
||||
|
||||
def _tune_layouts(self):
|
||||
"""Компоновка"""
|
||||
# Requests tab layout
|
||||
requests_layout = QVBoxLayout()
|
||||
requests_layout.addLayout(self.filter_layout)
|
||||
requests_layout.addWidget(self.requests_table)
|
||||
requests_layout.addLayout(self.requests_buttons)
|
||||
self.requests_widget.setLayout(requests_layout)
|
||||
|
||||
# Items tab layout
|
||||
items_layout = QVBoxLayout()
|
||||
items_layout.addLayout(self.search_layout)
|
||||
items_layout.addWidget(self.items_table)
|
||||
self.items_widget.setLayout(items_layout)
|
||||
|
||||
# Add tabs
|
||||
self.tabs.addTab(self.requests_widget, "Manage Requests")
|
||||
self.tabs.addTab(self.items_widget, "View Items")
|
||||
|
||||
# Root layout
|
||||
root_layout = QVBoxLayout()
|
||||
root_layout.addWidget(self.tabs)
|
||||
self.root.setLayout(root_layout)
|
||||
|
||||
self.setCentralWidget(self.root)
|
||||
|
||||
def _connect_slots(self):
|
||||
"""Подключение сигналов"""
|
||||
# Requests tab
|
||||
self.filter_button.clicked.connect(self._on_filter_requests)
|
||||
self.refresh_button.clicked.connect(self._on_refresh_requests)
|
||||
self.approve_button.clicked.connect(self._on_approve_request)
|
||||
self.reject_button.clicked.connect(self._on_reject_request)
|
||||
self.complete_button.clicked.connect(self._on_complete_request)
|
||||
self.view_details_button.clicked.connect(self._on_view_details)
|
||||
|
||||
# Items tab
|
||||
self.search_button.clicked.connect(self._on_search_items)
|
||||
self.show_all_button.clicked.connect(self._on_show_all_items)
|
||||
self.search_input.returnPressed.connect(self._on_search_items)
|
||||
|
||||
def _load_requests(self, status_filter=None):
|
||||
"""Загрузить заявки из БД"""
|
||||
from .db import get_all_requests
|
||||
|
||||
# Конвертируем фильтр в формат БД
|
||||
status_map = {
|
||||
"All": None,
|
||||
"Pending": "pending",
|
||||
"Approved": "approved",
|
||||
"Rejected": "rejected",
|
||||
"Completed": "completed",
|
||||
"Cancelled": "cancelled"
|
||||
}
|
||||
|
||||
db_status = status_map.get(status_filter, None)
|
||||
requests = get_all_requests(status_filter=db_status)
|
||||
|
||||
# Очистить модель
|
||||
self.requests_model.removeRows(0, self.requests_model.rowCount())
|
||||
|
||||
if not requests:
|
||||
return
|
||||
|
||||
# Заполнить модель
|
||||
for req in requests:
|
||||
row = [QStandardItem(str(field) if field else "") for field in req]
|
||||
self.requests_model.appendRow(row)
|
||||
|
||||
# Автоширина колонок
|
||||
self.requests_table.resizeColumnsToContents()
|
||||
|
||||
def _on_filter_requests(self):
|
||||
"""Применить фильтр"""
|
||||
status = self.status_filter.currentText()
|
||||
self._load_requests(status_filter=status)
|
||||
|
||||
def _on_refresh_requests(self):
|
||||
"""Обновить список заявок"""
|
||||
self._load_requests()
|
||||
|
||||
def _get_selected_request_id(self):
|
||||
"""Получить ID выбранной заявки"""
|
||||
index = self.requests_table.currentIndex()
|
||||
|
||||
if not index.isValid():
|
||||
QMessageBox.warning(self, "No Selection",
|
||||
"Please select a request first")
|
||||
return None
|
||||
|
||||
# ID в первой колонке (индекс 0)
|
||||
request_id = self.requests_model.item(index.row(), 0).text()
|
||||
return int(request_id) if request_id else None
|
||||
|
||||
def _on_approve_request(self):
|
||||
"""Одобрить заявку"""
|
||||
from .db import update_request_status
|
||||
|
||||
request_id = self._get_selected_request_id()
|
||||
if not request_id:
|
||||
return
|
||||
|
||||
confirm = QMessageBox.question(
|
||||
self,
|
||||
"Confirm Approval",
|
||||
f"Approve request #{request_id}?",
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
||||
)
|
||||
|
||||
if confirm == QMessageBox.StandardButton.Yes:
|
||||
success = update_request_status(request_id, 'approved')
|
||||
|
||||
if success:
|
||||
QMessageBox.information(self, "Success",
|
||||
f"Request #{request_id} approved!")
|
||||
self._on_refresh_requests()
|
||||
else:
|
||||
QMessageBox.critical(self, "Error",
|
||||
"Failed to approve request")
|
||||
|
||||
def _on_reject_request(self):
|
||||
"""Отклонить заявку"""
|
||||
from .db import update_request_status
|
||||
|
||||
request_id = self._get_selected_request_id()
|
||||
if not request_id:
|
||||
return
|
||||
|
||||
confirm = QMessageBox.question(
|
||||
self,
|
||||
"Confirm Rejection",
|
||||
f"Reject request #{request_id}?",
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
||||
)
|
||||
|
||||
if confirm == QMessageBox.StandardButton.Yes:
|
||||
success = update_request_status(request_id, 'rejected')
|
||||
|
||||
if success:
|
||||
QMessageBox.information(self, "Success",
|
||||
f"Request #{request_id} rejected")
|
||||
self._on_refresh_requests()
|
||||
else:
|
||||
QMessageBox.critical(self, "Error",
|
||||
"Failed to reject request")
|
||||
|
||||
def _on_complete_request(self):
|
||||
"""Завершить заявку"""
|
||||
from .db import update_request_status
|
||||
|
||||
request_id = self._get_selected_request_id()
|
||||
if not request_id:
|
||||
return
|
||||
|
||||
confirm = QMessageBox.question(
|
||||
self,
|
||||
"Confirm Completion",
|
||||
f"Mark request #{request_id} as completed?",
|
||||
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
|
||||
)
|
||||
|
||||
if confirm == QMessageBox.StandardButton.Yes:
|
||||
success = update_request_status(request_id, 'completed')
|
||||
|
||||
if success:
|
||||
QMessageBox.information(self, "Success",
|
||||
f"Request #{request_id} completed!")
|
||||
self._on_refresh_requests()
|
||||
else:
|
||||
QMessageBox.critical(self, "Error",
|
||||
"Failed to complete request")
|
||||
|
||||
def _on_view_details(self):
|
||||
"""Просмотр деталей заявки"""
|
||||
index = self.requests_table.currentIndex()
|
||||
|
||||
if not index.isValid():
|
||||
QMessageBox.warning(self, "No Selection",
|
||||
"Please select a request first")
|
||||
return
|
||||
|
||||
# Собираем данные из строки
|
||||
row = index.row()
|
||||
details = []
|
||||
|
||||
for col in range(self.requests_model.columnCount()):
|
||||
header = self.requests_model.horizontalHeaderItem(col).text()
|
||||
value = self.requests_model.item(row, col).text()
|
||||
details.append(f"{header}: {value}")
|
||||
|
||||
# Показываем диалог с деталями
|
||||
QMessageBox.information(
|
||||
self,
|
||||
"Request Details",
|
||||
"\n".join(details)
|
||||
)
|
||||
|
||||
def _on_search_items(self):
|
||||
"""Поиск товаров"""
|
||||
from .db import search_items
|
||||
|
||||
search_term = self.search_input.text().strip()
|
||||
|
||||
if not search_term:
|
||||
QMessageBox.warning(self, "Empty Search",
|
||||
"Please enter a search term")
|
||||
return
|
||||
|
||||
results = search_items(search_term)
|
||||
|
||||
if not results:
|
||||
QMessageBox.information(self, "No Results",
|
||||
f"No items found matching '{search_term}'")
|
||||
return
|
||||
|
||||
# Применяем фильтр к модели
|
||||
filter_str = f"name ILIKE '%{search_term}%' OR description ILIKE '%{search_term}%'"
|
||||
self.items_model.setFilter(filter_str)
|
||||
self.items_model.select()
|
||||
|
||||
def _on_show_all_items(self):
|
||||
"""Показать все товары"""
|
||||
self.search_input.clear()
|
||||
self.items_model.setFilter("")
|
||||
self.items_model.select()
|
||||
|
||||
def _apply_window_settings(self):
|
||||
"""Настройки окна"""
|
||||
self.setWindowTitle("Manager Panel")
|
||||
self.setFixedSize(1000, 600)
|
||||
self.setFixedSize(1100, 700)
|
||||
|
||||
# Загрузить заявки при открытии
|
||||
self._load_requests()
|
||||
|
||||
|
||||
class ClientWindow(BaseWindow):
|
||||
|
|
@ -481,48 +809,95 @@ class ClientWindow(BaseWindow):
|
|||
|
||||
def _on_submit_request(self):
|
||||
"""
|
||||
Обработка создания заявки
|
||||
|
||||
TODO: Реализовать логику создания заявки
|
||||
Обработка создания заявки (исправленная версия)
|
||||
"""
|
||||
item = self.item_combo.currentText()
|
||||
from .db import create_request, get_items
|
||||
|
||||
item_text = self.item_combo.currentText()
|
||||
date_from = self.date_from.date().toString("yyyy-MM-dd")
|
||||
date_to = self.date_to.date().toString("yyyy-MM-dd")
|
||||
|
||||
# Валидация
|
||||
if item == "No items available":
|
||||
# Валидация: проверка наличия товаров
|
||||
if item_text == "No items available":
|
||||
QMessageBox.warning(self, "No Items",
|
||||
"There are no items available at this moment")
|
||||
return
|
||||
|
||||
# Валидация: даты
|
||||
if not date_from or not date_to:
|
||||
QMessageBox.critical(self, "Input Error",
|
||||
"Please select valid dates")
|
||||
return
|
||||
|
||||
# Проверка дат
|
||||
# Валидация: даты не в прошлом
|
||||
if self.date_from.date() < QDate.currentDate() or \
|
||||
self.date_to.date() < QDate.currentDate():
|
||||
QMessageBox.warning(self, "Invalid Date",
|
||||
"Cannot select past dates")
|
||||
return
|
||||
|
||||
# TODO: Вызвать функцию создания заявки из db.py
|
||||
# success = create_request(item_id, self._user, date_from=date_from, date_to=date_to)
|
||||
# Валидация: date_to >= date_from
|
||||
if self.date_to.date() < self.date_from.date():
|
||||
QMessageBox.warning(self, "Invalid Date Range",
|
||||
"End date must be after start date")
|
||||
return
|
||||
|
||||
# Заглушка
|
||||
success = True
|
||||
# Получить item_id из выбранного товара
|
||||
items = get_items()
|
||||
if not items:
|
||||
QMessageBox.critical(self, "Error", "Failed to load items")
|
||||
return
|
||||
|
||||
# Найти item_id по названию
|
||||
item_id = None
|
||||
for item in items:
|
||||
if str(item[1]) == item_text: # item[1] = name
|
||||
item_id = item[0] # item[0] = id
|
||||
break
|
||||
|
||||
# КРИТИЧНО: Проверка ДО использования
|
||||
if item_id is None:
|
||||
QMessageBox.critical(self, "Error",
|
||||
"Failed to identify selected item")
|
||||
return # ← ВЫХОД, дальше item_id гарантированно НЕ None
|
||||
|
||||
# Теперь item_id точно не None, безопасно использовать
|
||||
quantity = 1 # TODO: Добавить поле для quantity в форме
|
||||
|
||||
# Создать заявку
|
||||
success = create_request(
|
||||
item_id=item_id, # ← Теперь это безопасно
|
||||
quantity=quantity,
|
||||
user=self._user,
|
||||
date_from=date_from,
|
||||
date_to=date_to,
|
||||
notes=None
|
||||
)
|
||||
|
||||
if success:
|
||||
QMessageBox.information(
|
||||
self,
|
||||
"Success",
|
||||
f"Request created successfully!\nItem: {item}\nPeriod: {date_from} - {date_to}"
|
||||
f"Request created successfully!\n"
|
||||
f"Item: {item_text}\n"
|
||||
f"Period: {date_from} → {date_to}\n"
|
||||
f"Status: Pending approval"
|
||||
)
|
||||
self.history_model.select() # Обновить историю
|
||||
self.history_model.select()
|
||||
|
||||
# Очистить форму
|
||||
self.date_from.setDate(QDate.currentDate())
|
||||
self.date_to.setDate(QDate.currentDate().addDays(1))
|
||||
else:
|
||||
QMessageBox.critical(self, "Error",
|
||||
"Failed to create request. Please try again later.")
|
||||
QMessageBox.critical(
|
||||
self,
|
||||
"Error",
|
||||
"Failed to create request.\n"
|
||||
"Possible reasons:\n"
|
||||
"- Item is unavailable\n"
|
||||
"- Insufficient quantity\n"
|
||||
"- Database error"
|
||||
)
|
||||
|
||||
def _apply_window_settings(self):
|
||||
self.setWindowTitle("Client Panel")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue