653 lines
28 KiB
Python
653 lines
28 KiB
Python
import sqlite3
|
||
import pandas as pd
|
||
import os
|
||
import sys
|
||
from datetime import datetime
|
||
|
||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||
RESOURCE_DIR = os.path.join(BASE_DIR, "Resource")
|
||
DB_PATH = os.path.join(BASE_DIR, "partners.db")
|
||
|
||
|
||
def create_tables(db_connection):
|
||
"""Создает все необходимые таблицы в базе данных"""
|
||
cursor = db_connection.cursor()
|
||
|
||
cursor.executescript('''
|
||
-- Типы контрагентов
|
||
CREATE TABLE IF NOT EXISTS ContractorType (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
type_name VARCHAR(100) NOT NULL UNIQUE
|
||
);
|
||
|
||
-- Контрагенты/Клиенты
|
||
CREATE TABLE IF NOT EXISTS Clients (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
contractor_type_id INTEGER REFERENCES ContractorType(id),
|
||
name VARCHAR(255) NOT NULL,
|
||
director VARCHAR(255),
|
||
email VARCHAR(255),
|
||
phone VARCHAR(50),
|
||
address TEXT,
|
||
inn VARCHAR(20) UNIQUE,
|
||
rating DECIMAL(3,2) DEFAULT 0.0,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
-- Категории продукции
|
||
CREATE TABLE IF NOT EXISTS Categories (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
category_name VARCHAR(100) NOT NULL UNIQUE,
|
||
coefficient DECIMAL(5,2) NOT NULL DEFAULT 1.0
|
||
);
|
||
|
||
-- Таблица материалов
|
||
CREATE TABLE IF NOT EXISTS Materials (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
material_name VARCHAR(100) NOT NULL UNIQUE,
|
||
description TEXT,
|
||
category VARCHAR(50),
|
||
color VARCHAR(50),
|
||
density DECIMAL(10,2),
|
||
thickness DECIMAL(10,2),
|
||
supplier VARCHAR(255),
|
||
country VARCHAR(100),
|
||
wear_class VARCHAR(20),
|
||
price_per_unit DECIMAL(15,2),
|
||
unit VARCHAR(20) DEFAULT 'шт',
|
||
in_stock INTEGER DEFAULT 0,
|
||
production_time_days INTEGER DEFAULT 1,
|
||
daily_capacity INTEGER DEFAULT 10,
|
||
cost_price DECIMAL(15,2),
|
||
markup_percent DECIMAL(5,2) DEFAULT 30,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
-- Каталог продукции
|
||
CREATE TABLE IF NOT EXISTS Catalog (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
category_id INTEGER REFERENCES Categories(id),
|
||
material_id INTEGER REFERENCES Materials(id),
|
||
product_name VARCHAR(255) NOT NULL,
|
||
article VARCHAR(100) UNIQUE NOT NULL,
|
||
description TEXT,
|
||
min_price DECIMAL(15,2) NOT NULL,
|
||
quantity_in_stock INTEGER DEFAULT 0,
|
||
production_time_days INTEGER DEFAULT 1,
|
||
daily_capacity INTEGER DEFAULT 10,
|
||
cost_price DECIMAL(15,2),
|
||
profit_per_unit DECIMAL(15,2),
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
-- Таблица корзин
|
||
CREATE TABLE IF NOT EXISTS Cart (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
client_id INTEGER REFERENCES Clients(id),
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||
status VARCHAR(50) DEFAULT 'активна'
|
||
);
|
||
|
||
-- Таблица товаров в корзине
|
||
CREATE TABLE IF NOT EXISTS CartItems (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
cart_id INTEGER REFERENCES Cart(id),
|
||
product_id INTEGER REFERENCES Catalog(id),
|
||
quantity INTEGER NOT NULL CHECK (quantity > 0),
|
||
price_at_moment DECIMAL(15,2) NOT NULL,
|
||
added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
-- Заказы
|
||
CREATE TABLE IF NOT EXISTS Orders (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
client_id INTEGER REFERENCES Clients(id),
|
||
order_date DATE NOT NULL,
|
||
total_amount DECIMAL(15,2) NOT NULL,
|
||
status VARCHAR(50) DEFAULT 'Новый',
|
||
production_days INTEGER DEFAULT 1,
|
||
production_start_date DATE,
|
||
production_end_date DATE,
|
||
production_status VARCHAR(50) DEFAULT 'Ожидает',
|
||
assembly_percent INTEGER DEFAULT 15,
|
||
delivery_percent INTEGER DEFAULT 10,
|
||
assembly_cost DECIMAL(15,2) DEFAULT 0,
|
||
delivery_cost DECIMAL(15,2) DEFAULT 0,
|
||
base_amount DECIMAL(15,2) DEFAULT 0,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
|
||
-- Состав заказа
|
||
CREATE TABLE IF NOT EXISTS OrderItems (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
order_id INTEGER NOT NULL REFERENCES Orders(id),
|
||
product_id INTEGER NOT NULL REFERENCES Catalog(id),
|
||
quantity INTEGER NOT NULL CHECK (quantity > 0),
|
||
price_at_moment DECIMAL(15,2) NOT NULL
|
||
);
|
||
|
||
-- Индексы для оптимизации
|
||
CREATE INDEX IF NOT EXISTS idx_client_type ON Clients(contractor_type_id);
|
||
CREATE INDEX IF NOT EXISTS idx_client_inn ON Clients(inn);
|
||
CREATE INDEX IF NOT EXISTS idx_catalog_category ON Catalog(category_id);
|
||
CREATE INDEX IF NOT EXISTS idx_catalog_material ON Catalog(material_id);
|
||
CREATE INDEX IF NOT EXISTS idx_catalog_article ON Catalog(article);
|
||
CREATE INDEX IF NOT EXISTS idx_material_name ON Materials(material_name);
|
||
CREATE INDEX IF NOT EXISTS idx_material_category ON Materials(category);
|
||
CREATE INDEX IF NOT EXISTS idx_material_supplier ON Materials(supplier);
|
||
CREATE INDEX IF NOT EXISTS idx_cart_client ON Cart(client_id);
|
||
CREATE INDEX IF NOT EXISTS idx_cart_status ON Cart(status);
|
||
CREATE INDEX IF NOT EXISTS idx_cart_items_cart ON CartItems(cart_id);
|
||
CREATE INDEX IF NOT EXISTS idx_order_client ON Orders(client_id);
|
||
CREATE INDEX IF NOT EXISTS idx_order_date ON Orders(order_date);
|
||
CREATE INDEX IF NOT EXISTS idx_order_status ON Orders(status);
|
||
CREATE INDEX IF NOT EXISTS idx_production_status ON Orders(production_status);
|
||
CREATE INDEX IF NOT EXISTS idx_orderitems_order ON OrderItems(order_id);
|
||
CREATE INDEX IF NOT EXISTS idx_orderitems_product ON OrderItems(product_id);
|
||
''')
|
||
|
||
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_clients(db_path=DB_PATH, sort_by='rating', ascending=False):
|
||
"""Получает данные о клиентах с возможностью сортировки"""
|
||
try:
|
||
conn = sqlite3.connect(db_path)
|
||
query = """
|
||
SELECT
|
||
ct.type_name AS "Тип клиента",
|
||
c.name AS "Наименование клиента",
|
||
c.director AS "Директор",
|
||
c.email AS "Электронная почта",
|
||
c.phone AS "Телефон",
|
||
c.address AS "Адрес",
|
||
c.inn AS "ИНН",
|
||
c.rating AS "Рейтинг",
|
||
c.created_at AS "Дата создания",
|
||
COALESCE(SUM(oi.quantity), 0) as total_quantity,
|
||
COALESCE(SUM(o.total_amount), 0) as total_amount
|
||
FROM Clients c
|
||
JOIN ContractorType ct ON c.contractor_type_id = ct.id
|
||
LEFT JOIN Orders o ON c.id = o.client_id
|
||
LEFT JOIN OrderItems oi ON o.id = oi.order_id
|
||
GROUP BY c.id
|
||
"""
|
||
|
||
if sort_by == 'discount':
|
||
query += " ORDER BY total_quantity"
|
||
elif sort_by == 'rating':
|
||
query += " ORDER BY c.rating"
|
||
elif sort_by == 'name':
|
||
query += " ORDER BY c.name"
|
||
elif sort_by == 'type':
|
||
query += " ORDER BY ct.type_name, c.name"
|
||
else:
|
||
query += " ORDER BY c.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])
|
||
df['Общая_сумма'] = df['total_amount'].apply(lambda x: f"{x:,.2f} руб.")
|
||
|
||
return df
|
||
|
||
except Exception as e:
|
||
print(f"❌ Ошибка: {e}")
|
||
return None
|
||
|
||
|
||
def get_orders_history(db_path=DB_PATH, limit=50, sort_by='date_desc'):
|
||
"""Получает историю заказов с разными вариантами сортировки"""
|
||
try:
|
||
conn = sqlite3.connect(db_path)
|
||
query = """
|
||
SELECT
|
||
o.order_date AS "Дата заказа",
|
||
c.name AS "Клиент",
|
||
GROUP_CONCAT(cat.product_name || ' x' || oi.quantity, ', ') AS "Товары",
|
||
SUM(oi.quantity) AS "Количество",
|
||
o.total_amount AS "Сумма заказа",
|
||
o.status AS "Статус"
|
||
FROM Orders o
|
||
JOIN Clients c ON o.client_id = c.id
|
||
LEFT JOIN OrderItems oi ON o.id = oi.order_id
|
||
LEFT JOIN Catalog cat ON oi.product_id = cat.id
|
||
GROUP BY o.id
|
||
"""
|
||
|
||
if sort_by == 'date_desc':
|
||
query += " ORDER BY o.order_date DESC, o.created_at DESC"
|
||
elif sort_by == 'date_asc':
|
||
query += " ORDER BY o.order_date ASC, o.created_at ASC"
|
||
elif sort_by == 'quantity_desc':
|
||
query += " ORDER BY SUM(oi.quantity) DESC"
|
||
elif sort_by == 'amount_desc':
|
||
query += " ORDER BY o.total_amount DESC"
|
||
elif sort_by == 'status':
|
||
query += " ORDER BY o.status, o.order_date DESC"
|
||
else:
|
||
query += " ORDER BY o.order_date DESC, o.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_client_cards(clients_df):
|
||
"""Выводит карточки клиентов в красивом формате"""
|
||
if clients_df is None or clients_df.empty:
|
||
print("📭 Нет данных о клиентах")
|
||
return
|
||
|
||
for index, row in clients_df.iterrows():
|
||
print("╔" + "═" * 79 + "╗")
|
||
print(f"║ {'КАРТОЧКА КЛИЕНТА':^77} ║")
|
||
print("╠" + "═" * 79 + "╣")
|
||
|
||
type_text = f"Тип: {row['Тип клиента']}"
|
||
name_text = f"Наименование: {row['Наименование клиента']}"
|
||
director_text = f"Директор: {row['Директор']}"
|
||
rating_text = f"Рейтинг: {row['Рейтинг']}"
|
||
quantity_text = f"Заказано единиц: {row['total_quantity']:,}"
|
||
amount_text = f"На сумму: {row['total_amount']:,.2f} руб."
|
||
discount_text = f"Скидка: {row['Скидка_текст']}"
|
||
email_text = f"Email: {row['Электронная почта']}"
|
||
phone_text = f"Телефон: {row['Телефон']}"
|
||
inn_text = f"ИНН: {row['ИНН']}"
|
||
|
||
address = row['Адрес'] if row['Адрес'] else 'Не указан'
|
||
if len(address) > 70:
|
||
address = address[:67] + "..."
|
||
address_text = f"Адрес: {address}"
|
||
|
||
print(f"║ {type_text:<77} ║")
|
||
print(f"║ {name_text:<77} ║")
|
||
print(f"║ {director_text:<77} ║")
|
||
print(f"║ {rating_text:<77} ║")
|
||
print(f"║ {quantity_text:<77} ║")
|
||
print(f"║ {amount_text:<77} ║")
|
||
print(f"║ {discount_text:<77} ║")
|
||
print(f"║ {'':<77} ║")
|
||
print(f"║ {email_text:<77} ║")
|
||
print(f"║ {phone_text:<77} ║")
|
||
print(f"║ {inn_text:<77} ║")
|
||
print(f"║ {address_text:<77} ║")
|
||
print("╚" + "═" * 79 + "╝")
|
||
print()
|
||
|
||
|
||
def print_orders_cards(orders_df):
|
||
"""Выводит карточки заказов в виде таблицы"""
|
||
if orders_df is None or orders_df.empty:
|
||
print("📭 Нет данных о заказах")
|
||
return
|
||
|
||
print("╔" + "═" * 167 + "╗")
|
||
print(f"║ {'ИСТОРИЯ ЗАКАЗОВ':^165} ║")
|
||
print("╠" + "═" * 167 + "╣")
|
||
|
||
headers = ["Дата", "Клиент", "Товары", "Кол-во", "Статус", "Сумма"]
|
||
print("║ {:<12} {:<25} {:<55} {:>12} {:<15} {:>15} ║".format(
|
||
headers[0], headers[1], headers[2], headers[3], headers[4], headers[5]
|
||
))
|
||
print("╠" + "═" * 167 + "╣")
|
||
|
||
for index, row in orders_df.iterrows():
|
||
date = str(row['Дата заказа'])[:10]
|
||
client = str(row['Клиент'])[:25] if len(str(row['Клиент'])) > 25 else str(row['Клиент'])
|
||
products = str(row['Товары'])[:55] if len(str(row['Товары'])) > 55 else str(row['Товары'])
|
||
quantity = f"{int(row['Количество']):,}"
|
||
status = str(row['Статус'])[:15] if len(str(row['Статус'])) > 15 else str(row['Статус'])
|
||
amount = f"{float(row['Сумма заказа']):,.2f}"
|
||
|
||
line = f"║ {date:<12} {client:<25} {products:<55} {quantity:>12} {status:<15} {amount:>15} ║"
|
||
print(line)
|
||
|
||
print("╚" + "═" * 167 + "╝")
|
||
|
||
total_quantity = orders_df['Количество'].sum()
|
||
total_amount = orders_df['Сумма заказа'].sum()
|
||
print(f"📊 ИТОГО: {len(orders_df)} заказов, {total_quantity:,.0f} единиц, общая сумма: {total_amount:,.2f} руб.")
|
||
|
||
status_stats = orders_df['Статус'].value_counts()
|
||
print("📊 Статусы заказов:")
|
||
for status, count in status_stats.items():
|
||
print(f" - {status}: {count}")
|
||
|
||
|
||
def simple_choice(options):
|
||
"""Упрощенная функция выбора"""
|
||
print("\n" + "=" * 60)
|
||
print("ВЫБЕРИТЕ ОПЦИЮ:")
|
||
print("=" * 60)
|
||
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 KeyboardInterrupt:
|
||
print("\n👋 Программа прервана пользователем.")
|
||
sys.exit(0)
|
||
|
||
|
||
def safe_float(value, default=None):
|
||
"""Безопасное преобразование в float"""
|
||
if pd.isna(value) or value == '-':
|
||
return default
|
||
try:
|
||
return float(value)
|
||
except (ValueError, TypeError):
|
||
return default
|
||
|
||
|
||
def safe_int(value, default=None):
|
||
"""Безопасное преобразование в int"""
|
||
if pd.isna(value) or value == '-':
|
||
return default
|
||
try:
|
||
return int(float(value))
|
||
except (ValueError, TypeError):
|
||
return default
|
||
|
||
|
||
def load_data_from_files():
|
||
"""Загружает данные из Excel файлов в базу данных"""
|
||
conn = sqlite3.connect(DB_PATH)
|
||
cursor = conn.cursor()
|
||
|
||
try:
|
||
print("\n📁 Введите имена файлов (или нажмите Enter для значений по умолчанию):")
|
||
clients_file = input("Файл с клиентами (Enter = Clients_import.xlsx): ").strip() or "Clients_import.xlsx"
|
||
categories_file = input("Файл с категориями (Enter = Categories_import.xlsx): ").strip() or "Categories_import.xlsx"
|
||
materials_file = input("Файл с материалами (Enter = Materials_import.xlsx): ").strip() or "Materials_import.xlsx"
|
||
catalog_file = input("Файл с каталогом (Enter = Products_import.xlsx): ").strip() or "Products_import.xlsx"
|
||
orders_file = input("Файл с заказами (Enter = Orders_import.xlsx): ").strip() or "Orders_import.xlsx"
|
||
orderitems_file = input("Файл с составом заказов (Enter = OrderItems_import.xlsx): ").strip() or "OrderItems_import.xlsx"
|
||
|
||
# Формируем полные пути
|
||
clients_file = os.path.join(RESOURCE_DIR, os.path.basename(clients_file))
|
||
categories_file = os.path.join(RESOURCE_DIR, os.path.basename(categories_file))
|
||
materials_file = os.path.join(RESOURCE_DIR, os.path.basename(materials_file))
|
||
catalog_file = os.path.join(RESOURCE_DIR, os.path.basename(catalog_file))
|
||
orders_file = os.path.join(RESOURCE_DIR, os.path.basename(orders_file))
|
||
orderitems_file = os.path.join(RESOURCE_DIR, os.path.basename(orderitems_file))
|
||
|
||
print(f"\n📂 Загружаем файлы из папки: {RESOURCE_DIR}")
|
||
|
||
# 1. Загрузка типов контрагентов
|
||
print("\n1. 📊 Загрузка типов контрагентов...")
|
||
clients_df = pd.read_excel(clients_file)
|
||
|
||
if 'Тип партнера' in clients_df.columns:
|
||
contractor_types = clients_df['Тип партнера'].unique()
|
||
for contractor_type in contractor_types:
|
||
cursor.execute("INSERT OR IGNORE INTO ContractorType (type_name) VALUES (?)", (contractor_type,))
|
||
print(f" Загружено {len(contractor_types)} типов")
|
||
|
||
# 2. Загрузка клиентов
|
||
print("2. 👥 Загрузка клиентов...")
|
||
loaded_clients = 0
|
||
for _, row in clients_df.iterrows():
|
||
type_value = row.get('Тип партнера', 'Клиент')
|
||
cursor.execute("SELECT id FROM ContractorType WHERE type_name = ?", (type_value,))
|
||
result = cursor.fetchone()
|
||
contractor_type_id = result[0] if result else 1
|
||
|
||
cursor.execute("""INSERT OR IGNORE INTO Clients
|
||
(contractor_type_id, name, director, email, phone, address, inn, rating)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
|
||
(contractor_type_id,
|
||
row.get('Наименование партнера', ''),
|
||
row.get('Директор', ''),
|
||
row.get('Электронная почта партнера', ''),
|
||
row.get('Телефон партнера', ''),
|
||
row.get('Юридический адрес партнера', ''),
|
||
row.get('ИНН', ''),
|
||
safe_float(row.get('Рейтинг', 0.0), 0.0))
|
||
)
|
||
loaded_clients += 1
|
||
print(f" Загружено {loaded_clients} клиентов")
|
||
|
||
# 3. Загрузка категорий
|
||
print("3. 📦 Загрузка категорий...")
|
||
categories_df = pd.read_excel(categories_file)
|
||
loaded_categories = 0
|
||
for _, row in categories_df.iterrows():
|
||
cursor.execute("INSERT OR IGNORE INTO Categories (category_name, coefficient) VALUES (?, ?)",
|
||
(row.get('Тип продукции', ''),
|
||
safe_float(row.get('Коэффициент типа продукции', 1.0), 1.0))
|
||
)
|
||
loaded_categories += 1
|
||
print(f" Загружено {loaded_categories} категорий")
|
||
|
||
# 4. Загрузка материалов
|
||
print("4. 📦 Загрузка материалов...")
|
||
materials_df = pd.read_excel(materials_file)
|
||
|
||
loaded_materials = 0
|
||
for _, row in materials_df.iterrows():
|
||
cursor.execute("""
|
||
INSERT OR IGNORE INTO Materials
|
||
(material_name, description, category, color, density, thickness,
|
||
supplier, country, wear_class, price_per_unit, unit, in_stock,
|
||
production_time_days, daily_capacity, markup_percent)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||
""", (
|
||
row.get('Наименование материала', ''),
|
||
row.get('Описание', ''),
|
||
row.get('Категория', ''),
|
||
row.get('Цвет', ''),
|
||
safe_float(row.get('Плотность', None)),
|
||
safe_float(row.get('Толщина', None)),
|
||
row.get('Поставщик', ''),
|
||
row.get('Страна', ''),
|
||
row.get('Класс износостойкости', ''),
|
||
safe_float(row.get('Цена за ед.', 0), 0),
|
||
row.get('Единица', 'шт'),
|
||
safe_int(row.get('В наличии', 0), 0),
|
||
1, 10, 30
|
||
))
|
||
loaded_materials += 1
|
||
print(f" ✅ Загружено {loaded_materials} материалов")
|
||
|
||
# 5. Загрузка каталога
|
||
print("5. 🏷️ Загрузка каталога продукции...")
|
||
catalog_df = pd.read_excel(catalog_file)
|
||
|
||
loaded_products = 0
|
||
for index, row in catalog_df.iterrows():
|
||
prod_days = 1
|
||
if 'production_time_days' in catalog_df.columns:
|
||
val = row['production_time_days']
|
||
if not pd.isna(val):
|
||
try:
|
||
prod_days = int(float(val))
|
||
except:
|
||
prod_days = 1
|
||
|
||
cursor.execute("""
|
||
INSERT OR IGNORE INTO Catalog
|
||
(category_id, material_id, product_name, article, description, min_price, quantity_in_stock,
|
||
production_time_days, daily_capacity)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||
""", (
|
||
safe_int(row.get('category_id', 1), 1),
|
||
safe_int(row.get('material_id', None)),
|
||
row.get('product_name', ''),
|
||
row.get('article', ''),
|
||
row.get('description', ''),
|
||
safe_float(row.get('min_price', 0), 0),
|
||
safe_int(row.get('quantity_in_stock', 0), 0),
|
||
prod_days,
|
||
10
|
||
))
|
||
loaded_products += 1
|
||
|
||
print(f" ✅ Загружено {loaded_products} товаров")
|
||
|
||
# 6. Загрузка заказов
|
||
print("6. 📝 Загрузка заказов...")
|
||
orders_df = pd.read_excel(orders_file)
|
||
loaded_orders = 0
|
||
for _, row in orders_df.iterrows():
|
||
# Преобразование дат
|
||
date_val = row.get('order_date')
|
||
if pd.isna(date_val):
|
||
order_date = datetime.now().strftime('%Y-%m-%d')
|
||
else:
|
||
if hasattr(date_val, 'strftime'):
|
||
order_date = date_val.strftime('%Y-%m-%d')
|
||
else:
|
||
order_date = str(date_val)
|
||
|
||
prod_start = row.get('production_start_date')
|
||
if pd.isna(prod_start):
|
||
prod_start = None
|
||
else:
|
||
if hasattr(prod_start, 'strftime'):
|
||
prod_start = prod_start.strftime('%Y-%m-%d')
|
||
else:
|
||
prod_start = str(prod_start)
|
||
|
||
prod_end = row.get('production_end_date')
|
||
if pd.isna(prod_end):
|
||
prod_end = None
|
||
else:
|
||
if hasattr(prod_end, 'strftime'):
|
||
prod_end = prod_end.strftime('%Y-%m-%d')
|
||
else:
|
||
prod_end = str(prod_end)
|
||
|
||
cursor.execute("""
|
||
INSERT INTO Orders
|
||
(id, client_id, order_date, total_amount, status,
|
||
production_days, production_start_date, production_end_date, production_status,
|
||
assembly_percent, delivery_percent, assembly_cost, delivery_cost, base_amount)
|
||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||
""", (
|
||
safe_int(row.get('id')),
|
||
safe_int(row.get('client_id')),
|
||
order_date,
|
||
safe_float(row.get('total_amount'), 0),
|
||
row.get('status', 'Новый'),
|
||
safe_int(row.get('production_days', 1)),
|
||
prod_start,
|
||
prod_end,
|
||
row.get('production_status', 'Ожидает'),
|
||
safe_int(row.get('assembly_percent', 15)),
|
||
safe_int(row.get('delivery_percent', 10)),
|
||
safe_float(row.get('assembly_cost', 0), 0),
|
||
safe_float(row.get('delivery_cost', 0), 0),
|
||
safe_float(row.get('base_amount', 0), 0)
|
||
))
|
||
loaded_orders += 1
|
||
print(f" ✅ Загружено {loaded_orders} заказов")
|
||
|
||
# 7. Загрузка состава заказов (OrderItems)
|
||
print("7. 📦 Загрузка состава заказов...")
|
||
orderitems_df = pd.read_excel(orderitems_file)
|
||
loaded_items = 0
|
||
for _, row in orderitems_df.iterrows():
|
||
cursor.execute("""
|
||
INSERT INTO OrderItems (order_id, product_id, quantity, price_at_moment)
|
||
VALUES (?, ?, ?, ?)
|
||
""", (
|
||
safe_int(row.get('order_id')),
|
||
safe_int(row.get('product_id')),
|
||
safe_int(row.get('quantity'), 1),
|
||
safe_float(row.get('price_at_moment'), 0)
|
||
))
|
||
loaded_items += 1
|
||
print(f" ✅ Загружено {loaded_items} позиций")
|
||
|
||
conn.commit()
|
||
print(f"✅ Данные успешно загружены!")
|
||
|
||
except Exception as e:
|
||
print(f"❌ Ошибка при загрузке данных: {e}")
|
||
import traceback
|
||
traceback.print_exc()
|
||
conn.rollback()
|
||
finally:
|
||
conn.close()
|
||
|
||
|
||
def display_menu():
|
||
"""Главное меню программы"""
|
||
menu_options = [
|
||
'КАРТОЧКИ КЛИЕНТОВ (сортировка по рейтингу)',
|
||
'КАРТОЧКИ КЛИЕНТОВ (сортировка по скидкам)',
|
||
'ИСТОРИЯ ЗАКАЗОВ',
|
||
'ЗАПОЛНЕНИЕ БД из файлов',
|
||
'ВЫХОД'
|
||
]
|
||
|
||
while True:
|
||
choice = simple_choice(menu_options)
|
||
|
||
if choice == 'КАРТОЧКИ КЛИЕНТОВ (сортировка по рейтингу)':
|
||
print("\n🎯 КАРТОЧКИ КЛИЕНТОВ (сортировка по рейтингу)")
|
||
print("═" * 80)
|
||
clients = get_clients(sort_by='rating', ascending=False)
|
||
print_client_cards(clients)
|
||
|
||
elif choice == 'КАРТОЧКИ КЛИЕНТОВ (сортировка по скидкам)':
|
||
print("\n📊 КАРТОЧКИ КЛИЕНТОВ (сортировка по скидкам)")
|
||
print("═" * 80)
|
||
clients = get_clients(sort_by='discount', ascending=False)
|
||
print_client_cards(clients)
|
||
|
||
elif choice == 'ИСТОРИЯ ЗАКАЗОВ':
|
||
print("\n📈 ИСТОРИЯ ЗАКАЗОВ")
|
||
print("═" * 80)
|
||
orders = get_orders_history(limit=50)
|
||
print_orders_cards(orders)
|
||
|
||
elif choice == 'ЗАПОЛНЕНИЕ БД из файлов':
|
||
if os.path.exists(DB_PATH):
|
||
os.remove(DB_PATH)
|
||
print("🗑️ База данных удалена")
|
||
else:
|
||
print("ℹ️ Создаем новую базу")
|
||
|
||
conn = sqlite3.connect(DB_PATH)
|
||
create_tables(conn)
|
||
conn.close()
|
||
load_data_from_files()
|
||
|
||
elif choice == 'ВЫХОД':
|
||
print("\n👋 До свидания!")
|
||
break
|
||
|
||
|
||
if __name__ == "__main__":
|
||
display_menu() |