Файл с партнерами: Partners_import.xlsx
Файл с типами продукции: Product_type_import.xlsx
Файл с продуктами: Products_import.xlsx
Файл с продажами: Partner_products_import.xlsx


# Импортируем библиотеку SQLite3 для взаимодействия с базами данных SQLite
import sqlite3
# Подключаем библиотеку Pandas для обработки и анализа данных
import pandas as pd
# Подключаем модуль операционной системы Python для работы с файлами и путями
import os
# Подключаем модуль sys для взаимодействия с интерпретатором Python и системой
import sys
# Подключаем библиотеку OpenPyXL для чтения и записи файлов Excel формата .xlsx
import openpyxl


import sqlite3
import pandas as pd
import os
import sys
import openpyxl

# Функция создает структуру таблиц в базе данных
def create_tables(db_connection):
    """Создает все необходимые таблицы в базе данных."""
    cursor = db_connection.cursor()

    # Создание таблиц и индексов
    cursor.executescript('''
    ...
    ''')  # Здесь прописаны запросы на создание таблиц и индексов

    db_connection.commit()
    print("✅ Таблицы успешно созданы")


# Функция рассчитывает скидку на основе объема продаж
def calculate_discount(total_quantity):
    """Рассчитывает скидку на основе общего количества проданной продукции."""
    if total_quantity >= 300000:
        return 15, '15% (более 300000 ед.)'
    elif total_quantity >= 50000:
        return 10, '10% (50000-300000 ед.)'
    elif total_quantity >= 10000:
        return 5, '5% (10000-50000 ед.)'
    else:
        return 0, '0% (до 10000 ед.)'


# Функция получает данные о партнерах из базы данных
def get_partners(db_path='partners.db', sort_by='rating', ascending=False):
    """Получает данные о партнерах с возможностью сортировки."""
    try:
        conn = sqlite3.connect(db_path)
        query = """
        ...
        """  # Здесь прописан SQL-запрос для выборки данных о партнерах

        # Применяем нужную сортировку и лимитируем количество записей
        if sort_by == 'discount':
            query += " ORDER BY total_quantity"
        elif sort_by == 'rating':
            query += " ORDER BY p.rating"
        elif sort_by == 'name':
            query += " ORDER BY p.name"
        elif sort_by == 'type':
            query += " ORDER BY pt.type_name, p.name"
        else:
            query += " ORDER BY p.rating"

        query += " DESC" if not ascending else " ASC"

        df = pd.read_sql_query(query, conn)
        conn.close()

        # Добавляем дополнительные колонки со скидкой
        if not df.empty:
            df['Скидка'] = df['total_quantity'].apply(lambda x: calculate_discount(x)[0])
            df['Текст_скидки'] = df['total_quantity'].apply(lambda x: calculate_discount(x)[1])

        return df

    except sqlite3.Error as e:
        print(f"❌ Ошибка базы данных: {e}")
        return None
    except Exception as e:
        print(f"❌ Общая ошибка: {e}")
        return None


# Функция получает историю продаж
def get_sales_history(db_path='partners.db', limit=50, sort_by='date_desc'):
    """Получает историю реализации продукции с разными вариантами сортировки."""
    try:
        conn = sqlite3.connect(db_path)
        query = """
        ...
        """  # Здесь прописан SQL-запрос для выборки истории продаж

        # Применяем сортировку и ограничение числа записей
        if sort_by == 'date_desc':
            query += " ORDER BY s.sale_date DESC, s.created_at DESC"
        elif sort_by == 'date_asc':
            query += " ORDER BY s.sale_date ASC, s.created_at ASC"
        elif sort_by == 'quantity_desc':
            query += " ORDER BY s.quantity DESC"
        elif sort_by == 'amount_desc':
            query += " ORDER BY (s.quantity * s.sale_price) DESC"
        else:
            query += " ORDER BY s.sale_date DESC, s.created_at DESC"

        query += " LIMIT ?"

        df = pd.read_sql_query(query, conn, params=(limit,))
        conn.close()
        return df
    except Exception as e:
        print(f"❌ Ошибка при получении истории продаж: {e}")
        return None


# Функция выводит информацию о партнерах в красивой форме
def print_partner_cards(partners_df):
    """Выводит карточки партнеров в красивом формате."""
    if partners_df is None or partners_df.empty:
        print("📭 Нет данных о партнерах")
        return

    # Красивый вывод карточек партнеров
    for index, row in partners_df.iterrows():
        # Оформление рамки вокруг карточки
        print("╔" + "═" * 69 + "╗")
        print(f"║ {'КАРТОЧКА ПАРТНЕРА':^67} ║")
        print("╠" + "═" * 69 + "╣")

        # Информация о партнере
        print(f"║ Тип: {row['Тип партнера']}{' ':<63}║")
        print(f"║ Наименование: {row['Наименование партнера']}{' ':<50}║")
        print(f"║ Директор: {row['Директор']}{' ':<61}║")
        print(f"║ Рейтинг: {row['Рейтинг']}{' ':<63}║")
        print(f"║ Продано единиц: {row['total_quantity']:,}{' ':<52}║")
        print(f"║ Скидка: {row['Текст_скидки']}{' ':<58}║")
        print(f"║ {' ':<67}║")
        print(f"║ Электронная почта: {row['Электронная почта']}{' ':<45}║")
        print(f"║ Телефон: {row['Телефон']}{' ':<61}║")
        print(f"║ {' ':<67}║")
        print(f"║ ИНН: {row['ИНН']}{' ':<63}║")
        print(f"║ Адрес: {row['Юридический адрес']}{' ':<59}║")
        print("╚" + "═" * 69 + "╝")
        print()


# Функция выводит историю продаж в табличном представлении
def print_sales_cards(sales_df):
    """Выводит карточки истории реализации в виде таблицы."""
    if sales_df is None or sales_df.empty:
        print("📭 Нет данных о продажах")
        return

    # Рамка таблицы
    print("╔" + "═" * 147 + "╗")
    print(f"║ {'ИСТОРИЯ РЕАЛИЗАЦИИ ПРОДУКЦИИ':^145} ║")
    print("╠" + "═" * 147 + "╣")

    # Заголовок таблицы
    headers = ["Дата", "Партнер", "Продукция", "Артикул", "Кол-во", "Цена", "Сумма"]
    print("║ {:<12} {:<18} {:<59} {:<3} {:>9} {:>8} {:>13}              ║".format(*headers))
    print("╠" + "═" * 147 + "╣")

    # Вывод данных о продажах
    for index, row in sales_df.iterrows():
        date = str(row['Дата продажи'])[:10]
        partner = row['Партнер']
        product = row['Продукция']
        article = str(row['Артикул'])
        quantity = f"{row['Количество']:,}"
        price = f"{row['Цена за единицу']:,.2f}"
        total = f"{row['Общая сумма']:,.2f}"

        print(f"║ {date} ║ {partner.ljust(16)} ║ {product.ljust(57)} ║ {article.ljust(8)} ║ {quantity.ljust(8)} ║ {price.ljust(10)} ║ {total.ljust(18)} ║")

    # Закрывающая рамка таблицы
    print("╚" + "═" * 147 + "╝")

    # Итоговая статистика
    total_quantity = sales_df['Количество'].sum()
    total_amount = sales_df['Общая сумма'].sum()
    print(f"📊 ИТОГО: {len(sales_df)} продаж, {total_quantity:,} единиц, общая сумма: {total_amount:,.2f} руб.")


# Простая функция выбора пункта меню
def simple_choice(options):
    """Упрощенная функция выбора."""
    print("\n" + "=" * 50)
    print("ВЫБЕРИТЕ ОПЦИЮ:")
    print("=" * 50)
    for i, option in enumerate(options, 1):
        print(f"{i}. {option}")

    while True:
        try:
            choice = input(f"\nВведите номер (1-{len(options)}): ").strip()
            if choice.isdigit():
                choice_num = int(choice)
                if 1 <= choice_num <= len(options):
                    return options[choice_num - 1]
            print(f"❌ Пожалуйста, введите число от 1 до {len(options)}")
        except (ValueError, EOFError):
            print("❌ Неверный ввод. Попробуйте еще раз.")
        except KeyboardInterrupt:
            print("\n👋 Программа прервана пользователем.")
            sys.exit(0)


# Проверяет наличие данных в базе
def check_database():
    """Проверяет загруженные данные в базе."""
    conn = sqlite3.connect('partners.db')
    try:
        cursor = conn.cursor()
        print("\n🔍 Проверка загруженных данных:")
        tables = ['PartnerType', 'Partner', 'ProductType', 'Product', 'Sale']
        for table in tables:
            cursor.execute(f"SELECT COUNT(*) FROM {table}")
            count = cursor.fetchone()[0]
            print(f"   {table}: {count} записей")
    finally:
        conn.close()


# Загружает данные из Excel-файлов в базу данных
def load_data_from_files():
    """Загружает данные из Excel файлов в базу данных."""
    conn = sqlite3.connect('partners.db')
    cursor = conn.cursor()

    try:
        # 1. Загрузка типов партнеров
        print("\n1. 📊 Загрузка типов партнеров...")
        partners_df = pd.read_excel(input("Файл с партнерами: "))
        partner_types = partners_df['Тип партнера'].unique()
        for partner_type in partner_types:
            cursor.execute("INSERT OR IGNORE INTO PartnerType (type_name) VALUES (?)", (partner_type,))

        # 2. Загрузка партнеров
        print("2. 👥 Загрузка партнеров...")
        for _, row in partners_df.iterrows():
            cursor.execute("SELECT id FROM PartnerType WHERE type_name = ?", (row['Тип партнера'],))
            partner_type_id = cursor.fetchone()[0]

            cursor.execute("""
                INSERT OR IGNORE INTO Partner
                (partner_type_id, name, director, email, phone, legal_address, inn, rating)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
                           (partner_type_id, row['Наименование партнера'], row['Директор'],
                            row['Электронная почта партнера'], row['Телефон партнера'],
                            row['Юридический адрес партнера'], row['ИНН'], row['Рейтинг'])
                           )

        # 3. Загрузка типов продукции
        print("3. 📦 Загрузка типов продукции...")
        product_type_df = pd.read_excel(input("Файл с типами продукции: "))
        for _, row in product_type_df.iterrows():
            cursor.execute("INSERT OR IGNORE INTO ProductType (type_name, coefficient) VALUES (?, ?)",
                           (row['Тип продукции'], row['Коэффициент типа продукции'])
                           )

        # 4. Загрузка продуктов
        print("4. 🏷️ Загрузка продуктов...")
        products_df = pd.read_excel(input("Файл с продуктами: "))
        for _, row in products_df.iterrows():
            cursor.execute("SELECT id FROM ProductType WHERE type_name = ?", (row['Тип продукции'],))
            product_type_id = cursor.fetchone()[0]

            cursor.execute("""
                INSERT OR IGNORE INTO Product
                (product_type_id, product_name, article, min_partner_price)
                VALUES (?, ?, ?, ?)""",
                           (product_type_id, row['Наименование продукции'],
                            row['Артикул'], row['Минимальная стоимость для партнера'])
                           )

        # 5. Загрузка продаж
        print("5. 💰 Загрузка продаж...")
        sales_df = pd.read_excel(input("Файл с продажами: "))
        loaded_sales = 0

        for _, row in sales_df.iterrows():
            # Находим ID продукта
            cursor.execute("SELECT id FROM Product WHERE product_name = ?", (row['Продукция'],))
            product_result = cursor.fetchone()
            if not product_result:
                print(f"   ⚠️ Продукт не найден: {row['Продукция']}")
                continue
            product_id = product_result[0]

            # Находим ID партнера
            cursor.execute("SELECT id FROM Partner WHERE name = ?", (row['Наименование партнера'],))
            partner_result = cursor.fetchone()
            if not partner_result:
                print(f"   ⚠️ Партнер не найден: {row['Наименование партнера']}")
                continue
            partner_id = partner_result[0]

            # Получаем цену продажи
            cursor.execute("SELECT min_partner_price FROM Product WHERE id = ?", (product_id,))
            min_price_result = cursor.fetchone()
            sale_price = min_price_result[0] if min_price_result else 0

            # Преобразуем дату
            sale_date = pd.to_datetime(row['Дата продажи']).strftime('%Y-%m-%d')

            # Вставляем продажу
            cursor.execute("""
                INSERT INTO Sale
                (product_id, partner_id, quantity, sale_date, sale_price)
                VALUES (?, ?, ?, ?, ?)""",
                           (product_id, partner_id, row['Количество продукции'], sale_date, sale_price)
                           )
            loaded_sales += 1

        conn.commit()
        print(f"✅ Данные успешно загружены! Загружено {loaded_sales} продаж")
        check_database()
Файл с партнерами: Partners_import.xlsx
Файл с типами продукции: Product_type_import.xlsx
Файл с продуктами: Products_import.xlsx
Файл с продажами: Partner_products_import.xlsx

    except Exception as e:
        print(f"❌ Ошибка при загрузке данных: {e}")
        conn.rollback()
    finally:
        conn.close()


# Основное меню программы
def display_menu():
    """Главное меню программы."""
    menu_options = [
        'КАРТОЧКИ ПАРТНЕРОВ (сортировка по рейтингу)',
        'КАРТОЧКИ ПАРТНЕРОВ (сортировка по скидкам)',
        'ИСТОРИЯ РЕАЛИЗАЦИИ',
        'ЗАПОЛНЕНИЕ БД из файлов',
        'ВЫХОД'
    ]

    while True:
        choice = simple_choice(menu_options)

        if choice == 'КАРТОЧКИ ПАРТНЕРОВ (сортировка по рейтингу)':
            print("\n🎯 КАРТОЧКИ ПАРТНЕРОВ (сортировка по рейтингу)")
            print("═" * 70)
            partners = get_partners(sort_by='rating', ascending=False)
            print_partner_cards(partners)

        elif choice == 'КАРТОЧКИ ПАРТНЕРОВ (сортировка по скидкам)':
            print("\n📊 КАРТОЧКИ ПАРТНЕРОВ (сортировка по скидкам)")
            print("═" * 70)
            partners = get_partners(sort_by='discount', ascending=False)
            print_partner_cards(partners)

        elif choice == 'ИСТОРИЯ РЕАЛИЗАЦИИ':
            print("\n📈 ИСТОРИЯ РЕАЛИЗАЦИИ ПРОДУКЦИИ")
            print("═" * 70)
            sales = get_sales_history(limit=50)
            print_sales_cards(sales)

        elif choice == 'ЗАПОЛНЕНИЕ БД из файлов':
            if os.path.exists('partners.db'):
                os.remove('partners.db')
                print("🗑️ База данных partners.db удалена")
            else:
                print("ℹ️ База данных partners.db не найдена, создаем новую")

            conn = sqlite3.connect('partners.db')
            create_tables(conn)
            conn.close()
            load_data_from_files()

        elif choice == 'ВЫХОД':
            print("\n👋 До свидания!")
            break


# Главная точка запуска программы
if __name__ == "__main__":
    display_menu()


###1 def calculate_discount(total_quantity):
"""Рассчитывает скидку на основе общего количества проданной продукции

    Args:
        total_quantity (int): общее количество проданной продукции

    Returns:
        tuple: кортеж содержащий:
            - discount_percent (int): процент скидки
            - discount_description (str): текстовое описание скидки

    Discount tiers:
        - 15%: при объеме продаж от 300000 единиц
        - 10%: при объеме продаж от 50000 до 300000 единиц
        - 5%: при объеме продаж от 10000 до 50000 единиц
        - 0%: при объеме продаж менее 10000 единиц
    """
###2 def get_partners(db_path='partners.db', sort_by='rating', ascending=False):
"""Получает данные о партнерах из базы данных с возможностью сортировки и расчета скидок

    Args:
        db_path (str): путь к файлу базы данных SQLite. По умолчанию 'partners.db'
        sort_by (str): поле для сортировки. Допустимые значения:
            - 'rating': по рейтингу (по умолчанию)
            - 'discount': по общему количеству продаж (для расчета скидки)
            - 'name': по наименованию партнера
            - 'type': по типу партнера и наименованию
        ascending (bool): направление сортировки.
            - False: по убыванию (по умолчанию)
            - True: по возрастанию

    Returns:
        pandas.DataFrame или None: DataFrame с данными партнеров или None в случае ошибки

    Структура возвращаемого DataFrame:
        - Тип партнера
        - Наименование партнера
        - Директор
        - Электронная почта
        - Телефон
        - Юридический адрес
        - ИНН
        - Рейтинг
        - Дата создания
        - total_quantity: общее количество продаж (скрытое поле)
        - Скидка: процент скидки на основе total_quantity
        - Текст_скидки: текстовое описание скидки

    Raises:
        sqlite3.Error: ошибки работы с базой данных
        Exception: другие возможные ошибки

    Example:
        >>> df = get_partners(sort_by='discount', ascending=True)
        >>> df = get_partners('my_database.db', sort_by='name')
    """
### 3  def get_sales_history(db_path='partners.db', limit=50, sort_by='date_desc'):
    """Получает историю реализации продукции с разными вариантами сортировки

    Args:
        db_path (str): путь к файлу базы данных SQLite. По умолчанию 'partners.db'
        limit (int): ограничение количества возвращаемых записей. По умолчанию 50
        sort_by (str): критерий сортировки данных. Допустимые значения:
            - 'date_desc': по дате продажи (новые сверху, по умолчанию)
            - 'date_asc': по дате продажи (старые сверху)
            - 'quantity_desc': по количеству (по убыванию)
            - 'amount_desc': по общей сумме (по убыванию)

    Returns:
        pandas.DataFrame или None: DataFrame с историей продаж или None в случае ошибки

    Структура возвращаемого DataFrame:
        - Дата продажи: дата осуществления продажи
        - Партнер: наименование партнера
        - Продукция: название продукции
        - Артикул: артикул продукции
        - Количество: количество проданных единиц
        - Цена за единицу: цена за одну единицу продукции
        - Общая сумма: общая сумма продажи (рассчитывается как количество × цена)
        - Тип продукции: категория продукции

    Raises:
        Exception: ошибки при выполнении запроса к базе данных

    Example:
        >>> # Получить последние 50 продаж
        >>> df = get_sales_history()

        >>> # Получить 100 самых крупных продаж по сумме
        >>> df = get_sales_history(limit=100, sort_by='amount_desc')

        >>> # Получить историю продаж в хронологическом порядке
        >>> df = get_sales_history(sort_by='date_asc', limit=200)
    """
###4 def print_partner_cards(partners_df):
    """Выводит карточки партнеров в красивом формате с рамкой

    Args:
        partners_df (pandas.DataFrame): DataFrame с данными партнеров, полученный из функции get_partners()

    Returns:
        None: функция выполняет только вывод в консоль

    Формат вывода:
        Каждая карточка партнера оформлена в виде рамки с следующими полями:
        - Тип партнера
        - Наименование партнера
        - Директор
        - Рейтинг
        - Общее количество проданных единиц (форматированное с разделителями тысяч)
        - Размер и описание скидки
        - Электронная почта
        - Телефон
        - ИНН
        - Юридический адрес (обрезается до 60 символов если слишком длинный)

    Особенности:
        - Если передан пустой DataFrame или None, выводится сообщение об отсутствии данных
        - Адрес автоматически обрезается если превышает 60 символов
        - Числовые значения количества форматируются с разделителями тысяч
        - Между карточками добавляются пустые строки для лучшей читаемости

    Example:
        >>> partners_data = get_partners()
        >>> print_partner_cards(partners_data)

        ╔═══════════════════════════════════════════════════════════════════════╗
        ║                          КАРТОЧКА ПАРТНЕРА                           ║
        ╠═══════════════════════════════════════════════════════════════════════╣
        ║ Тип: Поставщик                                                       ║
        ║ Наименование: ООО "Ромашка"                                          ║
        ║ Директор: Иванов Иван Иванович                                       ║
        ║ Рейтинг: 4.8                                                         ║
        ║ Продано единиц: 150,000                                              ║
        ║ Скидка: 10% (50000-300000 ед.)                                       ║
        ║                                                                       ║
        ║ Контакты: info@romashka.ru                                           ║
        ║ Телефон: +7 (495) 123-45-67                                          ║
        ║                                                                       ║
        ║ ИНН: 7712345678                                                      ║
        ║ Адрес: г. Москва, ул. Ленина, д. 1, офис 25                          ║
        ╚═══════════════════════════════════════════════════════════════════════╝
    """
###5 def print_sales_cards(sales_df):
    """Выводит историю реализации продукции в виде форматированной таблицы с рамкой

    Args:
        sales_df (pandas.DataFrame): DataFrame с данными о продажах, полученный из функции get_sales_history()

    Returns:
        None: функция выполняет только вывод в консоль

    Формат вывода:
        Таблица с рамкой содержит следующие колонки:
        - Дата: дата продажи (обрезается до 10 символов)
        - Партнер: наименование партнера (максимум 16 символов)
        - Продукция: название продукции (максимум 57 символов)
        - Артикул: артикул продукции (максимум 8 символов)
        - Кол-во: количество проданных единиц (форматируется с разделителями тысяч)
        - Цена: цена за единицу (форматируется с двумя decimal places)
        - Сумма: общая сумма продажи (форматируется с двумя decimal places)

    Особенности:
        - Если передан пустой DataFrame или None, выводится сообщение об отсутствии данных
        - Все числовые значения форматируются с разделителями тысяч и двумя знаками после запятой
        - В конце таблицы выводятся итоговые показатели:
            * Количество продаж
            * Общее количество проданных единиц
            * Общая сумма всех продаж
        - Ширина таблицы фиксирована (147 символов) для сохранения форматирования

    Example:
        >>> sales_data = get_sales_history(limit=10)
        >>> print_sales_cards(sales_data)

        ╔═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
        ║                                                          ИСТОРИЯ РЕАЛИЗАЦИИ ПРОДУКЦИИ                                                               ║
        ╠═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
        ║ Дата         Партнер           Продукция                                                  Арт   Кол-во      Цена           Сумма                      ║
        ╠═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╣
        ║ 2024-01-15 ║ ООО "Ромашка"   ║ Процессор Intel Core i7-13700K                           ║ A123  ║    150 ║ 25,000.00 ║     3,750,000.00 ║
        ║ 2024-01-14 ║ ИП Петров       ║ Монитор Samsung Odyssey G7 27"                          ║ B456  ║     50 ║ 35,000.00 ║     1,750,000.00 ║
        ╚═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
        📊 ИТОГО: 2 продаж, 200 единиц, общая сумма: 5,500,000.00 руб.
    """
###6  def check_database():
 """Упрощенная функция выбора опции из списка с валидацией ввода

    Args:
        options (list): список строк с доступными опциями для выбора

    Returns:
        str: выбранная опция из списка options

    Особенности:
        - Выводит пронумерованный список опций в красивом формате
        - Запрашивает ввод пользователя с валидацией
        - Обрабатывает некорректный ввод и повторяет запрос
        - Обрабатывает прерывание программы (Ctrl+C) с graceful shutdown
        - Поддерживает ввод только цифровых значений в допустимом диапазоне

    Raises:
        SystemExit: при прерывании программы пользователем (KeyboardInterrupt)

    Example:
        >>> options = ["Показать всех партнеров", "История продаж", "Выход"]
        >>> choice = simple_choice(options)

        ==================================================
        ВЫБЕРИТЕ ОПЦИЮ:
        ==================================================
        1. Показать всех партнеров
        2. История продаж
        3. Выход

        Введите номер (1-3): 2
        >>> print(choice)
        "История продаж"

    Обработка ошибок:
        - Некорректный ввод (не цифры): повторный запрос
        - Число вне диапазона: повторный запрос
        - Прерывание (Ctrl+C): graceful exit программы
        - EOF (Ctrl+D в Unix): обрабатывается как некорректный ввод
    """
"""Проверяет загруженные данные в базе данных и выводит статистику по таблицам

    Функция подключается к SQLite базе данных и подсчитывает количество записей
    в каждой из основных таблиц системы для проверки целостности данных.

    Args:
        None: использует фиксированный путь к базе данных 'partners.db'

    Returns:
        None: функция выполняет только вывод статистики в консоль

    Проверяемые таблицы:
        - PartnerType: типы партнеров (поставщики, клиенты и т.д.)
        - Partner: основные данные о партнерах
        - ProductType: категории продукции
        - Product: данные о продукции
        - Sale: история продаж

    Особенности:
        - Автоматически закрывает соединение с базой данных используя try-finally
        - Выводит результаты в читаемом формате с эмодзи для наглядности
        - Не обрабатывает ошибки явно - предполагается что база данных существует
          и доступна для чтения

    Example:
        >>> check_database()

        🔍 Проверка загруженных данных:
           PartnerType: 3 записей
           Partner: 15 записей
           ProductType: 5 записей
           Product: 25 записей
           Sale: 150 записей

    Note:
        Для работы функции требуется существование файла 'partners.db' и всех
        указанных таблиц в базе данных. В случае отсутствия таблиц может
        возникнуть исключение sqlite3.OperationalError.
    """
###7 def load_data_from_files():
    """Загружает данные из Excel файлов в базу данных SQLite

    Функция выполняет полную загрузку данных из четырех Excel файлов в соответствующие таблицы базы данных.
    Процесс загрузки состоит из пяти этапов, выполняемых последовательно с проверкой целостности данных.

    Args:
        None: имена файлов запрашиваются у пользователя через интерактивный ввод

    Returns:
        None: функция выполняет операции с базой данных и выводит результаты в консоль

    Процесс загрузки:
        1. 📊 Типы партнеров - из файла партнеров извлекаются уникальные типы
        2. 👥 Партнеры - загрузка основных данных о партнерах с привязкой к типам
        3. 📦 Типы продукции - загрузка категорий продукции с коэффициентами
        4. 🏷️ Продукты - загрузка данных о продукции с привязкой к типам
        5. 💰 Продажи - загрузка истории продаж с валидацией связей и преобразованием дат

    Требуемые файлы:
        - Файл с партнерами: содержит данные о партнерах и их типах
        - Файл с типами продукции: содержит категории продукции и коэффициенты
        - Файл с продуктами: содержит данные о продукции с привязкой к типам
        - Файл с продажами: содержит историю продаж с ссылками на партнеров и продукты

    Особенности:
        - Использует INSERT OR IGNORE для избежания дублирования записей
        - Выполняет проверку существования связанных записей перед вставкой продаж
        - Преобразует даты в стандартный SQL формат (YYYY-MM-DD)
        - Автоматически рассчитывает цену продажи на основе минимальной партнерской цены
        - В случае ошибки выполняет откат транзакции (rollback)
        - После успешной загрузки вызывает check_database() для отображения статистики

    Обработка ошибок:
        - Отлавливает и выводит подробные сообщения об ошибках
        - Продолжает загрузку при отсутствии некоторых продуктов/партнеров с предупреждениями
        - Подсчитывает и выводит количество успешно загруженных продаж

    Example:
        >>> load_data_from_files()

        📁 Введите имена файлов:
        Файл с партнерами: partners.xlsx
        Файл с типами продукции: product_types.xlsx
        Файл с продуктами: products.xlsx
        Файл с продажами: sales.xlsx

        1. 📊 Загрузка типов партнеров...
        2. 👥 Загрузка партнеров...
        3. 📦 Загрузка типов продукции...
        4. 🏷️ Загрузка продуктов...
        5. 💰 Загрузка продаж...
        ✅ Данные успешно загружены! Загружено 150 продаж

    Note:
        Для работы функции требуются файлы в формате Excel (.xlsx) с определенной структурой колонок,
        соответствующих ожидаемым названиям в коде.
    """
###8 def display_menu():
    """Главное меню программы для управления базой данных партнеров и продаж

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

    Args:
        None: все параметры задаются внутри функции или запрашиваются у пользователя

    Returns:
        None: функция выполняется до выбора опции выхода

    Основные функции меню:
        1. КАРТОЧКИ ПАРТНЕРОВ (сортировка по рейтингу) - отображение партнеров, отсортированных по рейтингу
        2. КАРТОЧКИ ПАРТНЕРОВ (сортировка по скидкам) - отображение партнеров, отсортированных по уровню скидки
        3. ИСТОРИЯ РЕАЛИЗАЦИИ - просмотр последних 50 записей о продажах
        4. ЗАПОЛНЕНИЕ БД из файлов - полная переинициализация базы данных с загрузкой из Excel файлов
        5. ВЫХОД - завершение работы программы

    Особенности работы:
        - Использует simple_choice() для интерактивного выбора опций
        - Бесконечный цикл до выбора опции выхода
        - При выборе загрузки данных удаляет существующую базу и создает новую
        - Автоматически создает необходимые таблицы при инициализации базы
        - Обеспечивает единообразное форматирование вывода для всех опций

    Flow программы:
        while True:
            Показать меню опций
            Получить выбор пользователя
            Выполнить соответствующую функцию
            Если выбран ВЫХОД - прервать цикл

    Example:
        ==================================================
        ВЫБЕРИТЕ ОПЦИЮ:
        ==================================================
        1. КАРТОЧКИ ПАРТНЕРОВ (сортировка по рейтингу)
        2. КАРТОЧКИ ПАРТНЕРОВ (сортировка по скидкам)
        3. ИСТОРИЯ РЕАЛИЗАЦИИ
        4. ЗАПОЛНЕНИЕ БД из файлов
        5. ВЫХОД

        Введите номер (1-5): 1

        🎯 КАРТОЧКИ ПАРТНЕРОВ (сортировка по рейтингу)
        ══════════════════════════════════════════════════════════════════════
        [вывод карточек партнеров...]

    Dependencies:
        - simple_choice(): для выбора опций меню
        - get_partners(): для получения данных партнеров
        - print_partner_cards(): для форматированного вывода партнеров
        - get_sales_history(): для получения истории продаж
        - print_sales_cards(): для форматированного вывода продаж
        - create_tables(): для создания структуры базы данных
        - load_data_from_files(): для загрузки данных из файлов
    """