Удалить finance_manager.py

This commit is contained in:
Алексей Багин 2026-04-02 19:14:31 +00:00
parent bbf4141316
commit fa1a7e559b

View File

@ -1,263 +0,0 @@
import csv
from datetime import datetime, timedelta
def load_transactions(filepath: str) -> list[dict]:
"""Загружает список транзакций из CSV-файла."""
transactions = []
try:
with open(filepath, 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
try:
transaction = {
'id': int(row['id']),
'date': row['date'],
'amount': float(row['amount']),
'category': row['category'],
'description': row['description']
}
transactions.append(transaction)
except (ValueError, KeyError):
# Пропускаем строки с некорректным форматом
continue
print(f"Загружено транзакций: {len(transactions)}")
return transactions
except FileNotFoundError:
print(f"Ошибка: Файл {filepath} не найден")
return []
except Exception as e:
print(f"Ошибка при чтении файла: {e}")
return []
def filter_by_date_range(transactions: list[dict], start_date: str, end_date: str) -> list[dict]:
"""Фильтрует транзакции по диапазону дат."""
return [t for t in transactions if start_date <= t['date'] <= end_date]
def filter_by_category(transactions: list[dict], categories: list[str], exclude: bool = False) -> list[dict]:
"""
Фильтрует транзакции по категориям.
Параметры:
- transactions: список транзакций.
- categories:список категорий для фильтрации
- exclude: если True - исключает указанные категории, если False - оставляет только их
Возвращает: отфильтрованый список транзакций
"""
categories_lower = [c.lower() for c in categories]
if exclude:
return [t for t in transactions if t['category'].lower() not in categories_lower]
else:
return [t for t in transactions if t['category'].lower() in categories_lower]
def filter_by_amount_threshold(transactions: list[dict], min_amount: float = None, max_amount: float = None) -> list[dict]:
"""Фильтрует транзакции по диапазону сумм"""
result = transactions
if min_amount is not None:
result = [t for t in result if t['amount'] >= min_amount]
if max_amount is not None:
result = [t for t in result if t['amount'] <= max_amount]
return result
def calculate_balance(transactions: list[dict]) -> float:
"""Вычисляет общий баланс"""
balance = sum(t['amount'] for t in transactions)
return round(balance, 2)
def group_by_category(transactions: list[dict]) -> dict[str, float]:
"""Группирует транзакции по категориям"""
groups = {}
for t in transactions:
category = t['category']
groups[category] = groups.get(category, 0) + t['amount']
return {cat: round(amount, 2) for cat, amount in groups.items()}
def get_top_expenses(transactions: list[dict], n: int) -> list[dict]:
"""Возвращает n транзакций с наибольшими расходами."""
expenses = [t for t in transactions if t['amount'] < 0]
expenses.sort(key=lambda x: x['amount']) # Сортировка от наиболее отрицательных
return expenses[:n]
def get_average_daily_expenses(transactions: list[dict], days: int = 30) -> float:
"""Вычисляет среднюю сумму расходов за последние days дней."""
if not transactions:
return 0.0
# Находим самую позднюю дату
latest_date = max(t['date'] for t in transactions)
latest_date_obj = datetime.strptime(latest_date, "%Y-%m-%d")
start_date_obj = latest_date_obj - timedelta(days=days - 1)
start_date = start_date_obj.strftime("%Y-%m-%d")
# Фильтруем расходы за указанный период
expenses_in_period = [
t for t in transactions
if t['amount'] < 0 and start_date <= t['date'] <= latest_date
]
if not expenses_in_period:
return 0.0
total_expenses = abs(sum(t['amount'] for t in expenses_in_period))
return round(total_expenses / days, 2)
def find_transactions_by_text(transactions: list[dict], keyword: str) -> list[dict]:
"""находит транзакции по ключевому слову в описании."""
keyword_lower = keyword.lower()
return [t for t in transactions if keyword_lower in t['description'].lower()]
def generate_summary_report(transactions: list[dict]) -> str:
"""генерирует текстовый отчет по транзакциям."""
if not transactions:
return "Нет данных для формирования отчета"
total_count = len(transactions)
incomes = [t for t in transactions if t['amount'] > 0]
expenses = [t for t in transactions if t['amount'] < 0]
total_income = sum(t['amount'] for t in incomes)
total_expense = abs(sum(t['amount'] for t in expenses))
balance = total_income - total_expense
# Топ-3 категории по расходам
expenses_by_category = {}
for t in expenses:
expenses_by_category[t['category']] = expenses_by_category.get(t['category'], 0) + abs(t['amount'])
top_categories = sorted(expenses_by_category.items(), key=lambda x: x[1], reverse=True)[:3]
# Самая крупная расходная транзакция
largest_expense = min(expenses, key=lambda x: x['amount']) if expenses else None
# Формируем отчёт
report = []
report.append("=" * 50)
report.append("ФИНАНСОВЫЙ ОТЧЕТ")
report.append("=" * 50)
report.append(f"Всего транзакций: {total_count}")
report.append(f"Общий доход: {total_income:.2f} руб.")
report.append(f"Общий расход: {total_expense:.2f} руб.")
report.append(f"Итоговый баланс: {balance:.2f} руб.")
report.append("-" * 50)
report.append("ТОП-3 КАТЕГОРИИ ПО РАСХОДАМ:")
for i, (cat, amount) in enumerate(top_categories, 1):
report.append(f" {i}. {cat}: {amount:.2f} руб.")
if largest_expense:
report.append("-" * 50)
report.append("САМАЯ КРУПНАЯ РАСХОДНАЯ ТРАНЗАКЦИЯ:")
report.append(f" Дата: {largest_expense['date']}")
report.append(f" Категория: {largest_expense['category']}")
report.append(f" Сумма: {largest_expense['amount']:.2f} руб.")
report.append(f" Описание: {largest_expense['description']}")
report.append("=" * 50)
return "\n".join(report)
def main():
"""Главная функция, демонстрирующая работу всех функций."""
print("=" * 60)
print("СИСТЕМА УПРАВЛЕНИЯ ЛИЧНЫМИ ФИНАНСАМИ")
print("=" * 60)
# 1.Загрузка данных
print("\n1. ЗАГРУЗКА ДАННЫХ")
print("-" * 40)
transactions = load_transactions('data/transactions.txt')
if not transactions:
print("Нет данных для обработки. Завершение работы.")
return
# 2. Фильтрация по дате (последние 90 дней)
print("\n2. ФИЛЬТРАЦИЯ ПО ДАТЕ (последние 90 дней)")
print("-" * 40)
# Находим самую позднюю и самую раннюю дату
latest_date = max(t['date'] for t in transactions)
earliest_date = min(t['date'] for t in transactions)
latest_date_obj = datetime.strptime(latest_date, "%Y-%m-%d")
# Вычисляем дату 90 дней назад
start_date_obj = latest_date_obj - timedelta(days=89)
start_date = start_date_obj.strftime("%Y-%m-%d")
end_date = latest_date
# Если start_date раньше earliest_date, то используем earliest_date
if start_date < earliest_date:
start_date = earliest_date
print(f"Примечание: Данных за последние 90 дней недостаточно")
print(f"Используем все доступные данные с {start_date} по {end_date}")
else:
print(f"Период: с {start_date} по {end_date}")
filtered_by_date = filter_by_date_range(transactions, start_date, end_date)
print(f"Транзакций после фильтрации по дате: {len(filtered_by_date)}")
# 3. Фильтрация по категориям (исключаем "Перевод" и "Инвестиции")
print("\n3. ФИЛЬТРАЦИЯ ПО КАТЕГОРИЯМ (исключаем 'Перевод' и 'Инвестиции')")
print("-" * 40)
excluded_categories = ["Перевод", "Инвестиции"]
filtered_by_category_data = filter_by_category(filtered_by_date, excluded_categories, exclude=True)
print(f"Транзакций после фильтрации по категориям: {len(filtered_by_category_data)}")
# 4. Расчёт баланса
print("\n4. РАСЧЁТ БАЛАНСА")
print("-" * 40)
balance = calculate_balance(filtered_by_category_data)
print(f"Баланс за период: {balance:.2f} руб.")
# 5. Топ-5 расходов
print("\n5. ТОП-5 РАСХОДОВ")
print("-" * 40)
top_expenses = get_top_expenses(filtered_by_category_data, 5)
if top_expenses:
for i, expense in enumerate(top_expenses, 1):
print(f"{i}. {expense['date']} | {expense['category']} | {expense['amount']:.2f} руб. | {expense['description']}")
else:
print("Нет расходов за указанный период")
# 6. Поиск транзакций по ключевому слову "кафе"
print("\n6. ПОИСК ПО КЛЮЧЕВОМУ СЛОВУ 'кафе'")
print("-" * 40)
found_transactions = find_transactions_by_text(filtered_by_category_data, "кафе")
if found_transactions:
print(f"Найдено транзакций: {len(found_transactions)}")
for t in found_transactions:
print(f" {t['date']} | {t['category']} | {t['amount']:.2f} руб. | {t['description']}")
else:
print("Транзакции с ключевым словом 'кафе' не найдены")
# 7. Среднедневные расходы за последние 30 дней
print("\n7. СРЕДНЕДНЕВНЫЕ РАСХОДЫ (последние 30 дней)")
print("-" * 40)
avg_expenses = get_average_daily_expenses(filtered_by_category_data, 30)
print(f"Среднедневные расходы: {avg_expenses:.2f} руб.")
# 8. Группировка по категориям
print("\n8. ГРУППИРОВКА ПО КАТЕГОРИЯМ")
print("-" * 40)
grouped = group_by_category(filtered_by_category_data)
for category, amount in sorted(grouped.items(), key=lambda x: x[1], reverse=True):
print(f" {category}: {amount:.2f} руб.")
# 9. Итоговый отчет
print("\n9. ИТОГОВЫЙ ОТЧЕТ")
print("-" * 40)
report = generate_summary_report(filtered_by_category_data)
print(report)
# 10. Демонстрация фильтрации по сумме
print("\n10. ДЕМОНСТРАЦИЯ ФИЛЬТРАЦИИ ПО СУММЕ")
print("-" * 40)
large_expenses = filter_by_amount_threshold(filtered_by_category_data, max_amount=-500)
print(f"Расходы более 500 руб. (сумма < -500): {len(large_expenses)} транзакций")
for expense in large_expenses[:3]: # Показываем первые 3
print(f" {expense['date']} | {expense['category']} | {expense['amount']:.2f} руб.")
print("\n" + "=" * 60)
print("ОБРАБОТКА ЗАВЕРШЕНА")
print("=" * 60)
if __name__ == "__main__":
main()