Загрузка данных
# main.py
import tkinter as tk
from tkinter import ttk, messagebox
from database import DatabaseManager
from datetime import datetime
class OrderApp:
def __init__(self, root):
self.root = root
self.root.title("Анализ заказов")
self.root.geometry("1000x700")
self.root.resizable(True, True)
# Подключение к БД
self.db = DatabaseManager()
try:
self.db.connect()
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось подключиться к БД: {e}")
self.root.quit()
# Данные
self.all_orders = []
self.filtered_orders = []
self.customers = []
self.customers_dict = {}
# Заголовок
title = tk.Label(root, text="Работа с заказами", font=("Arial", 18, "bold"))
title.pack(pady=10)
# Верхняя панель с фильтрацией
self.create_filter_panel()
# Панель поиска
self.create_search_panel()
# Панель сортировки
self.create_sort_panel()
# Таблица для отображения данных
self.create_table()
# Нижняя панель с итогами
self.create_bottom_panel()
# Загрузка данных
self.load_initial_data()
def create_filter_panel(self):
"""Создание панели фильтрации по клиенту"""
filter_frame = ttk.LabelFrame(self.root, text="Фильтр по заказчику", padding="10")
filter_frame.pack(fill=tk.X, padx=10, pady=5)
ttk.Label(filter_frame, text="Выберите заказчика:").grid(row=0, column=0, padx=5, pady=5)
self.customer_var = tk.StringVar()
self.customer_combo = ttk.Combobox(filter_frame, textvariable=self.customer_var, width=40)
self.customer_combo.grid(row=0, column=1, padx=5, pady=5)
ttk.Button(filter_frame, text="Фильтровать", command=self.filter_by_customer).grid(row=0, column=2, padx=5)
ttk.Button(filter_frame, text="Показать все", command=self.show_all).grid(row=0, column=3, padx=5)
def create_search_panel(self):
"""Создание панели поиска"""
search_frame = ttk.LabelFrame(self.root, text="Поиск", padding="10")
search_frame.pack(fill=tk.X, padx=10, pady=5)
ttk.Label(search_frame, text="Введите строку поиска:").grid(row=0, column=0, padx=5, pady=5)
self.search_var = tk.StringVar()
self.search_entry = ttk.Entry(search_frame, textvariable=self.search_var, width=40)
self.search_entry.grid(row=0, column=1, padx=5, pady=5)
ttk.Button(search_frame, text="Найти", command=self.search_text).grid(row=0, column=2, padx=5)
def create_sort_panel(self):
"""Создание панели сортировки"""
sort_frame = ttk.LabelFrame(self.root, text="Сортировка", padding="10")
sort_frame.pack(fill=tk.X, padx=10, pady=5)
ttk.Label(sort_frame, text="Выберите поле для сортировки:").grid(row=0, column=0, padx=5, pady=5)
self.sort_field = tk.StringVar(value="Заказчик")
sort_combo = ttk.Combobox(sort_frame, textvariable=self.sort_field,
values=["Заказчик", "Дата заказа", "Сумма заказа"],
state="readonly", width=20)
sort_combo.grid(row=0, column=1, padx=5, pady=5)
# Переключатели для направления сортировки
self.sort_order = tk.StringVar(value="asc")
ttk.Radiobutton(sort_frame, text="По возрастанию", variable=self.sort_order,
value="asc", command=self.apply_sort).grid(row=0, column=2, padx=10)
ttk.Radiobutton(sort_frame, text="По убыванию", variable=self.sort_order,
value="desc", command=self.apply_sort).grid(row=0, column=3, padx=10)
ttk.Button(sort_frame, text="Применить сортировку", command=self.apply_sort).grid(row=0, column=4, padx=10)
def create_table(self):
"""Создание таблицы для отображения данных"""
table_frame = ttk.Frame(self.root)
table_frame.pack(expand=True, fill=tk.BOTH, padx=10, pady=5)
# Скроллинг
scrollbar = ttk.Scrollbar(table_frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# Treeview
self.tree = ttk.Treeview(table_frame,
columns=("customer", "city", "phone", "date", "sum"),
show="headings",
yscrollcommand=scrollbar.set)
scrollbar.config(command=self.tree.yview)
# Заголовки
self.tree.heading("customer", text="Заказчик", command=lambda: self.sort_by_click("Заказчик"))
self.tree.heading("city", text="Город")
self.tree.heading("phone", text="Телефон")
self.tree.heading("date", text="Дата заказа", command=lambda: self.sort_by_click("Дата заказа"))
self.tree.heading("sum", text="Сумма заказа", command=lambda: self.sort_by_click("Сумма заказа"))
# Ширина колонок
self.tree.column("customer", width=250)
self.tree.column("city", width=150)
self.tree.column("phone", width=150)
self.tree.column("date", width=120)
self.tree.column("sum", width=120, anchor=tk.E)
self.tree.pack(expand=True, fill=tk.BOTH)
# Теги для выделения поиска
self.tree.tag_configure('found', background='yellow')
def create_bottom_panel(self):
"""Создание нижней панели с итогами"""
bottom_frame = ttk.Frame(self.root)
bottom_frame.pack(fill=tk.X, padx=10, pady=10)
self.total_orders_label = ttk.Label(bottom_frame, text="Всего заказов: 0",
font=("Arial", 11, "bold"))
self.total_orders_label.pack(side=tk.LEFT, padx=20)
self.total_sum_label = ttk.Label(bottom_frame, text="Общая сумма: 0.00",
font=("Arial", 11, "bold"))
self.total_sum_label.pack(side=tk.LEFT, padx=20)
self.status_label = ttk.Label(bottom_frame, text="Готово", font=("Arial", 10))
self.status_label.pack(side=tk.RIGHT, padx=20)
def load_initial_data(self):
"""Загрузка начальных данных"""
try:
# Загрузка клиентов
self.customers = self.db.get_customers()
self.customers_dict = {name: id for id, name in self.customers}
self.customer_combo['values'] = list(self.customers_dict.keys())
# Загрузка заказов
self.all_orders = self.db.get_all_orders()
self.filtered_orders = self.all_orders.copy()
self.display_data()
self.status_label.config(text=f"Загружено заказов: {len(self.all_orders)}")
except Exception as e:
messagebox.showerror("Ошибка", f"Не удалось загрузить данные: {e}")
def display_data(self):
"""Отображение данных в таблице"""
# Очистка таблицы
for item in self.tree.get_children():
self.tree.delete(item)
# Вставка данных
for order in self.filtered_orders:
# Извлечение города из адреса
city = self.extract_city(order.get('CITY', ''))
# Форматирование даты
date = order['ORDER_DATE']
if hasattr(date, 'strftime'):
date_str = date.strftime('%d.%m.%Y')
else:
date_str = str(date)
self.tree.insert("", tk.END, values=(
order['CUSTOMER_NAME'],
city,
order['PHONE'],
date_str,
f"{order['ORDER_SUM']:.2f}"
))
# Обновление итогов
self.update_totals()
def extract_city(self, address):
"""Извлечение города из адреса"""
if not address:
return ""
# Пытаемся найти "г. "
parts = address.split("г. ")
if len(parts) > 1:
city = parts[1].split(",")[0]
return city
return address[:30] if address else ""
def update_totals(self):
"""Обновление итоговых значений"""
total_orders = len(self.filtered_orders)
total_sum = sum(order['ORDER_SUM'] for order in self.filtered_orders)
self.total_orders_label.config(text=f"Всего заказов: {total_orders}")
self.total_sum_label.config(text=f"Общая сумма: {total_sum:,.2f}".replace(',', ' '))
def filter_by_customer(self):
"""Фильтрация по выбранному клиенту"""
customer_name = self.customer_var.get()
if not customer_name:
messagebox.showwarning("Предупреждение", "Выберите заказчика")
return
try:
customer_id = self.customers_dict.get(customer_name)
if customer_id:
self.filtered_orders = self.db.get_orders_by_customer(customer_id)
self.display_data()
self.status_label.config(text=f"Показаны заказы клиента: {customer_name}")
except Exception as e:
messagebox.showerror("Ошибка", f"Ошибка фильтрации: {e}")
def show_all(self):
"""Показать все заказы"""
self.customer_var.set("")
self.filtered_orders = self.all_orders.copy()
self.display_data()
self.status_label.config(text="Показаны все заказы")
def search_text(self):
"""Поиск и выделение текста"""
search_str = self.search_var.get().lower()
if not search_str:
# Сброс выделения
for item in self.tree.get_children():
self.tree.item(item, tags=())
return
# Поиск и выделение
found_count = 0
for item in self.tree.get_children():
values = self.tree.item(item)['values']
found = False
for value in values:
if search_str in str(value).lower():
found = True
found_count += 1
if found:
self.tree.item(item, tags=('found',))
else:
self.tree.item(item, tags=())
self.status_label.config(text=f"Найдено совпадений: {found_count}")
def apply_sort(self):
"""Применение сортировки"""
field = self.sort_field.get()
order = self.sort_order.get()
self.sort_data(field, order)
def sort_by_click(self, field):
"""Сортировка по клику на заголовок"""
# При клике переключаем направление
if self.sort_field.get() == field:
# Меняем направление
self.sort_order.set("desc" if self.sort_order.get() == "asc" else "asc")
else:
# Новое поле сортировки
self.sort_field.set(field)
self.sort_order.set("asc")
self.sort_data(field, self.sort_order.get())
def sort_data(self, field, order):
"""Сортировка данных"""
try:
if field == "Заказчик":
self.filtered_orders.sort(key=lambda x: x['CUSTOMER_NAME'],
reverse=(order == "desc"))
elif field == "Дата заказа":
self.filtered_orders.sort(key=lambda x: x['ORDER_DATE'],
reverse=(order == "desc"))
elif field == "Сумма заказа":
self.filtered_orders.sort(key=lambda x: x['ORDER_SUM'],
reverse=(order == "desc"))
self.display_data()
self.status_label.config(text=f"Отсортировано по {field} ({order})")
except Exception as e:
messagebox.showerror("Ошибка", f"Ошибка сортировки: {e}")
def __del__(self):
"""Деструктор - закрытие соединения с БД"""
try:
self.db.disconnect()
except:
pass
if __name__ == "__main__":
root = tk.Tk()
app = OrderApp(root)
root.mainloop()