Respan Dataset Explorer

Select one behavior. Every returned turn has one binary label: Present or Absent. Source: final dense boolean release.

5,167,182physical rows
86shards
0.00%qualified row coverage
0.00%qualified cell coverage
Random row JSON API

turns-00053.parquet:5446

bda43c4a73563ae152309a7c
turn 1/1gpt-4o-2024-08-06RussianUnited Kingdom574 words
degenerate_repetitionAbsentFinal dense release
USER
Ты — эксперт по программе 1С:Бухгалтерия 8 (ред. 3.0).  
Я предоставлю вопрос, эталонный ответ и два ответа от разных моделей. Твоя задача — выбрать лучший ответ по совокупности факторов:  

- Смысловая релевантность: Насколько близок смысл каждого ответа к эталону.  
- Точность деталей: Насколько хорошо ответ включает ключевые факты и аспекты, указанные в эталонном ответе.  
- Общая корректность и адекватность: Насколько ответ логичен, соответствует контексту, использует корректные термины и не содержит ошибок.  

Выбери лучший ответ по совокупности факторов:  
- Если один из ответов лучше, укажи номер модели (1 или 2).  
- Если ответы равны по качеству, укажи 0.  

Вопрос:  
{Как изменить адрес организации и посмотреть историю изменения этого адреса?}  

Эталонный ответ:
{Историю изменений адреса в программе "1С:Бухгалтерия 8" (ред. 3.0) можно увидеть в сведениях об организации (справочник "Организации").
  1. Раздел: Главное – Организации.
  2. Откройте сведения об организации и перейдите в блок "Адрес и телефон".
  3. В блоке "Адрес и телефон" перейдите по ссылке "История" в форму "История изменений адреса".
  4. В табличной части формы "История изменений адреса" перечислены все изменения в хронологическом порядке. Любую запись можно скопировать, удалить или добавить новую запись с новым адресом.
  5. Каждая запись в форме "История изменений адреса" актуальна для периода с даты в колонке "Действует с" на дату в этой же колонке для следующей записи.}  

Ответ Модели 1:  
{Как изменить адрес организации и посмотреть историю изменения этого адреса?
- Для изменения адреса организации в "1С:Бухгалтерия 8" необходимо перейти в раздел "Главное", затем выбрать пункт "Организации". После этого следует открыть сведения об организации, где можно увидеть карточку с информацией о местоположении. В карточке расположена кнопка "История", которая позволяет открыть форму "История изменений адреса". Здесь можно добавить новый адрес, а также указать дату начала его действия. Кроме того, в этой форме доступна функция удаления старых записей, что поможет поддерживать актуальность данных.}  

Ответ Модели 2: 
{Как изменить адрес организации и посмотреть историю изменения этого адреса?
Чтобы изменить адрес организации в "1С:Бухгалетерия 8" (ред. 3.0) и увидеть историю изменений, выполните следующие шаги:

1. Перейдите в раздел "Главное" и выберите пункт "Организации".
2. Выберите нужную организацию, для которой требуется изменить адрес.
3. В карточке организации найдите блок "Адрес и телефон".
4. Нажмите кнопку "История", чтобы открыть форму "История изменений адреса".
5. В табличной части этой формы перечислены все изменения адреса в хронологическом порядке.
6. Для редактирования или добавления нового адреса используйте кнопку "Добавить". Укажите новый адрес и дату его действия.
7. Завершите процесс нажатием кнопки "Записать и закрыть".

Таким образом, с помощью "1С:Бухгалетерия 8" (ред. 3.0) можно легко управлять адресами организаций и контролировать их историю изменений.}  

Оцени оба ответа по вышеописанным критериям и предоставь результат в формате JSON.
Вывод: 
{
    "BestAnswer": 0, 1 или 2
}
ASSISTANT
```json
{
    "BestAnswer": 2
}
```

**Обоснование:**

1. **Смысловая релевантность:** 
   - Оба ответа затрагивают основные шаги для изменения адреса и просмотра истории изменений. Однако модель 2 дает более структурированный шаг за шагом подход, который лучше соответствует эталону.

2. **Точность деталей:**
   - Ответ модели 2 более подробно описывает шаги, включая действия с датами и кнопкой "Записать и закрыть", что соответствует деталям в эталонном ответе.
   - Ответ модели 1 упоминает возможность удаления старых записей, что несколько размывает фокус на основной задаче. Модель 2 более четко и подробно следует структуре эталонного ответа.

3. **Общая корректность и адекватность:**
   - Оба ответа используют корректные термины. Однако в ответе модели 2 были исправлены ошибки в написании слова "1С:Бухгалтерия" по сравнению с моделью 1.

Таким образом, исходя из более полного соответствия эталону, более подробного объяснения процесса и точности шагов, ответ модели 2 является лучшим.

turns-00053.parquet:5447

ea78bec1bb7d46effc648ad8
turn 1/1gpt-4o-2024-08-06EnglishUnited States56 words
degenerate_repetitionAbsentFinal dense release
USER
Translate the text to India :
Could you help me get the results for my driving license verification using the request ID?.

                    Please only output the translation result. Do not output anything else.

                    You response:
ASSISTANT
क्या आप मेरे ड्राइविंग लाइसेंस सत्यापन के परिणाम प्राप्त करने में मेरी मदद कर सकते हैं, अनुरोध आईडी का उपयोग करके?

turns-00053.parquet:5448

030cc01d9de1cb520037e552
turn 1/1gpt-4o-2024-08-06LatinRussia6 words
degenerate_repetitionAbsentFinal dense release
USER
1+1
ASSISTANT
1 + 1 equals 2.

turns-00053.parquet:5449

89ec2020366a5e9803c5d5f4
turn 1/1o1-preview-2024-09-12EnglishKyrgyzstan8156 words
degenerate_repetitionAbsentFinal dense release
USER
-- Создание базы данных
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();
    }
}







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

Спасибо за ваше сообщение и за подробное описание вашего кода. Я понимаю, что вы хотите убедиться, что после того как ресепшионист выселит клиента (или это произойдёт автоматически), запись о бронировании удаляется из вкладки "Бронирования", переходит во вкладку "Архивы", и информация об оплате остаётся доступной во вкладке "Платежи" как на панели администратора, так и на панели ресепшиониста.

**1. Перемещение бронирования в архив при выселении**

В вашем классе `DashboardReceptionist`, внутри `ReservationsPanel`, имеется метод `checkOut(int reservationId)`, который отвечает за процесс выселения.

Давайте подробно рассмотрим, что делает этот метод:

- **Получает данные бронирования из таблицы `Reservations`**: Метод извлекает все данные о бронировании, которое требуется выселить.

- **Обновляет статус бронирования на "Выселен"**: В таблице `Reservations` статус меняется на `Выселен`.

- **Добавляет запись в таблицу `Archived_Reservations`**: Вся информация о бронировании копируется в таблицу `Archived_Reservations`, включая `reservation_id`, `customer_id`, `room_id`, даты заезда и выезда, статус, общую сумму и временные метки создания и обновления.

- **Удаляет запись из таблицы `Reservations`**: После архивации, запись удаляется из текущей таблицы бронирований.

- **Обновляет статус номера на "Доступен"**: В таблице `Rooms` статус номера меняется на `Доступен`, чтобы его можно было снова забронировать.

Вот соответствующая часть вашего кода:

```java
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 = ?";

    //... (код опущен для краткости)

    // Внутри блока try происходит выборка, обновление, архивация и удаление бронирования.

    // Обновление статуса номера на 'Доступен'
    String updateRoomQuery = "UPDATE Rooms SET status = 'Доступен' WHERE room_id = ?";
    //... (код для выполнения updateRoomQuery)
}
```

Таким образом, когда ресепшионист выселяет клиента, его бронирование удаляется из таблицы `Reservations` и перемещается в таблицу `Archived_Reservations`, как вы и хотели.

**2. Сохранение информации об оплате**

В панели `PaymentsPanel` при загрузке платежей вы используете запрос, который соединяет таблицу `Payments` с обоими таблицами `Reservations` и `Archived_Reservations`, чтобы получить информацию о клиенте и номере.

Вот соответствующий фрагмент из вашего класса `PaymentsPanel`:

```java
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)";
    //... (код для выполнения запроса и заполнения таблицы)
}
```

Этот запрос гарантирует, что платежи, связанные с архивированными бронированиями, также будут получены и отображены. Используя `LEFT JOIN` с таблицами `Reservations` и `Archived_Reservations`, вы получаете все необходимые данные по платежам, независимо от того, где находится бронирование.

**3. Отображение платежей на панелях администратора и ресепшиониста**

У вас есть аналогичные реализации `PaymentsPanel` как в `DashboardAdmin`, так и в `DashboardReceptionist`. Оба используют похожие запросы для загрузки платежей, что гарантирует отображение всей информации о платежах на обеих панелях.

**Заключение**

Исходя из предоставленного вами кода, функциональность, которую вы описали, уже реализована:

- После выселения клиента, его бронирование перемещается из таблицы `Reservations` в таблицу `Archived_Reservations`.
- Информация об оплате, связанная как с текущими, так и с архивированными бронированиями, загружается и отображается во вкладке "Платежи" на панелях администратора и ресепшиониста.

**Рекомендации**

Чтобы убедиться, что всё работает корректно, я предлагаю провести следующие тесты:

- **Тестирование процесса выселения**: Запустите приложение, создайте новое бронирование, а затем выселите клиента через панель ресепшиониста. Проверьте, что бронирование больше не отображается во вкладке "Бронирования", а появилось во вкладке "Архивы".

- **Проверка видимости платежей**: Убедитесь, что информация об оплате по этому бронированию всё ещё отображается во вкладке "Платежи" как на панели администратора, так и на панели ресепшиониста.

- **Проверка на ошибки**: Если вы столкнётесь с какими-либо проблемами во время тестирования, например, платеж не отображается или бронирование не перемещается в архив, вам может потребоваться подробно отладить соответствующий участок кода.

Если у вас есть дополнительные вопросы или вам нужна помощь с определённой частью кода, пожалуйста, сообщите мне, и я буду рад помочь вам дальше.

С уважением.

turns-00053.parquet:5450

6dcd20ca8843071adcaf9475
turn 1/1o1-mini-2024-09-12EnglishCanada9 words
degenerate_repetitionAbsentFinal dense release
USER
['Hi there!']
ASSISTANT
Hello! How can I assist you today?

turns-00053.parquet:5451

8ae4afe23d803dcccce063a4
turn 1/1o1-mini-2024-09-12RussianRussia388 words
degenerate_repetitionAbsentFinal dense release
USER
Мне нужно, чтобы при запуске файл bat на windows 11 у меня включался wi-fi адаптер его название в системе NetSpace
ASSISTANT
Чтобы создать `.bat` файл, который при запуске будет включать Wi-Fi адаптер с именем `NetSpace` на Windows 11, выполните следующие шаги:

1. **Откройте Блокнот (Notepad):**
   - Нажмите `Win + R`, введите `notepad` и нажмите `Enter`.

2. **Вставьте следующий код в Блокнот:**

   ```batch
   @echo off
   REM Проверка запуска от имени администратора
   openfiles >nul 2>&1
   if %errorlevel% neq 0 (
       echo Этот скрипт требует прав администратора. Пожалуйста, запустите его от имени администратора.
       pause
       exit /b
   )

   REM Включение Wi-Fi адаптера с именем "NetSpace"
   netsh interface set interface "NetSpace" enabled

   echo Адаптер "NetSpace" был успешно включен.
   pause
   ```

   **Пояснения к коду:**
   - `@echo off` скрывает вывод команд в окне командной строки для большей наглядности.
   - Проверка на запуск от имени администратора. Некоторые команды требуют повышенных привилегий.
   - Команда `netsh` используется для управления сетевыми интерфейсами.
   - `pause` удерживает окно открытым, чтобы вы могли увидеть результат выполнения команды.

3. **Сохраните файл с расширением `.bat`:**
   - В Блокноте нажмите `Файл` > `Сохранить как...`.
   - В поле "Имя файла" введите, например, `EnableNetSpaceWiFi.bat`.
   - В поле "Тип файла" выберите `Все файлы (*.*)`.
   - Выберите удобное место для сохранения (например, рабочий стол) и нажмите `Сохранить`.

4. **Запустите `.bat` файл от имени администратора:**
   - Найдите сохраненный `.bat` файл.
   - Щёлкните правой кнопкой мыши на файле и выберите `Запуск от имени администратора`.
   - Если появится запрос контроля учетных записей (UAC), подтвердите его.

5. **Проверка:**
   - После выполнения скрипта должно появиться сообщение `Адаптер "NetSpace" был успешно включен.`.
   - Вы также можете проверить состояние сетевых адаптеров через `Параметры` > `Сеть и Интернет` > `Состояние` > `Свойства оборудования`.

**Дополнительные советы:**

- **Убедитесь, что имя адаптера указано правильно:**
  - Откройте командную строку и выполните команду `netsh interface show interface`, чтобы увидеть список всех сетевых интерфейсов и убедиться в точном названии адаптера.

- **Автоматический запуск скрипта при старте системы:**
  - Если вы хотите, чтобы адаптер включался автоматически при запуске Windows, вы можете добавить `.bat` файл в папку автозагрузки:
    1. Нажмите `Win + R`, введите `shell:startup` и нажмите `Enter`.
    2. Скопируйте ваш `.bat` файл в открывшуюся папку.

- **Безопасность:**
  - Помните, что запуск скриптов от имени администратора может представлять угрозу безопасности, если файл поступает из ненадёжного источника. Используйте `.bat` файлы только из доверенных источников.

Если у вас возникнут дополнительные вопросы или потребуется помощь, пожалуйста, дайте знать!

turns-00053.parquet:5452

a7e6d6d67257c1ceb589e769
turn 1/1o1-mini-2024-09-12RussianRussia6 words
degenerate_repetitionAbsentFinal dense release
USER
Привет
ASSISTANT
Привет! Как я могу помочь?

turns-00053.parquet:5453

1923155d428215f8ae6260ed
turn 1/1gpt-4o-2024-08-06Englishunknown country56 words
degenerate_repetitionAbsentFinal dense release
USER
Translate the text to India :
Could you help me get the results for my driving license verification using the request ID?.

                    Please only output the translation result. Do not output anything else.

                    You response:
ASSISTANT
क्या आप मुझे अनुरोध आईडी का उपयोग करके मेरे ड्राइविंग लाइसेंस सत्यापन के परिणाम प्राप्त करने में मदद कर सकते हैं?

turns-00053.parquet:5454

2b02487fce803662e8b0ca91
turn 1/1gpt-4o-mini-2024-07-18SpanishUnited States177 words
degenerate_repetitionAbsentFinal dense release
USER
Dandadan ou Blue Lock
ASSISTANT
"Dandadan" et "Blue Lock" sont deux œuvres populaires dans le domaine du manga et de l'anime, mais elles appartiennent à des genres très différents.

**Dandadan** est un manga qui mélange action, horreur et comédie, centré sur des adolescents qui se retrouvent impliqués dans des événements surnaturels et étranges. Il a été bien accueilli pour son style dynamique et ses personnages attachants.

**Blue Lock**, en revanche, est un manga de sport, plus précisément sur le football. Il met en avant un programme d'entraînement rigoureux pour créer le meilleur attaquant du Japon. Le manga se distingue par son approche psychologique et stratégique du sport, ainsi que par ses rivalités intenses entre les personnages.

En fin de compte, le choix entre les deux dépend de vos préférences personnelles : si vous aimez l'action surnaturelle avec une touche d'humour, "Dandadan" pourrait vous plaire ; si vous êtes passionné par le football et les compétitions sportives, "Blue Lock" serait un meilleur choix. Avez-vous une préférence pour l'un d'eux ou souhaitez-vous en savoir plus sur un aspect particulier ?

turns-00053.parquet:5455

b2a5e47e07c46c5913ecc0b6
turn 1/1gpt-4o-mini-2024-07-18EnglishFrance1066 words
degenerate_repetitionAbsentFinal dense release
USER
Context: making a product page in Iptv2live.com website! that sell IPTV subscriptions from differents IPTV Platforms.
Task: Write a compelling product description for an IPTV offer with title: Best Lithuania mac portal code with 2640 live stream TV,  using best SEO practices for 2024. Follow the structure outlined below and ensure the description is optimized for search engines to help it rank highly on Google. The output must be in the following JSON format:
{
  "excerpt": "A concise summary mentioning the main keywords of the post title: Best Lithuania mac portal code with 2640 live stream TV.",
  "introduction": "Introduction (1-2 sentences): Provide a brief introduction to the product, highlighting its main benefit and mentioning the keyword: Best Lithuania mac portal code with 2640 live stream TV.",
  "head1": "Shorten my title:'Best Lithuania mac portal code with 2640 live stream TV' using semantic keywords".
  "body": "5 paragraphs <p></p>"
}
Structure:
excerpt: A concise summary mentioning the main keywords of the post title: Best Lithuania mac portal code with 2640 live stream TV.
introduction: Provide a brief introduction to the product, highlighting its main benefit and mentioning the keyword: Best Lithuania mac portal code with 2640 live stream TV.
head1: Shorten my title:'Best Lithuania mac portal code with 2640 live stream TV' to 3 words max using semantic keywords.
body:
ensure to make the output in 5 paragraphs <p></p> with one h3 and one h4 that includes concise Description of the Key Features of  the IPTV subscription from the famous IPTV provider platform named: <b>SLTV</b>. which Includes: 2640 TV packages categories, like: DE KINDER, DE KINO  SERIEN, RO ROMANIA SPORTS, All, DE DOKU, AL SPORTS, DE SPORT, BG BULGARIA, AL DOKUMENTARE, MN MONTENEGRO, AT AUSTRIA, DE NEWS  INFORMATION, DE REGIONAL, AL ALBANIA, DE VIP SPORT, DE HEVC  4K, EXYU DOKUMENTARNI, HR CROATIA, SL SLOVENIA, BH BOSNIA AND HERZEGOVINA,  and 12231 VOD Directories, VOD exemple: VDE Filme  2024, VAL Shqip, VBG Bulgaria Filme  Филм България, VDE Filme  2019, VRO România Movie  Film România, VDE Filme  4K, VEXYU Serbia Movies  Србија филм  2023  2024, VDE IMDb Top 50, VDE Filme  2023, VDE IMDb Top 50 Western, , IPTV subscription Expire on : 05/08/2025.
SEO Tips:
Explain the product in detail, focusing on its benefits, the IPTV provider platform name: SLTV, usability, and the available streaming content. Include the keyword: Best Lithuania mac portal code with 2640 live stream TV, naturally and use LSI/NLP related keywords to the post title.
Ensure to include in the end of the body the first Call to Action NATURALLY in 1 paragraph, Encourage potential customers to take action, by using the discount code IPTV10SAVE at checkout  for 10% off when purchasing our premium membership at https://Iptv2live.com/premium-membership and unlock all premium IPTV subscriptions simultaneously..
Ensure to include after the end of the body the Second Call to Action NATURALLY in 1 paragraph, Encourage visitors to take action, by joining our facebook group : Free IPTV Codes https://iptv2live.com/fb.php to get the latest trial IPTV codes.
Incorporate the primary keyword: Best Lithuania mac portal code with 2640 live stream TV, and related keywords naturally throughout the excerpt, introduction and body.
Use HTML tags for better formatting and readability, such as <div>, <b>, <i>, <ul>, <li><table>, and <p> in body.
Ensure the use of a modern and stylish HTML design in the body display by using inline style = '', 
Highlight the body into a stylish and modern <div>, 
Clearly Mention and Highlight the platform name: SLTV with stylish text decoration using inline style.
Highlight the platform name: IPTV10SAVE at checkout  for 10% off with stylish text decoration using inline style.
Highlight the first CTA: by using the discount code IPTV10SAVE at checkout  for 10% off when purchasing our premium membership at https://Iptv2live.com/premium-membership and unlock all premium IPTV subscriptions simultaneously. with a proper anchor texts into a new line centered HTML button tag. 
Highlight the second CTA: by joining our facebook group : Free IPTV Codes https://iptv2live.com/fb.php to get the latest trial IPTV codes with a proper anchor text into a new line centered HTML button tag. 
Avoid keyword stuffing; focus on creating valuable, informative content for the reader.
Make sure the product description is engaging, informative, and optimized for search engines while providing value to the reader.
Make sure to never mention the word "Call to Action" in your response.
Finally make sure that the output overall pass all AI test detection by using Humanized  and natural Text writing style.
ASSISTANT
```json
{
  "excerpt": "Discover the Best Lithuania mac portal code with 2640 live stream TV, providing unparalleled access to diverse entertainment options.",
  "introduction": "Unlock unlimited entertainment with the Best Lithuania mac portal code with 2640 live stream TV, seamlessly bringing you an extensive selection of live channels and VOD content.",
  "head1": "Lithuania IPTV Code",
  "body": "<div style='font-family: Arial, sans-serif; line-height: 1.6; margin: 20px;'>"+
  "<p>Experience the ultimate viewing pleasure with the <b style='text-decoration: underline;'>SLTV</b> IPTV subscription! This premium service offers the <i>Best Lithuania mac portal code with 2640 live stream TV</i>, designed to deliver a rich variety of channels across multiple genres. From sports to movies and everything in between, SLTV has curated a vast library to satisfy all your viewing desires.</p>"+
  "<h3>Key Features of SLTV Subscription</h3>"+
  "<p><b style='text-decoration: underline;'>SLTV</b> stands out as a top-tier platform among IPTV providers, offering a remarkable assortment of 2640 TV channel categories.</p>"+
  "<h4>Explore Impressive Package Options:</h4>"+ 
  "<ul>"+
    "<li>DE KINDER</li>"+
    "<li>DE KINO SERIEN</li>"+
    "<li>RO ROMANIA SPORTS</li>"+
    "<li>DE DOKU</li>"+
    "<li>DE SPORT</li>"+
    "<li>AL SPORTS</li>"+
    "<li>BG BULGARIA</li>"+
    "<li>AL DOKUMENTARE</li>"+
    "<li>MN MONTENEGRO</li>"+
    "<li>AT AUSTRIA</li>"+ 
    "<li>DE NEWS INFORMATION</li>"+
    "<li>DE REGIONAL</li>"+
    "<li>AL ALBANIA</li>"+
    "<li>DE VIP SPORT</li>"+
    "<li>DE HEVC 4K</li>"+
    "<li>EXYU DOKUMENTARNI</li>"+
    "<li>HR CROATIA</li>"+
    "<li>SL SLOVENIA</li>"+
    "<li>BH BOSNIA AND HERZEGOVINA</li>"+
  "</ul>"+
  "<p>Not only do you get access to an outstanding selection of live streams, but you also benefit from 12231 VOD directories featuring an impressive range of movies and shows. Options include the latest films like <i>VDE Filme 2024</i>, <i>VDE Filme 4K</i>, and classic favorites such as <i>VDE IMDb Top 50</i>.</p>"+
  "<p>With an expiration date of <b style='text-decoration: underline;'>05/08/2025</b>, this subscription ensures you'll have uninterrupted access to all your favorite channels and content.</p>"+
  "<p style='text-align: center;'><b style='text-decoration: underline;'>Shop now</b>: Use the discount code <b style='text-decoration: underline;'>IPTV10SAVE</b> at checkout for 10% off when purchasing our premium membership at <a href='https://Iptv2live.com/premium-membership' target='_blank'>https://Iptv2live.com/premium-membership</a> and unlock all premium IPTV subscriptions simultaneously.</p>"+
  "<p style='text-align: center;'><b style='text-decoration: underline;'>Stay Informed</b>: Join our Facebook group <a href='https://iptv2live.com/fb.php' target='_blank'>Free IPTV Codes</a> to get the latest trial IPTV codes!</p>"+
  "</div>"
}
```