-- Создание базы данных
CREATE DATABASE IF NOT EXISTS hotel;
USE hotel;

-- Таблица Administrators
CREATE TABLE Administrators (
    admin_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(150) NOT NULL,
    passport_number VARCHAR(20) UNIQUE NOT NULL,
    address TEXT NOT NULL,
    phone_number VARCHAR(30) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    login VARCHAR(30) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Таблица Receptionists
CREATE TABLE Receptionists (
    receptionist_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(150) NOT NULL,
    passport_number VARCHAR(20) UNIQUE NOT NULL,
    address TEXT NOT NULL,
    phone_number VARCHAR(15) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    login VARCHAR(20) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    admin_id INT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (admin_id) REFERENCES Administrators(admin_id) ON DELETE CASCADE
);

-- Таблица Rooms
CREATE TABLE Rooms (
    room_id INT AUTO_INCREMENT PRIMARY KEY,
    room_number INT UNIQUE NOT NULL,
    status ENUM('Доступен', 'Недоступен', 'Требует уборки') DEFAULT 'Доступен',
    price DECIMAL(10,2) NOT NULL,
    bed_type ENUM('Одноместный', 'Двухместный', 'Трехместный', 'Четырехместный') NOT NULL,
    room_type ENUM('Стандарт', 'Люкс', 'Делюкс') NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

-- Таблица Customers
CREATE TABLE Customers (
    customer_id INT AUTO_INCREMENT PRIMARY KEY,
    full_name VARCHAR(100) NOT NULL,
    phone VARCHAR(15) UNIQUE NOT NULL,
    email VARCHAR(100) UNIQUE,
    gender ENUM('Мужской', 'Женский'),
    country VARCHAR(50),
    address TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    receptionist_id INT,
    FOREIGN KEY (receptionist_id) REFERENCES Receptionists(receptionist_id) ON DELETE SET NULL
);

-- Таблица Reservations
CREATE TABLE Reservations (
    reservation_id INT AUTO_INCREMENT PRIMARY KEY,
    customer_id INT NOT NULL,
    room_id INT NOT NULL,
    check_in DATE NOT NULL,
    check_out DATE NOT NULL,
    status ENUM('Забронирован', 'Заселён', 'Выселен', 'Отменён') DEFAULT 'Забронирован',
    total_amount DECIMAL(10,2),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    receptionist_id INT,
    FOREIGN KEY (customer_id) REFERENCES Customers(customer_id) ON DELETE CASCADE,
    FOREIGN KEY (room_id) REFERENCES Rooms(room_id) ON DELETE CASCADE,
    FOREIGN KEY (receptionist_id) REFERENCES Receptionists(receptionist_id) ON DELETE RESTRICT
);

-- Таблица Payments
CREATE TABLE Payments (
    payment_id INT AUTO_INCREMENT PRIMARY KEY,
    reservation_id INT NOT NULL,
    amount DECIMAL(10, 2) NOT NULL,
    payment_date DATE NOT NULL,
    payment_method ENUM('Наличные', 'Кредитная карта', 'Дебетовая карта', 'Онлайн перевод') NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (reservation_id) REFERENCES Reservations(reservation_id) ON DELETE CASCADE
);

-- Таблица Archived_Reservations
CREATE TABLE IF NOT EXISTS Archived_Reservations (
    archive_id INT AUTO_INCREMENT PRIMARY KEY,
    reservation_id INT NOT NULL,
    customer_id INT NOT NULL,
    room_id INT NOT NULL,
    check_in DATE NOT NULL,
    check_out DATE NOT NULL,
    status ENUM('Заселён', 'Выселен', 'Отменён') NOT NULL,
    total_amount DECIMAL(10,2) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (customer_id) REFERENCES Customers(customer_id) ON DELETE CASCADE,
    FOREIGN KEY (room_id) REFERENCES Rooms(room_id) ON DELETE CASCADE
);










// src/h/DashboardAdmin.java
package h;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class DashboardAdmin extends JFrame {

    private int adminId; // Идентификатор администратора

    public DashboardAdmin(int adminId) {
        this.adminId = adminId;
        setTitle("Панель Администратора");
        setSize(900, 600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        // Создание вкладок
        JTabbedPane tabbedPane = new JTabbedPane();

        tabbedPane.addTab("Ресепшионисты", new ReceptionistsPanel());
        tabbedPane.addTab("Номера", new RoomsPanel());
        tabbedPane.addTab("Архивы", new ArchivesPanel());
        tabbedPane.addTab("Финансы", new FinancePanel());

        add(tabbedPane);
        setVisible(true);
    }

    // Метод для хеширования пароля
    private String hashPassword(String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = md.digest(password.getBytes());

            StringBuilder sb = new StringBuilder();
            for(byte b : hashBytes){
                sb.append(String.format("%02x", b));
            }

            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Панель управления ресепшионистами
    class ReceptionistsPanel extends JPanel {
        private JTable table;
        private DefaultTableModel tableModel;
        private JButton addButton, editButton, deleteButton;

        public ReceptionistsPanel() {
            setLayout(new BorderLayout());

            // Создание модели таблицы
            tableModel = new DefaultTableModel();
            tableModel.setColumnIdentifiers(new String[] {"ID", "Полное имя", "Паспорт", "Адрес", "Телефон", "Email", "Логин"});
            table = new JTable(tableModel);
            loadReceptionists();

            add(new JScrollPane(table), BorderLayout.CENTER);

            // Кнопки управления
            JPanel buttonPanel = new JPanel();
            addButton = new JButton("Добавить");
            editButton = new JButton("Редактировать");
            deleteButton = new JButton("Удалить");
            buttonPanel.add(addButton);
            buttonPanel.add(editButton);
            buttonPanel.add(deleteButton);

            add(buttonPanel, BorderLayout.SOUTH);

            // Обработчики событий
            addButton.addActionListener(e -> openReceptionistForm(null));
            editButton.addActionListener(e -> {
                int selectedRow = table.getSelectedRow();
                if (selectedRow >= 0) {
                    int receptionistId = (int)tableModel.getValueAt(selectedRow, 0);
                    openReceptionistForm(receptionistId);
                } else {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, выберите ресепшиониста для редактирования.");
                }
            });
            deleteButton.addActionListener(e -> {
                int selectedRow = table.getSelectedRow();
                if (selectedRow >= 0) {
                    int receptionistId = (int)tableModel.getValueAt(selectedRow, 0);
                    int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить этого ресепшиониста?", "Подтверждение", JOptionPane.YES_NO_OPTION);
                    if (confirm == JOptionPane.YES_OPTION) {
                        deleteReceptionist(receptionistId);
                        loadReceptionists();
                    }
                } else {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, выберите ресепшиониста для удаления.");
                }
            });
        }

        private void loadReceptionists() {
            tableModel.setRowCount(0);
            String query = "SELECT receptionist_id, full_name, passport_number, address, phone_number, email, login FROM Receptionists";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                while (rs.next()) {
                    tableModel.addRow(new Object[] {
                            rs.getInt("receptionist_id"),
                            rs.getString("full_name"),
                            rs.getString("passport_number"),
                            rs.getString("address"),
                            rs.getString("phone_number"),
                            rs.getString("email"),
                            rs.getString("login")
                    });
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке ресепшионистов.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        private void openReceptionistForm(Integer receptionistId) {
            new ReceptionistForm(receptionistId, this);
        }

        private void deleteReceptionist(int receptionistId) {
            String query = "DELETE FROM Receptionists WHERE receptionist_id = ?";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, receptionistId);
                pstmt.executeUpdate();

                JOptionPane.showMessageDialog(this, "Ресепшионист успешно удален.");

            } catch (SQLException e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при удалении ресепшиониста.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // Форма добавления/редактирования ресепшиониста
    class ReceptionistForm extends JDialog implements ActionListener {
        private JTextField nameField, passportField, addressField, phoneField, emailField, loginField;
        private JPasswordField passwordField;
        private JButton saveButton, cancelButton;
        private Integer receptionistId; // Null для добавления, не null для редактирования
        private ReceptionistsPanel parentPanel;

        public ReceptionistForm(Integer receptionistId, ReceptionistsPanel parentPanel) {
            this.receptionistId = receptionistId;
            this.parentPanel = parentPanel;

            setTitle(receptionistId == null ? "Добавить Ресепшиониста" : "Редактировать Ресепшиониста");
            setSize(400, 500);
            setLocationRelativeTo(null);
            setModal(true);
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(5,5,5,5);

            // Полное имя
            gbc.gridx = 0;
            gbc.gridy = 0;
            add(new JLabel("Полное имя:"), gbc);
            nameField = new JTextField(20);
            gbc.gridx = 1;
            add(nameField, gbc);

            // Паспорт
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Номер паспорта:"), gbc);
            passportField = new JTextField(20);
            gbc.gridx = 1;
            add(passportField, gbc);

            // Адрес
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Адрес:"), gbc);
            addressField = new JTextField(20);
            gbc.gridx = 1;
            add(addressField, gbc);

            // Телефон
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Телефон:"), gbc);
            phoneField = new JTextField(20);
            gbc.gridx = 1;
            add(phoneField, gbc);

            // Email
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Email:"), gbc);
            emailField = new JTextField(20);
            gbc.gridx = 1;
            add(emailField, gbc);

            // Логин
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Логин:"), gbc);
            loginField = new JTextField(20);
            gbc.gridx = 1;
            add(loginField, gbc);

            // Пароль
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Пароль:"), gbc);
            passwordField = new JPasswordField(20);
            gbc.gridx = 1;
            add(passwordField, gbc);

            // Кнопки
            gbc.gridx = 0;
            gbc.gridy++;
            gbc.gridwidth = 2;
            JPanel buttonPanel = new JPanel();
            saveButton = new JButton("Сохранить");
            cancelButton = new JButton("Отмена");
            buttonPanel.add(saveButton);
            buttonPanel.add(cancelButton);
            add(buttonPanel, gbc);

            // Загрузка данных для редактирования
            if (receptionistId != null) {
                loadReceptionistData();
            }

            // Обработчики
            saveButton.addActionListener(this);
            cancelButton.addActionListener(e -> dispose());

            setVisible(true);
        }

        private void loadReceptionistData() {
            String query = "SELECT * FROM Receptionists WHERE receptionist_id = ?";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, receptionistId);
                try (ResultSet rs = pstmt.executeQuery()) {
                    if (rs.next()) {
                        nameField.setText(rs.getString("full_name"));
                        passportField.setText(rs.getString("passport_number"));
                        addressField.setText(rs.getString("address"));
                        phoneField.setText(rs.getString("phone_number"));
                        emailField.setText(rs.getString("email"));
                        loginField.setText(rs.getString("login"));
                        // Пароль не загружается для безопасности
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке данных ресепшиониста.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == saveButton) {
                String fullName = nameField.getText().trim();
                String passport = passportField.getText().trim();
                String address = addressField.getText().trim();
                String phone = phoneField.getText().trim();
                String email = emailField.getText().trim();
                String login = loginField.getText().trim();
                String password = new String(passwordField.getPassword()).trim();

                // Валидация
                if (fullName.isEmpty() || passport.isEmpty() || address.isEmpty() ||
                        phone.isEmpty() || email.isEmpty() || login.isEmpty() ||
                        (receptionistId == null && password.isEmpty())) {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                try (ConnectMySQL connection = new ConnectMySQL()) {
                    Connection conn = connection.getConnection();
                    PreparedStatement pstmt;
                    if (receptionistId == null) {
                        // Добавление нового ресепшиониста
                        String query = "INSERT INTO Receptionists (full_name, passport_number, address, phone_number, email, login, password, admin_id, created_at, updated_at) " +
                                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";
                        pstmt = conn.prepareStatement(query);
                        pstmt.setString(1, fullName);
                        pstmt.setString(2, passport);
                        pstmt.setString(3, address);
                        pstmt.setString(4, phone);
                        pstmt.setString(5, email);
                        pstmt.setString(6, login);
                        pstmt.setString(7, hashPassword(password));
                        pstmt.setInt(8, adminId); // текущий администратор
                    } else {
                        // Обновление существующего ресепшиониста
                        String query = "UPDATE Receptionists SET full_name = ?, passport_number = ?, address = ?, phone_number = ?, email = ?, login = ?" +
                                (password.isEmpty() ? "" : ", password = ?") +
                                ", updated_at = NOW() WHERE receptionist_id = ?";
                        pstmt = conn.prepareStatement(query);
                        pstmt.setString(1, fullName);
                        pstmt.setString(2, passport);
                        pstmt.setString(3, address);
                        pstmt.setString(4, phone);
                        pstmt.setString(5, email);
                        pstmt.setString(6, login);
                        int paramIndex = 7;
                        if (!password.isEmpty()) {
                            pstmt.setString(paramIndex++, hashPassword(password));
                        }
                        pstmt.setInt(paramIndex, receptionistId);
                    }

                    pstmt.executeUpdate();
                    JOptionPane.showMessageDialog(this, "Данные успешно сохранены.");
                    parentPanel.loadReceptionists();
                    dispose();

                } catch (SQLIntegrityConstraintViolationException ex) {
                    JOptionPane.showMessageDialog(this, "Дублирование логина, паспорта или телефона.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(this, "Ошибка при сохранении данных ресепшиониста.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                }
            }
        }
    }

    // Панель управления номерами
    class RoomsPanel extends JPanel {
        private JTable table;
        private DefaultTableModel tableModel;
        private JButton addButton, editButton, deleteButton;

        public RoomsPanel() {
            setLayout(new BorderLayout());

            // Создание модели таблицы
            tableModel = new DefaultTableModel();
            tableModel.setColumnIdentifiers(new String[] {"ID", "Номер", "Статус", "Цена", "Тип кровати", "Тип номера"});
            table = new JTable(tableModel);
            loadRooms();

            add(new JScrollPane(table), BorderLayout.CENTER);

            // Кнопки управления
            JPanel buttonPanel = new JPanel();
            addButton = new JButton("Добавить");
            editButton = new JButton("Редактировать");
            deleteButton = new JButton("Удалить");
            buttonPanel.add(addButton);
            buttonPanel.add(editButton);
            buttonPanel.add(deleteButton);

            add(buttonPanel, BorderLayout.SOUTH);

            // Обработчики событий
            addButton.addActionListener(e -> openRoomForm(null));
            editButton.addActionListener(e -> {
                int selectedRow = table.getSelectedRow();
                if (selectedRow >= 0) {
                    int roomId = (int)tableModel.getValueAt(selectedRow, 0);
                    openRoomForm(roomId);
                } else {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, выберите номер для редактирования.");
                }
            });
            deleteButton.addActionListener(e -> {
                int selectedRow = table.getSelectedRow();
                if (selectedRow >= 0) {
                    int roomId = (int)tableModel.getValueAt(selectedRow, 0);
                    int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить этот номер?", "Подтверждение", JOptionPane.YES_NO_OPTION);
                    if (confirm == JOptionPane.YES_OPTION) {
                        deleteRoom(roomId);
                        loadRooms();
                    }
                } else {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, выберите номер для удаления.");
                }
            });
        }

        private void loadRooms() {
            tableModel.setRowCount(0);
            String query = "SELECT room_id, room_number, status, price, bed_type, room_type FROM Rooms";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                while (rs.next()) {
                    tableModel.addRow(new Object[] {
                            rs.getInt("room_id"),
                            rs.getInt("room_number"),
                            rs.getString("status"),
                            rs.getBigDecimal("price"),
                            rs.getString("bed_type"),
                            rs.getString("room_type")
                    });
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке номеров.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        private void openRoomForm(Integer roomId) {
            new RoomForm(roomId, this);
        }

        private void deleteRoom(int roomId) {
            String query = "DELETE FROM Rooms WHERE room_id = ?";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, roomId);
                pstmt.executeUpdate();

                JOptionPane.showMessageDialog(this, "Номер успешно удален.");

            } catch (SQLException e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при удалении номера.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // Форма добавления/редактирования номера
    class RoomForm extends JDialog implements ActionListener {
        private JTextField roomNumberField, priceField;
        private JComboBox<String> statusComboBox, bedTypeComboBox, roomTypeComboBox;
        private JButton saveButton, cancelButton;
        private Integer roomId;
        private RoomsPanel parentPanel;

        public RoomForm(Integer roomId, RoomsPanel parentPanel) {
            this.roomId = roomId;
            this.parentPanel = parentPanel;

            setTitle(roomId == null ? "Добавить Номер" : "Редактировать Номер");
            setSize(400, 400);
            setLocationRelativeTo(null);
            setModal(true);
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(5,5,5,5);

            // Номер комнаты
            gbc.gridx = 0;
            gbc.gridy = 0;
            add(new JLabel("Номер комнаты:"), gbc);
            roomNumberField = new JTextField(20);
            gbc.gridx = 1;
            add(roomNumberField, gbc);

            // Статус
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Статус:"), gbc);
            statusComboBox = new JComboBox<>(new String[] {"Доступен", "Недоступен"});
            gbc.gridx = 1;
            add(statusComboBox, gbc);

            // Цена
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Цена:"), gbc);
            priceField = new JTextField(20);
            gbc.gridx = 1;
            add(priceField, gbc);

            // Тип кровати
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Тип кровати:"), gbc);
            bedTypeComboBox = new JComboBox<>(new String[] {"Одноместный", "Двухместный", "Трехместный", "Четырехместный"});
            gbc.gridx = 1;
            add(bedTypeComboBox, gbc);

            // Тип номера
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Тип номера:"), gbc);
            roomTypeComboBox = new JComboBox<>(new String[] {"Стандарт", "Люкс", "Делюкс"});
            gbc.gridx = 1;
            add(roomTypeComboBox, gbc);

            // Кнопки
            gbc.gridx = 0;
            gbc.gridy++;
            gbc.gridwidth = 2;
            JPanel buttonPanel = new JPanel();
            saveButton = new JButton("Сохранить");
            cancelButton = new JButton("Отмена");
            buttonPanel.add(saveButton);
            buttonPanel.add(cancelButton);
            add(buttonPanel, gbc);

            // Загрузка данных для редактирования
            if (roomId != null) {
                loadRoomData();
            }

            // Обработчики
            saveButton.addActionListener(this);
            cancelButton.addActionListener(e -> dispose());

            setVisible(true);
        }

        private void loadRoomData() {
            String query = "SELECT * FROM Rooms WHERE room_id = ?";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, roomId);
                try (ResultSet rs = pstmt.executeQuery()) {
                    if (rs.next()) {
                        roomNumberField.setText(String.valueOf(rs.getInt("room_number")));
                        statusComboBox.setSelectedItem(rs.getString("status"));
                        priceField.setText(rs.getBigDecimal("price").toString());
                        bedTypeComboBox.setSelectedItem(rs.getString("bed_type"));
                        roomTypeComboBox.setSelectedItem(rs.getString("room_type"));
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке данных номера.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == saveButton) {
                String roomNumberStr = roomNumberField.getText().trim();
                String status = (String)statusComboBox.getSelectedItem();
                String priceStr = priceField.getText().trim();
                String bedType = (String)bedTypeComboBox.getSelectedItem();
                String roomType = (String)roomTypeComboBox.getSelectedItem();

                // Валидация
                if (roomNumberStr.isEmpty() || status == null || priceStr.isEmpty() || bedType == null || roomType == null) {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                int roomNumber;
                double price;
                try {
                    roomNumber = Integer.parseInt(roomNumberStr);
                    price = Double.parseDouble(priceStr);
                } catch (NumberFormatException ex) {
                    JOptionPane.showMessageDialog(this, "Номер комнаты и цена должны быть числовыми значениями.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                try (ConnectMySQL connection = new ConnectMySQL()) {
                    Connection conn = connection.getConnection();
                    PreparedStatement pstmt;

                    if (roomId == null) {
                        // Добавление нового номера
                        String query = "INSERT INTO Rooms (room_number, status, price, bed_type, room_type, created_at, updated_at) " +
                                "VALUES (?, ?, ?, ?, ?, NOW(), NOW())";
                        pstmt = conn.prepareStatement(query);
                        pstmt.setInt(1, roomNumber);
                        pstmt.setString(2, status);
                        pstmt.setDouble(3, price);
                        pstmt.setString(4, bedType);
                        pstmt.setString(5, roomType);
                    } else {
                        // Обновление существующего номера
                        String query = "UPDATE Rooms SET room_number = ?, status = ?, price = ?, bed_type = ?, room_type = ?, updated_at = NOW() WHERE room_id = ?";
                        pstmt = conn.prepareStatement(query);
                        pstmt.setInt(1, roomNumber);
                        pstmt.setString(2, status);
                        pstmt.setDouble(3, price);
                        pstmt.setString(4, bedType);
                        pstmt.setString(5, roomType);
                        pstmt.setInt(6, roomId);
                    }

                    pstmt.executeUpdate();
                    JOptionPane.showMessageDialog(this, "Данные успешно сохранены.");
                    parentPanel.loadRooms();
                    dispose();

                } catch (SQLIntegrityConstraintViolationException ex) {
                    JOptionPane.showMessageDialog(this, "Номер комнаты должен быть уникальным.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(this, "Ошибка при сохранении данных номера.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                }
            }
        }
    }

    // Панель архивов резервирований
    class ArchivesPanel extends JPanel {
        private JTable table;
        private DefaultTableModel tableModel;

        public ArchivesPanel() {
            setLayout(new BorderLayout());

            // Создание модели таблицы
            tableModel = new DefaultTableModel();
            tableModel.setColumnIdentifiers(new String[] {"Архив ID", "Бронирование ID", "Клиент", "Номер", "Дата заезда", "Дата выезда", "Статус", "Сумма"});
            table = new JTable(tableModel);
            loadArchivedReservations();

            add(new JScrollPane(table), BorderLayout.CENTER);
        }

        private void loadArchivedReservations() {
            tableModel.setRowCount(0);
            String query = "SELECT ar.archive_id, ar.reservation_id, c.full_name, r.room_number, ar.check_in, ar.check_out, ar.status, ar.total_amount " +
                    "FROM Archived_Reservations ar " +
                    "JOIN Customers c ON ar.customer_id = c.customer_id " +
                    "JOIN Rooms r ON ar.room_id = r.room_id";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                while (rs.next()) {
                    tableModel.addRow(new Object[] {
                            rs.getInt("archive_id"),
                            rs.getInt("reservation_id"),
                            rs.getString("full_name"),
                            rs.getInt("room_number"),
                            rs.getDate("check_in"),
                            rs.getDate("check_out"),
                            rs.getString("status"),
                            rs.getBigDecimal("total_amount")
                    });
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке архивных резервирований.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // Панель финансов
    class FinancePanel extends JPanel {
        private JTable table;
        private DefaultTableModel tableModel;
        private JLabel totalRevenueLabel;

        public FinancePanel() {
            setLayout(new BorderLayout());

            // Создание модели таблицы
            tableModel = new DefaultTableModel();
            tableModel.setColumnIdentifiers(new String[] {"Платеж ID", "Бронирование ID", "Клиент", "Номер", "Дата оплаты", "Сумма", "Метод оплаты"});
            table = new JTable(tableModel);
            loadPayments();

            add(new JScrollPane(table), BorderLayout.CENTER);

            // Панель для отображения общего дохода
            JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
            totalRevenueLabel = new JLabel("Общий доход: 0.00");
            bottomPanel.add(totalRevenueLabel);
            add(bottomPanel, BorderLayout.SOUTH);

            calculateTotalRevenue();
        }

        private void loadPayments() {
            tableModel.setRowCount(0);
            String query = "SELECT p.payment_id, p.reservation_id, c.full_name, r.room_number, " +
                    "p.payment_date, p.amount, p.payment_method " +
                    "FROM Payments p " +
                    "LEFT JOIN Reservations res ON p.reservation_id = res.reservation_id " +
                    "LEFT JOIN Archived_Reservations ar ON p.reservation_id = ar.reservation_id " +
                    "LEFT JOIN Customers c ON (res.customer_id = c.customer_id OR ar.customer_id = c.customer_id) " +
                    "LEFT JOIN Rooms r ON (res.room_id = r.room_id OR ar.room_id = r.room_id)";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                while (rs.next()) {
                    tableModel.addRow(new Object[] {
                            rs.getInt("payment_id"),
                            rs.getInt("reservation_id"),
                            rs.getString("full_name"),
                            rs.getInt("room_number"),
                            rs.getDate("payment_date"),
                            rs.getBigDecimal("amount"),
                            rs.getString("payment_method")
                    });
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке платежей.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        private void calculateTotalRevenue() {
            String query = "SELECT SUM(amount) AS total_revenue FROM Payments";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                if (rs.next()) {
                    double totalRevenue = rs.getDouble("total_revenue");
                    totalRevenueLabel.setText("Общий доход: " + String.format("%.2f", totalRevenue));
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при расчете общего дохода.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
}












// src/h/DashboardReceptionist.java
package h;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import org.jdatepicker.impl.*;
import java.util.Properties;
import java.text.ParseException;
import java.text.SimpleDateFormat;

public class DashboardReceptionist extends JFrame {

    private int receptionistId; // Идентификатор ресепшиониста

    public DashboardReceptionist(int receptionistId) {
        this.receptionistId = receptionistId;
        setTitle("Панель Ресепшиониста");
        setSize(1000, 700);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);

        // Создание вкладок
        JTabbedPane tabbedPane = new JTabbedPane();

        tabbedPane.addTab("Клиенты", new CustomersPanel());
        tabbedPane.addTab("Номера", new RoomsViewPanel());
        tabbedPane.addTab("Бронирования", new ReservationsPanel());
        tabbedPane.addTab("Платежи", new PaymentsPanel());
        tabbedPane.addTab("Архив", new ArchivePanel());

        add(tabbedPane);
        setVisible(true);
    }

    // Метод для хеширования пароля
    private String hashPassword(String password) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = md.digest(password.getBytes());

            StringBuilder sb = new StringBuilder();
            for(byte b : hashBytes){
                sb.append(String.format("%02x", b));
            }

            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Панель управления клиентами
    class CustomersPanel extends JPanel {
        private JTable table;
        private DefaultTableModel tableModel;
        private JButton addButton, editButton, deleteButton, refreshButton;

        public CustomersPanel() {
            setLayout(new BorderLayout());

            // Создание модели таблицы
            tableModel = new DefaultTableModel();
            tableModel.setColumnIdentifiers(new String[] {"ID", "Полное имя", "Телефон", "Email", "Пол", "Страна", "Адрес"});
            table = new JTable(tableModel);
            loadCustomers();

            add(new JScrollPane(table), BorderLayout.CENTER);

            // Кнопки управления
            JPanel buttonPanel = new JPanel();
            addButton = new JButton("Добавить");
            editButton = new JButton("Редактировать");
            deleteButton = new JButton("Удалить");
            refreshButton = new JButton("Обновить");
            buttonPanel.add(addButton);
            buttonPanel.add(editButton);
            buttonPanel.add(deleteButton);
            buttonPanel.add(refreshButton);

            add(buttonPanel, BorderLayout.SOUTH);

            // Обработчики событий
            addButton.addActionListener(e -> openCustomerForm(null));
            editButton.addActionListener(e -> {
                int selectedRow = table.getSelectedRow();
                if (selectedRow >= 0) {
                    int customerId = (int)tableModel.getValueAt(selectedRow, 0);
                    openCustomerForm(customerId);
                } else {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, выберите клиента для редактирования.");
                }
            });
            deleteButton.addActionListener(e -> {
                int selectedRow = table.getSelectedRow();
                if (selectedRow >= 0) {
                    int customerId = (int)tableModel.getValueAt(selectedRow, 0);
                    int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите удалить этого клиента?", "Подтверждение", JOptionPane.YES_NO_OPTION);
                    if (confirm == JOptionPane.YES_OPTION) {
                        deleteCustomer(customerId);
                        loadCustomers();
                    }
                } else {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, выберите клиента для удаления.");
                }
            });
            refreshButton.addActionListener(e -> loadCustomers());
        }

        private void loadCustomers() {
            tableModel.setRowCount(0);
            String query = "SELECT customer_id, full_name, phone, email, gender, country, address FROM Customers";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                while (rs.next()) {
                    tableModel.addRow(new Object[] {
                            rs.getInt("customer_id"),
                            rs.getString("full_name"),
                            rs.getString("phone"),
                            rs.getString("email"),
                            rs.getString("gender"),
                            rs.getString("country"),
                            rs.getString("address")
                    });
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке клиентов.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        private void openCustomerForm(Integer customerId) {
            new CustomerForm(customerId, this);
        }

        private void deleteCustomer(int customerId) {
            String query = "DELETE FROM Customers WHERE customer_id = ?";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, customerId);
                pstmt.executeUpdate();

                JOptionPane.showMessageDialog(this, "Клиент успешно удален.");

            } catch (SQLException e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при удалении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // Форма добавления/редактирования клиента
    class CustomerForm extends JDialog implements ActionListener {
        private JTextField nameField, phoneField, emailField, countryField, addressField;
        private JComboBox<String> genderComboBox;
        private JButton saveButton, cancelButton;
        private Integer customerId; // Null для добавления, не null для редактирования
        private CustomersPanel parentPanel;

        public CustomerForm(Integer customerId, CustomersPanel parentPanel) {
            this.customerId = customerId;
            this.parentPanel = parentPanel;

            setTitle(customerId == null ? "Добавить Клиента" : "Редактировать Клиента");
            setSize(500, 500);
            setLocationRelativeTo(null);
            setModal(true);
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(10,10,10,10);

            // Полное имя
            gbc.gridx = 0;
            gbc.gridy = 0;
            add(new JLabel("Полное имя:"), gbc);
            nameField = new JTextField(20);
            gbc.gridx = 1;
            add(nameField, gbc);

            // Телефон
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Телефон:"), gbc);
            phoneField = new JTextField(20);
            gbc.gridx = 1;
            add(phoneField, gbc);

            // Email
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Email:"), gbc);
            emailField = new JTextField(20);
            gbc.gridx = 1;
            add(emailField, gbc);

            // Пол
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Пол:"), gbc);
            genderComboBox = new JComboBox<>(new String[] {"Мужской", "Женский"});
            gbc.gridx = 1;
            add(genderComboBox, gbc);

            // Страна
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Страна:"), gbc);
            countryField = new JTextField(20);
            gbc.gridx = 1;
            add(countryField, gbc);

            // Адрес
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Адрес:"), gbc);
            addressField = new JTextField(20);
            gbc.gridx = 1;
            add(addressField, gbc);

            // Кнопки
            gbc.gridx = 0;
            gbc.gridy++;
            gbc.gridwidth = 2;
            JPanel buttonPanel = new JPanel();
            saveButton = new JButton("Сохранить");
            cancelButton = new JButton("Отмена");
            buttonPanel.add(saveButton);
            buttonPanel.add(cancelButton);
            add(buttonPanel, gbc);

            // Загрузка данных для редактирования
            if (customerId != null) {
                loadCustomerData();
            }

            // Обработчики
            saveButton.addActionListener(this);
            cancelButton.addActionListener(e -> dispose());

            setVisible(true);
        }

        private void loadCustomerData() {
            String query = "SELECT * FROM Customers WHERE customer_id = ?";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, customerId);
                try (ResultSet rs = pstmt.executeQuery()) {
                    if (rs.next()) {
                        nameField.setText(rs.getString("full_name"));
                        phoneField.setText(rs.getString("phone"));
                        emailField.setText(rs.getString("email"));
                        genderComboBox.setSelectedItem(rs.getString("gender"));
                        countryField.setText(rs.getString("country"));
                        addressField.setText(rs.getString("address"));
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке данных клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == saveButton) {
                String fullName = nameField.getText().trim();
                String phone = phoneField.getText().trim();
                String email = emailField.getText().trim();
                String gender = (String)genderComboBox.getSelectedItem();
                String country = countryField.getText().trim();
                String address = addressField.getText().trim();

                // Валидация
                if (fullName.isEmpty() || phone.isEmpty() || email.isEmpty() || gender == null || country.isEmpty() || address.isEmpty()) {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                try (ConnectMySQL connection = new ConnectMySQL()) {
                    Connection conn = connection.getConnection();
                    PreparedStatement pstmt;
                    if (customerId == null) {
                        // Добавление нового клиента
                        String query = "INSERT INTO Customers (full_name, phone, email, gender, country, address, created_at, updated_at, receptionist_id) " +
                                "VALUES (?, ?, ?, ?, ?, ?, NOW(), NOW(), ?)";
                        pstmt = conn.prepareStatement(query);
                        pstmt.setString(1, fullName);
                        pstmt.setString(2, phone);
                        pstmt.setString(3, email);
                        pstmt.setString(4, gender);
                        pstmt.setString(5, country);
                        pstmt.setString(6, address);
                        pstmt.setInt(7, receptionistId);
                    } else {
                        // Обновление существующего клиента
                        String query = "UPDATE Customers SET full_name = ?, phone = ?, email = ?, gender = ?, country = ?, address = ?, updated_at = NOW() WHERE customer_id = ?";
                        pstmt = conn.prepareStatement(query);
                        pstmt.setString(1, fullName);
                        pstmt.setString(2, phone);
                        pstmt.setString(3, email);
                        pstmt.setString(4, gender);
                        pstmt.setString(5, country);
                        pstmt.setString(6, address);
                        pstmt.setInt(7, customerId);
                    }

                    pstmt.executeUpdate();
                    JOptionPane.showMessageDialog(this, "Данные успешно сохранены.");
                    parentPanel.loadCustomers();
                    dispose();

                } catch (SQLIntegrityConstraintViolationException ex) {
                    JOptionPane.showMessageDialog(this, "Дублирование телефона или email.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                } catch (Exception ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(this, "Ошибка при сохранении данных клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                }
            }
        }
    }

    // Панель просмотра номеров
    class RoomsViewPanel extends JPanel {
        private JTable table;
        private DefaultTableModel tableModel;
        private JButton refreshButton;

        public RoomsViewPanel() {
            setLayout(new BorderLayout());

            // Создание модели таблицы
            tableModel = new DefaultTableModel();
            tableModel.setColumnIdentifiers(new String[] {"Номер ID", "Номер комнаты", "Статус", "Цена", "Тип кровати", "Тип номера"});
            table = new JTable(tableModel);
            loadRooms();

            add(new JScrollPane(table), BorderLayout.CENTER);

            // Кнопка обновления
            JPanel buttonPanel = new JPanel();
            refreshButton = new JButton("Обновить");
            buttonPanel.add(refreshButton);
            add(buttonPanel, BorderLayout.SOUTH);

            refreshButton.addActionListener(e -> loadRooms());
        }

        private void loadRooms() {
            tableModel.setRowCount(0);
            String query = "SELECT room_id, room_number, status, price, bed_type, room_type FROM Rooms";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                while (rs.next()) {
                    tableModel.addRow(new Object[] {
                            rs.getInt("room_id"),
                            rs.getInt("room_number"),
                            rs.getString("status"),
                            rs.getBigDecimal("price"),
                            rs.getString("bed_type"),
                            rs.getString("room_type")
                    });
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке номеров.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // Панель управления бронированиями
    class ReservationsPanel extends JPanel {
        private JTable table;
        private DefaultTableModel tableModel;
        private JButton addButton, editButton, refreshButton, checkInButton, checkOutButton;

        public ReservationsPanel() {
            setLayout(new BorderLayout());

            // Создание модели таблицы
            tableModel = new DefaultTableModel();
            tableModel.setColumnIdentifiers(new String[] {"ID", "Клиент", "Номер", "Дата заезда", "Дата выезда", "Статус", "Сумма"});
            table = new JTable(tableModel);
            loadReservations();

            add(new JScrollPane(table), BorderLayout.CENTER);

            // Кнопки управления
            JPanel buttonPanel = new JPanel();
            addButton = new JButton("Добавить");
            editButton = new JButton("Редактировать");
            checkInButton = new JButton("Заселить");
            checkOutButton = new JButton("Выселить");
            refreshButton = new JButton("Обновить");
            buttonPanel.add(addButton);
            buttonPanel.add(editButton);
            buttonPanel.add(checkInButton);
            buttonPanel.add(checkOutButton);
            buttonPanel.add(refreshButton);

            add(buttonPanel, BorderLayout.SOUTH);

            // Обработчики событий
            addButton.addActionListener(e -> openReservationForm(null));
            editButton.addActionListener(e -> {
                int selectedRow = table.getSelectedRow();
                if (selectedRow >= 0) {
                    int reservationId = (int)tableModel.getValueAt(selectedRow, 0);
                    openReservationForm(reservationId);
                } else {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, выберите бронирование для редактирования.");
                }
            });
            checkInButton.addActionListener(e -> {
                int selectedRow = table.getSelectedRow();
                if (selectedRow >= 0) {
                    int reservationId = (int)tableModel.getValueAt(selectedRow, 0);
                    checkIn(reservationId);
                    loadReservations();
                } else {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, выберите бронирование для заселения.");
                }
            });
            checkOutButton.addActionListener(e -> {
                int selectedRow = table.getSelectedRow();
                if (selectedRow >= 0) {
                    int reservationId = (int)tableModel.getValueAt(selectedRow, 0);
                    checkOut(reservationId);
                    loadReservations();
                } else {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, выберите бронирование для выселения.");
                }
            });
            refreshButton.addActionListener(e -> loadReservations());
        }

        private void loadReservations() {
            tableModel.setRowCount(0);
            String query = "SELECT res.reservation_id, c.full_name, r.room_number, res.check_in, res.check_out, res.status, res.total_amount " +
                    "FROM Reservations res " +
                    "JOIN Customers c ON res.customer_id = c.customer_id " +
                    "JOIN Rooms r ON res.room_id = r.room_id";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                while (rs.next()) {
                    tableModel.addRow(new Object[] {
                            rs.getInt("reservation_id"),
                            rs.getString("full_name"),
                            rs.getInt("room_number"),
                            rs.getDate("check_in"),
                            rs.getDate("check_out"),
                            rs.getString("status"),
                            rs.getBigDecimal("total_amount")
                    });
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке бронирований.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        private void openReservationForm(Integer reservationId) {
            new ReservationForm(reservationId, this, receptionistId);
        }

        private void deleteReservation(int reservationId) {
            String query = "DELETE FROM Reservations WHERE reservation_id = ?";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, reservationId);
                pstmt.executeUpdate();

                JOptionPane.showMessageDialog(this, "Бронирование успешно удалено.");

            } catch (SQLException e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при удалении бронирования.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        private void checkIn(int reservationId) {
            // Проверка и обновление статуса бронирования
            String updateQuery = "UPDATE Reservations SET status = 'Заселён', updated_at = NOW() WHERE reservation_id = ?";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(updateQuery)) {

                pstmt.setInt(1, reservationId);
                pstmt.executeUpdate();

                JOptionPane.showMessageDialog(this, "Клиент успешно заселен.");

            } catch (SQLException e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при заселении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        private void checkOut(int reservationId) {
            String selectQuery = "SELECT * FROM Reservations WHERE reservation_id = ?";
            String updateQuery = "UPDATE Reservations SET status = 'Выселен', updated_at = NOW() WHERE reservation_id = ?";
            String insertArchiveQuery = "INSERT INTO Archived_Reservations (reservation_id, customer_id, room_id, check_in, check_out, status, total_amount, created_at, updated_at) " +
                    "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
            String deleteQuery = "DELETE FROM Reservations WHERE reservation_id = ?";

            Connection conn = null;
            PreparedStatement selectStmt = null;
            PreparedStatement updateStmt = null;
            PreparedStatement insertArchiveStmt = null;
            PreparedStatement deleteStmt = null;

            try {
                ConnectMySQL connection = new ConnectMySQL();
                conn = connection.getConnection();
                conn.setAutoCommit(false); // Начало транзакции

                // Получение данных бронирования
                selectStmt = conn.prepareStatement(selectQuery);
                selectStmt.setInt(1, reservationId);
                ResultSet rs = selectStmt.executeQuery();

                if (!rs.next()) {
                    JOptionPane.showMessageDialog(this, "Бронирование не найдено.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                int customerId = rs.getInt("customer_id");
                int roomId = rs.getInt("room_id");
                Date checkIn = rs.getDate("check_in");
                Date checkOut = rs.getDate("check_out");
                String status = rs.getString("status");
                double totalAmount = rs.getDouble("total_amount");
                Timestamp createdAt = rs.getTimestamp("created_at");
                Timestamp updatedAt = rs.getTimestamp("updated_at");

                // Обновление статуса бронирования
                updateStmt = conn.prepareStatement(updateQuery);
                updateStmt.setInt(1, reservationId);
                updateStmt.executeUpdate();

                // Вставка в архив
                insertArchiveStmt = conn.prepareStatement(insertArchiveQuery);
                insertArchiveStmt.setInt(1, reservationId);
                insertArchiveStmt.setInt(2, customerId);
                insertArchiveStmt.setInt(3, roomId);
                insertArchiveStmt.setDate(4, checkIn);
                insertArchiveStmt.setDate(5, checkOut);
                insertArchiveStmt.setString(6, "Выселен");
                insertArchiveStmt.setDouble(7, totalAmount);
                insertArchiveStmt.setTimestamp(8, createdAt);
                insertArchiveStmt.setTimestamp(9, updatedAt);
                insertArchiveStmt.executeUpdate();

                // Удаление из текущих бронирований
                deleteStmt = conn.prepareStatement(deleteQuery);
                deleteStmt.setInt(1, reservationId);
                deleteStmt.executeUpdate();

                // Обновление статуса номера на 'Доступен'
                String updateRoomQuery = "UPDATE Rooms SET status = 'Доступен' WHERE room_id = ?";
                try (PreparedStatement pstmt = conn.prepareStatement(updateRoomQuery)) {
                    pstmt.setInt(1, roomId);
                    pstmt.executeUpdate();
                }

                conn.commit(); // Коммит транзакции
                JOptionPane.showMessageDialog(this, "Клиент успешно выселен.");

            } catch (SQLException e) {
                e.printStackTrace();
                if (conn != null) {
                    try {
                        conn.rollback(); // Откат транзакции при ошибке
                    } catch (SQLException ex) {
                        ex.printStackTrace();
                    }
                }
                JOptionPane.showMessageDialog(this, "Ошибка при выселении клиента.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } finally {
                try {
                    if (selectStmt != null) selectStmt.close();
                    if (updateStmt != null) updateStmt.close();
                    if (insertArchiveStmt != null) insertArchiveStmt.close();
                    if (deleteStmt != null) deleteStmt.close();
                    if (conn != null) conn.setAutoCommit(true);
                    if (conn != null) conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    // Форма добавления/редактирования бронирования
    class ReservationForm extends JDialog implements ActionListener {
        private JComboBox<String> customerComboBox, roomComboBox;
        private JDatePickerImpl checkInDatePicker, checkOutDatePicker;
        private JButton saveButton, cancelButton;
        private Integer reservationId; // Null для добавления, не null для редактирования
        private ReservationsPanel parentPanel;
        private int receptionistId;

        public ReservationForm(Integer reservationId, ReservationsPanel parentPanel, int receptionistId) {
            this.reservationId = reservationId;
            this.parentPanel = parentPanel;
            this.receptionistId = receptionistId;

            setTitle(reservationId == null ? "Добавить Бронирование" : "Редактировать Бронирование");
            setSize(500, 400);
            setLocationRelativeTo(null);
            setModal(true);
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.fill = GridBagConstraints.HORIZONTAL;
            gbc.insets = new Insets(10,10,10,10);

            // Клиент
            gbc.gridx = 0;
            gbc.gridy = 0;
            add(new JLabel("Клиент:"), gbc);
            customerComboBox = new JComboBox<>();
            loadCustomers();
            gbc.gridx = 1;
            add(customerComboBox, gbc);

            // Номер
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Номер:"), gbc);
            roomComboBox = new JComboBox<>();
            loadAvailableRooms();
            gbc.gridx = 1;
            add(roomComboBox, gbc);

            // Дата заезда
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Дата заезда:"), gbc);
            checkInDatePicker = createDatePicker();
            gbc.gridx = 1;
            add(checkInDatePicker, gbc);

            // Дата выезда
            gbc.gridx = 0;
            gbc.gridy++;
            add(new JLabel("Дата выезда:"), gbc);
            checkOutDatePicker = createDatePicker();
            gbc.gridx = 1;
            add(checkOutDatePicker, gbc);

            // Кнопки
            gbc.gridx = 0;
            gbc.gridy++;
            gbc.gridwidth = 2;
            JPanel buttonPanel = new JPanel();
            saveButton = new JButton("Сохранить");
            cancelButton = new JButton("Отмена");
            buttonPanel.add(saveButton);
            buttonPanel.add(cancelButton);
            add(buttonPanel, gbc);

            // Загрузка данных для редактирования
            if (reservationId != null) {
                loadReservationData();
            }

            // Обработчики
            saveButton.addActionListener(this);
            cancelButton.addActionListener(e -> dispose());

            setVisible(true);
        }

        private void loadCustomers() {
            String query = "SELECT customer_id, full_name FROM Customers";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                while (rs.next()) {
                    customerComboBox.addItem(rs.getInt("customer_id") + " - " + rs.getString("full_name"));
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке клиентов.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        private void loadAvailableRooms() {
            // Упрощенный запрос для загрузки всех доступных номеров
            String query = "SELECT room_id, room_number FROM Rooms WHERE status = 'Доступен'";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                while (rs.next()) {
                    roomComboBox.addItem(rs.getInt("room_id") + " - " + rs.getInt("room_number"));
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке номеров.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        private JDatePickerImpl createDatePicker() {
            UtilDateModel model = new UtilDateModel();
            Properties p = new Properties();
            p.put("text.today", "Сегодня");
            p.put("text.month", "Месяц");
            p.put("text.year", "Год");
            JDatePanelImpl datePanel = new JDatePanelImpl(model, p);
            return new JDatePickerImpl(datePanel, new DateLabelFormatter());
        }

        private void loadReservationData() {
            String query = "SELECT * FROM Reservations WHERE reservation_id = ?";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, reservationId);
                try (ResultSet rs = pstmt.executeQuery()) {
                    if (rs.next()) {
                        customerComboBox.setSelectedItem(rs.getInt("customer_id") + " - " + getCustomerName(rs.getInt("customer_id")));
                        roomComboBox.setSelectedItem(rs.getInt("room_id") + " - " + getRoomNumber(rs.getInt("room_id")));
                        checkInDatePicker.getModel().setDate(rs.getDate("check_in").toLocalDate().getYear(), rs.getDate("check_in").toLocalDate().getMonthValue() - 1, rs.getDate("check_in").toLocalDate().getDayOfMonth());
                        checkInDatePicker.getModel().setSelected(true);
                        checkOutDatePicker.getModel().setDate(rs.getDate("check_out").toLocalDate().getYear(), rs.getDate("check_out").toLocalDate().getMonthValue() - 1, rs.getDate("check_out").toLocalDate().getDayOfMonth());
                        checkOutDatePicker.getModel().setSelected(true);
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке данных бронирования.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        private String getCustomerName(int customerId) {
            String name = "";
            String query = "SELECT full_name FROM Customers WHERE customer_id = ?";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, customerId);
                try (ResultSet rs = pstmt.executeQuery()) {
                    if (rs.next()) {
                        name = rs.getString("full_name");
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
            return name;
        }

        private int getRoomNumber(int roomId) {
            int roomNumber = -1;
            String query = "SELECT room_number FROM Rooms WHERE room_id = ?";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, roomId);
                try (ResultSet rs = pstmt.executeQuery()) {
                    if (rs.next()) {
                        roomNumber = rs.getInt("room_number");
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
            return roomNumber;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == saveButton) {
                String customerStr = (String)customerComboBox.getSelectedItem();
                String roomStr = (String)roomComboBox.getSelectedItem();
                java.util.Date checkInDate = (java.util.Date)checkInDatePicker.getModel().getValue();
                java.util.Date checkOutDate = (java.util.Date)checkOutDatePicker.getModel().getValue();

                if (customerStr == null || roomStr == null || checkInDate == null || checkOutDate == null) {
                    JOptionPane.showMessageDialog(this, "Пожалуйста, заполните все поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                int customerId = Integer.parseInt(customerStr.split(" - ")[0]);
                int roomId = Integer.parseInt(roomStr.split(" - ")[0]);

                java.sql.Date checkInSqlDate = new java.sql.Date(checkInDate.getTime());
                java.sql.Date checkOutSqlDate = new java.sql.Date(checkOutDate.getTime());

                // Валидация дат
                if (!validateDates(checkInSqlDate, checkOutSqlDate)) {
                    JOptionPane.showMessageDialog(this, "Дата выезда должна быть позже даты заезда.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                // Проверка доступности номера
                if (!isRoomAvailable(roomId, checkInSqlDate, checkOutSqlDate, reservationId)) {
                    JOptionPane.showMessageDialog(this, "Номер уже забронирован на указанные даты.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                    return;
                }

                // Вычисление общей суммы
                double totalAmount = calculateTotalAmount(roomId, checkInSqlDate, checkOutSqlDate);

                try (ConnectMySQL connection = new ConnectMySQL()) {
                    Connection conn = connection.getConnection();
                    PreparedStatement pstmt;
                    if (reservationId == null) {
                        // Добавление нового бронирования
                        String query = "INSERT INTO Reservations (customer_id, room_id, check_in, check_out, status, total_amount, created_at, updated_at, receptionist_id) " +
                                "VALUES (?, ?, ?, ?, 'Забронирован', ?, NOW(), NOW(), ?)";
                        pstmt = conn.prepareStatement(query);
                        pstmt.setInt(1, customerId);
                        pstmt.setInt(2, roomId);
                        pstmt.setDate(3, checkInSqlDate);
                        pstmt.setDate(4, checkOutSqlDate);
                        pstmt.setDouble(5, totalAmount);
                        pstmt.setInt(6, receptionistId);
                    } else {
                        // Обновление существующего бронирования
                        String query = "UPDATE Reservations SET customer_id = ?, room_id = ?, check_in = ?, check_out = ?, status = 'Забронирован', total_amount = ?, updated_at = NOW(), receptionist_id = ? WHERE reservation_id = ?";
                        pstmt = conn.prepareStatement(query);
                        pstmt.setInt(1, customerId);
                        pstmt.setInt(2, roomId);
                        pstmt.setDate(3, checkInSqlDate);
                        pstmt.setDate(4, checkOutSqlDate);
                        pstmt.setDouble(5, totalAmount);
                        pstmt.setInt(6, receptionistId);
                        pstmt.setInt(7, reservationId);
                    }

                    pstmt.executeUpdate();
                    JOptionPane.showMessageDialog(this, "Бронирование успешно сохранено.");
                    parentPanel.loadReservations();
                    dispose();

                } catch (SQLException ex) {
                    ex.printStackTrace();
                    JOptionPane.showMessageDialog(this, "Ошибка при сохранении бронирования.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                }
            }
        }

        private boolean validateDates(java.sql.Date checkIn, java.sql.Date checkOut) {
            return checkOut.after(checkIn);
        }

        private boolean isRoomAvailable(int roomId, java.sql.Date checkIn, java.sql.Date checkOut, Integer currentReservationId) {
            String query = "SELECT COUNT(*) AS count FROM Reservations WHERE room_id = ? AND status NOT IN ('Отменён', 'Выселен') AND (" +
                    "(check_in <= ? AND check_out > ?) OR " +
                    "(check_in < ? AND check_out >= ?) OR " +
                    "(check_in >= ? AND check_out <= ?))";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, roomId);
                pstmt.setDate(2, checkOut);
                pstmt.setDate(3, checkIn);
                pstmt.setDate(4, checkIn);
                pstmt.setDate(5, checkOut);
                pstmt.setDate(6, checkIn);
                pstmt.setDate(7, checkOut);

                try (ResultSet rs = pstmt.executeQuery()) {
                    if (rs.next()) {
                        int count = rs.getInt("count");
                        if (currentReservationId != null && count > 0) {
                            // Исключение текущего бронирования из проверки
                            String excludeQuery = "SELECT COUNT(*) AS exclude_count FROM Reservations WHERE reservation_id = ? AND " +
                                    "room_id = ? AND status NOT IN ('Отменён', 'Выселен') AND (" +
                                    "(check_in <= ? AND check_out > ?) OR " +
                                    "(check_in < ? AND check_out >= ?) OR " +
                                    "(check_in >= ? AND check_out <= ?))";
                            try (PreparedStatement pstmtExclude = connection.getConnection().prepareStatement(excludeQuery)) {
                                pstmtExclude.setInt(1, currentReservationId);
                                pstmtExclude.setInt(2, roomId);
                                pstmtExclude.setDate(3, checkOut);
                                pstmtExclude.setDate(4, checkIn);
                                pstmtExclude.setDate(5, checkIn);
                                pstmtExclude.setDate(6, checkOut);
                                pstmtExclude.setDate(7, checkIn);
                                pstmtExclude.setDate(8, checkOut);

                                try (ResultSet rsExclude = pstmtExclude.executeQuery()) {
                                    if (rsExclude.next()) {
                                        int excludeCount = rsExclude.getInt("exclude_count");
                                        if (excludeCount > 0) {
                                            count -= excludeCount;
                                        }
                                    }
                                }
                            }
                        }
                        return count == 0;
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
            return false;
        }

        private double calculateTotalAmount(int roomId, java.sql.Date checkIn, java.sql.Date checkOut) {
            String query = "SELECT price FROM Rooms WHERE room_id = ?";
            double price = 0.0;
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

                pstmt.setInt(1, roomId);
                try (ResultSet rs = pstmt.executeQuery()) {
                    if (rs.next()) {
                        price = rs.getDouble("price");
                    }
                }

                long diffInMillies = checkOut.getTime() - checkIn.getTime();
                long days = diffInMillies / (1000 * 60 * 60 * 24);
                return price * days;

            } catch (Exception e) {
                e.printStackTrace();
            }
            return price;
        }
    }

    // Панель управления платежами
    class PaymentsPanel extends JPanel {
        private JTable table;
        private DefaultTableModel tableModel;
        private JButton refreshButton;
        private JLabel totalRevenueLabel;

        public PaymentsPanel() {
            setLayout(new BorderLayout());

            // Панель для отображения общего дохода
            JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
            totalRevenueLabel = new JLabel("Общий доход: 0.00");
            topPanel.add(totalRevenueLabel);
            add(topPanel, BorderLayout.NORTH); // Добавление верхней панели

            // Создание модели таблицы
            tableModel = new DefaultTableModel();
            tableModel.setColumnIdentifiers(new String[] {"ID Платежа", "Бронирование ID", "Клиент", "Номер", "Дата оплаты", "Сумма", "Метод оплаты"});
            table = new JTable(tableModel);
            loadPayments();

            add(new JScrollPane(table), BorderLayout.CENTER);

            // Кнопки управления
            JPanel buttonPanel = new JPanel();
            refreshButton = new JButton("Обновить");
            buttonPanel.add(refreshButton);
            add(buttonPanel, BorderLayout.SOUTH);

            // Обработчики событий
            refreshButton.addActionListener(e -> loadPayments());
        }

        private void loadPayments() {
            tableModel.setRowCount(0);
            String query = "SELECT p.payment_id, p.reservation_id, c.full_name, r.room_number, " +
                    "p.payment_date, p.amount, p.payment_method " +
                    "FROM Payments p " +
                    "LEFT JOIN Reservations res ON p.reservation_id = res.reservation_id " +
                    "LEFT JOIN Archived_Reservations ar ON p.reservation_id = ar.reservation_id " +
                    "LEFT JOIN Customers c ON (res.customer_id = c.customer_id OR ar.customer_id = c.customer_id) " +
                    "LEFT JOIN Rooms r ON (res.room_id = r.room_id OR ar.room_id = r.room_id)";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                while (rs.next()) {
                    tableModel.addRow(new Object[] {
                            rs.getInt("payment_id"),
                            rs.getInt("reservation_id"),
                            rs.getString("full_name"),
                            rs.getInt("room_number"),
                            rs.getDate("payment_date"),
                            rs.getBigDecimal("amount"),
                            rs.getString("payment_method")
                    });
                }

                // Вычисление общего дохода
                calculateTotalRevenue();

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке платежей.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        private void calculateTotalRevenue() {
            String query = "SELECT SUM(amount) AS total_revenue FROM Payments";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                if (rs.next()) {
                    double totalRevenue = rs.getDouble("total_revenue");
                    totalRevenueLabel.setText("Общий доход: " + String.format("%.2f", totalRevenue));
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при расчете общего дохода.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // Панель архивов бронирований
    class ArchivePanel extends JPanel {
        private JTable table;
        private DefaultTableModel tableModel;
        private JButton refreshButton;

        public ArchivePanel() {
            setLayout(new BorderLayout());

            // Создание модели таблицы
            tableModel = new DefaultTableModel();
            tableModel.setColumnIdentifiers(new String[] {"Архив ID", "Бронирование ID", "Клиент", "Номер", "Дата заезда", "Дата выезда", "Статус", "Сумма"});
            table = new JTable(tableModel);
            loadArchivedReservations();

            add(new JScrollPane(table), BorderLayout.CENTER);

            // Кнопка обновления
            JPanel buttonPanel = new JPanel();
            refreshButton = new JButton("Обновить");
            buttonPanel.add(refreshButton);
            add(buttonPanel, BorderLayout.SOUTH);

            refreshButton.addActionListener(e -> loadArchivedReservations());
        }

        private void loadArchivedReservations() {
            tableModel.setRowCount(0);
            String query = "SELECT ar.archive_id, ar.reservation_id, c.full_name, r.room_number, ar.check_in, ar.check_out, ar.status, ar.total_amount " +
                    "FROM Archived_Reservations ar " +
                    "JOIN Customers c ON ar.customer_id = c.customer_id " +
                    "JOIN Rooms r ON ar.room_id = r.room_id";
            try (ConnectMySQL connection = new ConnectMySQL();
                 PreparedStatement pstmt = connection.getConnection().prepareStatement(query);
                 ResultSet rs = pstmt.executeQuery()) {

                while (rs.next()) {
                    tableModel.addRow(new Object[] {
                            rs.getInt("archive_id"),
                            rs.getInt("reservation_id"),
                            rs.getString("full_name"),
                            rs.getInt("room_number"),
                            rs.getDate("check_in"),
                            rs.getDate("check_out"),
                            rs.getString("status"),
                            rs.getBigDecimal("total_amount")
                    });
                }

            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка при загрузке архивных бронирований.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    // Класс для форматирования даты в JDatePicker
    class DateLabelFormatter extends JFormattedTextField.AbstractFormatter {

        private String datePattern = "yyyy-MM-dd";
        private SimpleDateFormat dateFormatter = new SimpleDateFormat(datePattern);

        @Override
        public Object stringToValue(String text) throws ParseException {
            if (text == null || text.isEmpty()) {
                return null;
            }
            return dateFormatter.parse(text);
        }

        @Override
        public String valueToString(Object value) throws ParseException {
            if (value != null) {
                if (value instanceof java.util.Date) {
                    java.util.Date date = (java.util.Date) value;
                    return dateFormatter.format(date);
                } else if (value instanceof java.util.Calendar) {
                    java.util.Calendar cal = (java.util.Calendar) value;
                    return dateFormatter.format(cal.getTime());
                }
            }
            return "";
        }
    }
}













// src/h/ConnectMySQL.java
package h;

import java.sql.*;

public class ConnectMySQL implements AutoCloseable {
    private static final String URL = "jdbc:mysql://localhost:1369/hotel?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASSWORD = "1369sukAnigghaD1ck";

    private Connection connection;

    public ConnectMySQL() throws SQLException {
        // Класс загрузки драйвера MySQL JDBC теперь не нужен
        this.connection = DriverManager.getConnection(URL, USER, PASSWORD);
    }

    public Connection getConnection() {
        return connection;
    }

    @Override
    public void close() throws SQLException {
        if (connection != null && !connection.isClosed()) {
            connection.close();
        }
    }
}














// src/h/Login.java
package h;

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.sql.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Login extends JFrame implements ActionListener {

    private JLabel usernameLabel, passwordLabel;
    private JTextField usernameField;
    private JPasswordField passwordField;
    private JButton loginButton, cancelButton;
    private JCheckBox showPasswordCheck;
    private JButton signupLink;

    public Login() {
        setTitle("Авторизация");
        setBounds(700, 300, 400, 300);
        setLayout(null);

        // Метка и поле ввода для логина
        usernameLabel = new JLabel("Имя пользователя:");
        usernameLabel.setBounds(50, 50, 120, 30);
        add(usernameLabel);

        usernameField = new JTextField();
        usernameField.setBounds(180, 50, 150, 30);
        add(usernameField);

        // Метка и поле ввода для пароля
        passwordLabel = new JLabel("Пароль:");
        passwordLabel.setBounds(50, 100, 120, 30);
        add(passwordLabel);

        passwordField = new JPasswordField();
        passwordField.setBounds(180, 100, 150, 30);
        add(passwordField);

        // Чекбокс для показа пароля
        showPasswordCheck = new JCheckBox("Показать пароль");
        showPasswordCheck.setBounds(180, 140, 150, 25);
        showPasswordCheck.setBackground(Color.WHITE);
        showPasswordCheck.addActionListener(this);
        add(showPasswordCheck);

        // Кнопка входа
        loginButton = new JButton("Войти");
        loginButton.setBounds(50, 180, 120, 30);
        loginButton.setForeground(Color.BLACK);
        loginButton.setBackground(Color.BLACK);
        loginButton.addActionListener(this);
        add(loginButton);

        // Кнопка отмены
        cancelButton = new JButton("Выход");
        cancelButton.setBounds(210, 180, 120, 30);
        cancelButton.setForeground(Color.BLACK);
        cancelButton.setBackground(Color.BLACK);
        cancelButton.addActionListener(this);
        add(cancelButton);

        // Ссылка на регистрацию
        signupLink = new JButton("<HTML><U>Нет аккаунта? Зарегистрироваться</U></HTML>");
        signupLink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        signupLink.setBorderPainted(false);
        signupLink.setForeground(Color.BLUE.darker());
        signupLink.setBackground(Color.WHITE);
        signupLink.setFocusPainted(false);
        signupLink.setBounds(100, 220, 200, 25);
        signupLink.addActionListener(this);
        add(signupLink);

        getContentPane().setBackground(Color.WHITE);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    // Метод для хеширования пароля
    private String hashPassword(String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hash = md.digest(password.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : hash) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Обработка событий
    public void actionPerformed(ActionEvent ae) {
        // Обработка чекбокса показа пароля
        if (ae.getSource() == showPasswordCheck) {
            if (showPasswordCheck.isSelected()) {
                passwordField.setEchoChar((char) 0);
            } else {
                passwordField.setEchoChar('•');
            }
        }

        // Обработка кнопки "Войти"
        if (ae.getSource() == loginButton) {
            authenticateUser();
        }

        // Обработка кнопки "Отмена"
        if (ae.getSource() == cancelButton) {
            int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите выйти?", "Подтверждение", JOptionPane.YES_NO_OPTION);
            if (confirm == JOptionPane.YES_OPTION) {
                System.exit(0);
            }
        }

        // Обработка ссылки на регистрацию
        if (ae.getSource() == signupLink) {
            new SignUp().setVisible(true);
            this.dispose();
        }
    }

    // Метод аутентификации пользователя
    private void authenticateUser() {
        String username = usernameField.getText().trim();
        String password = new String(passwordField.getPassword()).trim();

        if (username.isEmpty() || password.isEmpty()) {
            JOptionPane.showMessageDialog(this, "Пожалуйста, введите имя пользователя и пароль.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        String hashedPassword = hashPassword(password);
        if (hashedPassword == null) {
            JOptionPane.showMessageDialog(this, "Ошибка хеширования пароля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            return;
        }

        // Попытка авторизоваться как Администратор
        Pr user = authenticateInRole("Administrators", "admin_id", "login", "password");
        if (user != null) {
            JOptionPane.showMessageDialog(this, "Добро пожаловать, Администратор!");
            new DashboardAdmin(user.getId()).setVisible(true);
            this.dispose();
            return;
        }

        // Попытка авторизоваться как Ресепшионист
        user = authenticateInRole("Receptionists", "receptionist_id", "login", "password");
        if (user != null) {
            JOptionPane.showMessageDialog(this, "Добро пожаловать, Ресепшионист!");
            new DashboardReceptionist(user.getId()).setVisible(true);
            this.dispose();
            return;
        }

        // Если пользователь не найден
        JOptionPane.showMessageDialog(this, "Неверные имя пользователя или пароль.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        usernameField.setText("");
        passwordField.setText("");
    }

    /**
     * Метод для аутентификации пользователя в заданной роли.
     *
     * @param tableName      Название таблицы (Administrators или Receptionists)
     * @param idColumn       Название столбца ID (admin_id или receptionist_id)
     * @param loginColumn    Название столбца с логином
     * @param passwordColumn Название столбца с паролем
     * @return Объект Pr с информацией о пользователе или null, если не найден
     */
    private Pr authenticateInRole(String tableName, String idColumn, String loginColumn, String passwordColumn) {
        String query = "SELECT * FROM " + tableName + " WHERE " + loginColumn + " = ? AND " + passwordColumn + " = ?";
        try (ConnectMySQL connection = new ConnectMySQL();
             PreparedStatement pstmt = connection.getConnection().prepareStatement(query)) {

            pstmt.setString(1, usernameField.getText().trim());
            pstmt.setString(2, hashPassword(new String(passwordField.getPassword()).trim()));

            try (ResultSet rs = pstmt.executeQuery()) {
                if (rs.next()) {
                    int id = rs.getInt(idColumn);
                    String fullName = rs.getString("full_name");
                    String role = tableName.equals("Administrators") ? "Administrator" : "Receptionist";
                    return new Pr(id, fullName, role);
                }
            }

        } catch (SQLException e) {
            e.printStackTrace();
            JOptionPane.showMessageDialog(this, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
        }
        return null;
    }

    public static void main(String[] args) {
        // Установка системного вида для современного оформления
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ignored) {}

        new Login();
    }
}
















// src/h/Pr.java
package h;

public class Pr {
    private int id;
    private String fullName;
    private String role;

    public Pr(int id, String fullName, String role) {
        this.id = id;
        this.fullName = fullName;
        this.role = role;
    }

    public int getId() {
        return id;
    }

    public String getFullName() {
        return fullName;
    }

    public String getRole() {
        return role;
    }
}


















// src/h/SignUp.java
package h;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.sql.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SignUp extends JFrame implements ActionListener {

    private JTextField nameField, passportField, addressField, phoneField, emailField, loginField;
    private JPasswordField passwordField;
    private JCheckBox showPasswordCheck;
    private JButton signupButton, cancelButton;
    private JButton loginLink;

    public SignUp() {
        setTitle("Регистрация Администратора");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(500, 500);
        setLocationRelativeTo(null);

        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.HORIZONTAL;

        gbc.insets = new Insets(5,5,5,5);

        // Полное имя
        JLabel nameLabel = new JLabel("Полное имя:");
        gbc.gridx = 0;
        gbc.gridy = 0;
        panel.add(nameLabel, gbc);

        nameField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(nameField, gbc);

        // Номер паспорта
        JLabel passportLabel = new JLabel("Номер паспорта:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(passportLabel, gbc);

        passportField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(passportField, gbc);

        // Адрес
        JLabel addressLabel = new JLabel("Адрес:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(addressLabel, gbc);

        addressField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(addressField, gbc);

        // Телефон
        JLabel phoneLabel = new JLabel("Телефон:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(phoneLabel, gbc);

        phoneField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(phoneField, gbc);

        // Email
        JLabel emailLabel = new JLabel("Email:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(emailLabel, gbc);

        emailField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(emailField, gbc);

        // Логин
        JLabel loginLabel = new JLabel("Логин:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(loginLabel, gbc);

        loginField = new JTextField(20);
        gbc.gridx = 1;
        panel.add(loginField, gbc);

        // Пароль
        JLabel passwordLabel = new JLabel("Пароль:");
        gbc.gridx = 0;
        gbc.gridy++;
        panel.add(passwordLabel, gbc);

        passwordField = new JPasswordField(20);
        gbc.gridx = 1;
        panel.add(passwordField, gbc);

        // Чекбокс для показа пароля
        showPasswordCheck = new JCheckBox("Показать пароль");
        gbc.gridx = 1;
        gbc.gridy++;
        panel.add(showPasswordCheck, gbc);
        showPasswordCheck.addActionListener(this);

        // Кнопки регистрации и отмены
        signupButton = new JButton("Зарегистрироваться");
        gbc.gridx = 0;
        gbc.gridy++;
        gbc.gridwidth = 2;
        gbc.insets = new Insets(20,5,5,5);
        panel.add(signupButton, gbc);
        signupButton.addActionListener(this);

        cancelButton = new JButton("Отмена");
        gbc.gridy++;
        panel.add(cancelButton, gbc);
        cancelButton.addActionListener(this);

        // Ссылка на окно входа
        loginLink = new JButton("<HTML><U>Уже есть аккаунт? Войти</U></HTML>");
        loginLink.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        loginLink.setBorderPainted(false);
        loginLink.setForeground(Color.BLUE.darker());
        loginLink.setBackground(Color.WHITE);
        loginLink.setFocusPainted(false);
        loginLink.addActionListener(this);
        gbc.gridy++;
        panel.add(loginLink, gbc);

        add(panel);
        setVisible(true);
    }

    // Метод для хеширования пароля
    private String hashPassword(String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hashBytes = md.digest(password.getBytes());

            StringBuilder sb = new StringBuilder();
            for(byte b : hashBytes){
                sb.append(String.format("%02x", b));
            }

            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    // Обработка событий
    @Override
    public void actionPerformed(ActionEvent ae) {
        Object source = ae.getSource();

        if (source == showPasswordCheck) {
            if (showPasswordCheck.isSelected()) {
                passwordField.setEchoChar((char)0);
            } else {
                passwordField.setEchoChar('•');
            }
        }

        if (source == signupButton) {
            String fullName = nameField.getText().trim();
            String passportNumber = passportField.getText().trim();
            String address = addressField.getText().trim();
            String phone = phoneField.getText().trim();
            String email = emailField.getText().trim();
            String login = loginField.getText().trim();
            String password = new String(passwordField.getPassword()).trim();

            // Валидация
            if (fullName.isEmpty() || passportNumber.isEmpty() || address.isEmpty() ||
                    phone.isEmpty() || email.isEmpty() || login.isEmpty() || password.isEmpty()) {
                JOptionPane.showMessageDialog(this, "Пожалуйста, заполните все обязательные поля.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                return;
            }

            try {
                ConnectMySQL connection = new ConnectMySQL();
                Connection conn = connection.getConnection();

                String query = "INSERT INTO Administrators (full_name, passport_number, address, phone_number, email, login, password, created_at, updated_at) "
                        + "VALUES (?, ?, ?, ?, ?, ?, ?, NOW(), NOW())";

                PreparedStatement pstmt = conn.prepareStatement(query);
                pstmt.setString(1, fullName);
                pstmt.setString(2, passportNumber);
                pstmt.setString(3, address);
                pstmt.setString(4, phone);
                pstmt.setString(5, email);
                pstmt.setString(6, login);
                pstmt.setString(7, hashPassword(password));

                int rowsAffected = pstmt.executeUpdate();
                if (rowsAffected > 0) {
                    JOptionPane.showMessageDialog(this, "Аккаунт администратора успешно создан!");
                    new Login().setVisible(true);
                    this.dispose();
                } else {
                    JOptionPane.showMessageDialog(this, "Ошибка при создании аккаунта. Пожалуйста, попробуйте снова.", "Ошибка", JOptionPane.ERROR_MESSAGE);
                }

                conn.close();

            } catch (SQLIntegrityConstraintViolationException e) {
                JOptionPane.showMessageDialog(this, "Такой логин, номер паспорта, телефон или email уже существуют!", "Ошибка", JOptionPane.ERROR_MESSAGE);
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog(this, "Ошибка подключения к базе данных.", "Ошибка", JOptionPane.ERROR_MESSAGE);
            }
        }

        if (source == cancelButton) {
            int confirm = JOptionPane.showConfirmDialog(this, "Вы уверены, что хотите отменить регистрацию?", "Подтверждение", JOptionPane.YES_NO_OPTION);
            if (confirm == JOptionPane.YES_OPTION) {
                new Login().setVisible(true);
                this.dispose();
            }
        }

        if (source == loginLink) {
            new Login().setVisible(true);
            this.dispose();
        }
    }

    public static void main(String[] args) {
        // Установка системного вида для современного оформления
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception ignored) {}

        new SignUp();
    }
}







у меня идея что после того как клиента выселит ресепшионист или автоматически выселится то его запись удаляется из вкладки бронирований и переходит во вкладку архивов и информация об оплате при этом должна также сохранится во вкладке платежей на панелях и администратора и ресепшиониста