init commit

This commit is contained in:
2025-12-10 22:09:31 +09:00
commit b79adf1c69
361 changed files with 47414 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
"""Analytics service module"""
from app.services.analytics.report_service import ReportService
__all__ = ["ReportService"]

View File

@@ -0,0 +1,111 @@
"""Report service for analytics"""
from typing import List, Dict
from datetime import datetime, timedelta
from sqlalchemy.orm import Session
from app.db.repositories import TransactionRepository, CategoryRepository
from app.db.models import TransactionType
class ReportService:
"""Service for generating financial reports"""
def __init__(self, session: Session):
self.session = session
self.transaction_repo = TransactionRepository(session)
self.category_repo = CategoryRepository(session)
def get_expenses_by_category(
self, family_id: int, start_date: datetime, end_date: datetime
) -> Dict[str, float]:
"""Get expense breakdown by category"""
transactions = self.transaction_repo.get_transactions_by_period(
family_id, start_date, end_date
)
expenses_by_category = {}
for transaction in transactions:
if transaction.transaction_type == TransactionType.EXPENSE:
category_name = transaction.category.name if transaction.category else "Без категории"
if category_name not in expenses_by_category:
expenses_by_category[category_name] = 0
expenses_by_category[category_name] += transaction.amount
# Sort by amount descending
return dict(sorted(expenses_by_category.items(), key=lambda x: x[1], reverse=True))
def get_expenses_by_user(
self, family_id: int, start_date: datetime, end_date: datetime
) -> Dict[str, float]:
"""Get expense breakdown by user"""
transactions = self.transaction_repo.get_transactions_by_period(
family_id, start_date, end_date
)
expenses_by_user = {}
for transaction in transactions:
if transaction.transaction_type == TransactionType.EXPENSE:
user_name = f"{transaction.user.first_name or ''} {transaction.user.last_name or ''}".strip()
if not user_name:
user_name = transaction.user.username or f"User {transaction.user.id}"
if user_name not in expenses_by_user:
expenses_by_user[user_name] = 0
expenses_by_user[user_name] += transaction.amount
return dict(sorted(expenses_by_user.items(), key=lambda x: x[1], reverse=True))
def get_daily_expenses(
self, family_id: int, days: int = 30
) -> Dict[str, float]:
"""Get daily expenses for period"""
end_date = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
start_date = end_date - timedelta(days=days)
transactions = self.transaction_repo.get_transactions_by_period(
family_id, start_date, end_date
)
daily_expenses = {}
for transaction in transactions:
if transaction.transaction_type == TransactionType.EXPENSE:
date_key = transaction.transaction_date.date().isoformat()
if date_key not in daily_expenses:
daily_expenses[date_key] = 0
daily_expenses[date_key] += transaction.amount
return dict(sorted(daily_expenses.items()))
def get_month_comparison(self, family_id: int) -> Dict[str, float]:
"""Compare expenses: current month vs last month"""
today = datetime.utcnow()
current_month_start = today.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
# Last month
last_month_end = current_month_start - timedelta(days=1)
last_month_start = last_month_end.replace(day=1)
current_transactions = self.transaction_repo.get_transactions_by_period(
family_id, current_month_start, today
)
last_transactions = self.transaction_repo.get_transactions_by_period(
family_id, last_month_start, last_month_end
)
current_expenses = sum(
t.amount for t in current_transactions
if t.transaction_type == TransactionType.EXPENSE
)
last_expenses = sum(
t.amount for t in last_transactions
if t.transaction_type == TransactionType.EXPENSE
)
difference = current_expenses - last_expenses
percent_change = ((difference / last_expenses * 100) if last_expenses > 0 else 0)
return {
"current_month": current_expenses,
"last_month": last_expenses,
"difference": difference,
"percent_change": percent_change,
}