124 lines
4.4 KiB
Python
124 lines
4.4 KiB
Python
import sqlite3
|
|
from tkinter import messagebox
|
|
|
|
import customtkinter as ctk
|
|
|
|
from app.ui.base_frame import BaseAppFrame
|
|
from app.utils.validators import normalize_text, parse_float
|
|
|
|
|
|
class AccountsFrame(BaseAppFrame):
|
|
"""Screen for account management."""
|
|
|
|
def __init__(self, master, refresh_callback) -> None:
|
|
super().__init__(master, 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=20)
|
|
form_frame.grid(row=0, column=0, sticky="ns", padx=(8, 12), pady=8)
|
|
|
|
self.title_label(form_frame, "Счета и карты").pack(
|
|
anchor="w", padx=18, pady=(18, 4)
|
|
)
|
|
self.subtitle_label(
|
|
form_frame,
|
|
"Добавьте карту, кошелёк, счёт или наличные.",
|
|
).pack(anchor="w", padx=18, pady=(0, 18))
|
|
|
|
self.name_entry = ctk.CTkEntry(
|
|
form_frame,
|
|
width=300,
|
|
placeholder_text="Название счёта",
|
|
)
|
|
self.name_entry.pack(padx=18, pady=8)
|
|
|
|
self.type_menu = ctk.CTkOptionMenu(
|
|
form_frame,
|
|
width=300,
|
|
values=["Карта", "Наличные", "Счёт", "Электронный кошелёк"],
|
|
)
|
|
self.type_menu.set("Карта")
|
|
self.type_menu.pack(padx=18, pady=8)
|
|
|
|
self.balance_entry = ctk.CTkEntry(
|
|
form_frame,
|
|
width=300,
|
|
placeholder_text="Стартовый баланс",
|
|
)
|
|
self.balance_entry.pack(padx=18, pady=8)
|
|
|
|
self.add_button = self.primary_button(
|
|
form_frame,
|
|
"Добавить счёт",
|
|
lambda: self.run_safe(self.add_account, self.add_button),
|
|
)
|
|
self.add_button.pack(fill="x", 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 = normalize_text(self.name_entry.get(), "Название")
|
|
account_type = self.type_menu.get()
|
|
balance = parse_float(self.balance_entry.get(), "Стартовый баланс")
|
|
self.service.add_account(name, account_type, balance)
|
|
self.name_entry.delete(0, "end")
|
|
self.balance_entry.delete(0, "end")
|
|
self.refresh_callback()
|
|
|
|
def delete_account(self, account_id: int) -> None:
|
|
if not messagebox.askyesno("Подтверждение", "Удалить выбранный счёт?"):
|
|
return
|
|
try:
|
|
self.service.delete_account(account_id)
|
|
except sqlite3.IntegrityError:
|
|
messagebox.showerror(
|
|
"Ошибка",
|
|
"Нельзя удалить счёт, пока к нему привязаны операции.",
|
|
)
|
|
return
|
|
self.refresh_callback()
|
|
|
|
def refresh_data(self) -> None:
|
|
self.clear(self.list_frame)
|
|
rows = self.service.list_accounts()
|
|
if not rows:
|
|
self._empty("Пока нет ни одного счёта.")
|
|
return
|
|
|
|
for row in rows:
|
|
card = ctk.CTkFrame(self.list_frame, corner_radius=16)
|
|
card.pack(fill="x", padx=6, pady=6)
|
|
card.grid_columnconfigure(0, weight=1)
|
|
|
|
ctk.CTkLabel(
|
|
card,
|
|
text=row["name"],
|
|
font=ctk.CTkFont(size=18, weight="bold"),
|
|
).grid(row=0, column=0, sticky="w", padx=16, pady=(12, 4))
|
|
|
|
button = self.danger_button(
|
|
card,
|
|
"Удалить",
|
|
lambda account_id=row["id"]: self.run_safe(
|
|
lambda: self.delete_account(account_id)
|
|
),
|
|
)
|
|
button.grid(row=0, column=1, sticky="e", padx=16, pady=(12, 4))
|
|
|
|
ctk.CTkLabel(
|
|
card,
|
|
text=f"Тип: {row['account_type']} | Баланс: {self.money(row['balance'])}",
|
|
text_color="gray70",
|
|
).grid(row=1, column=0, columnspan=2, sticky="w", padx=16, pady=(0, 14))
|
|
|
|
def _empty(self, text: str) -> None:
|
|
ctk.CTkLabel(self.list_frame, text=text, text_color="gray70").pack(
|
|
anchor="w", padx=10, pady=10
|
|
)
|