first commit

This commit is contained in:
Mateusz Gruszczyński
2026-03-13 15:17:32 +01:00
commit 986ffb200a
91 changed files with 4423 additions and 0 deletions

133
app/main/routes.py Normal file
View File

@@ -0,0 +1,133 @@
from __future__ import annotations
from datetime import date
from flask import Blueprint, jsonify, redirect, render_template, request, session, url_for
from flask_login import current_user, login_required
from ..extensions import db
from ..forms import PreferencesForm, UserCategoryForm
from ..models import Category
from ..services.analytics import (
compare_years,
daily_totals,
monthly_summary,
payment_method_totals,
quarterly_totals,
range_totals,
top_expenses,
weekday_totals,
yearly_category_totals,
yearly_overview,
yearly_totals,
)
from ..services.audit import log_action
from ..services.i18n import translate as _
from ..services.settings import get_bool_setting
main_bp = Blueprint('main', __name__)
@main_bp.route('/')
def index():
if current_user.is_authenticated:
return redirect(url_for('main.dashboard'))
return redirect(url_for('auth.login'))
@main_bp.post('/language')
def set_language():
lang = request.form.get('language', 'pl')
if lang not in ['pl', 'en']:
lang = 'pl'
session['language'] = lang
if current_user.is_authenticated:
current_user.language = lang
db.session.commit()
return redirect(request.form.get('next') or request.referrer or url_for('main.index'))
@main_bp.route('/dashboard')
@login_required
def dashboard():
today = date.today()
year = request.args.get('year', today.year, type=int)
month = request.args.get('month', today.month, type=int)
expenses, total, category_totals, alerts = monthly_summary(current_user.id, year, month)
chart_categories = [{'label': k, 'amount': float(v)} for k, v in category_totals.items()]
chart_payments = payment_method_totals(current_user.id, year, month)
return render_template('main/dashboard.html', expenses=expenses, total=total, category_totals=category_totals, alerts=alerts, selected_year=year, selected_month=month, chart_categories=chart_categories, chart_payments=chart_payments)
@main_bp.route('/statistics')
@login_required
def statistics():
year = request.args.get('year', date.today().year, type=int)
month = request.args.get('month', 0, type=int)
start_year = request.args.get('start_year', max(year - 4, 2000), type=int)
end_year = request.args.get('end_year', year, type=int)
if start_year > end_year:
start_year, end_year = end_year, start_year
return render_template('main/statistics.html', selected_year=year, selected_month=month, start_year=start_year, end_year=end_year)
@main_bp.route('/analytics/data')
@login_required
def analytics_data():
year = request.args.get('year', date.today().year, type=int)
month = request.args.get('month', 0, type=int)
month = month or None
start_year = request.args.get('start_year', max(year - 4, 2000), type=int)
end_year = request.args.get('end_year', year, type=int)
if start_year > end_year:
start_year, end_year = end_year, start_year
return jsonify({
'yearly_totals': yearly_totals(current_user.id, year, month),
'daily_totals': daily_totals(current_user.id, year, month),
'category_totals': yearly_category_totals(current_user.id, year, month),
'payment_methods': payment_method_totals(current_user.id, year, month),
'top_expenses': top_expenses(current_user.id, year, month),
'overview': yearly_overview(current_user.id, year, month),
'comparison': compare_years(current_user.id, year, month),
'range_totals': range_totals(current_user.id, start_year, end_year, month),
'quarterly_totals': quarterly_totals(current_user.id, year, month),
'weekday_totals': weekday_totals(current_user.id, year, month),
})
@main_bp.route('/preferences', methods=['GET', 'POST'])
@login_required
def preferences():
form = PreferencesForm(obj=current_user)
form.language.choices = [('pl', _('language.polish')), ('en', _('language.english'))]
form.theme.choices = [('light', _('theme.light')), ('dark', _('theme.dark'))]
form.report_frequency.choices = [('off', _('report.off')), ('daily', _('report.daily')), ('weekly', _('report.weekly')), ('monthly', _('report.monthly'))]
category_form = UserCategoryForm(prefix='cat')
if request.method == 'POST' and 'language' in request.form and form.validate():
current_user.language = form.language.data
current_user.theme = form.theme.data
current_user.report_frequency = form.report_frequency.data if get_bool_setting('reports_enabled', True) else 'off'
current_user.default_currency = form.default_currency.data
db.session.commit()
flash = __import__('flask').flash
flash(_('flash.settings_saved'), 'success')
return redirect(url_for('main.preferences'))
if request.method == 'POST' and 'cat-key' in request.form and category_form.validate():
key = f'u{current_user.id}_{category_form.key.data.strip().lower()}'
category = Category.query.filter_by(user_id=current_user.id, key=key).first()
if not category:
category = Category(user_id=current_user.id, key=key, name=category_form.name_en.data.strip(), is_active=True)
db.session.add(category)
category.name = category_form.name_en.data.strip()
category.name_pl = category_form.name_pl.data.strip()
category.name_en = category_form.name_en.data.strip()
category.color = category_form.color.data
db.session.commit()
log_action('user_category_saved', 'category', category.id, owner=current_user.id)
flash = __import__('flask').flash
flash(_('flash.category_saved'), 'success')
return redirect(url_for('main.preferences'))
my_categories = Category.query.filter_by(user_id=current_user.id).order_by(Category.name_pl).all()
report_options_enabled = get_bool_setting('reports_enabled', True)
return render_template('main/preferences.html', form=form, category_form=category_form, my_categories=my_categories, report_options_enabled=report_options_enabled)