from __future__ import annotations from dataclasses import dataclass from datetime import datetime from enum import Enum class TransactionKind(str, Enum): EXPENSE = "expense" INCOME = "income" class Category(str, Enum): PRODUCTS = "products" ENTERTAINMENT = "entertainment" CAR = "car" CREDITS = "credits" RENOVATION = "renovation" OTHER = "other" INCOME = "income" @dataclass(frozen=True, slots=True) class ParsedTransaction: amount_kopecks: int description: str kind: TransactionKind debt_effect: int debt_effect_override: int | None = None @dataclass(frozen=True, slots=True) class Transaction: id: int user_id: int amount_kopecks: int description: str kind: TransactionKind category: Category debt_effect: int occurred_at: datetime author_name: str | None = None budget_category_id: int | None = None budget_category_name: str | None = None budget_category_icon: str | None = None parent_category_name: str | None = None parent_category_icon: str | None = None @dataclass(frozen=True, slots=True) class BudgetCategory: id: int name: str icon: str parent_id: int | None parent_name: str | None = None parent_icon: str | None = None system_key: str | None = None kind: str = "expense" @property def display_name(self) -> str: if self.parent_name: return f"{self.parent_icon or '📁'} {self.parent_name} → {self.icon} {self.name}" return f"{self.icon} {self.name}" @dataclass(frozen=True, slots=True) class FamilyInfo: household_id: int invite_code: str members: tuple[str, ...] owner_user_id: int notification_chat_id: int | None = None notification_chat_title: str | None = None @dataclass(frozen=True, slots=True) class FamilyJoinRequest: candidate_user_id: int candidate_name: str owner_chat_id: int @dataclass(frozen=True, slots=True) class Totals: income: int = 0 expense: int = 0 @property def balance(self) -> int: return self.income - self.expense