project/main.py
2025-10-23 12:07:36 +05:00

366 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

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 datetime
import sys
import pandas as pd
import os
#armina
#17
if os.path.exists('partners.db'):
os.remove('partners.db')
print(f"База данных {'partners.db'} удалена")
else:
print(f"База данных {'partners.db'} не найдена, создаем новую")
conn = sqlite3.connect('partners.db')
cursor = conn.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);
''')
partner_types = [
('ЗАО',),
('ООО',),
('ПАО',),
('ОАО',)
]
cursor.executemany('INSERT OR IGNORE INTO PartnerType (type_name) VALUES (?)', partner_types)
partners = [
(1, 'База Строитель', 'Иванова Александра Ивановна', 'aleksandraivanova@ml.ru',
'493 123 45 67', '652050, Кемеровская область, город Юрга, ул. Лесная, 15', '2222455179', 7),
(2, 'Паркет 29', 'Петров Василий Петрович', 'vppetrov@vl.ru',
'987 123 56 78', '164500, Архангельская область, город Северодвинск, ул. Строителей, 18', '3333888520', 7),
(3, 'Стройсервис', 'Соловьев Андрей Николаевич', 'ansolovev@st.ru',
'812 223 32 00', '188910, Ленинградская область, город Приморск, ул. Парковая, 21', '4440391035', 7),
(4, 'Ремонт и отделка', 'Воробьева Екатерина Валерьевна', 'ekaterina.vorobeva@ml.ru',
'444 222 33 11', '143960, Московская область, город Реутов, ул. Свободы, 51', '1111520857', 5),
(1, 'МонтажПро', 'Степанов Степан Сергеевич', 'stepanov@stepan.ru',
'912 888 33 33', '309500, Белгородская область, город Старый Оскол, ул. Рабочая, 122', '5552431140', 10)
]
cursor.executemany('''
INSERT OR IGNORE INTO Partner (partner_type_id, name, director, email, phone, legal_address, inn, rating)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
''', partners)
# Заполняем типы продукции
product_types = [
('Ламинат', 2.35),
('Массивная доска', 5.15),
('Паркетная доска', 4.34),
('Пробковое покрытие', 1.5)
]
cursor.executemany('INSERT OR IGNORE INTO ProductType (type_name, coefficient) VALUES (?, ?)', product_types)
products = [
(3, 'Паркетная доска Ясень темный однополосная 14 мм', '8758385', 4456.90),
(3, 'Инженерная доска Дуб Французская елка однополосная 12 мм', '8858958', 7330.99),
(1, 'Ламинат Дуб дымчато-белый 33 класс 12 мм', '7750282', 1799.33),
(1, 'Ламинат Дуб серый 32 класс 8 мм с фаской', '7028748', 3890.41),
(4, 'Пробковое напольное клеевое покрытие 32 класс 4 мм', '5012543', 5450.59)
]
cursor.executemany('''
INSERT OR IGNORE INTO Product (product_type_id, product_name, article, min_partner_price)
VALUES (?, ?, ?, ?)
''', products)
# Заполняем продажи
sales_data = [
# Формат: (product_name, partner_name, quantity, sale_date)
('Паркетная доска Ясень темный однополосная 14 мм', 'База Строитель', 15500, '2023-03-23'),
('Ламинат Дуб дымчато-белый 33 класс 12 мм', 'База Строитель', 12350, '2023-12-18'),
('Ламинат Дуб серый 32 класс 8 мм с фаской', 'База Строитель', 37400, '2024-06-07'),
('Инженерная доска Дуб Французская елка однополосная 12 мм', 'Паркет 29', 35000, '2022-12-02'),
('Пробковое напольное клеевое покрытие 32 класс 4 мм', 'Паркет 29', 1250, '2023-05-17'),
('Ламинат Дуб дымчато-белый 33 класс 12 мм', 'Паркет 29', 1000, '2024-06-07'),
('Паркетная доска Ясень темный однополосная 14 мм', 'Паркет 29', 7550, '2024-07-01'),
('Паркетная доска Ясень темный однополосная 14 мм', 'Стройсервис', 7250, '2023-01-22'),
('Инженерная доска Дуб Французская елка однополосная 12 мм', 'Стройсервис', 2500, '2024-07-05'),
('Ламинат Дуб серый 32 класс 8 мм с фаской', 'Ремонт и отделка', 59050, '2023-03-20'),
('Ламинат Дуб дымчато-белый 33 класс 12 мм', 'Ремонт и отделка', 37200, '2024-03-12'),
('Пробковое напольное клеевое покрытие 32 класс 4 мм', 'Ремонт и отделка', 4500, '2024-05-14'),
('Ламинат Дуб дымчато-белый 33 класс 12 мм', 'МонтажПро', 50000, '2023-09-19'),
('Ламинат Дуб серый 32 класс 8 мм с фаской', 'МонтажПро', 670000, '2023-11-10'),
('Паркетная доска Ясень темный однополосная 14 мм', 'МонтажПро', 35000, '2024-04-15'),
('Инженерная доска Дуб Французская елка однополосная 12 мм', 'МонтажПро', 25000, '2024-06-12')
]
def get_ids(product_name, partner_name):
cursor.execute('SELECT id FROM Product WHERE product_name = ?', (product_name,))
product_id = cursor.fetchone()[0]
cursor.execute('SELECT id FROM Partner WHERE name = ?', (partner_name,))
partner_id = cursor.fetchone()[0]
cursor.execute('SELECT min_partner_price FROM Product WHERE product_name = ?', (product_name,))
sale_price = cursor.fetchone()[0]
return product_id, partner_id, sale_price
for sale in sales_data:
product_name, partner_name, quantity, sale_date = sale
try:
product_id, partner_id, sale_price = get_ids(product_name, partner_name)
cursor.execute('''
INSERT INTO Sale (product_id, partner_id, quantity, sale_date, sale_price)
VALUES (?, ?, ?, ?, ?)
''', (product_id, partner_id, quantity, sale_date, sale_price))
except Exception as e:
print(f"Ошибка при добавлении продажи: {sale}, ошибка: {e}")
# Сохраняем изменения
conn.commit()
def get_partners(db_path='partners.db', sort_by= 'rating', ascending =False):
try:
# Подключаемся к базе данных
conn = sqlite3. connect (db_path)
# SQL запрос для получения данных о партнерах
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 "Дата создания"
FROM Partner p
JOIN PartnerType pt ON p.partner_type_id = pt.id
"""
if 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()
return df
except sqlite3.Error as e:
print(f"Ошибка базы данных: {e}")
return None
except Exception as e:
print(f"Общая ошибка: {e}")
return None
def print_partners(partners_df):
"""ФУНКЦИЯ для красивого вывода данных о партнерах"""
if partners_df is None or partners_df.empty:
print("Нет данных о партнерах")
return
# Выводим данные в удобном формате
print("=" * 120)
print("{:<7} {:<20} {:<35} {:<20} {:<10}".format(
"Тип", "Наименование", "Директор","Телефон","Рейтинг"
))
print("=" * 120)
for _, row in partners_df.iterrows():
print("{:<7} {:<20} {:<35} {:<20} {:<10}".format(
row['Тип партнера'] [:7],
row['Наименование партнера'] [:20],
row['Директор'] [:35],
row['Телефон'][:20],
row['Рейтинг']
))
print("=" * 120)
print(f"Всего партнеров: {len(partners_df)}")
def get_partners_with_stats(db_path='partners.db'):
"""Функция для получения партнеров со статистикой продаж"""
try:
conn = sqlite3.connect(db_path)
query = """
SELECT
pt.type_name AS "Тип партнера",
p.name AS "Наименование партнера",
p.director AS "Директор",
p.rating AS "Рейтинг",
COUNT (s.id) AS "Количество продаж",
SUM(COALESCE(s.quantity, 0)) AS "Общее количество товаров",
SUM(COALESCE(s.quantity * s.sale_price, 0)) AS "Общий объем продаж",
p.created_at AS "Дата регистрации"
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
ORDER BY "Общий объем продаж" DESC"""
df = pd.read_sql_query(query, conn)
conn.close()
return df
except Exception as e:
print(f"Общая ошибка: {e}")
return None
# print("╔" + "═" * 69 + "╗")
# print(f"║ {'КАРТОЧКА ПАРТНЕРА':^67} ║")
# print("╠" + "═" * 69 + "╣")
# print("╚" + "═" * 69 + "╝")
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("╔" + "═" * 70 + "╗")
print(f"║{'КАРТОЧКА ПАРТНЕРА':^70}║")
print("╠" + "═" * 70 + "╣")
# Используем разные кавычки для избежания конфликта
type_text = f"Тип: {row['Тип партнера']}"
name_text = f"Наименование: {row['Наименование партнера']}"
director_text = f"Директор: {row['Директор']}"
rating_text = f"Рейтинг: {row['Рейтинг']}"
email_text = f"Контакты: {row['Электронная почта']}"
phone_text = f"Телефон: {row['Телефон']}"
inn_text = f"ИНН: {row['ИНН']}"
address_text = row['Юридический адрес']
print(f"║{type_text:<70}║")
print(f"║{name_text:<70}║")
print(f"║{director_text:<70}║")
print(f"║{rating_text:<70}║")
print(f"║{'':<70}║")
print(f"║{email_text:<70}║")
print(f"║{phone_text:<70}║")
print(f"║{'':<70}║")
print(f"║{inn_text:<70}║")
print(f"║{address_text:<70}║")
print("╚" + "═" * 70 + "╝")
print()
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 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Домой! 👋")
break
elif choice == 'ВЫХОД':
print("\nДо свидания! 👋")
break
if __name__ == "__main__":
# Проверяем данные
print("Данные успешно добавлены в базу данных!")
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} записей")
conn.close()
display_menu()
# print("\n3. Партнеры со статистикой продаж:")
# partners_stats = get_partners_with_stats()
#
# if partners_stats is not None:
# print(partners_stats.to_string(index=False))
#
# print("\n4. Полные данные о партнерах:")
# # Выводим полную информацию в табличном виде
# full_data = get_partners()
# if full_data is not None:
# print(full_data.to_string(index=False))