import sqlite3 from tkinter import messagebox import customtkinter as ctk from app.database import get_connection class AccountsFrame(ctk.CTkFrame): def __init__(self, master, refresh_callback) -> None: super().__init__(master) self.refresh_callback = refresh_callback self.grid_columnconfigure(1, weight=1) self.grid_rowconfigure(0, weight=1) self._build_form() self._build_list() def _build_form(self) -> None: form_frame = ctk.CTkFrame(self, corner_radius=18) form_frame.grid(row=0, column=0, sticky="ns", padx=(8, 12), pady=8) title = ctk.CTkLabel( form_frame, text="Счета и карты", font=ctk.CTkFont(size=26, weight="bold"), ) title.pack(anchor="w", padx=18, pady=(18, 6)) subtitle = ctk.CTkLabel( form_frame, text="Добавьте карту, кошелёк или наличные.", text_color="gray75", ) subtitle.pack(anchor="w", padx=18, pady=(0, 18)) self.name_entry = ctk.CTkEntry( form_frame, width=280, placeholder_text="Название", ) self.name_entry.pack(padx=18, pady=8) self.type_menu = ctk.CTkOptionMenu( form_frame, width=280, values=["Карта", "Наличные", "Счёт", "Электронный кошелёк"], ) self.type_menu.pack(padx=18, pady=8) self.type_menu.set("Карта") self.balance_entry = ctk.CTkEntry( form_frame, width=280, placeholder_text="Стартовый баланс", ) self.balance_entry.pack(padx=18, pady=8) add_button = ctk.CTkButton( form_frame, text="Добавить счёт", width=280, height=42, command=self.add_account, ) add_button.pack(padx=18, pady=(12, 18)) def _build_list(self) -> None: self.list_frame = ctk.CTkScrollableFrame(self, label_text="Список счетов") self.list_frame.grid(row=0, column=1, sticky="nsew", padx=(0, 8), pady=8) def add_account(self) -> None: name = self.name_entry.get().strip() account_type = self.type_menu.get() balance_text = self.balance_entry.get().strip().replace(",", ".") if not name or not balance_text: messagebox.showerror("Ошибка", "Заполните все поля.") return try: balance = float(balance_text) except ValueError: messagebox.showerror("Ошибка", "Баланс должен быть числом.") return with get_connection() as connection: connection.execute( """ INSERT INTO accounts (name, account_type, balance) VALUES (?, ?, ?) """, (name, account_type, balance), ) connection.commit() self.name_entry.delete(0, "end") self.balance_entry.delete(0, "end") self.refresh_callback() def delete_account(self, account_id: int) -> None: try: with get_connection() as connection: connection.execute("DELETE FROM accounts WHERE id = ?", (account_id,)) connection.commit() except sqlite3.IntegrityError: messagebox.showerror( "Ошибка", "Нельзя удалить счёт, пока к нему привязаны операции.", ) return self.refresh_callback() def refresh_data(self) -> None: for widget in self.list_frame.winfo_children(): widget.destroy() with get_connection() as connection: accounts = connection.execute( "SELECT * FROM accounts ORDER BY id DESC" ).fetchall() if not accounts: empty_label = ctk.CTkLabel( self.list_frame, text="Пока нет ни одного счёта.", text_color="gray70", ) empty_label.pack(anchor="w", padx=10, pady=10) return for account in accounts: card = ctk.CTkFrame(self.list_frame, corner_radius=16) card.pack(fill="x", padx=6, pady=6) title = ctk.CTkLabel( card, text=account["name"], font=ctk.CTkFont(size=18, weight="bold"), ) title.grid(row=0, column=0, sticky="w", padx=16, pady=(12, 6)) delete_button = ctk.CTkButton( card, text="Удалить", width=90, fg_color="#b33939", hover_color="#932f2f", command=lambda account_id=account["id"]: self.delete_account(account_id), ) delete_button.grid(row=0, column=1, sticky="e", padx=16, pady=(12, 6)) info = ctk.CTkLabel( card, text=( f"Тип: {account['account_type']} | Баланс: " f"{account['balance']:,.2f} ₽" ).replace(",", " "), text_color="gray75", ) info.grid(row=1, column=0, columnspan=2, sticky="w", padx=16, pady=(0, 14))