rim_project/main.py
2025-10-23 14:45:22 +05:00

973 lines
42 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import sqlite3
import pandas as pd
import os
import sys
from datetime import datetime, timedelta
def create_tables(db_connection):
"""Создает все необходимые таблицы в базе данных"""
cursor = db_connection.cursor()
cursor.executescript('''
CREATE TABLE IF NOT EXISTS PartnerType (
id INTEGER PRIMARY KEY AUTOINCREMENT,
type_name VARCHAR(100) NOT NULL UNIQUE
);
CREATE TABLE IF NOT EXISTS Partner (
id INTEGER PRIMARY KEY AUTOINCREMENT,
partner_type_id INTEGER REFERENCES PartnerType(id),
name VARCHAR(255) NOT NULL,
director VARCHAR(255),
email VARCHAR(255),
phone VARCHAR(50),
legal_address TEXT,
inn VARCHAR(20) UNIQUE,
rating DECIMAL(3,2) DEFAULT 0.0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS ProductType (
id INTEGER PRIMARY KEY AUTOINCREMENT,
type_name VARCHAR(100) NOT NULL UNIQUE,
coefficient DECIMAL(5,2) NOT NULL DEFAULT 1.0
);
CREATE TABLE IF NOT EXISTS Product (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_type_id INTEGER REFERENCES ProductType(id),
product_name VARCHAR(255) NOT NULL,
article VARCHAR(100) UNIQUE NOT NULL,
min_partner_price DECIMAL(15,2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE IF NOT EXISTS Sale (
id INTEGER PRIMARY KEY AUTOINCREMENT,
product_id INTEGER REFERENCES Product(id),
partner_id INTEGER REFERENCES Partner(id),
quantity INTEGER NOT NULL CHECK (quantity > 0),
sale_date DATE NOT NULL,
sale_price DECIMAL(15,2) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_partner_type ON Partner(partner_type_id);
CREATE INDEX IF NOT EXISTS idx_partner_inn ON Partner(inn);
CREATE INDEX IF NOT EXISTS idx_product_type ON Product(product_type_id);
CREATE INDEX IF NOT EXISTS idx_product_article ON Product(article);
CREATE INDEX IF NOT EXISTS idx_sale_product ON Sale(product_id);
CREATE INDEX IF NOT EXISTS idx_sale_partner ON Sale(partner_id);
CREATE INDEX IF NOT EXISTS idx_sale_date ON Sale(sale_date);
''')
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 = """
SELECT
pt.type_name AS "Тип партнера",
p.name AS "Наименование партнера",
p.director AS "Директор",
p.email AS "Электронная почта",
p.phone AS "Телефон",
p.legal_address AS "Юридический адрес",
p.inn AS "ИНН",
p.rating AS "Рейтинг",
p.created_at AS "Дата создания",
COALESCE(SUM(s.quantity), 0) as total_quantity,
COALESCE(SUM(s.quantity * s.sale_price), 0) as total_sales
FROM Partner p
JOIN PartnerType pt ON p.partner_type_id = pt.id
LEFT JOIN Sale s ON p.id = s.partner_id
GROUP BY p.id
"""
# Добавляем сортировку
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"
elif sort_by == 'sales':
query += " ORDER BY total_sales"
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 = """
SELECT
s.sale_date AS "Дата продажи",
p.name AS "Партнер",
pr.product_name AS "Продукция",
pr.article AS "Артикул",
s.quantity AS "Количество",
s.sale_price AS "Цена за единицу",
(s.quantity * s.sale_price) AS "Общая сумма",
pt.type_name AS "Тип продукции"
FROM Sale s
JOIN Partner p ON s.partner_id = p.id
JOIN Product pr ON s.product_id = pr.id
JOIN ProductType pt ON pr.product_type_id = pt.id
"""
# Добавляем сортировку по дате
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 get_sales_statistics(db_path='partners.db', period='all'):
"""Получает статистику продаж за различные периоды"""
try:
conn = sqlite3.connect(db_path)
# Определяем условия для периода
if period == 'month':
date_condition = "WHERE s.sale_date >= date('now', 'start of month')"
elif period == 'quarter':
date_condition = "WHERE s.sale_date >= date('now', 'start of month', '-2 months')"
elif period == 'year':
date_condition = "WHERE s.sale_date >= date('now', 'start of year')"
else:
date_condition = ""
query = f"""
SELECT
COUNT(*) as total_sales,
SUM(s.quantity) as total_quantity,
SUM(s.quantity * s.sale_price) as total_amount,
AVG(s.quantity) as avg_quantity,
AVG(s.sale_price) as avg_price,
COUNT(DISTINCT s.partner_id) as unique_partners,
COUNT(DISTINCT s.product_id) as unique_products
FROM Sale s
{date_condition}
"""
stats = conn.execute(query).fetchone()
# Статистика по типам продукции
type_query = f"""
SELECT
pt.type_name,
SUM(s.quantity) as quantity,
SUM(s.quantity * s.sale_price) as amount,
COUNT(*) as sales_count
FROM Sale s
JOIN Product pr ON s.product_id = pr.id
JOIN ProductType pt ON pr.product_type_id = pt.id
{date_condition}
GROUP BY pt.type_name
ORDER BY amount DESC
"""
type_stats = conn.execute(type_query).fetchall()
conn.close()
return dict(stats), type_stats
except Exception as e:
print(f"❌ Ошибка при получении статистики: {e}")
return None, None
def export_partners_to_excel(db_path='partners.db', filename='partners_export.xlsx'):
"""Экспортирует данные о партнерах в Excel файл"""
try:
partners_df = get_partners(db_path, sort_by='name', ascending=True)
if partners_df is not None and not partners_df.empty:
# Убираем служебные колонки
export_df = partners_df.drop(['total_quantity', 'Текст_скидки'], axis=1, errors='ignore')
with pd.ExcelWriter(filename, engine='openpyxl') as writer:
export_df.to_excel(writer, sheet_name='Партнеры', index=False)
# Добавляем лист со статистикой
stats_df = pd.DataFrame([{
'Всего партнеров': len(export_df),
'Средний рейтинг': export_df['Рейтинг'].mean(),
'Максимальная скидка': export_df['Скидка'].max(),
'Минимальная скидка': export_df['Скидка'].min()
}])
stats_df.to_excel(writer, sheet_name='Статистика', index=False)
print(f"✅ Данные экспортированы в файл: {filename}")
return True
else:
print("❌ Нет данных для экспорта")
return False
except Exception as e:
print(f"❌ Ошибка при экспорте: {e}")
return False
def export_sales_to_excel(db_path='partners.db', filename='sales_export.xlsx'):
"""Экспортирует историю продаж в Excel файл"""
try:
sales_df = get_sales_history(db_path, limit=1000, sort_by='date_desc')
if sales_df is not None and not sales_df.empty:
with pd.ExcelWriter(filename, engine='openpyxl') as writer:
sales_df.to_excel(writer, sheet_name='История продаж', index=False)
# Сводная таблица по партнерам
pivot_df = sales_df.groupby('Партнер').agg({
'Количество': 'sum',
'Общая сумма': 'sum'
}).reset_index()
pivot_df.to_excel(writer, sheet_name='По партнерам', index=False)
print(f"✅ Данные экспортированы в файл: {filename}")
return True
else:
print("❌ Нет данных для экспорта")
return False
except Exception as e:
print(f"❌ Ошибка при экспорте: {e}")
return False
def export_statistics_to_excel(db_path='partners.db', filename='statistics_export.xlsx'):
"""Экспортирует статистику в Excel файл"""
try:
with pd.ExcelWriter(filename, engine='openpyxl') as writer:
# Статистика за разные периоды
periods = ['all', 'month', 'quarter', 'year']
period_names = ['Весь период', 'Текущий месяц', 'Текущий квартал', 'Текущий год']
all_stats = []
for period, period_name in zip(periods, period_names):
stats, type_stats = get_sales_statistics(db_path, period=period)
if stats:
stats['Период'] = period_name
all_stats.append(stats)
if all_stats:
stats_df = pd.DataFrame(all_stats)
stats_df.to_excel(writer, sheet_name='Статистика', index=False)
print(f"✅ Данные экспортированы в файл: {filename}")
return True
except Exception as e:
print(f"❌ Ошибка при экспорте: {e}")
return False
def search_partners(db_path='partners.db', search_term=''):
"""Поиск партнеров по различным критериям"""
try:
conn = sqlite3.connect(db_path)
query = """
SELECT
pt.type_name AS "Тип партнера",
p.name AS "Наименование партнера",
p.director AS "Директор",
p.email AS "Электронная почта",
p.phone AS "Телефон",
p.legal_address AS "Юридический адрес",
p.inn AS "ИНН",
p.rating AS "Рейтинг",
COALESCE(SUM(s.quantity), 0) as total_quantity
FROM Partner p
JOIN PartnerType pt ON p.partner_type_id = pt.id
LEFT JOIN Sale s ON p.id = s.partner_id
WHERE p.name LIKE ? OR p.director LIKE ? OR p.email LIKE ? OR p.inn LIKE ?
GROUP BY p.id
ORDER BY p.name
"""
search_pattern = f'%{search_term}%'
df = pd.read_sql_query(query, conn, params=(search_pattern, search_pattern, search_pattern, search_pattern))
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 Exception as e:
print(f"❌ Ошибка при поиске: {e}")
return None
def get_top_products(db_path='partners.db', limit=10):
"""Получает топ продуктов по продажам"""
try:
conn = sqlite3.connect(db_path)
query = """
SELECT
pr.product_name AS "Продукция",
pr.article AS "Артикул",
pt.type_name AS "Тип продукции",
SUM(s.quantity) AS "Общее количество",
SUM(s.quantity * s.sale_price) AS "Общая сумма",
COUNT(*) AS "Количество продаж",
AVG(s.sale_price) AS "Средняя цена"
FROM Sale s
JOIN Product pr ON s.product_id = pr.id
JOIN ProductType pt ON pr.product_type_id = pt.id
GROUP BY pr.id
ORDER BY "Общее количество" DESC
LIMIT ?
"""
df = pd.read_sql_query(query, conn, params=(limit,))
conn.close()
return df
except Exception as e:
print(f"❌ Ошибка при получении топ продуктов: {e}")
return None
def get_product_type_analysis(db_path='partners.db'):
"""Анализ по типам продукции"""
try:
conn = sqlite3.connect(db_path)
query = """
SELECT
pt.type_name AS "Тип продукции",
COUNT(DISTINCT pr.id) AS "Количество продуктов",
SUM(s.quantity) AS "Общее количество",
SUM(s.quantity * s.sale_price) AS "Общая сумма",
AVG(s.quantity) AS "Среднее количество за продажу",
AVG(s.sale_price) AS "Средняя цена"
FROM ProductType pt
LEFT JOIN Product pr ON pt.id = pr.product_type_id
LEFT JOIN Sale s ON pr.id = s.product_id
GROUP BY pt.id
ORDER BY "Общая сумма" DESC
"""
df = pd.read_sql_query(query, conn)
conn.close()
return df
except Exception as e:
print(f"❌ Ошибка при анализе типов продукции: {e}")
return None
def get_sales_seasonality(db_path='partners.db'):
"""Анализ сезонности продаж"""
try:
conn = sqlite3.connect(db_path)
query = """
SELECT
strftime('%Y', s.sale_date) AS "Год",
strftime('%m', s.sale_date) AS "Месяц",
SUM(s.quantity) AS "Количество",
SUM(s.quantity * s.sale_price) AS "Сумма",
COUNT(*) AS "Продаж"
FROM Sale s
GROUP BY "Год", "Месяц"
ORDER BY "Год", "Месяц"
"""
df = pd.read_sql_query(query, conn)
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 + "╣")
type_text = f"Тип: {row['Тип партнера']}"
name_text = f"Наименование: {row['Наименование партнера']}"
director_text = f"Директор: {row['Директор']}"
rating_text = f"Рейтинг: {row['Рейтинг']}"
quantity_text = f"Продано единиц: {row['total_quantity']:,}"
discount_text = f"Скидка: {row['Текст_скидки']}"
email_text = f"Контакты: {row['Электронная почта']}"
phone_text = f"Телефон: {row['Телефон']}"
inn_text = f"ИНН: {row['ИНН']}"
address = row['Юридический адрес']
if len(address) > 60:
address = address[:57] + "..."
address_text = f"Адрес: {address}"
print(f"║ {type_text:<67} ║")
print(f"║ {name_text:<67} ║")
print(f"║ {director_text:<67} ║")
print(f"║ {rating_text:<67} ║")
print(f"║ {quantity_text:<67} ║")
print(f"║ {discount_text:<67} ║")
print(f"║ {'':<67} ║")
print(f"║ {email_text:<67} ║")
print(f"║ {phone_text:<67} ║")
print(f"║ {'':<67} ║")
print(f"║ {inn_text:<67} ║")
print(f"║ {address_text:<67} ║")
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[0], headers[1], headers[2], headers[3], headers[4], headers[5], headers[6]
))
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 print_statistics(stats, type_stats):
"""Выводит статистику продаж"""
if not stats:
print("📭 Нет данных для статистики")
return
print("╔" + "═" * 50 + "╗")
print(f"║ {'СТАТИСТИКА ПРОДАЖ':^48} ║")
print("╠" + "═" * 50 + "╣")
print(f"║ {'Всего продаж:':<30} {stats['total_sales']:>18} ║")
print(f"║ {'Общее количество:':<30} {stats['total_quantity']:>18,} ║")
print(f"║ {'Общая сумма:':<30} {stats['total_amount']:>18,.2f} ║")
print(f"║ {'Среднее количество:':<30} {stats['avg_quantity']:>18.1f} ║")
print(f"║ {'Средняя цена:':<30} {stats['avg_price']:>18.2f} ║")
print(f"║ {'Уникальных партнеров:':<30} {stats['unique_partners']:>18} ║")
print(f"║ {'Уникальных продуктов:':<30} {stats['unique_products']:>18} ║")
print("╚" + "═" * 50 + "╝")
if type_stats:
print(f"\n📊 СТАТИСТИКА ПО ТИПАМ ПРОДУКЦИИ:")
print("╔" + "═" * 60 + "╗")
print(f"║ {'Тип продукции':<25} {'Количество':>12} {'Сумма':>15} {'Продаж':>8} ║")
print("╠" + "═" * 60 + "╣")
for row in type_stats:
print(f"║ {row['type_name']:<25} {row['quantity']:>12,} {row['amount']:>15,.2f} {row['sales_count']:>8} ║")
print("╚" + "═" * 60 + "╝")
def print_top_products(top_products):
"""Выводит топ продуктов"""
if top_products is None or top_products.empty:
print("📭 Нет данных о продуктах")
return
print("╔" + "═" * 120 + "╗")
print(f"║ {'ТОП ПРОДУКТОВ ПО ПРОДАЖАМ':^118} ║")
print("╠" + "═" * 120 + "╣")
headers = ["Продукция", "Тип", "Количество", "Сумма", "Продаж", "Ср. цена"]
print(f"║ {headers[0]:<40} {headers[1]:<15} {headers[2]:>12} {headers[3]:>15} {headers[4]:>8} {headers[5]:>10} ║")
print("╠" + "═" * 120 + "╣")
for index, row in top_products.iterrows():
product = row['Продукция'][:38] + "..." if len(row['Продукция']) > 38 else row['Продукция']
product_type = row['Тип продукции']
quantity = f"{row['Общее количество']:,}"
amount = f"{row['Общая сумма']:,.2f}"
sales_count = f"{row['Количество продаж']}"
avg_price = f"{row['Средняя цена']:,.2f}"
print(f"║ {product:<40} {product_type:<15} {quantity:>12} {amount:>15} {sales_count:>8} {avg_price:>10} ║")
print("╚" + "═" * 120 + "╝")
def print_product_type_analysis(type_analysis):
"""Выводит анализ по типам продукции"""
if type_analysis is None or type_analysis.empty:
print("📭 Нет данных для анализа")
return
print("╔" + "═" * 90 + "╗")
print(f"║ {'АНАЛИЗ ПО ТИПАМ ПРОДУКЦИИ':^88} ║")
print("╠" + "═" * 90 + "╣")
headers = ["Тип продукции", "Продуктов", "Количество", "Сумма", "Ср.кол-во", "Ср.цена"]
print(f"║ {headers[0]:<20} {headers[1]:>10} {headers[2]:>12} {headers[3]:>15} {headers[4]:>10} {headers[5]:>10} ║")
print("╠" + "═" * 90 + "╣")
for index, row in type_analysis.iterrows():
product_type = str(row['Тип продукции'])[:18] + ".." if len(str(row['Тип продукции'])) > 18 else str(
row['Тип продукции'])
products_count = f"{int(row['Количество продуктов'])}"
quantity = f"{int(row['Общее количество']):,}" if pd.notna(row['Общее количество']) else "0"
amount = f"{float(row['Общая сумма']):,.2f}" if pd.notna(row['Общая сумма']) else "0.00"
avg_quantity = f"{float(row['Среднее количество за продажу']):.1f}" if pd.notna(
row['Среднее количество за продажу']) else "0.0"
avg_price = f"{float(row['Средняя цена']):,.2f}" if pd.notna(row['Средняя цена']) else "0.00"
print(
f"║ {product_type:<20} {products_count:>10} {quantity:>12} {amount:>15} {avg_quantity:>10} {avg_price:>10} ║")
print("╚" + "═" * 90 + "╝")
def print_sales_seasonality(seasonality):
"""Выводит анализ сезонности"""
if seasonality is None or seasonality.empty:
print("📭 Нет данных для анализа сезонности")
return
print("╔" + "═" * 60 + "╗")
print(f"║ {'СЕЗОННОСТЬ ПРОДАЖ':^58} ║")
print("╠" + "═" * 60 + "╣")
headers = ["Год", "Месяц", "Количество", "Сумма", "Продаж"]
print(f"║ {headers[0]:<6} {headers[1]:<6} {headers[2]:>12} {headers[3]:>15} {headers[4]:>8} ║")
print("╠" + "═" * 60 + "╣")
for index, row in seasonality.iterrows():
year = row['Год']
month = row['Месяц']
quantity = f"{row['Количество']:,}"
amount = f"{row['Сумма']:,.2f}"
sales_count = f"{row['Продаж']}"
print(f"║ {year:<6} {month:<6} {quantity:>12} {amount:>15} {sales_count:>8} ║")
print("╚" + "═" * 60 + "╝")
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()
def load_data_from_files():
"""Загружает данные из Excel файлов в базу данных"""
conn = sqlite3.connect('partners.db')
cursor = conn.cursor()
try:
# Используем файлы по умолчанию
partners_file = 'Partners_import.xlsx'
product_type_file = 'Product_type_import.xlsx'
products_file = 'Products_import.xlsx'
sales_file = 'Partner_products_import.xlsx'
print(f"📁 Используемые файлы:")
print(f" Партнеры: {partners_file}")
print(f" Типы продукции: {product_type_file}")
print(f" Продукты: {products_file}")
print(f" Продажи: {sales_file}")
# 1. Загрузка типов партнеров
print("\n1. 📊 Загрузка типов партнеров...")
partners_df = pd.read_excel(partners_file)
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(product_type_file)
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(products_file)
for _, row in products_df.iterrows():
cursor.execute("SELECT id FROM ProductType WHERE type_name = ?", (row['Тип продукции'],))
product_type_result = cursor.fetchone()
# Проверяем, что тип продукции найден
if product_type_result is None:
print(f" ⚠️ Тип продукции не найден: {row['Тип продукции']}")
continue
product_type_id = product_type_result[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(sales_file)
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()
except Exception as e:
print(f"❌ Ошибка при загрузке данных: {e}")
conn.rollback()
finally:
conn.close()
def display_menu():
"""Главное меню программы"""
menu_options = [
'КАРТОЧКИ ПАРТНЕРОВ (сортировка по рейтингу)',
'КАРТОЧКИ ПАРТНЕРОВ (сортировка по скидкам)',
'ИСТОРИЯ РЕАЛИЗАЦИИ',
'СТАТИСТИКА ПРОДАЖ',
'ПОИСК ПАРТНЕРОВ',
'ЭКСПОРТ ДАННЫХ В EXCEL',
'АНАЛИЗ ПРОДУКЦИИ',
'ЗАПОЛНЕНИЕ БД из файлов',
'ВЫХОД'
]
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)
# Выбор сортировки для истории продаж
sort_options = [
'По дате (новые сначала)',
'По дате (старые сначала)',
'По количеству (по убыванию)',
'По сумме (по убыванию)'
]
sort_choice = simple_choice(sort_options)
sort_mapping = {
'По дате (новые сначала)': 'date_desc',
'По дате (старые сначала)': 'date_asc',
'По количеству (по убыванию)': 'quantity_desc',
'По сумме (по убыванию)': 'amount_desc'
}
sales = get_sales_history(limit=50, sort_by=sort_mapping[sort_choice])
print_sales_cards(sales)
elif choice == 'СТАТИСТИКА ПРОДАЖ':
print("\n📊 СТАТИСТИКА ПРОДАЖ")
print("═" * 70)
period_options = [
'За весь период',
'За текущий месяц',
'За текущий квартал',
'За текущий год'
]
period_choice = simple_choice(period_options)
period_mapping = {
'За весь период': 'all',
'За текущий месяц': 'month',
'За текущий квартал': 'quarter',
'За текущий год': 'year'
}
stats, type_stats = get_sales_statistics(period=period_mapping[period_choice])
print_statistics(stats, type_stats)
elif choice == 'ПОИСК ПАРТНЕРОВ':
print("\n🔍 ПОИСК ПАРТНЕРОВ")
print("═" * 70)
search_term = input("Введите поисковый запрос (название, директор, email или ИНН): ").strip()
if search_term:
partners = search_partners(search_term=search_term)
if partners is not None and not partners.empty:
print(f"\n🎯 Найдено партнеров: {len(partners)}")
print_partner_cards(partners)
else:
print("📭 Партнеры по вашему запросу не найдены")
else:
print("❌ Введите поисковый запрос")
elif choice == 'ЭКСПОРТ ДАННЫХ В EXCEL':
print("\n💾 ЭКСПОРТ ДАННЫХ В EXCEL")
print("═" * 70)
export_options = [
'Экспорт партнеров',
'Экспорт истории продаж',
'Экспорт статистики'
]
export_choice = simple_choice(export_options)
if export_choice == 'Экспорт партнеров':
filename = input("Введите имя файла (по умолчанию: partners_export.xlsx): ").strip()
if not filename:
filename = 'partners_export.xlsx'
success = export_partners_to_excel(filename=filename)
if success:
print(f"✅ Данные успешно экспортированы в {filename}")
else:
print("❌ Ошибка при экспорте данных")
elif export_choice == 'Экспорт истории продаж':
filename = input("Введите имя файла (по умолчанию: sales_export.xlsx): ").strip()
if not filename:
filename = 'sales_export.xlsx'
success = export_sales_to_excel(filename=filename)
if success:
print(f"✅ Данные успешно экспортированы в {filename}")
else:
print("❌ Ошибка при экспорте данных")
elif export_choice == 'Экспорт статистики':
filename = input("Введите имя файла (по умолчанию: statistics_export.xlsx): ").strip()
if not filename:
filename = 'statistics_export.xlsx'
success = export_statistics_to_excel(filename=filename)
if success:
print(f"✅ Данные успешно экспортированы в {filename}")
else:
print("❌ Ошибка при экспорте данных")
elif choice == 'АНАЛИЗ ПРОДУКЦИИ':
print("\n📈 АНАЛИЗ ПРОДУКЦИИ")
print("═" * 70)
analysis_options = [
'Топ продуктов по продажам',
'Анализ по типам продукции',
'Сезонность продаж'
]
analysis_choice = simple_choice(analysis_options)
if analysis_choice == 'Топ продуктов по продажам':
top_products = get_top_products(limit=10)
print_top_products(top_products)
elif analysis_choice == 'Анализ по типам продукции':
type_analysis = get_product_type_analysis()
print_product_type_analysis(type_analysis)
elif analysis_choice == 'Сезонность продаж':
seasonality = get_sales_seasonality()
print_sales_seasonality(seasonality)
elif choice == 'ЗАПОЛНЕНИЕ БД из файлов':
if os.path.exists('partners.db'):
confirm = input("🗑️ База данных partners.db будет удалена. Продолжить? (y/n): ").strip().lower()
if confirm != 'y':
print("❌ Операция отменена")
continue
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__":
print("🚀 СИСТЕМА УПРАВЛЕНИЯ ПАРТНЕРАМИ И ПРОДАЖАМИ")
print("=" * 50)
# Проверяем существование базы данных
if not os.path.exists('partners.db'):
print("ℹ️ База данных не найдена. Создаем новую...")
conn = sqlite3.connect('partners.db')
create_tables(conn)
conn.close()
print("✅ База данных создана. Для работы необходимо загрузить данные через меню 'ЗАПОЛНЕНИЕ БД из файлов'")
else:
print("✅ База данных найдена")
check_database()
display_menu()
#hfkjshfks