From 81493afa53a1a1d5ff4b417d05febf9f9e2a172b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20=27Necoro=27=20Neumann?= Date: Thu, 23 Jul 2020 00:28:47 +0200 Subject: Restructure --- app/views/expenses.py | 224 -------------------------------------------------- 1 file changed, 224 deletions(-) delete mode 100644 app/views/expenses.py (limited to 'app/views/expenses.py') diff --git a/app/views/expenses.py b/app/views/expenses.py deleted file mode 100644 index 90c8ffd..0000000 --- a/app/views/expenses.py +++ /dev/null @@ -1,224 +0,0 @@ -# -*- coding: utf-8 -*- -from . import Blueprint, flash, db, \ - current_user, login_required, \ - assert_authorisation, templated, redirect, request, url_for, today - -from flask import Markup - -from ..model import Category, SingleExpense, CatExpense, MonthExpense -from .. import forms as F - -import datetime -from sqlalchemy import func -from functools import partial - -assert_authorisation = partial(assert_authorisation, SingleExpense.get) -mod = Blueprint('expenses', __name__) - -# -# Form -# -class ExpenseForm(F.Form): - date = F.DateField('Datum', F.req, - default=lambda: today()) - - expense = F.DecimalField('Betrag', F.req, - description='EUR', - places=2) - - description = F.StringField('Beschreibung') - - category = F.QuerySelectField('Kategorie', - get_label='name', - get_pk=lambda c: c.id) - - def __init__(self, obj = None, description_req = True): - super().__init__(obj = obj) - self.category.query = Category.of(current_user).order_by(Category.name) - - if description_req: - self.description.validators.extend(F.req) - -# -# Utilities -# -def calc_month_exp(year, month): - """Returns the `MonthExpense` for the given month.""" - ssum = func.sum(SingleExpense.expense) - query = SingleExpense.of_month(current_user, month, year) - - result = query.group_by(SingleExpense.category_id).\ - values(SingleExpense.category_id, ssum) - - exps = [CatExpense(Category.get(c), s, query.filter(SingleExpense.category_id == c)) for c,s in result] - - return MonthExpense(current_user, datetime.date(year, month, 1), exps) - - -def pie_data(exp): - """Generates the dictionary needed to show the pie diagram. - The resulting dict is category → sum of expenses. - """ - expenses = {} - for c in exp.catexps: - expenses[c.cat.name] = float(c.sum) - - for c in Category.of(current_user).order_by(Category.name).all(): - yield (c.name, expenses.get(c.name, 0.0)) - - -def calc_month_and_pie(year, month): - exp = calc_month_exp(year,month) - pie = pie_data(exp) - return (exp, dict(pie)) - - -def entry_flash(msg, exp): - """When changing/adding an entry, a message is shown.""" - url = url_for('.edit', id = exp.id) - link = "%s" % (url, exp.description) - flash(Markup(msg % link)) - -DATE_FORMAT='%Y%m%d' -def parse_date(value): - try: - dt = datetime.datetime.strptime(value, DATE_FORMAT) - except ValueError: - return today() - else: - return dt.date() - -def gen_date(value): - return value.strftime(DATE_FORMAT) - -# -# Template additions -# -@mod.app_template_filter() -def prev_date(exp): - if exp.date.month == 1: - return exp.date.replace(year = exp.date.year - 1, month = 12) - else: - return exp.date.replace(month = exp.date.month - 1) - - -@mod.app_template_filter() -def next_date(exp): - if exp.date.month == 12: - return exp.date.replace(year = exp.date.year + 1, month = 1) - else: - return exp.date.replace(month = exp.date.month + 1) - - -@mod.app_template_test('last_date') -def is_last(exp): - return exp.date >= today().replace(day = 1) - -# -# Views -# -@mod.route('/') -@login_required -@templated -def show(): - """Show this and the last month.""" - d = today() - - first, pfirst = calc_month_and_pie(d.year, d.month) - if d.month == 1: - second, psecond = calc_month_and_pie(d.year - 1, 12) - else: - second, psecond = calc_month_and_pie(d.year, d.month - 1) - - return { 'exps' : [first, second], 'pies': [pfirst, psecond] } - - -@mod.route('//') -@login_required -@templated('.show') -def show_date(year, month): - """Show the expenses of the specified month.""" - c,p = calc_month_and_pie(year, month) - return { 'exps' : [c], 'pies' : [p] } - -# shortcut to allow calling the above route, when year/month is a string -mod.add_url_rule('/', endpoint = 'show_date_str', build_only = True) - - -@mod.route('/edit/', methods=('GET', 'POST')) -@login_required -@assert_authorisation('id') -@templated -def edit(id): - """Edit a single expense, given by `id`.""" - exp = SingleExpense.get(id) - form = ExpenseForm(exp) - - if form.is_submitted(): - if 'deleteB' in request.form: - db.session.delete(exp) - - elif form.flash_validate(): # change - form.populate_obj(exp) - - else: - return { 'form': form } - - db.session.commit() - entry_flash("Eintrag %s geändert.", exp) - return redirect('index') - - return { 'form': form } - - -@mod.route('/add', methods=('GET', 'POST')) -@login_required -@templated -def add(): - """Add a new expense.""" - form = ExpenseForm(description_req=False) - - if request.method == 'GET' and 'date' in request.args: - form.date.data = parse_date(request.args['date']) - - if form.validate_on_submit(): - if not form.description.data.strip(): - form.description.data = form.category.data.name - - exp = SingleExpense() - - form.populate_obj(exp) - exp.user = current_user - - db.session.add(exp) - db.session.commit() - - entry_flash("Neuer Eintrag %s hinzugefügt.", exp) - - return redirect('.add', date = gen_date(exp.date) if exp.date != today() else None) - - return { 'form': form } - -@mod.route('/search', methods=('POST', 'GET')) -@login_required -@templated -def search(): - try: - query = request.form['search'].strip() - except KeyError: - flash("Ungültige Suchanfrage") - return redirect('index') - - if not query: - flash("Leere Suche") - return redirect('index') - - exps = SingleExpense.of(current_user).filter(SingleExpense.description.ilike(query))\ - .order_by(SingleExpense.year.desc(), SingleExpense.month, SingleExpense.day, SingleExpense.description)\ - .all() - - if not exps: - flash("Keine Ergebnisse") - return redirect('index') - - return { 'exps': exps } -- cgit v1.2.3