init commit
This commit is contained in:
5
app/services/analytics/__init__.py
Normal file
5
app/services/analytics/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
"""Analytics service module"""
|
||||
|
||||
from app.services.analytics.report_service import ReportService
|
||||
|
||||
__all__ = ["ReportService"]
|
||||
111
app/services/analytics/report_service.py
Normal file
111
app/services/analytics/report_service.py
Normal 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,
|
||||
}
|
||||
Reference in New Issue
Block a user