diff options
author | René 'Necoro' Neumann <necoro@necoro.eu> | 2020-07-23 00:28:47 +0200 |
---|---|---|
committer | René 'Necoro' Neumann <necoro@necoro.eu> | 2020-07-23 00:28:47 +0200 |
commit | 81493afa53a1a1d5ff4b417d05febf9f9e2a172b (patch) | |
tree | 00de0a1bb7c386cff4203aa7b0789569e75347bb /app/views/expenses.py | |
parent | 6f6c8af2a55fabb69372e3fc4e8504167805d018 (diff) | |
download | kosten-81493afa53a1a1d5ff4b417d05febf9f9e2a172b.tar.gz kosten-81493afa53a1a1d5ff4b417d05febf9f9e2a172b.tar.bz2 kosten-81493afa53a1a1d5ff4b417d05febf9f9e2a172b.zip |
Restructure
Diffstat (limited to 'app/views/expenses.py')
-rw-r--r-- | app/views/expenses.py | 224 |
1 files changed, 0 insertions, 224 deletions
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 = "<a href=\"%s\">%s</a>" % (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('/<int(fixed_digits=4):year>/<int(fixed_digits=2):month>') -@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('/<path:p>', endpoint = 'show_date_str', build_only = True) - - -@mod.route('/edit/<int:id>', 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 } |