



----------------------------------------------------------------------------------
3
----------------------------------------------------------------------------------

import psycopg2
import pandas as pd
from psycopg2 import sql
from psycopg2.extras import execute_batch
import logging
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import time
import os

# Настройка логирования
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# SQL-скрипт для создания структуры БД
CREATE_TABLES_SQL = """
-- Типы продукции
CREATE TABLE IF NOT EXISTS product_types (
    type_id SERIAL PRIMARY KEY,
    name VARCHAR(255) UNIQUE NOT NULL,
    coefficient NUMERIC(10,2) NOT NULL CHECK (coefficient > 0)
);

-- Партнеры
CREATE TABLE IF NOT EXISTS partners (
    partner_id SERIAL PRIMARY KEY,
    partner_type VARCHAR(10) NOT NULL CHECK (partner_type IN ('ЗАО','ООО','ОАО','ПАО')),
    name VARCHAR(255) UNIQUE NOT NULL,
    director VARCHAR(255) NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    phone VARCHAR(20) NOT NULL,
    legal_address TEXT NOT NULL,
    inn VARCHAR(12) UNIQUE NOT NULL CHECK (inn ~ '^\\d{10,12}$'),
    rating INTEGER NOT NULL CHECK (rating BETWEEN 1 AND 10)
);

-- Продукция
CREATE TABLE IF NOT EXISTS products (
    product_id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    type_id INTEGER NOT NULL REFERENCES product_types(type_id),
    min_partner_cost NUMERIC(10,2) NOT NULL CHECK (min_partner_cost >= 0),
    article VARCHAR(50) UNIQUE NOT NULL,
    UNIQUE (name, type_id)
);

-- Заявки партнеров
CREATE TABLE IF NOT EXISTS orders (
    order_id SERIAL PRIMARY KEY,
    partner_id INTEGER NOT NULL REFERENCES partners(partner_id),
    product_id INTEGER NOT NULL REFERENCES products(product_id),
    quantity INTEGER NOT NULL CHECK (quantity > 0),
    UNIQUE (partner_id, product_id)
);

-- Индексы для оптимизации
CREATE INDEX IF NOT EXISTS idx_orders_partner ON orders(partner_id);
CREATE INDEX IF NOT EXISTS idx_orders_product ON orders(product_id);
"""

class DatabaseManager:
    def __init__(self, db_config):
        self.db_config = db_config.copy()
        self.db_config_without_dbname = db_config.copy()
        if 'dbname' in self.db_config_without_dbname:
            del self.db_config_without_dbname['dbname']
        self.conn = None
        self.cur = None

    def connect(self):
        """Устанавливает соединение с базой данных"""
        try:
            self.conn = psycopg2.connect(**self.db_config)
            self.cur = self.conn.cursor()
            logging.info("Соединение с базой данных установлено")
        except Exception as e:
            logging.error(f"Ошибка подключения к базе данных: {e}")
            raise

    def disconnect(self):
        """Закрывает соединение с базой данных"""
        if self.cur:
            self.cur.close()
        if self.conn:
            self.conn.close()
        logging.info("Соединение с базой данных закрыто")

    def create_database(self):
        """Создание базы данных"""
        conn = None
        try:
            conn = psycopg2.connect(**self.db_config_without_dbname)
            conn.autocommit = True
            cur = conn.cursor()
            
            cur.execute("SELECT 1 FROM pg_catalog.pg_database WHERE datname = %s", 
                       (self.db_config['dbname'],))
            
            if not cur.fetchone():
                cur.execute(sql.SQL("CREATE DATABASE {}").format(
                    sql.Identifier(self.db_config['dbname'])))
                logging.info(f"База данных {self.db_config['dbname']} создана")
                
        except Exception as e:
            logging.error(f"Ошибка при создании БД: {e}")
            raise
        finally:
            if conn:
                cur.close()
                conn.close()

    def initialize_tables(self):
        """Создание таблиц в существующей БД"""
        conn = None
        try:
            conn = psycopg2.connect(**self.db_config)
            cur = conn.cursor()
            
            cur.execute(CREATE_TABLES_SQL)
            conn.commit()
            logging.info("Таблицы успешно созданы")
            
        except Exception as e:
            logging.error(f"Ошибка при создании таблиц: {e}")
            conn.rollback()
            raise
        finally:
            if conn:
                cur.close()
                conn.close()

    def import_data(self):
        """Импорт данных из Excel файлов"""
        conn = None
        try:
            conn = psycopg2.connect(**self.db_config)
            cur = conn.cursor()
            
            # Очистка таблиц перед импортом
            cur.execute("TRUNCATE TABLE orders, products, partners, product_types CASCADE")
            conn.commit()
            logging.info("Таблицы очищены")
            
            # Импорт типов продукции
            df_pt = pd.read_excel("Product_type_import.xlsx")
            product_types = [(row['Тип продукции'], row['Коэффициент типа продукции']) 
                            for _, row in df_pt.iterrows()]
            execute_batch(cur, """
                INSERT INTO product_types (name, coefficient)
                VALUES (%s, %s)
                ON CONFLICT (name) DO NOTHING
            """, product_types)
            conn.commit()
            logging.info("Типы продукции импортированы")

            # Импорт партнеров
            df_p = pd.read_excel("Partners_import.xlsx")
            partners = [(row['Тип партнера'], row['Наименование партнера'], row['Директор'],
                        row['Электронная почта партнера'], row['Телефон партнера'], 
                        row['Юридический адрес партнера'], row['ИНН'], row['Рейтинг'])
                        for _, row in df_p.iterrows()]
            execute_batch(cur, """
                INSERT INTO partners (partner_type, name, director, email, phone, 
                                    legal_address, inn, rating)
                VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
                ON CONFLICT (name) DO NOTHING
            """, partners)
            conn.commit()
            logging.info("Партнеры импортированы")

            # Импорт продукции и заявок
            df_o = pd.read_excel("Partner_products_request_import.xlsx")
            
            existing_articles = set()
            
            for _, row in df_o.iterrows():
                try:
                    product_name = str(row['Продукция'])
                    type_name = self._extract_type_from_name(product_name)
                    
                    cur.execute("SELECT type_id FROM product_types WHERE name = %s", (type_name,))
                    type_result = cur.fetchone()
                    
                    if not type_result:
                        cur.execute("""
                            INSERT INTO product_types (name, coefficient) 
                            VALUES (%s, %s) 
                            ON CONFLICT (name) DO UPDATE SET coefficient = EXCLUDED.coefficient
                            RETURNING type_id
                        """, (type_name, 1.0))
                        type_result = cur.fetchone()
                        conn.commit()
                    
                    type_id = type_result[0]
                    
                    base_article = self._generate_article(product_name)
                    suffix = 1
                    article = base_article
                    
                    while article in existing_articles:
                        article = f"{base_article}{suffix}"
                        suffix += 1
                    
                    while True:
                        cur.execute("SELECT 1 FROM products WHERE article = %s", (article,))
                        if cur.fetchone():
                            article = f"{base_article}{suffix}"
                            suffix += 1
                        else:
                            break
                    
                    existing_articles.add(article)
                    
                    cur.execute("""
                        INSERT INTO products (name, type_id, min_partner_cost, article)
                        VALUES (%s, %s, %s, %s)
                        ON CONFLICT (name, type_id) DO NOTHING
                        RETURNING product_id
                    """, (product_name, type_id, 100.0, article))
                    
                    product_result = cur.fetchone()
                    if not product_result:
                        cur.execute("SELECT product_id FROM products WHERE name = %s AND type_id = %s",
                                  (product_name, type_id))
                        product_result = cur.fetchone()
                    
                    if not product_result:
                        continue
                    
                    product_id = product_result[0]
                    
                    cur.execute("SELECT partner_id FROM partners WHERE name = %s", 
                              (row['Наименование партнера'],))
                    partner_result = cur.fetchone()
                    
                    if partner_result:
                        cur.execute("""
                            INSERT INTO orders (partner_id, product_id, quantity)
                            VALUES (%s, %s, %s)
                            ON CONFLICT (partner_id, product_id) 
                            DO UPDATE SET quantity = EXCLUDED.quantity
                        """, (partner_result[0], product_id, row['Количество продукции']))
                        
                    if _ % 100 == 0:
                        conn.commit()
                        time.sleep(0.1)
                
                except Exception as e:
                    logging.error(f"Ошибка при обработке строки {_}: {e}")
                    conn.rollback()
                    continue
            
            conn.commit()
            logging.info("Данные успешно импортированы")
            
        except Exception as e:
            logging.error(f"Ошибка при импорте данных: {e}")
            conn.rollback()
            raise
        finally:
            if conn:
                cur.close()
                conn.close()

    def calculate_material_required(self, product_type_id, material_type_id, 
                                required_quantity, stock_quantity, 
                                param1, param2, defect_rate):
        """
        Метод расчета необходимого количества материала
        
        :param product_type_id: Идентификатор типа продукции
        :param material_type_id: Идентификатор типа материала
        :param required_quantity: Требуемое количество продукции
        :param stock_quantity: Количество продукции на складе
        :param param1: Первый параметр продукции (вещественное число)
        :param param2: Второй параметр продукции (вещественное число)
        :param defect_rate: Процент брака материала (вещественное число)
        :return: Необходимое количество материала (целое число) или -1 при ошибке
        """
        conn = None
        cur = None
        try:
            # Устанавливаем соединение
            conn = psycopg2.connect(**self.db_config)
            cur = conn.cursor()

            # Проверка входных данных
            if not all(isinstance(x, (int, float)) for x in [
                product_type_id, material_type_id, required_quantity, 
                stock_quantity, param1, param2, defect_rate]):
                return -1
                
            if param1 <= 0 or param2 <= 0:
                return -1
                
            if defect_rate < 0 or defect_rate > 1:
                return -1
                
            # Получаем коэффициент типа продукции
            cur.execute("""
                SELECT coefficient FROM product_types 
                WHERE type_id = %s
            """, (product_type_id,))
            pt_result = cur.fetchone()
            
            if not pt_result:
                return -1
                
            product_coefficient = float(pt_result[0])
            
            # Рассчитываем необходимое количество продукции
            net_quantity = max(0, required_quantity - stock_quantity)
            
            if net_quantity == 0:
                return 0
                
            # Рассчитываем необходимое количество материала
            material_required = net_quantity * param1 * param2 * product_coefficient
            
            # Учитываем брак
            material_with_defect = material_required / (1 - defect_rate)
            
            # Возвращаем округленное значение вверх
            return int(material_with_defect + 0.999)
            
        except Exception as e:
            logging.error(f"Ошибка при расчете материала: {e}")
            return -1
        finally:
            if cur:
                cur.close()
            if conn:
                conn.close()

    def get_partner_products(self, partner_id):
        """Получение списка продукции для конкретного партнера"""
        conn = None
        try:
            conn = psycopg2.connect(**self.db_config)
            cur = conn.cursor()
            
            cur.execute("""
                SELECT p.name, o.quantity, pt.coefficient, pr.min_partner_cost
                FROM orders o
                JOIN products pr ON o.product_id = pr.product_id
                JOIN product_types pt ON pr.type_id = pt.type_id
                JOIN partners p ON o.partner_id = p.partner_id
                WHERE p.partner_id = %s
            """, (partner_id,))
            
            results = cur.fetchall()
            products = []
            
            for name, quantity, coefficient, min_cost in results:
                item_cost = quantity * min_cost * coefficient
                products.append({
                    'name': name,
                    'quantity': quantity,
                    'price': min_cost,
                    'coefficient': coefficient,
                    'item_cost': item_cost
                })
            
            return products
            
        except Exception as e:
            logging.error(f"Ошибка при получении продукции партнера: {e}")
            return []
        finally:
            if conn:
                cur.close()
                conn.close()

    def _extract_type_from_name(self, product_name):
        """Определяет тип продукции из названия"""
        if pd.isna(product_name):
            return "Разное"
            
        product_name = str(product_name).lower()
        
        if "плитк" in product_name:
            return "Плитка"
        elif any(keyword in product_name for keyword in ["ламинат", "паркет"]):
            return "Напольные покрытия"
        elif any(keyword in product_name for keyword in ["панел", "обшивк"]):
            return "Декоративные панели"
        elif any(keyword in product_name for keyword in ["фанер", "дсп", "двл", "дву"]):
            return "Древесно-плитные материалы"
        elif any(keyword in product_name for keyword in ["бетон", "кирпич"]):
            return "Фасадные материалы"
        else:
            return "Разное"

    def _generate_article(self, product_name):
        """Генерирует уникальный артикул"""
        words = str(product_name).split()
        base = "".join([word[0].upper() for word in words if len(word) > 3])
        return base[:8]

class PartnerOrderApp:
    def __init__(self, root, db_manager):
        self.db_manager = db_manager
        self.root = root
        self.root.title("Система управления заявками партнеров")
        self.root.geometry("1200x800")
        self.root.iconbitmap('warehouse.ico') if os.path.exists('warehouse.ico') else None
        
        # Инициализация интерфейса
        self.create_menu()
        self.create_main_frame()
        self.refresh_orders()
        
    def create_menu(self):
        """Создание меню приложения"""
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)
        
        file_menu = tk.Menu(menubar, tearoff=0)
        file_menu.add_command(label="Выход", command=self.root.quit)
        menubar.add_cascade(label="Файл", menu=file_menu)
        
        help_menu = tk.Menu(menubar, tearoff=0)
        help_menu.add_command(label="О программе", command=self.show_about)
        menubar.add_cascade(label="Справка", menu=help_menu)
    
    def show_about(self):
        """Показ информации о программе"""
        about_window = tk.Toplevel(self.root)
        about_window.title("О программе")
        about_window.geometry("400x300")
        
        ttk.Label(about_window, text="Система управления заявками партнеров\n\n", font=("Arial", 12, "bold")).pack(pady=10)
        ttk.Label(about_window, text="Версия: 1.0\nРазработчик: [Ваше имя]\nДата: 2025-06-24").pack(pady=10)
        ttk.Button(about_window, text="Закрыть", command=about_window.destroy).pack(pady=10)
    
    def create_main_frame(self):
        """Создание основного интерфейса"""
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # Заголовок
        title_label = ttk.Label(main_frame, text="Список заявок партнеров", font=("Arial", 14, "bold"))
        title_label.pack(pady=10)
        
        # Таблица заявок
        columns = ("partner", "product", "quantity", "cost")
        self.tree = ttk.Treeview(main_frame, columns=columns, show='headings')
        
        # Настройка колонок
        self.tree.heading("partner", text="Партнер")
        self.tree.heading("product", text="Продукция")
        self.tree.heading("quantity", text="Количество")
        self.tree.heading("cost", text="Стоимость")
        
        self.tree.column("partner", width=200)
        self.tree.column("product", width=400)
        self.tree.column("quantity", width=100)
        self.tree.column("cost", width=150)
        
        self.tree.pack(fill=tk.BOTH, expand=True)
        
        # Кнопки управления
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(pady=10)
        
        ttk.Button(button_frame, text="Добавить заявку", command=self.add_order).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="Редактировать заявку", command=self.edit_order).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="Обновить", command=self.refresh_orders).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="Показать продукцию", command=self.show_partner_products).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="Рассчитать материалы", command=self.calculate_materials).pack(side=tk.LEFT, padx=5)
    
    def refresh_orders(self):
        """Обновление списка заявок"""
        for item in self.tree.get_children():
            self.tree.delete(item)
        
        try:
            self.db_manager.connect()
            self.db_manager.cur.execute("""
                SELECT p.name, pr.name, o.quantity, pt.coefficient, pr.min_partner_cost
                FROM orders o
                JOIN partners p ON o.partner_id = p.partner_id
                JOIN products pr ON o.product_id = pr.product_id
                JOIN product_types pt ON pr.type_id = pt.type_id
            """)
            
            results = self.db_manager.cur.fetchall()
            
            for partner_name, product_name, quantity, coefficient, min_cost in results:
                item_cost = quantity * min_cost * coefficient
                self.tree.insert("", tk.END, values=(
                    partner_name,
                    product_name,
                    quantity,
                    f"{item_cost:.2f}"
                ))
                
        except Exception as e:
            messagebox.showerror("Ошибка", f"Не удалось загрузить данные: {e}")
        finally:
            self.db_manager.disconnect()
    
    def add_order(self):
        """Открытие формы добавления заявки"""
        AddEditOrderWindow(self.root, self.db_manager, self, "Добавить новую заявку")
    
    def edit_order(self):
        """Открытие формы редактирования заявки"""
        selected = self.tree.selection()
        if not selected:
            messagebox.showwarning("Предупреждение", "Выберите заявку для редактирования")
            return
            
        values = self.tree.item(selected[0])['values']
        order_data = {
            'partner': values[0],
            'product': values[1],
            'quantity': values[2]
        }
        
        AddEditOrderWindow(self.root, self.db_manager, self, "Редактировать заявку", order_data)
    
    def show_partner_products(self):
        """Показ продукции для выбранного партнера"""
        selected = self.tree.selection()
        if not selected:
            messagebox.showwarning("Предупреждение", "Выберите заявку для просмотра продукции")
            return
            
        partner_name = self.tree.item(selected[0])['values'][0]
        try:
            self.db_manager.connect()
            self.db_manager.cur.execute("SELECT partner_id FROM partners WHERE name = %s", (partner_name,))
            partner_result = self.db_manager.cur.fetchone()
            
            if partner_result:
                products = self.db_manager.get_partner_products(partner_result[0])
                
                product_window = tk.Toplevel(self.root)
                product_window.title(f"Продукция партнера: {partner_name}")
                product_window.geometry("800x600")
                
                columns = ("name", "quantity", "cost")
                tree = ttk.Treeview(product_window, columns=columns, show='headings')
                
                tree.heading("name", text="Наименование")
                tree.heading("quantity", text="Количество")
                tree.heading("cost", text="Стоимость")
                
                tree.column("name", width=400)
                tree.column("quantity", width=150)
                tree.column("cost", width=150)
                
                tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
                
                for product in products:
                    tree.insert("", tk.END, values=(
                        product['name'],
                        product['quantity'],
                        f"{product['item_cost']:.2f}"
                    ))
                
                ttk.Button(product_window, text="Закрыть", command=product_window.destroy).pack(pady=10)
                
        except Exception as e:
            messagebox.showerror("Ошибка", f"Не удалось получить данные: {e}")
        finally:
            self.db_manager.disconnect()
    
    def calculate_materials(self):
        """Рассчитываем материалы для заявки"""
        selected = self.tree.selection()
        if not selected:
            messagebox.showwarning("Предупреждение", "Выберите заявку для расчета материалов")
            return

        values = self.tree.item(selected[0])['values']
        partner_name = values[0]
        product_name = values[1]
        
        try:
            quantity = int(values[2])
        except (ValueError, TypeError):
            messagebox.showerror("Ошибка", "Некорректное количество продукции в заявке")
            return

        try:
            self.db_manager.connect()
            cur = self.db_manager.cur

            # Получаем ID партнера
            cur.execute("SELECT partner_id FROM partners WHERE name = %s", (partner_name,))
            partner_result = cur.fetchone()
            if not partner_result:
                raise ValueError(f"Партнер '{partner_name}' не найден в базе данных")

            partner_id = partner_result[0]

            # Получаем ID продукта
            cur.execute("SELECT product_id FROM products WHERE name = %s", (product_name,))
            product_result = cur.fetchone()
            if not product_result:
                raise ValueError(f"Продукция '{product_name}' не найдена в базе данных")

            product_id = product_result[0]

            # Получаем тип продукции (type_id)
            cur.execute("SELECT type_id FROM products WHERE product_id = %s", (product_id,))
            type_result = cur.fetchone()
            if not type_result:
                raise ValueError(f"Для продукции '{product_name}' не определён тип")

            product_type_id = type_result[0]

            # Получаем коэффициент типа продукции
            cur.execute("SELECT coefficient FROM product_types WHERE type_id = %s", (product_type_id,))
            pt_result = cur.fetchone()
            if not pt_result:
                raise ValueError(f"Тип продукции с ID {product_type_id} не найден")

            product_coefficient = pt_result[0]

            # Параметры (предположим, что они взяты из каких-то данных продукта)
            param1 = 1.5  # Пример: длина продукции
            param2 = 2.0  # Пример: ширина продукции

            # Запрашиваем наличие на складе (фиктивное значение)
            stock_quantity = 0  # Можно получить из таблицы склада, если есть

            # Процент брака материала
            defect_rate = 0.05  # 5% брака (примерное значение)

            # Вызов метода с правильными параметрами
            result = self.db_manager.calculate_material_required(
                product_type_id=product_type_id,
                material_type_id=1,  # Предположим, что материал по умолчанию
                required_quantity=quantity,
                stock_quantity=stock_quantity,
                param1=param1,
                param2=param2,
                defect_rate=defect_rate
            )

            if result == -1:
                messagebox.showerror("Ошибка", "Некорректные параметры для расчета")
                return

            calc_window = tk.Toplevel(self.root)
            calc_window.title("Результаты расчета")
            calc_window.geometry("400x200")

            ttk.Label(calc_window, text=f"Требуется материалов: {result} единиц", font=("Arial", 12)).pack(pady=20)
            ttk.Button(calc_window, text="Закрыть", command=calc_window.destroy).pack(pady=10)

        except ValueError as ve:
            messagebox.showerror("Ошибка валидации", str(ve))
        except Exception as e:
            logging.error(f"Не удалось выполнить расчет: {e}")
            messagebox.showerror("Ошибка", f"Не удалось выполнить расчет: {e}")
        finally:
            self.db_manager.disconnect()

class AddEditOrderWindow:
    def __init__(self, parent, db_manager, app, title, order_data=None):
        self.db_manager = db_manager
        self.app = app
        self.order_data = order_data
        
        self.window = tk.Toplevel(parent)
        self.window.title(title)
        self.window.geometry("500x400")
        
        self.create_widgets()
        
        if order_data:
            self.load_data()
    
    def create_widgets(self):
        """Создание элементов интерфейса формы"""
        frame = ttk.Frame(self.window, padding="10")
        frame.pack(fill=tk.BOTH, expand=True)
        
        # Партнер
        ttk.Label(frame, text="Партнер:").grid(row=0, column=0, sticky=tk.W)
        self.partner_combo = ttk.Combobox(frame, state="readonly")
        self.partner_combo.grid(row=0, column=1, sticky=(tk.W, tk.E))
        
        # Продукция
        ttk.Label(frame, text="Продукция:").grid(row=1, column=0, sticky=tk.W)
        self.product_combo = ttk.Combobox(frame, state="readonly")
        self.product_combo.grid(row=1, column=1, sticky=(tk.W, tk.E))
        
        # Количество
        ttk.Label(frame, text="Количество:").grid(row=2, column=0, sticky=tk.W)
        self.quantity_entry = ttk.Entry(frame)
        self.quantity_entry.grid(row=2, column=1, sticky=(tk.W, tk.E))
        
        # Кнопки
        button_frame = ttk.Frame(frame)
        button_frame.grid(row=3, column=0, columnspan=2, pady=10)
        
        ttk.Button(button_frame, text="Сохранить", command=self.save).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="Отмена", command=self.window.destroy).pack(side=tk.LEFT, padx=5)
        
        self.load_comboboxes()
    
    def load_comboboxes(self):
        """Загрузка данных в комбобоксы"""
        try:
            self.db_manager.connect()
            cur = self.db_manager.cur
            
            cur.execute("SELECT name FROM partners ORDER BY name")
            self.partner_combo['values'] = [row[0] for row in cur.fetchall()]
            
            cur.execute("SELECT name FROM products ORDER BY name")
            self.product_combo['values'] = [row[0] for row in cur.fetchall()]
            
        except Exception as e:
            messagebox.showerror("Ошибка", f"Не удалось загрузить данные: {e}")
        finally:
            self.db_manager.disconnect()
    
    def load_data(self):
        """Загрузка данных для редактирования"""
        self.partner_combo.set(self.order_data['partner'])
        self.product_combo.set(self.order_data['product'])
        self.quantity_entry.insert(0, self.order_data['quantity'])
    
    def save(self):
        """Сохранение заявки"""
        try:
            partner = self.partner_combo.get()
            product = self.product_combo.get()
            quantity = int(self.quantity_entry.get())
            
            if not partner or not product:
                raise ValueError("Необходимо выбрать партнера и продукт")
            if quantity <= 0:
                raise ValueError("Количество должно быть положительным числом")
                
            self.db_manager.connect()
            cur = self.db_manager.cur
            
            cur.execute("SELECT partner_id FROM partners WHERE name = %s", (partner,))
            partner_id = cur.fetchone()[0]
            
            cur.execute("SELECT product_id FROM products WHERE name = %s", (product,))
            product_id = cur.fetchone()[0]
            
            if self.order_data:  # Редактирование
                cur.execute("""
                    UPDATE orders
                    SET quantity = %s
                    WHERE partner_id = %s AND product_id = %s
                """, (quantity, partner_id, product_id))
            else:  # Добавление
                cur.execute("""
                    INSERT INTO orders (partner_id, product_id, quantity)
                    VALUES (%s, %s, %s)
                    ON CONFLICT (partner_id, product_id) DO NOTHING
                """, (partner_id, product_id, quantity))
            
            self.db_manager.conn.commit()
            self.app.refresh_orders()
            self.window.destroy()
            
        except ValueError as ve:
            messagebox.showwarning("Предупреждение", str(ve))
        except Exception as e:
            self.db_manager.conn.rollback()
            messagebox.showerror("Ошибка", f"Не удалось сохранить данные: {e}")
        finally:
            self.db_manager.disconnect()

if __name__ == "__main__":
    DB_CONFIG = {
        "dbname": "warehouse3",
        "user": "postgres",
        "password": "NikitaStillSLATT",
        "host": "localhost"
    }
    
    try:
        db_manager = DatabaseManager(DB_CONFIG)
        
        # Создание БД
        db_manager.create_database()
        
        # Подключение к БД
        db_manager.connect()
        
        # Создание таблиц
        db_manager.initialize_tables()
        
        # Импорт данных
        db_manager.import_data()
        
        # Запуск GUI
        root = tk.Tk()
        app = PartnerOrderApp(root, db_manager)
        root.mainloop()
        
    except Exception as e:
        logging.error(f"Критическая ошибка: {e}")
        messagebox.showerror("Критическая ошибка", f"Произошла критическая ошибка: {e}")
    finally:
        try:
            db_manager.disconnect()
        except:
            pass
