Удалить finance_manager.py
This commit is contained in:
parent
88de2fa12a
commit
c2aa7c33a8
@ -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()
|
|
||||||
Loading…
Reference in New Issue
Block a user