Загрузка данных


import os
import tkinter as tk
from tkinter import messagebox, ttk
# ------------------------------------
import pandas as pd
from openpyxl import Workbook
from openpyxl.utils.dataframe import dataframe_to_rows
# --- ИСПРАВЛЕННЫЙ ИМПОРТ ---
# Теперь мы импортируем обе необходимые функции из базы данных
from modules.database_module import list_groups, list_indicators


def create_excel_template(groups_codes, output_filename):
    """
    Функция создаёт шаблон Excel-файла для заданных групп и сохраняет его.
    Все необходимые данные подгружаются за один проход без повторных запросов.
    """
    wb = Workbook()
    
    # Загружаем группы и их индикаторы со связями EAGER loading, 
    # чтобы избежать обращения к БД при обращении к .group или .matrices
    all_groups_with_data = list_groups()
    
    for group_code in groups_codes:
        try:
            # Ищем группу в уже загруженном списке
            group = next((g for g in all_groups_with_data if g.code == group_code), None)
            
            # Проверяем наличие группы и её индикаторов
            indicators_list = getattr(group, 'indicators', []) if group else []
            if not indicators_list:
                continue

            sheet_title = f"{group.name}"
            ws = wb.create_sheet(title=sheet_title)

            # --- ЗАГОЛОВКИ ТАБЛИЦЫ ---
            ws.cell(row=1, column=1, value="№ п/п")
            ws.cell(row=1, column=2, value="Показатель")
            ws.cell(row=1, column=3, value="Код")

            # --- ЗАПОЛНЯЕМ ТАБЛИЦУ ПОКАЗАТЕЛЕЙ ---
            for idx, ind in enumerate(indicators_list):
                ws.cell(row=idx + 2, column=1, value=str(idx + 1))
                ws.cell(row=idx + 2, column=2, value=ind.name)
                ws.cell(row=idx + 2, column=3, value=ind.code)

            # --- ПОДГОТОВКА К СОЗДАНИЮ МАТРИЦЫ ---
            start_col = 4
            matrix_start_row = 1
            for col_idx, label in enumerate([ind.code for ind in indicators_list]):
                ws.cell(row=matrix_start_row, column=start_col + col_idx, value=label)
                
            matrix_size = len(indicators_list)

            # --- СОЗДАЕМ СЛОВАРЬ ДЛЯ БЫСТРОГО ПОИСКА ЗНАЧЕНИЙ ИЗ БАЗЫ ---
            matrix_data_dict = {}
            if group and hasattr(group, 'indicators') and group.indicators:
                for ind in group.indicators: # Проходим по индикаторам конкретной группы
                    if hasattr(ind, 'matrices'):
                        for entry in ind.matrices: # Берём матрицы конкретного индикатора
                            matrix_data_dict[(entry.row, entry.col)] = entry.value

            # --- ЗАПОЛНЯЕМ ЯЧЕЙКИ МАТРИЦЫ ДАННЫМИ ИЗ БАЗЫ ---
            for r_idx in range(matrix_size):
                for c_idx in range(matrix_size):
                    db_value = matrix_data_dict.get((r_idx, c_idx))
                    target_cell = ws.cell(
                        row=matrix_start_row + r_idx + 1,
                        column=start_col + c_idx
                    )
                    
                    if db_value is not None:
                        target_cell.value = float(db_value)
                    elif r_idx == c_idx:
                        target_cell.value = 1.0
                    else:
                        target_cell.value = ""

        except Exception as e:
            print(f"Ошибка при обработке группы '{group_code}': {e}")

    if "Sheet" in wb.sheetnames:
        del wb["Sheet"]
        
    wb.save(output_filename)


class ExportMatrixWindow(tk.Toplevel):
    def __init__(self, parent):
        super().__init__(parent)
        self.title("Создание файла для эксперта")
        self.geometry("450x200")
        main_frame = ttk.Frame(self)
        main_frame.pack(padx=10, pady=10, fill="both", expand=True)
        self.groups = []
        self.selected_groups = []
        self.num_experts = tk.IntVar()
        tk.Label(main_frame, text="Группа:").grid(row=0, column=0, sticky="w")
        self.group_var = tk.StringVar()
        self.combobox = ttk.Combobox(
            main_frame, textvariable=self.group_var, state="readonly"
        )
        self.combobox.grid(row=0, column=1, padx=(5, 10), sticky="ew")
        self.refresh_groups()
        add_group_btn = ttk.Button(
            main_frame, text="Добавить группу", command=self.add_group
        )
        add_group_btn.grid(row=0, column=2, padx=(0, 10), sticky="e")
        tk.Label(main_frame, text="Выбранные группы:").grid(row=1, column=0, sticky="w")
        self.selected_groups_text = tk.Text(main_frame, width=30, height=4)
        self.selected_groups_text.grid(
            row=1, column=1, columnspan=2, pady=(5, 10), sticky="ew"
        )
        tk.Label(main_frame, text="Количество экспертов:").grid(
            row=2, column=0, sticky="w"
        )
        self.experts_count_entry = ttk.Entry(main_frame, textvariable=self.num_experts)
        self.experts_count_entry.grid(row=2, column=1, sticky="w")
        remove_group_btn = ttk.Button(
            main_frame, text="Удалить группу", command=self.remove_group
        )
        remove_group_btn.grid(row=2, column=2, sticky="e")
        export_btn = ttk.Button(
            main_frame, text="Экспортировать в Excel", command=self.export_to_excel
        )
        export_btn.grid(row=3, column=1, pady=(10, 0))

    def refresh_groups(self):
        self.groups = [grp.name for grp in list_groups()]
        self.combobox.config(values=self.groups)

    def add_group(self):
        group_name = self.group_var.get()
        if group_name and group_name.strip():
            self.selected_groups.append(group_name)
            self.selected_groups_text.insert(tk.END, f"{group_name}\n")

    def remove_group(self):
        if len(self.selected_groups) > 0:
            last_group = self.selected_groups.pop(-1)
            current_text = self.selected_groups_text.get("1.0", tk.END).strip()
            updated_text = "\n".join(
                line for line in current_text.split("\n") if line != last_group
            )
            self.selected_groups_text.delete("1.0", tk.END)
            self.selected_groups_text.insert(tk.END, updated_text)

    def export_to_excel(self):
        """Логика экспорта в Excel (ИСПРАВЛЕННАЯ ВЕРСИЯ)."""
        selected_group_names = (
            self.selected_groups_text.get("1.0", tk.END).strip().split("\n")
        )
        # Составляем список кодов групп на основе выбранных названий
        groups_codes = []
        all_db_groups = list_groups()
        for name in selected_group_names:
            if name:
                group = next((g for g in all_db_groups if g.name == name), None)
                if group:
                    groups_codes.append(group.code)
        if not groups_codes:
            messagebox.showwarning("Предупреждение", "Не выбрано ни одной группы.")
            return

        try:
            num_experts = int(self.num_experts.get())
            if num_experts <= 0:
                raise ValueError
        except Exception:
            messagebox.showerror(
                "Ошибка", "Количество экспертов должно быть положительным числом."
            )
            return

        experts_folder = os.path.join(os.path.dirname(__file__), "..", "experts")
        os.makedirs(experts_folder, exist_ok=True)

        for expert_num in range(1, num_experts + 1):
            output_filename = os.path.join(experts_folder, f"Эксперт_{expert_num}.xlsx")
            create_excel_template(groups_codes, output_filename)

        messagebox.showinfo(
            title="Экспорт завершён",
            message=f"Успешно создано {num_experts} файлов экспертов.\n\nРасположение файлов:\n{experts_folder}",
        )