Скачиваний:
3
Добавлен:
29.03.2025
Размер:
131.77 Кб
Скачать
import tkinter as tk
from tkinter import *
from tkinter import ttk
import sqlite3
from tkinter import messagebox


path = "C:/Users/admin/source/repos/UNIVERSITY_repos/4 course/7 sem/mispris/coursework-2/furniture.db"



class DatabaseApp:
    def __init__(self, root):
        self.root = root
        self.root.title("coursework")
        root.geometry("1000x600")

        self.conn = sqlite3.connect(path)
        self.cursor = self.conn.cursor()

        self.tree = ttk.Treeview(root, show="headings")
        self.tree.grid(row=0, column=0, columnspan=6, sticky="nsew", padx=6, pady=10)



        self.load_button = ttk.Button(root, text="Load Products", command=self.load_products)
        self.load_button.grid(row=1, column=0, sticky="ew", padx=6, pady=2)

        self.add_product_button = ttk.Button(root, text="Add product", command=self.add_product)
        self.add_product_button.grid(row=2, column=0, sticky="ew", padx=6, pady=2)

        self.edit_button = ttk.Button(root, text="Edit Selected", command=self.edit_product)
        self.edit_button.grid(row=3, column=0, sticky="ew", padx=6, pady=2)

        self.delete_button = ttk.Button(root, text="Delete Selected", command=self.delete_product)
        self.delete_button.grid(row=4, column=0, sticky="ew", padx=6, pady=2)

        self.load_find_components_by_objectbutton = ttk.Button(root, text="find components by object ", command=self.load_find_components_by_object)
        self.load_find_components_by_objectbutton.grid(row=5, column=0, sticky="ew", padx=6, pady=2)

        self.find_components_recursive_object_button = ttk.Button(root, text="find components recursive", command=self.find_components_recursive)
        self.find_components_recursive_object_button.grid(row=6, column=0, sticky="ew", padx=6, pady=2)

        self.load_existing_acceptable_components_by_object_button = ttk.Button(root, text="available components category", command=self.load_existing_acceptable_components_by_object)
        self.load_existing_acceptable_components_by_object_button.grid(row=7, column=0, sticky="ew", padx=6, pady=2)

        self.load_existing_acceptable_components_by_object_recursive_button = ttk.Button(root, text="available components recursive category", command=self.load_existing_acceptable_components_by_object_recursive)
        self.load_existing_acceptable_components_by_object_recursive_button.grid(row=8, column=0, sticky="ew", padx=6, pady=2)





        self.load_category_button = ttk.Button(root, text="Load Categories", command=self.load_categories)
        self.load_category_button.grid(row=1, column=1, sticky="ew", padx=6, pady=2)

        self.add_category_button = ttk.Button(root, text="Add Category", command=self.add_category)
        self.add_category_button.grid(row=2, column=1, sticky="ew", padx=6, pady=2)

        self.edit_category_button = ttk.Button(root, text="Edit Category", command=self.edit_category)
        self.edit_category_button.grid(row=3, column=1, sticky="ew", padx=6, pady=2)

        self.delete_category_button = ttk.Button(root, text="Delete Category", command=self.delete_category)
        self.delete_category_button.grid(row=4, column=1, sticky="ew", padx=6, pady=2)

        self.show_parents_button = ttk.Button(root, text="Show Parents", command=self.show_category_parents)
        self.show_parents_button.grid(row=5, column=1, sticky="ew", padx=6, pady=2)

        self.show_children_button = ttk.Button(root, text="Show Children", command=self.show_category_children)
        self.show_children_button.grid(row=6, column=1, sticky="ew", padx=6, pady=2)

        self.show_products_button = ttk.Button(root, text="Show products", command=self.show_products_for_category)
        self.show_products_button.grid(row=7, column=1, sticky="ew", padx=6, pady=2)

        self.load_acceptable_components_by_class_button = ttk.Button(root, text="Show acceptable components by class", command=self.load_acceptable_components_by_class)
        self.load_acceptable_components_by_class_button.grid(row=8, column=1, sticky="ew", padx=6, pady=2)

        self.load_acceptable_components_by_class_recursive_button = ttk.Button(root, text="Show acceptable components by class recoursive", command=self.load_acceptable_components_by_class_recursive)
        self.load_acceptable_components_by_class_recursive_button.grid(row=9, column=1, sticky="ew", padx=6, pady=2)





        self.load_unit_button = ttk.Button(root, text="Load Unit", command=self.load_unit)
        self.load_unit_button.grid(row=1, column=2, sticky="ew", padx=6, pady=2)

        self.add_unit_button = ttk.Button(root, text="Add Unit", command=self.add_unit)
        self.add_unit_button.grid(row=2, column=2, sticky="ew", padx=6, pady=2)

        self.edit_unit_button = ttk.Button(root, text="Edit Selected", command=self.edit_unit)
        self.edit_unit_button.grid(row=3, column=2, sticky="ew", padx=6, pady=2)

        self.delete_unit_button = ttk.Button(root, text="Delete Selected", command=self.delete_unit)
        self.delete_unit_button.grid(row=4, column=2, sticky="ew", padx=6, pady=2)




        self.load_acceptable_components_button = ttk.Button(root, text="Load acceptable components", command=self.load_acceptable_component)
        self.load_acceptable_components_button.grid(row=1, column=3, sticky="ew", padx=6, pady=2)

        self.create_acceptable_component_button = ttk.Button(root, text="create acceptable component", command=self.create_acceptable_component)
        self.create_acceptable_component_button.grid(row=2, column=3, sticky="ew", padx=6, pady=2)

        self.inherit_acceptable_components_button = ttk.Button(root, text="inherit acceptable components", command=self.inherit_acceptable_components)
        self.inherit_acceptable_components_button.grid(row=3, column=3, sticky="ew", padx=6, pady=2)

        self.delete_acceptable_component_button = ttk.Button(root, text="Delete acceptable components", command=self.delete_acceptable_component)
        self.delete_acceptable_component_button.grid(row=4, column=3, sticky="ew", padx=6, pady=2)



        self.load_prod_position_union_button = ttk.Button(root, text="Load prod position union", command=self.load_prod_position_union)
        self.load_prod_position_union_button.grid(row=1, column=4, sticky="ew", padx=6, pady=2)

        self.create_prod_position_union_button = ttk.Button(root, text="create prod position union", command=self.create_prod_position_union)
        self.create_prod_position_union_button.grid(row=2, column=4, sticky="ew", padx=6, pady=2)

        self.delete_prod_position_union_button = ttk.Button(root, text="Delete prod position row", command=self.delete_prod_position_union)
        self.delete_prod_position_union_button.grid(row=3, column=4, sticky="ew", padx=6, pady=2)

        self.edit_prod_position_union_quantity_button = ttk.Button(root, text="New quantity prod position", command=self.edit_prod_position_union_quantity)
        self.edit_prod_position_union_quantity_button.grid(row=4, column=4, sticky="ew", padx=6, pady=2)



        self.fill_example_data_button = ttk.Button(self.root, text="Fill Example Data", command=self.fill_example_data)
        self.fill_example_data_button.grid(row=1, column=5, sticky="ew", padx=6, pady=2)

        self.delete_all_data_button = ttk.Button(self.root, text="Delete All Data", command=self.delete_all_data)
        self.delete_all_data_button.grid(row=2, column=5, sticky="ew", padx=6, pady=2)






        # Configure row and column to resize
        root.rowconfigure(0, weight=1)
        root.columnconfigure(0, weight=1)
        root.columnconfigure(1, weight=1)
        root.columnconfigure(2, weight=1)
        root.columnconfigure(3, weight=1)
        root.columnconfigure(4, weight=1)
        root.columnconfigure(5, weight=1)



        def create_category_table():
            self.cursor.execute('''CREATE TABLE IF NOT EXISTS category
                            (id INTEGER PRIMARY KEY AUTOINCREMENT,
                                id_parent INTEGER CHECK (id_parent != id),
                                category_name TEXT UNIQUE,
                                id_unit INTEGER,
                                FOREIGN KEY (id_parent) REFERENCES category(id))''')
            self.conn.commit()


        def create_product_table():
            self.cursor.execute('''CREATE TABLE IF NOT EXISTS product
                            (id INTEGER PRIMARY KEY AUTOINCREMENT,
                                id_category INTEGER,
                                id_unit INTEGER,
                                product_name TEXT NOT NULL,
                                quantity INTEGER DEFAULT 0,
                                price REAL DEFAULT 0,
                                FOREIGN KEY (id_unit) REFERENCES unit(id),
                                FOREIGN KEY (id_category) REFERENCES category(id))''')
            self.conn.commit()


        def create_unit_table():
            self.cursor.execute('''CREATE TABLE IF NOT EXISTS unit
                            (id INTEGER PRIMARY KEY AUTOINCREMENT,
                                unit_name TEXT NOT NULL UNIQUE,
                                unit_name_short TEXT NOT NULL)''')
            self.conn.commit()

        def create_acceptable_components_table():
            self.cursor.execute('''
                CREATE TABLE IF NOT EXISTS acceptable_components (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    class_id INTEGER NOT NULL,
                    component_id INTEGER NOT NULL,
                    UNIQUE(class_id, component_id),
                    FOREIGN KEY (class_id) REFERENCES category(id) ON DELETE CASCADE,
                    FOREIGN KEY (component_id) REFERENCES category(id) ON DELETE CASCADE
                )
            ''')
            self.conn.commit()

        def create_prod_position_union_table():
            self.cursor.execute('''
                CREATE TABLE IF NOT EXISTS prod_position_union (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    prod_id INTEGER NOT NULL,
                    comp_id INTEGER NOT NULL,
                    quantity INTEGER NOT NULL CHECK (quantity > 0),
                    UNIQUE(prod_id, comp_id),
                    FOREIGN KEY (prod_id) REFERENCES product(id) ON DELETE CASCADE,
                    FOREIGN KEY (comp_id) REFERENCES product(id) ON DELETE CASCADE
                )
            ''')
            self.conn.commit()

        def creating_tables():
            create_category_table()
            create_product_table()
            create_unit_table()

            # coursework-2
            create_acceptable_components_table()
            create_prod_position_union_table()


        creating_tables()

    def load_unit(self):
        # Очистка текущих данных из Treeview
        for row in self.tree.get_children():
            self.tree.delete(row)

        # Получение данных из таблицы unit
        self.cursor.execute("SELECT * FROM unit")
        rows = self.cursor.fetchall()
        column_names = [description[0] for description in self.cursor.description]

        # Очистка старых заголовков столбцов
        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)  # Устанавливаем ширину столбцов

        # Вставка данных в Treeview
        for row in rows:
            self.tree.insert("", "end", values=row)


    def load_products(self):
        # Очистка текущих данных из Treeview
        for row in self.tree.get_children():
            self.tree.delete(row)

        # Получение данных из таблицы product
        self.cursor.execute("SELECT * FROM product")
        rows = self.cursor.fetchall()
        column_names = [description[0] for description in self.cursor.description]

        # Очистка старых заголовков столбцов
        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)  # Устанавливаем ширину столбцов

        # Вставка данных в Treeview
        for row in rows:
            self.tree.insert("", END, values=row)

    def load_categories(self):
        # Очистка текущих данных из Treeview
        for row in self.tree.get_children():
            self.tree.delete(row)

        # Получение данных из таблицы category
        self.cursor.execute("SELECT * FROM category")
        rows = self.cursor.fetchall()
        column_names = [description[0] for description in self.cursor.description]

        # Очистка старых заголовков столбцов
        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)  # Устанавливаем ширину столбцов

        # Вставка данных в Treeview
        for row in rows:
            self.tree.insert("", END, values=row)

    def add_category(self):
        add_window = Toplevel(self.root)
        add_window.title("Add Category")

        Label(add_window, text="Category Name").grid(row=0, column=0)
        category_name_entry = Entry(add_window)
        category_name_entry.grid(row=0, column=1)

        Label(add_window, text="Parent Category Name (optional)").grid(row=1, column=0)
        parent_category_entry = Entry(add_window)
        parent_category_entry.grid(row=1, column=1)

        def save_new_category():
            category_name = category_name_entry.get()
            parent_name = parent_category_entry.get()

            if not category_name:
                messagebox.showerror("Error", "Category name cannot be empty.")
                return

            if parent_name:
                self.cursor.execute("SELECT id FROM category WHERE category_name = ?", (parent_name,))
                result = self.cursor.fetchone()
                if result:
                    parent_id = result[0]
                else:
                    messagebox.showerror("Error", f"Parent category '{parent_name}' not found.")
                    return
            else:
                parent_id = None

            try:
                if parent_id is not None:
                    self.cursor.execute('''
                        INSERT INTO category (category_name, id_parent)
                        VALUES (?, ?)
                    ''', (category_name, parent_id))
                else:
                    self.cursor.execute('''
                        INSERT INTO category (category_name, id_parent)
                        VALUES (?, NULL)
                    ''', (category_name,))
                self.conn.commit()
                self.load_categories()
                add_window.destroy()
                print('Категория успешно добавлена.')
            except Exception as _ex:
                print(f'Error {_ex} - такое название категории уже есть!')
                messagebox.showerror("Error", f"Error {_ex} - такое название категории уже есть!")

        Button(add_window, text="Save", command=save_new_category).grid(row=2, column=0, columnspan=2)


    def edit_category(self):
        try:
            selected_item = self.tree.selection()[0]
            selected_category = self.tree.item(selected_item)['values']
            category_id = selected_category[0]

            edit_window = Toplevel(self.root)
            edit_window.title("Edit Category")

            entries = {}
            row_count = 0
            for col in self.tree["columns"]:
                Label(edit_window, text=col).grid(row=row_count, column=0)
                entry = Entry(edit_window)
                entry.grid(row=row_count, column=1)
                if col == "id":
                    entry.insert(0, selected_category[row_count])
                    entry.config(state="readonly")
                elif col == "id_parent":
                    self.cursor.execute("SELECT id_parent FROM category WHERE id = ?", (category_id,))
                    parent_id = self.cursor.fetchone()[0]
                    if parent_id:
                        entry.insert(0, parent_id)
                else:
                    entry.insert(0, selected_category[row_count])
                entries[col] = entry
                row_count += 1

            def update_category():
                update_values = []
                id_parent = None
                set_clause_parts = []
                for col in self.tree["columns"]:
                    if col == "id":
                        continue
                    value = entries[col].get()
                    if col == "id_parent":
                        if value:
                            if value == str(category_id):
                                messagebox.showerror("Error", "A category cannot be its own parent.")
                                return

                            self.cursor.execute("SELECT id FROM category WHERE id = ?", (value,))
                            result = self.cursor.fetchone()
                            if result:
                                id_parent = result[0]
                            else:
                                messagebox.showerror("Error", f"Parent category with id '{value}' not found.")
                                return

                            if self.check_cyclic_dependency(id_parent, category_id):
                                messagebox.showerror("Error", "Cyclic dependency detected.")
                                return
                        set_clause_parts.append(f"{col} = ?")
                        update_values.append(id_parent)
                    else:
                        set_clause_parts.append(f"{col} = ?")
                        update_values.append(value)

                set_clause = ", ".join(set_clause_parts)
                # print(f'set_clause - {set_clause}')
                self.cursor.execute(f"UPDATE category SET {set_clause} WHERE id = ?", update_values + [category_id])
                self.conn.commit()
                self.load_categories()
                edit_window.destroy()

            Button(edit_window, text="Save", command=update_category).grid(row=row_count, column=0, columnspan=2)

        except IndexError:
            pass


    def check_cyclic_dependency(self, new_parent_id, category_id):
        def fetch_parent_category(cat_id):
            self.cursor.execute("SELECT id_parent FROM category WHERE id = ?", (cat_id,))
            return self.cursor.fetchone()[0]

        current_id = new_parent_id
        while current_id is not None:
            if current_id == category_id:
                return True
            current_id = fetch_parent_category(current_id)
        return False


    def add_unit(self):
        add_window = Toplevel(self.root)
        add_window.title("Add Unit")

        Label(add_window, text="Unit Name").grid(row=0, column=0)
        unit_name_entry = Entry(add_window)
        unit_name_entry.grid(row=0, column=1)

        Label(add_window, text="Unit Name Short").grid(row=1, column=0)
        unit_name_short_entry = Entry(add_window)
        unit_name_short_entry.grid(row=1, column=1)

        def save_new_unit():
            unit_name = unit_name_entry.get()
            unit_name_short = unit_name_short_entry.get()

            if not unit_name:
                messagebox.showerror("Error", "Unit name cannot be empty.")
                return

            if not unit_name_short:
                messagebox.showerror("Error", "Unit name short cannot be empty.")
                return

            try:
                self.cursor.execute('''
                    INSERT INTO unit (unit_name, unit_name_short)
                    VALUES (?, ?)
                ''', (unit_name, unit_name_short))
                self.conn.commit()
                self.load_unit()
                add_window.destroy()
                print('Unit successfully added.')
            except Exception as e:
                messagebox.showerror("Error", f"Error {e} - something went wrong when adding the unit!")

        Button(add_window, text="Save", command=save_new_unit).grid(row=2, column=0, columnspan=2)


    def edit_unit(self):
        try:
            selected_item = self.tree.selection()[0]
            selected_product = self.tree.item(selected_item)['values']
            unit_id = selected_product[0]

            edit_window = Toplevel(self.root)
            edit_window.title("Edit Product")

            entries = {}
            row_count = 0

            # print(f'\n self.tree["columns"] = {self.tree["columns"]} \n')

            for col in self.tree["columns"]:
                Label(edit_window, text=col).grid(row=row_count, column=0)
                entry = Entry(edit_window)
                entry.grid(row=row_count, column=1)
                if col == "id":
                    entry.insert(0, selected_product[row_count])
                    entry.config(state="readonly")
                else:
                    entry.insert(0, selected_product[row_count])
                entries[col] = entry
                row_count += 1

            def update_unit():
                update_values = {}
                unit_name = None
                for col in self.tree["columns"]:
                    if col == "id":
                        continue
                    value = entries[col].get()
                    if col == "unit_name":
                        if not value.isdigit():
                            self.cursor.execute("SELECT COUNT(*) FROM unit WHERE unit_name = ?", (value,))
                            result = self.cursor.fetchone()[0]
                            # print(f'value in update_unit() - {value}')
                            # print(f'result in update_unit() - {result}')
                            if result == 0:
                                unit_name = value
                            else:
                                messagebox.showerror("Error", f"Unit_name already exists.")
                                return
                        else:
                            messagebox.showerror("Error", "unit_name must NOT be a number.")
                            return
                        update_values[col] = unit_name
                    if col == "unit_name_short":
                        if not value.isdigit():
                            update_values[col] = value
                        else:
                            messagebox.showerror("Error", "unit_name_short must NOT be a number.")
                            return

                set_clause_parts = [f"{col} = ?" for col in update_values.keys()]
                # print(f'\nset_clause_parts - {set_clause_parts}\n')
                set_clause = ", ".join(set_clause_parts)
                # print(f'\n set_clause -- {set_clause} \n')

                update_values_list = list(update_values.values())
                # print(f'update_values_list - {update_values_list}')

                update_values_list.append(unit_id)
                # print(f'update_values_list ----------- {update_values_list}')
                self.cursor.execute(f"UPDATE unit SET {set_clause} WHERE id = ?", update_values_list)
                self.conn.commit()
                self.load_unit()
                edit_window.destroy()

            Button(edit_window, text="Save", command=update_unit).grid(row=row_count, column=0, columnspan=2)

        except IndexError:
            pass


    def delete_unit(self):
        try:
            selected_item = self.tree.selection()[0]
            selected_unit = self.tree.item(selected_item)['values']
            id_unit = selected_unit[0]
            self.cursor.execute("DELETE FROM unit WHERE id = ?", (id_unit,))

            self.cursor.execute("UPDATE product SET id_unit = NULL WHERE id_unit = ?", (id_unit,))

            # self.load_products()

            self.conn.commit()
            self.load_unit()
        except IndexError:
            pass


    def add_product(self):
        add_window = Toplevel(self.root)
        add_window.title("Add Product")

        Label(add_window, text="Product Name").grid(row=0, column=0)
        product_name_entry = Entry(add_window)
        product_name_entry.grid(row=0, column=1)

        Label(add_window, text="id Category").grid(row=1, column=0)
        id_category_entry = Entry(add_window)
        id_category_entry.grid(row=1, column=1)

        Label(add_window, text="id unit").grid(row=2, column=0)
        id_unit_entry = Entry(add_window)
        id_unit_entry.grid(row=2, column=1)

        Label(add_window, text="Quantity (optional)").grid(row=3, column=0)
        quantity_entry = Entry(add_window)
        quantity_entry.grid(row=3, column=1)

        Label(add_window, text="Price (optional)").grid(row=4, column=0)
        price_entry = Entry(add_window)
        price_entry.grid(row=4, column=1)

        def save_new_product():
            product_name = product_name_entry.get()
            id_category = id_category_entry.get()
            id_unit = id_unit_entry.get()
            quantity = quantity_entry.get()
            price = price_entry.get()

            try:
                if quantity:
                    quantity = int(quantity_entry.get())
            except Exception as _ex:
                print(f'in add_product() error: {_ex}')
                messagebox.showerror("Error", "Quantity type should be type = int.")
                return

            try:
                if price:
                    price = int(price_entry.get())
            except Exception as _ex:
                print(f'in add_product() error: {_ex}')
                messagebox.showerror("Error", "Price type should be type = int.")
                return

            # print(f'type(quantity) - {type(quantity)}')
            # print(f'type(price) - {type(price)}')


            if not product_name:
                messagebox.showerror("Error", "Product name cannot be empty.")
                return


            self.cursor.execute("SELECT COUNT(*) FROM category WHERE id = ?", (id_category,))
            result = self.cursor.fetchone()
            # print(f'result on add_prod() - {result}')

            ## а мб все же так надо???
            if result[0] == 0:
                messagebox.showerror("Error", f"Parent category with id - '{id_category}' not found.")
                return

            # if id_category == 0:
            #     messagebox.showerror("Error", f"Parent category with id - '{id_category}' not found.")
            #     return

            if id_unit:
                self.cursor.execute("SELECT COUNT(*) FROM unit WHERE id = ?", (id_unit,))
                result_unit_id = self.cursor.fetchone()
                if result_unit_id[0] == 0:
                    messagebox.showerror("Error", f"unit with id - '{id_unit}' not found.")
                    return

            # try:

            self.cursor.execute('''
                INSERT INTO product (id_category, product_name, id_unit, quantity, price)
                VALUES (?, ?, ?, ?, ?)
            ''', (id_category, product_name, id_unit, quantity, price))

            self.conn.commit()
            self.load_products()
            add_window.destroy()
            print('Изделие успешно добавлено.')
            # except Exception as _ex:
            #     messagebox.showerror("Error", f"Error {_ex} - что-то пошло не так при добавлении изделия!")

        Button(add_window, text="Save", command=save_new_product).grid(row=5, column=0, columnspan=2)


    def edit_product(self):
        try:
            selected_item = self.tree.selection()[0]
            selected_product = self.tree.item(selected_item)['values']
            product_id = selected_product[0]

            edit_window = Toplevel(self.root)
            edit_window.title("Edit Product")

            entries = {}
            row_count = 0

            # print(f'\n self.tree["columns"] = {self.tree["columns"]} \n')

            for col in self.tree["columns"]:
                Label(edit_window, text=col).grid(row=row_count, column=0)
                entry = Entry(edit_window)
                entry.grid(row=row_count, column=1)
                if col == "id":
                    entry.insert(0, selected_product[row_count])
                    entry.config(state="readonly")
                else:
                    entry.insert(0, selected_product[row_count])
                entries[col] = entry
                row_count += 1

            def update_product():
                update_values = {}
                id_category = None
                for col in self.tree["columns"]:
                    if col == "id":
                        continue
                    value = entries[col].get()
                    if col == "id_category":
                        if value.isdigit():
                            self.cursor.execute("SELECT COUNT(*) FROM category WHERE id = ?", (value,))
                            result = self.cursor.fetchone()
                            if result[0] > 0:
                                id_category = value
                            else:
                                messagebox.showerror("Error", f"Category with id '{value}' not found.")
                                return
                        else:
                            messagebox.showerror("Error", "id_category must be a number.")
                            return
                        update_values[col] = id_category
                    if col == "quantity":
                        if not value.isdigit():
                            messagebox.showerror("Error", "Quantity must be a number.")
                            return
                        else:
                            update_values[col] = value
                    if col == "price":
                        if not value.isdigit():
                            messagebox.showerror("Error", "Price must be a number.")
                            return
                        else:
                            update_values[col] = value
                    if col == 'id_unit':
                        if value:
                            self.cursor.execute("SELECT COUNT(*) FROM unit WHERE id = ?", (value,))
                            result_unit_id = self.cursor.fetchone()
                            if result_unit_id[0] == 0:
                                messagebox.showerror("Error", f"unit with id - '{value}' not found.")
                                return
                            else:
                                update_values[col] = value
                    else:
                        update_values[col] = value

                set_clause_parts = [f"{col} = ?" for col in update_values.keys()]
                # print(f'\nset_clause_parts - {set_clause_parts}\n')
                set_clause = ", ".join(set_clause_parts)
                # print(f'\n set_clause ---- {set_clause} \n')

                update_values_list = list(update_values.values())
                # print(f'update_values_list - {update_values_list}')

                update_values_list.append(product_id)
                self.cursor.execute(f"UPDATE product SET {set_clause} WHERE id = ?", update_values_list)
                self.conn.commit()
                self.load_products()
                edit_window.destroy()

            Button(edit_window, text="Save", command=update_product).grid(row=row_count, column=0, columnspan=2)

        except IndexError:
            pass


    def delete_product(self):
        try:
            selected_item = self.tree.selection()[0]
            selected_product = self.tree.item(selected_item)['values']
            product_id = selected_product[0]
            self.cursor.execute("DELETE FROM product WHERE id = ?", (product_id,))
            self.conn.commit()
            self.load_products()
        except IndexError:
            pass


    def fill_example_data(self):
        # Проверка, пусты ли все таблицы
        self.cursor.execute("SELECT COUNT(*) FROM product")
        if self.cursor.fetchone()[0] != 0:
            messagebox.showinfo("Info", "Tables are not empty. No data added.")
            return

        self.cursor.execute("SELECT COUNT(*) FROM category")
        if self.cursor.fetchone()[0] != 0:
            messagebox.showinfo("Info", "Tables are not empty. No data added.")
            return

        self.cursor.execute("SELECT COUNT(*) FROM unit")
        if self.cursor.fetchone()[0] != 0:
            messagebox.showinfo("Info", "Tables are not empty. No data added.")
            return

        # Вызов функции для заполнения контрольным примером
        self.add_example_data()

        self.load_products()
        messagebox.showinfo("Success", "Example data has been successfully added.")



    def load_products(self):
        # Очистка текущих данных из Treeview
        for row in self.tree.get_children():
            self.tree.delete(row)

        # Получение данных из таблицы product
        self.cursor.execute("SELECT * FROM product")
        rows = self.cursor.fetchall()
        column_names = [description[0] for description in self.cursor.description]

        # Очистка старых заголовков столбцов
        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)  # Устанавливаем ширину столбцов

        # Вставка данных в Treeview
        for row in rows:
            self.tree.insert("", END, values=row)


    def delete_category(self):
        try:
            selected_item = self.tree.selection()[0]
            # print(f'selected_item - {selected_item}')
            selected_category = self.tree.item(selected_item)['values']
            # print(f'selected_category - {selected_category}')
            category_name = selected_category[-1]
            # print(f'category_name - {category_name}')


            if self.is_category_exists(category_name):
                self.cursor.execute("SELECT id FROM category WHERE category_name = ?;", (category_name,))
                delete_id = self.cursor.fetchone()[0]

                # Перемещаем все подкатегории удаляемой категории в категорию "неопределенные"
                self.cursor.execute("UPDATE category SET id_parent = (SELECT id FROM category WHERE category_name = 'неопределенные') WHERE id_parent = ?", (delete_id,))

                self.cursor.execute("SELECT id_parent FROM category WHERE category_name = ?", ('неопределенные',))
                cat_id_undef = self.cursor.fetchone()
                if cat_id_undef:
                    self.cursor.execute("UPDATE category SET id_parent = NULL WHERE category_name = ?", ('неопределенные',))
                    # self.conn.commit()

                # Перемещаем все изделия удаляемой категории в категорию "неопределенные"
                self.cursor.execute("UPDATE product SET id_category = (SELECT id FROM category WHERE category_name = 'неопределенные') WHERE id_category = ?", (delete_id,))

                # Удаляем категорию
                self.cursor.execute("DELETE FROM category WHERE id = ?", (delete_id,))
                self.conn.commit()

                self.load_categories()
                print('Категория успешно удалена.')
            else:
                print('Указанная категория не существует.')
                messagebox.showerror("Error", "Указанная категория не существует.")

        except Exception as _ex:
            print(f"Произошла ошибка при удалении категории: {_ex}")
            messagebox.showerror("Error", f"Произошла ошибка при удалении категории: {_ex}")



    def is_category_exists(self, category_name):
        self.cursor.execute("SELECT COUNT(*) FROM category WHERE category_name = ?", (category_name,))
        count = self.cursor.fetchone()[0]
        return count > 0





















    # additional interface function only (several getters)



    def show_category_parents(self):
        try:
            selected_item = self.tree.selection()[0]
            selected_category = self.tree.item(selected_item)['values']
            category_id = selected_category[0]

            self.cursor.execute("SELECT category_name FROM category WHERE id = ?", (category_id,))
            clicked_category_name = self.cursor.fetchone()[0]

            # Получаем все предки выбранной категории
            parents = []

            while category_id:
                self.cursor.execute("SELECT id, id_parent, category_name FROM category WHERE id = ?", (category_id,))
                result = self.cursor.fetchone()
                if not result:
                    break
                id, parent_id, category_name = result
                # print(f'\n\nresult - {result}\n\n')

                parents.append([id, parent_id, category_name])
                category_id = parent_id

            # Отображаем новое окно с предками категории
            parent_window = Toplevel(self.root)
            parent_window.minsize(600, 300)
            parent_window.title("Category Parents")

            # Получаем имена столбцов из таблицы category
            self.cursor.execute("PRAGMA table_info(category)")
            columns_info = self.cursor.fetchall()
            column_names = [info[1] for info in columns_info]

            # Создаем Treeview для отображения предков
            parent_tree = ttk.Treeview(parent_window, columns=column_names, show='headings')
            parent_tree.pack(expand=True, fill='both')


            self.cursor.execute("SELECT id, id_parent, category_name FROM category WHERE category_name = ?", (clicked_category_name,))
            result_to_del = self.cursor.fetchone()

            id_self, parent_id_self, category_name_self = result_to_del
            parents.remove([id_self, parent_id_self, category_name_self])

            # Устанавливаем заголовки столбцов
            for col in column_names:
                parent_tree.heading(col, text=col)
                parent_tree.column(col, width=100)




            # Вставляем данные предков в Treeview
            for parent in reversed(parents):  # Обратный порядок для отображения от корня к категории
                parent_tree.insert('', 'end', values=parent)

        except IndexError:
            messagebox.showerror("Error", "No category selected.")



    def show_category_children(self):
        try:
            selected_item = self.tree.selection()[0]
            selected_category = self.tree.item(selected_item)['values']
            category_id = selected_category[0]

            # Рекурсивно получаем всех потомков выбранной категории
            children = self.get_all_children(category_id)

            # Отображаем новое окно с потомками категории
            child_window = Toplevel(self.root)
            child_window.minsize(300, 100)
            child_window.title("Category Children")

            # Получаем имена столбцов из таблицы category
            self.cursor.execute("PRAGMA table_info(category)")
            columns_info = self.cursor.fetchall()
            column_names = [info[1] for info in columns_info]

            # Создаем Treeview для отображения предков
            parent_tree = ttk.Treeview(child_window, columns=column_names, show='headings')
            parent_tree.pack(expand=True, fill='both')

            # Устанавливаем заголовки столбцов
            for col in column_names:
                parent_tree.heading(col, text=col)
                parent_tree.column(col, width=100)

            for parent in children:  # Обратный порядок для отображения от корня к категории
                parent_tree.insert('', 'end', values=parent)

        except IndexError:
            messagebox.showerror("Error", "No category selected.")


    def get_all_children(self, category_id):
        children = []

        # Получаем все дочерние категории для данного родителя
        self.cursor.execute("SELECT id, id_parent, category_name FROM category WHERE id_parent = ?", (category_id,))
        result = self.cursor.fetchall()
        # print(f'\nresult in children - {result}\n')
        for row in result:
            id, id_parent, category_name = row
            children.append([id, id_parent, category_name])  # Добавляем имя дочерней категории
            children.extend(self.get_all_children(row[0]))  # Рекурсивно добавляем всех потомков для каждой дочерней категории

        return children



    def show_products_for_category(self):
        def get_all_children(category_id):
            children = []
            self.cursor.execute("SELECT id FROM category WHERE id_parent = ?", (category_id,))
            results = self.cursor.fetchall()
            for result in results:
                children.append(result[0])
                children.extend(get_all_children(result[0]))  # Assuming id is the first column
            return children

        try:
            selected_item = self.tree.selection()[0]
            selected_category = self.tree.item(selected_item)['values']
            category_id = selected_category[0]

            # Получаем все дочерние категории выбранной категории
            all_category_ids = [category_id] + get_all_children(category_id)

            # Получаем все изделия для выбранной категории и всех дочерних категорий
            products = []
            for cat_id in all_category_ids:
                self.cursor.execute("SELECT * FROM product WHERE id_category = ?", (cat_id,))
                products.extend(self.cursor.fetchall())

            column_names = [description[0] for description in self.cursor.description]

            # Отображаем новое окно со списком изделий для выбранной категории и её дочерних категорий
            products_window = Toplevel(self.root)
            products_window.minsize(600, 400)
            products_window.title("Products for Category")

            # Создаем Treeview для отображения изделий
            product_tree = ttk.Treeview(products_window, columns=column_names, show='headings')
            product_tree.pack(expand=True, fill='both')

            # Устанавливаем заголовки для столбцов
            for col in column_names:
                product_tree.heading(col, text=col)
                product_tree.column(col, width=100)

            # Вставляем данные изделий в Treeview
            for product in products:
                product_tree.insert('', 'end', values=product)

        except IndexError:
            messagebox.showerror("Error", "No category selected.")



    # coursework-2

    def load_acceptable_component(self):
        for row in self.tree.get_children():
            self.tree.delete(row)

        self.cursor.execute("SELECT * FROM acceptable_components")
        rows = self.cursor.fetchall()
        column_names = [description[0] for description in self.cursor.description]

        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)  # Устанавливаем ширину столбцов

        for row in rows:
            self.tree.insert("", END, values=row)


    # new_class_id, new_component_id
    def create_acceptable_component(self):
        add_window = Toplevel(self.root)
        add_window.title("Add acceptable component")

        Label(add_window, text="Component name").grid(row=0, column=0)
        component_name_entry = Entry(add_window)
        component_name_entry.grid(row=0, column=1)

        Label(add_window, text="Class name").grid(row=1, column=0)
        class_name_entry = Entry(add_window)
        class_name_entry.grid(row=1, column=1)

        def save_new_component():
            class_name = class_name_entry.get()
            component_name = component_name_entry.get()

            self.cursor.execute("SELECT id FROM category WHERE category_name = ?", (class_name,))
            new_class_id = self.cursor.fetchone()
            if new_class_id:
                new_class_id = new_class_id[0]
            else:
                messagebox.showerror("Error", f"Class name with id - '{new_class_id}' not found.")
                return


            self.cursor.execute("SELECT id FROM category WHERE category_name = ?", (component_name,))
            new_component_id = self.cursor.fetchone()
            if new_component_id:
                new_component_id = new_component_id[0]
            else:
                messagebox.showerror("Error", f"Component name with id - '{new_component_id}' not found.")
                return


            if new_class_id == new_component_id:
                messagebox.showerror("Error: нельзя создать цикл с одинаковыми class_id и component_id!")
                return

            try:
                # Recursive query to check for cycles in acceptable_components
                self.cursor.execute('''
                    WITH RECURSIVE cycle_check(class_id, comp_id) AS (
                        SELECT class_id, component_id
                        FROM acceptable_components
                        WHERE class_id = ?
                        UNION ALL
                        SELECT ac.class_id, ac.component_id
                        FROM acceptable_components ac
                        INNER JOIN cycle_check cc ON ac.class_id = cc.comp_id
                    )
                    SELECT 1 FROM cycle_check WHERE comp_id = ?
                ''', (new_component_id, new_class_id))

                # If a result exists, it means adding the new entry would create a cycle
                if self.cursor.fetchone():
                    print(f"Error: добавление пары ({new_class_id}, {new_component_id}) создаёт цикл!")
                    return 0  # Failure

                # Insert the new relationship if no cycle is detected
                self.cursor.execute('''
                    INSERT INTO acceptable_components (class_id, component_id)
                    VALUES (?, ?)
                ''', (new_class_id, new_component_id))
                self.conn.commit()

                self.load_acceptable_component()

                add_window.destroy()

                print(f"Компонент успешно добавлен: class_id={new_class_id}, component_id={new_component_id}")
                return 1  # Success
            except sqlite3.OperationalError as e:
                print(f"SQL Error: {e}")
                return 0  # Failure
            except sqlite3.IntegrityError:
                print("Error: нарушение ограничений UNIQUE или FOREIGN KEY.")
                return 0  # Failure

        Button(add_window, text="Save", command=save_new_component).grid(row=5, column=0, columnspan=2)


    # cl_id - для какого класса наследуемся
    def inherit_acceptable_components(self):
        add_window = Toplevel(self.root)
        add_window.title("Inherit acceptable components")

        Label(add_window, text="Class name").grid(row=0, column=0)
        class_name_entry = Entry(add_window)
        class_name_entry.grid(row=0, column=1)

        def save_new_inherit_acceptable_components():
            class_name = class_name_entry.get()

            self.cursor.execute("SELECT id FROM category WHERE category_name = ?", (class_name,))
            cl_id = self.cursor.fetchone()
            if cl_id:
                cl_id = cl_id[0]
            else:
                messagebox.showerror("Error", f"Category name with id - '{cl_id}' not found.")
                return

            inserted_count = 0
            try:
                self.cursor.execute('SELECT id_parent FROM category WHERE id = ?', (cl_id,))
                parent_cl_id = self.cursor.fetchone()
                if parent_cl_id is None:
                    messagebox.showerror("Parent class ID not found")
                    return

                self.cursor.execute('''
                    SELECT component_id FROM acceptable_components
                    WHERE class_id = ?
                ''', (parent_cl_id[0],))
                components = self.cursor.fetchall()


                # Insert acceptable components for the child class
                for (component_id,) in components:
                    self.cursor.execute('''
                        INSERT OR IGNORE INTO acceptable_components (class_id, component_id)
                        VALUES (?, ?)
                    ''', (cl_id, component_id))
                    inserted_count += self.cursor.rowcount

                self.conn.commit()

                messagebox.showinfo("Success", f"произведено {inserted_count} наследований.")

                add_window.destroy()

                print(f'произведено {inserted_count} наследований')
            except Exception as e:
                print(f"Error: {e}")
            return inserted_count

        Button(add_window, text="Save", command=save_new_inherit_acceptable_components).grid(row=5, column=0, columnspan=2)



    def load_prod_position_union(self):
        for row in self.tree.get_children():
            self.tree.delete(row)

        self.cursor.execute("SELECT * FROM prod_position_union")
        rows = self.cursor.fetchall()
        column_names = [description[0] for description in self.cursor.description]

        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)  # Устанавливаем ширину столбцов

        for row in rows:
            self.tree.insert("", END, values=row)



    # new_object_id, new_component_id, new_quantity
    def create_prod_position_union(self):
        add_window = Toplevel(self.root)
        add_window.title("Add prod position union")

        Label(add_window, text="Product name").grid(row=0, column=0)
        product_name_entry = Entry(add_window)
        product_name_entry.grid(row=0, column=1)

        Label(add_window, text="Component product name").grid(row=1, column=0)
        component_name_entry = Entry(add_window)
        component_name_entry.grid(row=1, column=1)

        Label(add_window, text="Quantity").grid(row=2, column=0)
        quantity_entry = Entry(add_window)
        quantity_entry.grid(row=2, column=1)

        def save_new_prod_position_union():
            product_name = product_name_entry.get()
            component_name = component_name_entry.get()
            quantity_str = quantity_entry.get()

            try:
                quantity = int(quantity_str)
            except ValueError:
                messagebox.showerror("Error", "Quantity must be a valid integer.")
                return

            if (quantity <= 0):
                messagebox.showerror("Error", f"quantity cant be <= 0.")
                return

            self.cursor.execute("SELECT id FROM product WHERE product_name = ?", (product_name,))
            new_object_id = self.cursor.fetchone()
            if new_object_id:
                new_object_id = new_object_id[0]
            else:
                messagebox.showerror("Error", f"Product name with id - '{new_object_id}' not found.")
                return


            self.cursor.execute("SELECT id FROM product WHERE product_name = ?", (component_name,))
            new_component_id = self.cursor.fetchone()
            if new_component_id:
                new_component_id = new_component_id[0]
            else:
                messagebox.showerror("Error", f"Component with id - '{new_component_id}' not found.")
                return

            try:
                self.cursor.execute('SELECT id_category FROM product WHERE id = ?', (new_object_id,))

                obj_class_id = self.cursor.fetchone()
                if obj_class_id is None:
                    messagebox.showerror("Object ID not found")
                    return

                self.cursor.execute('SELECT id_category FROM product WHERE id = ?', (new_component_id,))
                comp_class_id = self.cursor.fetchone()
                if comp_class_id is None:
                    messagebox.showerror("Component ID not found")
                    return

                self.cursor.execute('''
                    SELECT 1
                    FROM acceptable_components
                    WHERE class_id = ? AND component_id = ?
                ''', (obj_class_id[0], comp_class_id[0]))
                if self.cursor.fetchone() is None:
                    messagebox.showerror("Invalid composition for the object!")
                    return

                self.cursor.execute('''
                    INSERT INTO prod_position_union (prod_id, comp_id, quantity)
                    VALUES (?, ?, ?)
                ''', (new_object_id, new_component_id, quantity))
                self.conn.commit()

                self.load_prod_position_union()

                add_window.destroy()

                print('таблица prod_position_union успешно обновлена новым значением.')
                return 1  # Success
            except Exception as e:
                print(f"Error: {e}")
                return 0  # Failure

        Button(add_window, text="Save", command=save_new_prod_position_union).grid(row=5, column=0, columnspan=2)


    def delete_prod_position_union(self):
        try:
            selected_item = self.tree.selection()[0]
            selected_product = self.tree.item(selected_item)['values']
            prod_position_union_id = selected_product[0]
            self.cursor.execute("DELETE FROM prod_position_union WHERE id = ?", (prod_position_union_id,))
            self.conn.commit()
            self.load_prod_position_union()
        except IndexError:
            pass


    def delete_acceptable_component(self):
        try:
            selected_item = self.tree.selection()[0]
            selected_product = self.tree.item(selected_item)['values']
            acceptable_component_id = selected_product[0]
            self.cursor.execute("DELETE FROM acceptable_components WHERE id = ?", (acceptable_component_id,))
            self.conn.commit()
            self.load_acceptable_component()
        except IndexError:
            pass


    def edit_prod_position_union_quantity(self):
            selected_item = self.tree.selection()[0]
            selected_product = self.tree.item(selected_item)['values']
            prod_position_union_id = selected_product[0]

            add_window = Toplevel(self.root)
            add_window.title("Enter new quantity")

            Label(add_window, text="Product name").grid(row=0, column=0)
            quantity_entry = Entry(add_window)
            quantity_entry.grid(row=0, column=1)

            def save_quantity():
                quantity_str = quantity_entry.get()

                try:
                    quantity = int(quantity_str)
                except ValueError:
                    messagebox.showerror("Error", "Quantity must be a valid integer.")
                    return

                if (quantity <= 0):
                    messagebox.showerror("Error", f"quantity cant be <= 0.")
                    return

                try:

                    self.cursor.execute('''
                        UPDATE prod_position_union
                        SET quantity = ?
                        WHERE id = ?
                    ''', (quantity, prod_position_union_id))
                    self.conn.commit()

                    self.load_prod_position_union()

                    add_window.destroy()


                except IndexError:
                    pass

            Button(add_window, text="Save", command=save_quantity).grid(row=5, column=0, columnspan=2)


    def load_acceptable_components_by_class(self):
        selected_item = self.tree.selection()[0]
        selected_product = self.tree.item(selected_item)['values']
        class_id = selected_product[0]

        # Clear the treeview
        for row in self.tree.get_children():
            self.tree.delete(row)

        # Fetch component IDs
        self.cursor.execute("SELECT component_id FROM acceptable_components WHERE class_id = ?", (class_id,))
        component_ids = self.cursor.fetchall()

        if not component_ids:
            print(f"No components found for class_id {class_id}.")
            return

        # Fetch component names for each ID
        result = []
        for component_id in component_ids:

            print(f'component_id - {component_id}')

            self.cursor.execute("SELECT category_name FROM category WHERE id = ?", (component_id[0],))
            name = self.cursor.fetchone()
            if name:
                print(f'component_id[0], name[0] - {component_id[0], name[0]}')
                result.append((component_id[0], name[0]))

        print(f'Для класса с id = {class_id}, составные части: {result}')

        for res in result:
            print(f'res = {res}')

        # Explicitly set up the columns
        self.tree["columns"] = ("component_id", "category_name")
        self.tree.heading("#0", text="", anchor="w")  # Clear default column
        self.tree.column("#0", width=0, stretch=False)  # Hide the first empty column
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col, anchor="w")
            self.tree.column(col, anchor="w", width=150)  # Set width for each column

        # self.tree.insert("", "end", values=result)

        # Insert rows into the treeview
        for row in result:
            self.tree.insert("", "end", values=(row[0], row[1]))
            # self.tree.insert("", END, values=row)







    def load_find_components_by_object(self):

        selected_item = self.tree.selection()[0]
        selected_product = self.tree.item(selected_item)['values']
        object_id = selected_product[0]


        for row in self.tree.get_children():
            self.tree.delete(row)

        self.cursor.execute("SELECT comp_id, quantity FROM prod_position_union WHERE prod_id = ?", (object_id,))
        components = self.cursor.fetchall()

        if not components:
            return []


        result = []
        for comp_id, quantity in components:
            self.cursor.execute("SELECT product_name, quantity FROM product WHERE id = ?", (comp_id,))
            name = self.cursor.fetchone()
            if name:
                result.append(( [name[0]], [ quantity]))

        print(f'для объекта с id = {object_id}, составные части: {result}')

        column_names = [description[0] for description in self.cursor.description]

        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)  # Устанавливаем ширину столбцов


        for row in result:
            self.tree.insert("", END, values=row)



    def load_acceptable_components_by_class_recursive(self):
        selected_item = self.tree.selection()[0]
        selected_product = self.tree.item(selected_item)['values']
        class_id = selected_product[0]

        for row in self.tree.get_children():
            self.tree.delete(row)


        def find_components(class_id, result):
            self.cursor.execute("SELECT component_id FROM acceptable_components WHERE class_id = ?", (class_id,))
            components = self.cursor.fetchall()

            for component in components:
                component_id = component[0]
                result.add(component_id)
                find_components(component_id, result)

        result = set()
        find_components(class_id, result)

        # Fetch component names for the result set
        component_names = []
        for component_id in result:
            self.cursor.execute("SELECT category_name FROM category WHERE id = ?", (component_id,))
            component_name = self.cursor.fetchone()
            if component_name:
                component_names.append((component_name[0], component_id))

        print(f'результат подходящих компонент для id {class_id} - ({component_names})')

        column_names = [description[0] for description in self.cursor.description]

        print(f'column_names - - - -{column_names}')

        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=120)  # Устанавливаем ширину столбцов

        for row in component_names:
            self.tree.insert("", END, values=row)



    # object_id
    def find_components_recursive(self):

        selected_item = self.tree.selection()[0]
        selected_product = self.tree.item(selected_item)['values']
        object_id = selected_product[0]

        for row in self.tree.get_children():
            self.tree.delete(row)


        # Recursive function to find components
        def find_components(obj_id, result):
            self.cursor.execute("SELECT comp_id, quantity FROM prod_position_union WHERE prod_id = ?", (obj_id,))
            components = self.cursor.fetchall()

            for comp_id, quantity in components:
                result[comp_id] = result.get(comp_id, 0) + quantity
                find_components(comp_id, result)

        result = {}
        find_components(object_id, result)

        # Fetch component names for the result
        final_result = []
        for comp_id, total_quantity in result.items():
            self.cursor.execute("SELECT product_name FROM product WHERE id = ?", (comp_id,))
            name = self.cursor.fetchone()
            if name:
                final_result.append((name[0], comp_id, total_quantity))

        print(f'для объекта с id = {object_id} компоненты, найденные рекурсивно: {final_result}')


        column_names = [description[0] for description in self.cursor.description]

        print(f'column_names - - - -{column_names}')

        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=120)  # Устанавливаем ширину столбцов

        for row in final_result:
            self.tree.insert("", END, values=row)



    def load_existing_acceptable_components_by_object(self):
        selected_item = self.tree.selection()[0]
        selected_product = self.tree.item(selected_item)['values']
        object_id = selected_product[0]

        for row in self.tree.get_children():
            self.tree.delete(row)


        self.cursor.execute("SELECT id_category FROM product WHERE id = ?", (object_id,))
        id_category = self.cursor.fetchone()[0]

        # Find the class_id of the object
        self.cursor.execute("SELECT id_parent FROM category WHERE id = ?", (id_category,))
        class_info = self.cursor.fetchone()
        if not class_info:
            return []

        class_id = class_info[0]
        self.cursor.execute('''
            SELECT component_id FROM acceptable_components WHERE class_id = ?
        ''', (class_id,))
        components = self.cursor.fetchall()

        # Fetch component names for the result
        result = []
        for component in components:
            component_id = component[0]
            self.cursor.execute("SELECT category_name FROM category WHERE id = ?", (component_id,))
            name = self.cursor.fetchone()
            if name:
                # result.append((component_id, name[0]))
                result.append((name[0]))

        print(f'result - {result}')

        column_names = [description[0] for description in self.cursor.description]

        print(f'column_names - - - -{column_names}')

        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=120)  # Устанавливаем ширину столбцов

        for row in result:
            self.tree.insert("", END, values=row)






    def load_existing_acceptable_components_by_object_recursive(self):
        selected_item = self.tree.selection()[0]
        selected_product = self.tree.item(selected_item)['values']
        obj_id = selected_product[0]

        self.cursor.execute("SELECT id_category FROM product WHERE id = ?", (obj_id,))
        class_id = self.cursor.fetchone()

        if not class_id:
            return []

        class_id = class_id[0]

        for row in self.tree.get_children():
            self.tree.delete(row)



        def find_acceptable_components_by_class_recursive(class_id):
            try:
                def find_components(class_id, result):
                    self.cursor.execute("SELECT component_id FROM acceptable_components WHERE class_id = ?", (class_id,))
                    components = self.cursor.fetchall()

                    for component in components:
                        component_id = component[0]
                        result.add(component_id)
                        find_components(component_id, result)

                result = set()
                find_components(class_id, result)

                # Fetch component names for the result set
                component_names = []
                for component_id in result:
                    self.cursor.execute("SELECT category_name FROM category WHERE id = ?", (component_id,))
                    component_name = self.cursor.fetchone()
                    if component_name:
                        component_names.append((component_id, component_name[0]))

                print(f'результат подходящих компонент для id {class_id} - ({component_names})')

                return component_names

            except Exception as e:
                print(f"Error occurred while finding acceptable components: {e}")
                return []



        def find_components(cl_id):
            components = []

            acceptable_components = find_acceptable_components_by_class_recursive(cl_id)

            for component in acceptable_components:
                component_id = component[0]
                self.cursor.execute("SELECT id, product_name FROM product WHERE id_category = ?", (component_id,))
                obj_data = self.cursor.fetchone()

                if obj_data:
                    # components.append({
                    #     obj_data[1]
                    # })
                    components.append({
                        'component_name': obj_data[1],
                        'component_id': obj_data[0]
                    })

            return components

        components = find_components(class_id)



        column_names = [description[0] for description in self.cursor.description]

        print(f'column_names - - - -{column_names}')

        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=120)


        for row in components:
            self.tree.insert("", END, values=(row['component_id'], row['component_name']))


    # coursework-2







    def delete_all_data(self):
        def dropAllTables():
            try:
                # Список таблиц в порядке, в котором их нужно удалить (сначала те, которые не содержат внешних ключей)
                tables_order = ['category', 'unit', 'product', 'prod_position_union', 'acceptable_components','sqlite_sequence']

                # Удаление данных из таблиц с внешними ключами
                for table_name in tables_order[::-1]:
                    self.cursor.execute(f"DELETE FROM {table_name};")

                # Удаление самих таблиц
                self.cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';")
                tables = self.cursor.fetchall()

                for table in tables:
                    table_name = table[0]
                    self.cursor.execute(f"DROP TABLE IF EXISTS {table_name};")

                self.conn.commit()

                print("Все таблицы успешно удалены.")
            except Exception as _ex:
                print(f"Произошла ошибка при удалении таблиц: {_ex}")

        def confirm_delete():
            if messagebox.askokcancel("Confirm Delete", "Are you sure you want to delete all data from all tables?"):
                try:
                    # self.cursor.execute("DELETE FROM product")
                    # self.cursor.execute("DELETE FROM category")
                    # self.cursor.execute("DELETE FROM unit")

                    dropAllTables()
                    self.conn.commit()

                    # повторное создание таблиц для сброса id autoincrement
                    self.cursor.execute('''CREATE TABLE IF NOT EXISTS category
                            (id INTEGER PRIMARY KEY AUTOINCREMENT,
                                id_parent INTEGER,
                                category_name TEXT UNIQUE,
                                id_unit INTEGER,
                                FOREIGN KEY (id_parent) REFERENCES category(id))''')
                    self.conn.commit()

                    self.cursor.execute('''CREATE TABLE IF NOT EXISTS product
                                                (id INTEGER PRIMARY KEY AUTOINCREMENT,
                                                    id_category INTEGER,
                                                    id_unit INTEGER,
                                                    product_name TEXT NOT NULL,
                                                    quantity INTEGER DEFAULT 0,
                                                    price REAL DEFAULT 0,
                                                    FOREIGN KEY (id_unit) REFERENCES unit(id),
                                                    FOREIGN KEY (id_category) REFERENCES category(id))''')
                    self.conn.commit()

                    self.cursor.execute('''CREATE TABLE IF NOT EXISTS unit
                                                (id INTEGER PRIMARY KEY AUTOINCREMENT,
                                                    unit_name TEXT NOT NULL UNIQUE,
                                                    unit_name_short TEXT NOT NULL)''')
                    self.conn.commit()

                    self.cursor.execute('''
                        CREATE TABLE IF NOT EXISTS acceptable_components (
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
                            class_id INTEGER NOT NULL,
                            component_id INTEGER NOT NULL,
                            UNIQUE(class_id, component_id),
                            FOREIGN KEY (class_id) REFERENCES category(id) ON DELETE CASCADE,
                            FOREIGN KEY (component_id) REFERENCES category(id) ON DELETE CASCADE
                        )
                    ''')
                    self.conn.commit()

                    self.cursor.execute('''
                        CREATE TABLE IF NOT EXISTS prod_position_union (
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
                            prod_id INTEGER NOT NULL,
                            comp_id INTEGER NOT NULL,
                            quantity INTEGER NOT NULL CHECK (quantity > 0),
                            UNIQUE(prod_id, comp_id),
                            FOREIGN KEY (prod_id) REFERENCES product(id) ON DELETE CASCADE,
                            FOREIGN KEY (comp_id) REFERENCES product(id) ON DELETE CASCADE
                        )
                    ''')
                    self.conn.commit()
                    # повторное создание таблиц для сброса id autoincrement

                    messagebox.showinfo("Success", "All data successfully deleted.")
                    self.load_products()
                except Exception as e:
                    messagebox.showerror("Error", f"Error {e} occurred while deleting data.")

        confirm_delete_window = Toplevel(self.root)
        confirm_delete_window.title("Confirm Delete")

        Label(confirm_delete_window, text="Are you sure you want to delete all data from all tables?").grid(row=0, column=0, columnspan=2, padx=6, pady=10)

        Button(confirm_delete_window, text="OK", command=confirm_delete).grid(row=1, column=0, padx=6, pady=10)
        Button(confirm_delete_window, text="Cancel", command=confirm_delete_window.destroy).grid(row=1, column=1, padx=6, pady=10)





    def add_example_data(self):

        self.cursor.execute("INSERT INTO unit (unit_name, unit_name_short) VALUES ('килограмм', 'кг')")
        self.cursor.execute("INSERT INTO unit (unit_name, unit_name_short) VALUES ('штук', 'шт')")
        self.cursor.execute("INSERT INTO unit (unit_name, unit_name_short) VALUES ('метр', 'м')")
        self.cursor.execute("INSERT INTO unit (unit_name, unit_name_short) VALUES ('квадратный метр', 'м2')")
        self.cursor.execute("INSERT INTO unit (unit_name, unit_name_short) VALUES ('кубический метр', 'м3')")
        self.cursor.execute("INSERT INTO unit (unit_name, unit_name_short) VALUES ('миллиметр', 'мм')")
        self.cursor.execute("INSERT INTO unit (unit_name, unit_name_short) VALUES ('ватт', 'вт')")
        self.cursor.execute("INSERT INTO unit (unit_name, unit_name_short) VALUES ('вольт', 'в')")
        self.cursor.execute("INSERT INTO unit (unit_name, unit_name_short) VALUES ('ампер', 'а')")



        # добавление корневых категорий
        self.cursor.execute('INSERT INTO category (category_name, id_parent) VALUES (?, NULL)', ('неопределенные',)) #1
        self.cursor.execute('INSERT INTO category (category_name, id_parent) VALUES (?, NULL)', ('изделия',)) #2

        ##
        self.cursor.execute('INSERT INTO category (category_name, id_parent) VALUES (?, ?)', ("столы", 2)) #3

        self.cursor.execute('INSERT INTO category (category_name, id_parent) VALUES (?, ?)', ("столы-металл", 3)) #4

        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('стол_arizone', 4, 2, 110, 2500.0)")
        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('стол_garden_story', 4, 2, 54, 5665.0)")
        #

        self.cursor.execute('INSERT INTO category (category_name, id_parent) VALUES (?, ?)', ("столы-дерево", 3)) #5

        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('стол_эстер', 5, 2, 124, 6460.0)")
        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('стол_кентуки', 5, 2, 1340, 2400.0)")

        ##
        self.cursor.execute('INSERT INTO category (category_name, id_parent) VALUES (?, ?)', ("стулья", 2)) #6

        self.cursor.execute('INSERT INTO category (category_name, id_parent) VALUES (?, ?)', ("стулья-пластик", 6)) #7


        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('стул_rambo', 7, 2, 435, 1580.0)")
        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('стул_keter', 7, 2, 252, 1300.0)")

        #
        self.cursor.execute('INSERT INTO category (category_name, id_parent) VALUES (?, ?)', ("стулья-металл", 6)) #8


        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('стул_arizone', 8, 2, 245, 3400.0)")
        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('стул_giardino', 8, 2, 25, 2400.0)")

        ##
        self.cursor.execute('INSERT INTO category (category_name, id_parent) VALUES (?, ?)', ("кресла", 2)) #9

        self.cursor.execute('INSERT INTO category (category_name, id_parent) VALUES (?, ?)', ("кресла-кресло_кокон", 9)) #10

        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('кресло-m-group', 10, 2, 24, 12000.0)")
        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('кресло-гамак', 10, 2, 14, 15500.0)")
        #

        self.cursor.execute('INSERT INTO category (category_name, id_parent) VALUES (?, ?)', ("кресла-двухместное_кресло", 9)) #11

        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('кресло-gemini_promob', 11, 2, 4, 8999.0)")
        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('кресло-парящая_кровать', 11, 2, 54, 9999.0)")


        # coursework-2

        self.cursor.execute('INSERT INTO category (category_name, id_parent, id_unit) VALUES (?, ?, ?)', ("ножка стола", 3, 6)) #12
        self.cursor.execute('INSERT INTO category (category_name, id_parent, id_unit) VALUES (?, ?, ?)', ("основание ножки стола", 12, 6)) #13
        self.cursor.execute('INSERT INTO category (category_name, id_parent, id_unit) VALUES (?, ?, ?)', ("крепление ножки стола", 12, 6)) #14

        self.cursor.execute('INSERT INTO category (category_name, id_parent, id_unit) VALUES (?, ?, ?)', ("столешница стола", 3, 6)) #15
        self.cursor.execute('INSERT INTO category (category_name, id_parent, id_unit) VALUES (?, ?, ?)', ("основная часть столешница", 15, 6)) #16
        self.cursor.execute('INSERT INTO category (category_name, id_parent, id_unit) VALUES (?, ?, ?)', ("крепления столешницы стола", 15, 6)) #17



        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('ножка_стола_стальная', 12, 6, 440, 200.0)")
        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('основание-ножка_стола_стальная', 13, 6, 880, 10.0)")
        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('крепление-ножка_стола_стальная', 14, 6, 880, 10.0)")

        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('столешница_стола_стальная', 15, 6, 110, 800.0)")
        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('основа-столешница_стола_стальная', 16, 6, 110, 400.0)")
        self.cursor.execute("INSERT INTO product (product_name, id_category, id_unit, quantity, price) VALUES ('крепление-столешница_стола_стальная', 17, 6, 110, 200.0)")


        self.cursor.execute('INSERT INTO acceptable_components (class_id, component_id)  VALUES (?, ?)', (3, 12)) # для "столы" ножки
        self.cursor.execute('INSERT INTO acceptable_components (class_id, component_id)  VALUES (?, ?)', (3, 15)) # для "столы" столешницы

        # чтобы отдельно не писать для каждого стола можно вызвать функцию
        # inherit_acceptable_components(cl_name), где cl_name - класс для которого
        # хотим наследоваться

        # self.cursor.execute('INSERT INTO acceptable_components (class_id, component_id)  VALUES (?, ?)', (4, 12))

        self.cursor.execute('INSERT INTO acceptable_components (class_id, component_id)  VALUES (?, ?)', (12, 13))
        self.cursor.execute('INSERT INTO acceptable_components (class_id, component_id)  VALUES (?, ?)', (12, 14))


        self.cursor.execute('INSERT INTO acceptable_components (class_id, component_id)  VALUES (?, ?)', (15, 16))
        self.cursor.execute('INSERT INTO acceptable_components (class_id, component_id)  VALUES (?, ?)', (15, 17))



        self.cursor.execute('INSERT INTO prod_position_union (prod_id, comp_id, quantity)  VALUES (?, ?, ?)', (1, 13, 4)) # ножка_стола_стальная

        self.cursor.execute('INSERT INTO prod_position_union (prod_id, comp_id, quantity)  VALUES (?, ?, ?)', (13, 14, 1)) # основание-ножка_стола_стальная
        self.cursor.execute('INSERT INTO prod_position_union (prod_id, comp_id, quantity)  VALUES (?, ?, ?)', (13, 15, 1)) # крепление-ножка_стола_стальная



        self.cursor.execute('INSERT INTO prod_position_union (prod_id, comp_id, quantity)  VALUES (?, ?, ?)', (1, 16, 4)) # столешница_стола_стальная

        self.cursor.execute('INSERT INTO prod_position_union (prod_id, comp_id, quantity)  VALUES (?, ?, ?)', (16, 17, 1)) # основа-столешница_стола_стальная
        self.cursor.execute('INSERT INTO prod_position_union (prod_id, comp_id, quantity)  VALUES (?, ?, ?)', (16, 18, 1)) # крепление-столешница_стола_стальная





        self.conn.commit()


    def __del__(self):
        self.conn.close()












###################################################################################################################




class DatabaseUserApp:

    def __init__(self, root):
        self.root = root
        self.root.title("coursework")
        root.geometry("1000x600")

        self.conn = sqlite3.connect(path)
        self.cursor = self.conn.cursor()

        self.tree = ttk.Treeview(root, show="headings")
        self.tree.grid(row=0, column=0, columnspan=5, sticky="nsew", padx=6, pady=10)



        self.load_button = ttk.Button(root, text="Load Products", command=self.load_products)
        self.load_button.grid(row=1, column=0, sticky="ew", padx=6, pady=2)




        self.load_find_components_by_objectbutton = ttk.Button(root, text="find components by object ", command=self.load_find_components_by_object)
        self.load_find_components_by_objectbutton.grid(row=5, column=0, sticky="ew", padx=6, pady=2)

        self.find_components_recursive_object_button = ttk.Button(root, text="find components recursive", command=self.find_components_recursive)
        self.find_components_recursive_object_button.grid(row=6, column=0, sticky="ew", padx=6, pady=2)

        self.load_existing_acceptable_components_by_object_button = ttk.Button(root, text="available components category", command=self.load_existing_acceptable_components_by_object)
        self.load_existing_acceptable_components_by_object_button.grid(row=7, column=0, sticky="ew", padx=6, pady=2)

        self.load_existing_acceptable_components_by_object_recursive_button = ttk.Button(root, text="available components recursive category", command=self.load_existing_acceptable_components_by_object_recursive)
        self.load_existing_acceptable_components_by_object_recursive_button.grid(row=8, column=0, sticky="ew", padx=6, pady=2)



        self.load_category_button = ttk.Button(root, text="Load Categories", command=self.load_categories)
        self.load_category_button.grid(row=1, column=1, sticky="ew", padx=6, pady=2)




        self.show_parents_button = ttk.Button(root, text="Show Parents", command=self.show_category_parents)
        self.show_parents_button.grid(row=5, column=1, sticky="ew", padx=6, pady=2)

        self.show_children_button = ttk.Button(root, text="Show Children", command=self.show_category_children)
        self.show_children_button.grid(row=6, column=1, sticky="ew", padx=6, pady=2)

        self.show_products_button = ttk.Button(root, text="Show products", command=self.show_products_for_category)
        self.show_products_button.grid(row=7, column=1, sticky="ew", padx=6, pady=2)

        self.load_acceptable_components_by_class_button = ttk.Button(root, text="Show acceptable components by class", command=self.load_acceptable_components_by_class)
        self.load_acceptable_components_by_class_button.grid(row=8, column=1, sticky="ew", padx=6, pady=2)

        self.load_acceptable_components_by_class_recursive_button = ttk.Button(root, text="Show acceptable components by class recoursive", command=self.load_acceptable_components_by_class_recursive)
        self.load_acceptable_components_by_class_recursive_button.grid(row=9, column=1, sticky="ew", padx=6, pady=2)




        self.load_unit_button = ttk.Button(root, text="Load Unit", command=self.load_unit)
        self.load_unit_button.grid(row=1, column=2, sticky="ew", padx=6, pady=2)



        self.load_acceptable_components_button = ttk.Button(root, text="Load acceptable components", command=self.load_acceptable_component)
        self.load_acceptable_components_button.grid(row=1, column=3, sticky="ew", padx=6, pady=2)




        self.load_prod_position_union_button = ttk.Button(root, text="Load prod position union", command=self.load_prod_position_union)
        self.load_prod_position_union_button.grid(row=1, column=4, sticky="ew", padx=6, pady=2)




        # Configure row and column to resize
        root.rowconfigure(0, weight=1)
        root.columnconfigure(0, weight=1)
        root.columnconfigure(1, weight=1)
        root.columnconfigure(2, weight=1)
        root.columnconfigure(3, weight=1)
        root.columnconfigure(4, weight=1)



        def create_category_table():
            self.cursor.execute('''CREATE TABLE IF NOT EXISTS category
                            (id INTEGER PRIMARY KEY AUTOINCREMENT,
                                id_parent INTEGER CHECK (id_parent != id),
                                category_name TEXT UNIQUE,
                                id_unit INTEGER,
                                FOREIGN KEY (id_parent) REFERENCES category(id))''')
            self.conn.commit()


        def create_product_table():
            self.cursor.execute('''CREATE TABLE IF NOT EXISTS product
                            (id INTEGER PRIMARY KEY AUTOINCREMENT,
                                id_category INTEGER,
                                id_unit INTEGER,
                                product_name TEXT NOT NULL,
                                quantity INTEGER DEFAULT 0,
                                price REAL DEFAULT 0,
                                FOREIGN KEY (id_unit) REFERENCES unit(id),
                                FOREIGN KEY (id_category) REFERENCES category(id))''')
            self.conn.commit()


        def create_unit_table():
            self.cursor.execute('''CREATE TABLE IF NOT EXISTS unit
                            (id INTEGER PRIMARY KEY AUTOINCREMENT,
                                unit_name TEXT NOT NULL UNIQUE,
                                unit_name_short TEXT NOT NULL)''')
            self.conn.commit()

        def create_acceptable_components_table():
            self.cursor.execute('''
                CREATE TABLE IF NOT EXISTS acceptable_components (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    class_id INTEGER NOT NULL,
                    component_id INTEGER NOT NULL,
                    UNIQUE(class_id, component_id),
                    FOREIGN KEY (class_id) REFERENCES category(id) ON DELETE CASCADE,
                    FOREIGN KEY (component_id) REFERENCES category(id) ON DELETE CASCADE
                )
            ''')
            self.conn.commit()

        def create_prod_position_union_table():
            self.cursor.execute('''
                CREATE TABLE IF NOT EXISTS prod_position_union (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    prod_id INTEGER NOT NULL,
                    comp_id INTEGER NOT NULL,
                    quantity INTEGER NOT NULL CHECK (quantity > 0),
                    UNIQUE(prod_id, comp_id),
                    FOREIGN KEY (prod_id) REFERENCES product(id) ON DELETE CASCADE,
                    FOREIGN KEY (comp_id) REFERENCES product(id) ON DELETE CASCADE
                )
            ''')
            self.conn.commit()

        def creating_tables():
            create_category_table()
            create_product_table()
            create_unit_table()

            # coursework-2
            create_acceptable_components_table()
            create_prod_position_union_table()


        creating_tables()


    def load_unit(self):
        # Очистка текущих данных из Treeview
        for row in self.tree.get_children():
            self.tree.delete(row)

        # Получение данных из таблицы unit
        self.cursor.execute("SELECT * FROM unit")
        rows = self.cursor.fetchall()
        column_names = [description[0] for description in self.cursor.description]

        # Очистка старых заголовков столбцов
        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)  # Устанавливаем ширину столбцов

        # Вставка данных в Treeview
        for row in rows:
            self.tree.insert("", "end", values=row)


    def load_products(self):
        # Очистка текущих данных из Treeview
        for row in self.tree.get_children():
            self.tree.delete(row)

        # Получение данных из таблицы product
        self.cursor.execute("SELECT * FROM product")
        rows = self.cursor.fetchall()
        column_names = [description[0] for description in self.cursor.description]

        # Очистка старых заголовков столбцов
        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)  # Устанавливаем ширину столбцов

        # Вставка данных в Treeview
        for row in rows:
            self.tree.insert("", END, values=row)


    def load_categories(self):
        # Очистка текущих данных из Treeview
        for row in self.tree.get_children():
            self.tree.delete(row)

        # Получение данных из таблицы category
        self.cursor.execute("SELECT * FROM category")
        rows = self.cursor.fetchall()
        column_names = [description[0] for description in self.cursor.description]

        # Очистка старых заголовков столбцов
        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)  # Устанавливаем ширину столбцов

        # Вставка данных в Treeview
        for row in rows:
            self.tree.insert("", END, values=row)



    def load_products(self):
        # Очистка текущих данных из Treeview
        for row in self.tree.get_children():
            self.tree.delete(row)

        # Получение данных из таблицы product
        self.cursor.execute("SELECT * FROM product")
        rows = self.cursor.fetchall()
        column_names = [description[0] for description in self.cursor.description]

        # Очистка старых заголовков столбцов
        self.tree["columns"] = column_names
        for col in self.tree["columns"]:
            self.tree.heading(col, text=col)
            self.tree.column(col, width=100)  # Устанавливаем ширину столбцов

        # Вставка данных в Treeview
        for row in rows:
            self.tree.insert("", END, values=row)



    # additional interface function only (several getters)

    def show_category_parents(self):
        try:
            selected_item = self.tree.selection()[0]
            selected_category = self.tree.item(selected_item)['values']
            category_id = selected_category[0]

            self.cursor.execute("SELECT category_name FROM category WHERE id = ?", (category_id,))
            clicked_category_name = self.cursor.fetchone()[0]

            # Получаем все предки выбранной категории
            parents = []

            while category_id:
                self.cursor.execute("SELECT id, id_parent, category_name FROM category WHERE id = ?", (category_id,))
                result = self.cursor.fetchone()
                if not result:
                    break
                id, parent_id, category_name = result
                # print(f'\n\nresult - {result}\n\n')

                parents.append([id, parent_id, category_name])
                category_id = parent_id

            # Отображаем новое окно с предками категории
            parent_window = Toplevel(self.root)
            parent_window.minsize(600, 300)
            parent_window.title("Category Parents")

            # Получаем имена столбцов из таблицы category
            self.cursor.execute("PRAGMA table_info(category)")
            columns_info = self.cursor.fetchall()
            column_names = [info[1] for info in columns_info]

            # Создаем Treeview для отображения предков
            parent_tree = ttk.Treeview(parent_window, columns=column_names, show='headings')
            parent_tree.pack(expand=True, fill='both')


            self.cursor.execute("SELECT id, id_parent, category_name FROM category WHERE category_name = ?", (clicked_category_name,))
            result_to_del = self.cursor.fetchone()

            id_self, parent_id_self, category_name_self = result_to_del
            parents.remove([id_self, parent_id_self, category_name_self])

            # Устанавливаем заголовки столбцов
            for col in column_names:
                parent_tree.heading(col, text=col)
                parent_tree.column(col, width=100)




            # Вставляем данные предков в Treeview
            for parent in reversed(parents):  # Обратный порядок для отображения от корня к категории
                parent_tree.insert('', 'end', values=parent)

        except IndexError:
            messagebox.showerror("Error", "No category selected.")



    def show_category_children(self):
        try:
            selected_item = self.tree.selection()[0]
            selected_category = self.tree.item(selected_item)['values']
            category_id = selected_category[0]

            # Рекурсивно получаем всех потомков выбранной категории
            children = self.get_all_children(category_id)

            # Отображаем новое окно с потомками категории
            child_window = Toplevel(self.root)
            child_window.minsize(300, 100)
            child_window.title("Category Children")

            # Получаем имена столбцов из таблицы category
            self.cursor.execute("PRAGMA table_info(category)")
            columns_info = self.cursor.fetchall()
            column_names = [info[1] for info in columns_info]

            # Создаем Treeview для отображения предков
            parent_tree = ttk.Treeview(child_window, columns=column_names, show='headings')
            parent_tree.pack(expand=True, fill='both')

            # Устанавливаем заголовки столбцов
            for col in column_names:
                parent_tree.heading(col, text=col)
                parent_tree.column(col, width=100)

            for parent in children:  # Обратный порядок для отображения от корня к категории
                parent_tree.insert('', 'end', values=parent)

        except IndexError:
            messagebox.showerror("Error", "No category selected.")


    def get_all_children(self, category_id):
        children = []

        # Получаем все дочерние категории для данного родителя
        self.cursor.execute("SELECT id, id_parent, category_name FROM category WHERE id_parent = ?", (category_id,))
        result = self.cursor.fetchall()
        # print(f'\nresult in children - {result}\n')
        for row in result:
            id, id_parent, category_name = row
            children.append([id, id_parent, category_name])  # Добавляем имя дочерней категории
            children.extend(self.get_all_children(row[0]))  # Рекурсивно добавляем всех потомков для каждой дочерней категории

        return children



    def show_products_for_category(self):
        def get_all_children(category_id):
            children = []
            self.cursor.execute("SELECT id FROM category WHERE id_parent = ?", (category_
Соседние файлы в папке курсач