fina/backup/fina-1/app/routes/main.py

290 lines
9.4 KiB
Python
Raw Permalink Normal View History

2025-12-26 00:52:56 +00:00
from flask import Blueprint, render_template, request, jsonify
from flask_login import login_required, current_user
from app import db
from app.models import Expense, Category
from sqlalchemy import func, extract
from datetime import datetime, timedelta
from collections import defaultdict
bp = Blueprint('main', __name__)
@bp.route('/')
def index():
if current_user.is_authenticated:
return render_template('dashboard.html')
return render_template('landing.html')
@bp.route('/dashboard')
@login_required
def dashboard():
return render_template('dashboard.html')
@bp.route('/transactions')
@login_required
def transactions():
return render_template('transactions.html')
@bp.route('/reports')
@login_required
def reports():
return render_template('reports.html')
@bp.route('/settings')
@login_required
def settings():
return render_template('settings.html')
@bp.route('/documents')
@login_required
def documents():
return render_template('documents.html')
@bp.route('/api/dashboard-stats')
@login_required
def dashboard_stats():
now = datetime.utcnow()
# Current month stats
current_month_start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
# Previous month stats
if now.month == 1:
prev_month_start = now.replace(year=now.year-1, month=12, day=1)
else:
prev_month_start = current_month_start.replace(month=current_month_start.month-1)
# Total spent this month
current_month_total = db.session.query(func.sum(Expense.amount)).filter(
Expense.user_id == current_user.id,
Expense.date >= current_month_start,
Expense.currency == current_user.currency
).scalar() or 0
# Previous month total
prev_month_total = db.session.query(func.sum(Expense.amount)).filter(
Expense.user_id == current_user.id,
Expense.date >= prev_month_start,
Expense.date < current_month_start,
Expense.currency == current_user.currency
).scalar() or 0
# Calculate percentage change
if prev_month_total > 0:
percent_change = ((current_month_total - prev_month_total) / prev_month_total) * 100
else:
percent_change = 100 if current_month_total > 0 else 0
# Active categories
active_categories = Category.query.filter_by(user_id=current_user.id).count()
# Total transactions this month
total_transactions = Expense.query.filter(
Expense.user_id == current_user.id,
Expense.date >= current_month_start
).count()
# Category breakdown
category_stats = db.session.query(
Category.name,
Category.color,
func.sum(Expense.amount).label('total')
).join(Expense).filter(
Expense.user_id == current_user.id,
Expense.date >= current_month_start,
Expense.currency == current_user.currency
).group_by(Category.id).all()
# Monthly breakdown (last 6 months)
monthly_data = []
for i in range(5, -1, -1):
month_date = now - timedelta(days=30*i)
month_start = month_date.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
if month_date.month == 12:
month_end = month_date.replace(year=month_date.year+1, month=1, day=1)
else:
month_end = month_date.replace(month=month_date.month+1, day=1)
month_total = db.session.query(func.sum(Expense.amount)).filter(
Expense.user_id == current_user.id,
Expense.date >= month_start,
Expense.date < month_end,
Expense.currency == current_user.currency
).scalar() or 0
monthly_data.append({
'month': month_start.strftime('%b'),
'total': float(month_total)
})
return jsonify({
'total_spent': float(current_month_total),
'percent_change': round(percent_change, 1),
'active_categories': active_categories,
'total_transactions': total_transactions,
'currency': current_user.currency,
'category_breakdown': [
{'name': stat[0], 'color': stat[1], 'amount': float(stat[2])}
for stat in category_stats
],
'monthly_data': monthly_data
})
@bp.route('/api/recent-transactions')
@login_required
def recent_transactions():
limit = request.args.get('limit', 10, type=int)
expenses = Expense.query.filter_by(user_id=current_user.id)\
.order_by(Expense.date.desc())\
.limit(limit)\
.all()
return jsonify({
'transactions': [expense.to_dict() for expense in expenses]
})
@bp.route('/api/reports-stats')
@login_required
def reports_stats():
"""
Generate comprehensive financial reports
Security: Only returns data for current_user (enforced by user_id filter)
"""
period = request.args.get('period', '30') # days
category_filter = request.args.get('category_id', type=int)
try:
days = int(period)
except ValueError:
days = 30
now = datetime.utcnow()
period_start = now - timedelta(days=days)
# Query with security filter
query = Expense.query.filter(
Expense.user_id == current_user.id,
Expense.date >= period_start
)
if category_filter:
query = query.filter_by(category_id=category_filter)
expenses = query.all()
# Total spent in period
total_spent = sum(exp.amount for exp in expenses if exp.currency == current_user.currency)
# Previous period comparison
prev_period_start = period_start - timedelta(days=days)
prev_expenses = Expense.query.filter(
Expense.user_id == current_user.id,
Expense.date >= prev_period_start,
Expense.date < period_start,
Expense.currency == current_user.currency
).all()
prev_total = sum(exp.amount for exp in prev_expenses)
percent_change = 0
if prev_total > 0:
percent_change = ((total_spent - prev_total) / prev_total) * 100
elif total_spent > 0:
percent_change = 100
# Top category
category_totals = {}
for exp in expenses:
if exp.currency == current_user.currency:
cat_name = exp.category.name
category_totals[cat_name] = category_totals.get(cat_name, 0) + exp.amount
top_category = max(category_totals.items(), key=lambda x: x[1]) if category_totals else ('None', 0)
# Average daily spending
avg_daily = total_spent / days if days > 0 else 0
prev_avg_daily = prev_total / days if days > 0 else 0
avg_change = 0
if prev_avg_daily > 0:
avg_change = ((avg_daily - prev_avg_daily) / prev_avg_daily) * 100
elif avg_daily > 0:
avg_change = 100
# Savings rate (placeholder - would need income data)
savings_rate = 18.5 # Placeholder
# Category breakdown for pie chart
category_breakdown = []
for cat_name, amount in sorted(category_totals.items(), key=lambda x: x[1], reverse=True):
category = Category.query.filter_by(user_id=current_user.id, name=cat_name).first()
if category:
percentage = (amount / total_spent * 100) if total_spent > 0 else 0
category_breakdown.append({
'name': cat_name,
'color': category.color,
'amount': float(amount),
'percentage': round(percentage, 1)
})
# Daily spending trend (last 30 days)
daily_trend = []
for i in range(min(30, days)):
day_date = now - timedelta(days=i)
day_start = day_date.replace(hour=0, minute=0, second=0, microsecond=0)
day_end = day_start + timedelta(days=1)
day_total = db.session.query(func.sum(Expense.amount)).filter(
Expense.user_id == current_user.id,
Expense.date >= day_start,
Expense.date < day_end,
Expense.currency == current_user.currency
).scalar() or 0
daily_trend.insert(0, {
'date': day_date.strftime('%d %b'),
'amount': float(day_total)
})
# Monthly comparison (last 6 months)
monthly_comparison = []
for i in range(5, -1, -1):
month_date = now - timedelta(days=30*i)
month_start = month_date.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
if month_date.month == 12:
month_end = month_date.replace(year=month_date.year+1, month=1, day=1)
else:
month_end = month_date.replace(month=month_date.month+1, day=1)
month_total = db.session.query(func.sum(Expense.amount)).filter(
Expense.user_id == current_user.id,
Expense.date >= month_start,
Expense.date < month_end,
Expense.currency == current_user.currency
).scalar() or 0
monthly_comparison.append({
'month': month_start.strftime('%b'),
'amount': float(month_total)
})
return jsonify({
'total_spent': float(total_spent),
'percent_change': round(percent_change, 1),
'top_category': {'name': top_category[0], 'amount': float(top_category[1])},
'avg_daily': float(avg_daily),
'avg_daily_change': round(avg_change, 1),
'savings_rate': savings_rate,
'category_breakdown': category_breakdown,
'daily_trend': daily_trend,
'monthly_comparison': monthly_comparison,
'currency': current_user.currency,
'period_days': days
})