initial
This commit is contained in:
commit
3c2137da2b
9 changed files with 737 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.venv
|
||||
__pycache__
|
||||
*\.pyc
|
||||
72
composer.py
Normal file
72
composer.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
from src.windows import LoginWindow, AdminWindow, ClientWindow
|
||||
from src.objects import User, Rights
|
||||
from src.db import DB_AUTH_HARDCODED as config
|
||||
|
||||
from PyQt6.QtWidgets import QApplication
|
||||
from PyQt6.QtCore import QObject, pyqtSlot, pyqtSignal
|
||||
from PyQt6.QtSql import QSqlDatabase
|
||||
|
||||
class Composer(QObject):
|
||||
render_request = pyqtSignal(User)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._current = None
|
||||
self._app = QApplication([])
|
||||
self._init_db()
|
||||
self.render_request.connect(self._render)
|
||||
|
||||
def _init_db(self):
|
||||
self._db = QSqlDatabase("QPSQL")
|
||||
self._db.setDatabaseName(config['dbname'])
|
||||
self._db.setPort(config['port'])
|
||||
self._db.setHostName(config['host'])
|
||||
self._db.setUserName(config['user'])
|
||||
self._db.setPassword(config['password'])
|
||||
self._db.open()
|
||||
|
||||
@pyqtSlot(User)
|
||||
def _render(self, user: User):
|
||||
match user.rights:
|
||||
case Rights.ADMIN:
|
||||
self._admin_fabric()
|
||||
case Rights.MANAGER:
|
||||
pass
|
||||
case Rights.CLIENT:
|
||||
self._client_fabric(user)
|
||||
|
||||
def _login_fabric(self):
|
||||
self.wlogin = LoginWindow(self, self._db)
|
||||
|
||||
if self._current:
|
||||
self._current.close()
|
||||
|
||||
self.wlogin.show()
|
||||
|
||||
self._current = self.wlogin
|
||||
|
||||
def _admin_fabric(self):
|
||||
self.wadmin = AdminWindow(self, self._db)
|
||||
|
||||
if self._current:
|
||||
self._current.close()
|
||||
|
||||
self.wadmin.show()
|
||||
|
||||
self._current = self.wadmin
|
||||
|
||||
def _client_fabric(self, user: User):
|
||||
self.wclient = ClientWindow(self, self._db, user)
|
||||
|
||||
if self._current:
|
||||
self._current.close()
|
||||
|
||||
self.wclient.show()
|
||||
|
||||
self._current = self.wclient
|
||||
|
||||
def run(self):
|
||||
import sys
|
||||
self._login_fabric()
|
||||
self._current.show()
|
||||
sys.exit(self._app.exec())
|
||||
8
main.py
Normal file
8
main.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
from composer import Composer
|
||||
|
||||
def main():
|
||||
composer = Composer()
|
||||
composer.run()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
18
scrapper.sh
Executable file
18
scrapper.sh
Executable file
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
OUTPUT="all_code.txt"
|
||||
ROOT="."
|
||||
|
||||
> "$OUTPUT"
|
||||
|
||||
find "$ROOT" \
|
||||
-type d -name "__pycache__" -prune -o \
|
||||
-type f -name "*.py" ! -name "*.pyc" \
|
||||
-print | sort | while read -r file; do
|
||||
echo "########################################" >> "$OUTPUT"
|
||||
echo "# FILE: $file" >> "$OUTPUT"
|
||||
echo "########################################" >> "$OUTPUT"
|
||||
echo >> "$OUTPUT"
|
||||
cat "$file" >> "$OUTPUT"
|
||||
echo -e "\n\n" >> "$OUTPUT"
|
||||
done
|
||||
0
src/__init__.py
Normal file
0
src/__init__.py
Normal file
153
src/db.py
Normal file
153
src/db.py
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
import psycopg2 as pg
|
||||
|
||||
from .objects import User, Rights
|
||||
|
||||
DB_AUTH_HARDCODED = {
|
||||
"host": "127.0.0.1",
|
||||
"port": 5432,
|
||||
"dbname": "examdb",
|
||||
"user": "postgres",
|
||||
"password": "213k2010###"
|
||||
}
|
||||
|
||||
def get_connection():
|
||||
return pg.connect(**DB_AUTH_HARDCODED)
|
||||
|
||||
def do_request(autocommit=False):
|
||||
def upper_wrapper(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
conn = get_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
try:
|
||||
kwargs['cursor'] = cursor
|
||||
|
||||
result = func(*args, **kwargs)
|
||||
|
||||
if autocommit:
|
||||
conn.commit()
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: Can't request query to DB: {e}")
|
||||
return None
|
||||
|
||||
finally:
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return wrapper
|
||||
|
||||
return upper_wrapper
|
||||
|
||||
@do_request()
|
||||
def auth(login: str, password: str, *, cursor) -> User | None:
|
||||
cursor.execute("""
|
||||
SELECT id, name, rights
|
||||
FROM users
|
||||
WHERE name = %s
|
||||
AND password = %s;
|
||||
""", (login, password))
|
||||
|
||||
user = cursor.fetchone()
|
||||
|
||||
if not user:
|
||||
print("Warning: Login Forbidden: Can't find such user!")
|
||||
return None
|
||||
|
||||
rights = None
|
||||
|
||||
match user[2]:
|
||||
case "admin":
|
||||
rights = Rights.ADMIN
|
||||
case "customer":
|
||||
rights = Rights.CLIENT
|
||||
case "manager":
|
||||
rights = Rights.MANAGER
|
||||
case _:
|
||||
return None
|
||||
|
||||
return User(
|
||||
id=user[0],
|
||||
name=user[1],
|
||||
rights=rights
|
||||
)
|
||||
|
||||
@do_request()
|
||||
def get_free_numbers(*, cursor):
|
||||
cursor.execute("""
|
||||
SELECT *
|
||||
FROM rooms
|
||||
WHERE status = 'free';
|
||||
""")
|
||||
|
||||
free = cursor.fetchall()
|
||||
|
||||
if not free:
|
||||
return None
|
||||
|
||||
return free
|
||||
|
||||
@do_request(autocommit=True)
|
||||
def update_number_status(number: str, checkin: str,
|
||||
checkout: str, user: User,
|
||||
*, cursor):
|
||||
cursor.execute("""
|
||||
SELECT password
|
||||
FROM users
|
||||
WHERE id = %s
|
||||
""", (user.id,))
|
||||
|
||||
password = cursor.fetchone()
|
||||
|
||||
if not password:
|
||||
return False
|
||||
|
||||
cursor.execute("""
|
||||
SELECT id
|
||||
FROM guests
|
||||
WHERE name = %s
|
||||
AND PHONE = %s
|
||||
""", (user.name, password[0]))
|
||||
|
||||
guest = cursor.fetchone()
|
||||
|
||||
if not guest:
|
||||
return False
|
||||
|
||||
cursor.execute("""
|
||||
SELECT id
|
||||
FROM rooms
|
||||
WHERE number = %s;
|
||||
""", (number,))
|
||||
|
||||
number_id = cursor.fetchone()
|
||||
|
||||
if not number_id:
|
||||
return False
|
||||
|
||||
cursor.execute("""
|
||||
SELECT guest, room
|
||||
FROM bookings
|
||||
WHERE guest = %s
|
||||
AND room = %s;
|
||||
""", (guest[0], number_id[0]))
|
||||
|
||||
request_exists = cursor.fetchone()
|
||||
|
||||
if request_exists:
|
||||
return False
|
||||
|
||||
cursor.execute("""
|
||||
INSERT INTO bookings(guest, room, checkin, checkout, status)
|
||||
VALUES (%s, %s, %s, %s, 'active');
|
||||
""", (guest[0], number_id[0], checkin, checkout))
|
||||
|
||||
cursor.execute("""
|
||||
UPDATE rooms
|
||||
SET status = 'booked'
|
||||
WHERE number = %s;
|
||||
""", (number,))
|
||||
|
||||
return True
|
||||
17
src/objects.py
Normal file
17
src/objects.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
from enum import Enum, auto
|
||||
from dataclasses import dataclass
|
||||
|
||||
class SignalCode(Enum):
|
||||
SIGFALSE = auto()
|
||||
SIGERR = auto()
|
||||
|
||||
class Rights(Enum):
|
||||
ADMIN = auto()
|
||||
CLIENT = auto()
|
||||
MANAGER = auto()
|
||||
|
||||
@dataclass
|
||||
class User:
|
||||
id: int
|
||||
name: str
|
||||
rights: Rights
|
||||
70
src/utils.py
Normal file
70
src/utils.py
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
from PyQt6.QtWidgets import (
|
||||
QWidget,
|
||||
QTableView,
|
||||
QHBoxLayout,
|
||||
QVBoxLayout,
|
||||
QDateEdit,
|
||||
QPushButton,
|
||||
QLabel
|
||||
)
|
||||
from PyQt6.QtSql import QSqlTableModel
|
||||
|
||||
class TabWidgetCustom(QWidget):
|
||||
def __init__(self, name: str, db):
|
||||
super().__init__()
|
||||
self._name = name
|
||||
self._db = db
|
||||
self._setup()
|
||||
|
||||
def _setup(self):
|
||||
self.root = QVBoxLayout(self)
|
||||
|
||||
if self._name in ("bookings", "payments"):
|
||||
self.header = QHBoxLayout()
|
||||
|
||||
self.from_date = QDateEdit()
|
||||
self.from_date.setCalendarPopup(True)
|
||||
|
||||
self.to_date = QDateEdit()
|
||||
self.to_date.setCalendarPopup(True)
|
||||
|
||||
self.button_filter = QPushButton("Фильтровать")
|
||||
self.button_all = QPushButton("Показать всё")
|
||||
|
||||
self.header.addWidget(QLabel("С:"))
|
||||
self.header.addWidget(self.from_date)
|
||||
self.header.addWidget(QLabel("По:"))
|
||||
self.header.addWidget(self.to_date)
|
||||
self.header.addWidget(self.button_filter)
|
||||
self.header.addWidget(self.button_all)
|
||||
|
||||
self.root.addLayout(self.header)
|
||||
|
||||
self.view = QTableView()
|
||||
|
||||
self.btoolbar = QHBoxLayout()
|
||||
|
||||
self.button_add = QPushButton("+ Добавить")
|
||||
self.button_del = QPushButton("- Удалить")
|
||||
self.button_ok = QPushButton("\\_/ Применить")
|
||||
self.button_deny = QPushButton("-- Отменить")
|
||||
self.button_csv = QPushButton("Выгрузить отчёт в CSV")
|
||||
|
||||
self.btoolbar.addWidget(self.button_add)
|
||||
self.btoolbar.addWidget(self.button_del)
|
||||
self.btoolbar.addWidget(self.button_ok)
|
||||
self.btoolbar.addWidget(self.button_deny)
|
||||
self.btoolbar.addWidget(self.button_csv)
|
||||
|
||||
self.root.addWidget(self.view)
|
||||
self.root.addLayout(self.btoolbar)
|
||||
|
||||
self._setup_db()
|
||||
|
||||
def _setup_db(self):
|
||||
self.model = QSqlTableModel(db=self._db)
|
||||
self.model.setTable(self._name)
|
||||
self.model.setEditStrategy(QSqlTableModel.EditStrategy.OnManualSubmit)
|
||||
self.model.select()
|
||||
|
||||
self.view.setModel(self.model)
|
||||
396
src/windows.py
Normal file
396
src/windows.py
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
import csv
|
||||
from .db import auth, get_free_numbers, update_number_status
|
||||
from .objects import User, SignalCode
|
||||
from .utils import TabWidgetCustom
|
||||
from PyQt6.QtWidgets import (
|
||||
QWidget,
|
||||
QLineEdit,
|
||||
QPushButton,
|
||||
QGroupBox,
|
||||
QFormLayout,
|
||||
QVBoxLayout,
|
||||
QMessageBox,
|
||||
QTabWidget,
|
||||
QMainWindow,
|
||||
QComboBox,
|
||||
QDateEdit,
|
||||
QTableView
|
||||
)
|
||||
from PyQt6.QtGui import QStandardItemModel, QStandardItem
|
||||
from PyQt6.QtSql import QSqlTableModel
|
||||
from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot, QDate
|
||||
|
||||
FIW = 160 # Fixed Input Width
|
||||
NO_NUMBERS_CONST = "Нет свободных номеров"
|
||||
|
||||
class BaseWindow(QMainWindow):
|
||||
def __init__(self, composer, db, user=None):
|
||||
super().__init__()
|
||||
self._composer = composer
|
||||
self._db = db
|
||||
self._user = user
|
||||
self._define_widgets()
|
||||
self._tune_layouts()
|
||||
self._connect_slots()
|
||||
self._apply_window_settings()
|
||||
|
||||
def _define_widgets(self):
|
||||
pass
|
||||
|
||||
def _tune_layouts(self):
|
||||
pass
|
||||
|
||||
def _connect_slots(self):
|
||||
pass
|
||||
|
||||
def _apply_window_settings(self):
|
||||
pass
|
||||
|
||||
class LoginWindow(BaseWindow):
|
||||
login_success = pyqtSignal(User)
|
||||
login_forbidden = pyqtSignal(SignalCode)
|
||||
|
||||
def _define_widgets(self):
|
||||
self.root = QWidget()
|
||||
|
||||
self.auth_form = QGroupBox("Логин")
|
||||
self.auth_form.setAlignment(Qt.AlignmentFlag.AlignHCenter |
|
||||
Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
self.login_line = QLineEdit()
|
||||
self.login_line.setFixedWidth(FIW)
|
||||
|
||||
self.password_line = QLineEdit()
|
||||
self.password_line.setFixedWidth(FIW)
|
||||
self.password_line.setEchoMode(QLineEdit.EchoMode.Password)
|
||||
|
||||
self.auth_button = QPushButton("Авторизоваться")
|
||||
|
||||
def _tune_layouts(self):
|
||||
self.root_l = QVBoxLayout()
|
||||
|
||||
self.form = QFormLayout()
|
||||
self.form.addRow("Логин:", self.login_line)
|
||||
self.form.addRow("Пароль:", self.password_line)
|
||||
|
||||
self.auth_form.setLayout(self.form)
|
||||
|
||||
self.root_l.addWidget(self.auth_form)
|
||||
self.root_l.addWidget(self.auth_button)
|
||||
|
||||
self.root.setLayout(self.root_l)
|
||||
|
||||
self.setCentralWidget(self.root)
|
||||
|
||||
def _connect_slots(self):
|
||||
self.auth_button.clicked.connect(self._on_auth_button_clicked)
|
||||
self.login_success.connect(self._on_login_success)
|
||||
self.login_forbidden.connect(self._on_login_forbidden)
|
||||
|
||||
def _on_auth_button_clicked(self):
|
||||
login = self.login_line.text()
|
||||
password = self.password_line.text()
|
||||
|
||||
if not login or not password:
|
||||
self.login_forbidden.emit(SignalCode.SIGERR)
|
||||
return
|
||||
|
||||
user = auth(login, password)
|
||||
|
||||
if not user:
|
||||
self.login_forbidden.emit(SignalCode.SIGFALSE)
|
||||
return
|
||||
|
||||
print(f"Login OK: {user.name} {user.rights}")
|
||||
|
||||
self.login_success.emit(user)
|
||||
|
||||
@pyqtSlot(User)
|
||||
def _on_login_success(self, user: User):
|
||||
self._composer.render_request.emit(user)
|
||||
|
||||
@pyqtSlot(SignalCode)
|
||||
def _on_login_forbidden(self, code: SignalCode):
|
||||
match code:
|
||||
case SignalCode.SIGFALSE:
|
||||
QMessageBox().information(self,
|
||||
"Предупреждение!",
|
||||
"Вы ввели некорректные данные")
|
||||
case SignalCode.SIGERR:
|
||||
QMessageBox().information(self,
|
||||
"Ошибка!",
|
||||
"Вы ввели неприемлемые данные")
|
||||
|
||||
def _apply_window_settings(self):
|
||||
self.setWindowTitle("Авторизация")
|
||||
self.setFixedSize(260,180)
|
||||
|
||||
class AdminWindow(BaseWindow):
|
||||
def _define_widgets(self):
|
||||
self.root = QWidget()
|
||||
|
||||
self.tabs = QTabWidget()
|
||||
|
||||
self.users_tab = TabWidgetCustom("users", self._db)
|
||||
self.guests_tab = TabWidgetCustom("guests", self._db)
|
||||
self.rooms_tab = TabWidgetCustom("rooms", self._db)
|
||||
self.bookings_tab = TabWidgetCustom("bookings", self._db)
|
||||
self.staff_tab = TabWidgetCustom("staff", self._db)
|
||||
self.payments_tab = TabWidgetCustom("payments", self._db)
|
||||
|
||||
self.tabs.addTab(self.users_tab, "Пользователи")
|
||||
self.tabs.addTab(self.guests_tab, "Постояльцы")
|
||||
self.tabs.addTab(self.rooms_tab, "Номера")
|
||||
self.tabs.addTab(self.bookings_tab, "Бронирования")
|
||||
self.tabs.addTab(self.staff_tab, "Персонал")
|
||||
self.tabs.addTab(self.payments_tab, "Платежи")
|
||||
|
||||
def _tune_layouts(self):
|
||||
self.root_l = QVBoxLayout()
|
||||
self.root_l.addWidget(self.tabs)
|
||||
self.root.setLayout(self.root_l)
|
||||
self.setCentralWidget(self.root)
|
||||
|
||||
def _connect_slots(self):
|
||||
for i in range(self.tabs.count()):
|
||||
tab = self.tabs.widget(i)
|
||||
|
||||
try:
|
||||
tab.button_all.clicked.connect(lambda _, t=tab: self._select_all(t))
|
||||
tab.button_filter.clicked.connect(lambda _, t=tab: self._select_filter(t))
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
tab.button_add.clicked.connect(lambda _, t=tab: self._add_row(t))
|
||||
tab.button_del.clicked.connect(lambda _, t=tab: self._del_row(t))
|
||||
tab.button_csv.clicked.connect(lambda _, t=tab: self._csv_row(t))
|
||||
tab.button_ok.clicked.connect(lambda _, t=tab: self._apply_changes(t))
|
||||
tab.button_deny.clicked.connect(lambda _, t=tab: self._revert_changes(t))
|
||||
|
||||
def _select_all(self, tab):
|
||||
tab.model.setFilter("")
|
||||
tab.model.select()
|
||||
|
||||
def _select_filter(self, tab):
|
||||
date_from = tab.from_date.date().toString("yyyy-MM-dd")
|
||||
date_to = tab.to_date.date().toString("yyyy-MM-dd")
|
||||
|
||||
if tab._name == "bookings":
|
||||
tab.model.setFilter(f"DATE(checkin) >= \'{date_from}\' AND DATE(checkout) <= \'{date_to}\'")
|
||||
tab.model.select()
|
||||
elif tab._name == "payments":
|
||||
tab.model.setFilter(f"date <= \'{date_from}\' AND date <= \'{date_to}\'")
|
||||
tab.model.select()
|
||||
|
||||
def _add_row(self, tab):
|
||||
row = tab.model.rowCount()
|
||||
tab.model.insertRow(row)
|
||||
tab.view.selectRow(row)
|
||||
tab.view.edit(tab.model.index(row, 0))
|
||||
|
||||
def _del_row(self, tab):
|
||||
idx = tab.view.currentIndex()
|
||||
|
||||
if not idx.isValid():
|
||||
print("Error: Fatal: row index is not valid!")
|
||||
return
|
||||
|
||||
msg = QMessageBox.question(self, "Подтверждение",
|
||||
"Вы уверены что хотите удалить выбранную строку ?"
|
||||
"Изменения будут необратимы")
|
||||
|
||||
if msg == QMessageBox.StandardButton.Yes:
|
||||
tab.model.removeRow(idx.row())
|
||||
tab.model.submitAll()
|
||||
|
||||
def _apply_changes(self, tab):
|
||||
if not tab.model.isDirty():
|
||||
return
|
||||
|
||||
msg = QMessageBox.question(self, "Подтверждение",
|
||||
"Применить изменения ?")
|
||||
|
||||
if msg == QMessageBox.StandardButton.Yes:
|
||||
if not tab.model.submitAll():
|
||||
QMessageBox.critical(self, "Ошибка БД",
|
||||
"Не получилось применить изменения,"
|
||||
f"\n{tab.model.lastError().text()}")
|
||||
tab.model.revertAll()
|
||||
|
||||
def _revert_changes(self, tab):
|
||||
if not tab.model.isDirty():
|
||||
return
|
||||
|
||||
tab.model.revertAll()
|
||||
|
||||
def _csv_row(self, tab):
|
||||
path = f"{tab._name}.csv"
|
||||
|
||||
with open(path, "w", newline="", encoding="utf-8") as f:
|
||||
writer = csv.writer(f)
|
||||
header = [tab.model.headerData(i, Qt.Orientation.Horizontal) for i in range(tab.model.columnCount())]
|
||||
|
||||
writer.writerow(header)
|
||||
|
||||
for row in range(tab.model.rowCount()):
|
||||
row_data = []
|
||||
for col in range(tab.model.columnCount()):
|
||||
value = tab.model.data(tab.model.index(row, col))
|
||||
|
||||
if hasattr(value, "toString"):
|
||||
value = value.toString()
|
||||
|
||||
row_data.append(value)
|
||||
|
||||
writer.writerow(row_data)
|
||||
|
||||
QMessageBox.information(self, "Информация",
|
||||
"Отчёт был сохранён в корневую директорию приложения")
|
||||
|
||||
def _apply_window_settings(self):
|
||||
self.setWindowTitle("Панель Администратора")
|
||||
self.setFixedSize(1200,800)
|
||||
|
||||
class ClientWindow(BaseWindow):
|
||||
def _define_widgets(self):
|
||||
self.root = QTabWidget()
|
||||
|
||||
self._define_request_box()
|
||||
self._define_free_rooms()
|
||||
self._define_client_bookings()
|
||||
|
||||
def _tune_layouts(self):
|
||||
self.root_l = QVBoxLayout()
|
||||
|
||||
self._tune_request_box()
|
||||
self._tune_free_rooms()
|
||||
self._tune_client_bookings()
|
||||
|
||||
self.root.addTab(self.rb_widget, "Окно заявки")
|
||||
self.root.addTab(self.fr_widget, "Свободные номера")
|
||||
self.root.addTab(self.cl_widget, "Ваши заявки")
|
||||
|
||||
self.root.setLayout(self.root_l)
|
||||
|
||||
self.setCentralWidget(self.root)
|
||||
|
||||
def _define_request_box(self):
|
||||
self.rb_widget = QWidget()
|
||||
self.req_box = QGroupBox("Создание заявки")
|
||||
self.req_box.setAlignment(Qt.AlignmentFlag.AlignVCenter |
|
||||
Qt.AlignmentFlag.AlignHCenter)
|
||||
|
||||
self.room_combo = QComboBox()
|
||||
|
||||
free_rooms = get_free_numbers()
|
||||
|
||||
if free_rooms:
|
||||
for room in free_rooms:
|
||||
number = room[1]
|
||||
self.room_combo.addItem(str(number))
|
||||
else:
|
||||
self.room_combo.addItem(NO_NUMBERS_CONST)
|
||||
|
||||
self.checkin = QDateEdit()
|
||||
self.checkin.setCalendarPopup(True)
|
||||
|
||||
self.checkout = QDateEdit()
|
||||
self.checkout.setCalendarPopup(True)
|
||||
|
||||
self.book_button = QPushButton("Забронировать")
|
||||
|
||||
def _tune_request_box(self):
|
||||
self.req_l = QVBoxLayout()
|
||||
self.form_l = QFormLayout()
|
||||
|
||||
self.form_l.addRow("Комната:", self.room_combo)
|
||||
self.form_l.addRow("Заезд:", self.checkin)
|
||||
self.form_l.addRow("Выезд:", self.checkout)
|
||||
|
||||
self.req_box.setLayout(self.form_l)
|
||||
|
||||
self.req_l.addWidget(self.req_box)
|
||||
self.req_l.addWidget(self.book_button)
|
||||
|
||||
self.rb_widget.setLayout(self.req_l)
|
||||
|
||||
def _define_free_rooms(self):
|
||||
self.fr_widget = QWidget()
|
||||
self.fr_table = QTableView()
|
||||
|
||||
free_rooms = get_free_numbers()
|
||||
|
||||
self.fr_model = QStandardItemModel()
|
||||
self.fr_model.setHorizontalHeaderLabels(["Номер Комнаты"])
|
||||
|
||||
if free_rooms:
|
||||
for room in free_rooms:
|
||||
item = room[1]
|
||||
self.fr_model.appendRow(QStandardItem(str(item)))
|
||||
|
||||
self.fr_table.setModel(self.fr_model)
|
||||
|
||||
def _tune_free_rooms(self):
|
||||
self.f_rooms_l = QVBoxLayout()
|
||||
self.f_rooms_l.addWidget(self.fr_table)
|
||||
|
||||
self.fr_widget.setLayout(self.f_rooms_l)
|
||||
|
||||
def _define_client_bookings(self):
|
||||
self.cl_widget = QWidget()
|
||||
self.cl_table = QTableView()
|
||||
|
||||
self.cl_model = QSqlTableModel(db=self._db)
|
||||
self.cl_model.setTable("bookings")
|
||||
self.cl_model.select()
|
||||
|
||||
self.cl_table.setModel(self.cl_model)
|
||||
|
||||
def _tune_client_bookings(self):
|
||||
self.c_bookings_l = QVBoxLayout()
|
||||
self.c_bookings_l.addWidget(self.cl_table)
|
||||
|
||||
self.cl_widget.setLayout(self.c_bookings_l)
|
||||
|
||||
def _connect_slots(self):
|
||||
self.book_button.clicked.connect(self._book_button_handler)
|
||||
|
||||
def _book_button_handler(self):
|
||||
room = self.room_combo.currentText()
|
||||
checkin = self.checkin.date().toString("yyyy-MM-dd")
|
||||
checkout = self.checkout.date().toString("yyyy-MM-dd")
|
||||
|
||||
if room == NO_NUMBERS_CONST:
|
||||
QMessageBox.information(self, "Информация",
|
||||
"На данный момент у нас нет свободных номеров,"
|
||||
"приносим свои извинения за доставленные неудобства")
|
||||
return
|
||||
|
||||
if not checkin or not checkout:
|
||||
QMessageBox.critical(self, "Информация",
|
||||
"Пожалуйста, введите корректную дату прибытия и отбытия")
|
||||
return
|
||||
|
||||
current_date = QDate.currentDate()
|
||||
|
||||
if self.checkin.date() < current_date or self.checkout.date() < current_date:
|
||||
QMessageBox.critical(self, "Предупреждение",
|
||||
"Вы не можете выбрать прошедшую дату!")
|
||||
return
|
||||
|
||||
status = update_number_status(room, checkin, checkout, self._user)
|
||||
|
||||
if not status:
|
||||
QMessageBox.critical(self, "Ошибка!",
|
||||
"Не получилось забронировать ваш номер, попробуйте позже")
|
||||
return
|
||||
else:
|
||||
QMessageBox.information(self, "Успешно!",
|
||||
f"Вы забронировали номер {room} на даты"
|
||||
f"\nС {checkin} по {checkout}, будем рады вас видеть!")
|
||||
|
||||
self.cl_model.select()
|
||||
|
||||
def _apply_window_settings(self):
|
||||
self.setWindowTitle("Панель Пользователя")
|
||||
self.setFixedSize(800,400)
|
||||
Loading…
Add table
Add a link
Reference in a new issue