summaryrefslogtreecommitdiff
path: root/app/views/expenses.py
diff options
context:
space:
mode:
authorRené 'Necoro' Neumann <necoro@necoro.eu>2020-07-23 00:28:47 +0200
committerRené 'Necoro' Neumann <necoro@necoro.eu>2020-07-23 00:28:47 +0200
commit81493afa53a1a1d5ff4b417d05febf9f9e2a172b (patch)
tree00de0a1bb7c386cff4203aa7b0789569e75347bb /app/views/expenses.py
parent6f6c8af2a55fabb69372e3fc4e8504167805d018 (diff)
downloadkosten-81493afa53a1a1d5ff4b417d05febf9f9e2a172b.tar.gz
kosten-81493afa53a1a1d5ff4b417d05febf9f9e2a172b.tar.bz2
kosten-81493afa53a1a1d5ff4b417d05febf9f9e2a172b.zip
Restructure
Diffstat (limited to 'app/views/expenses.py')
-rw-r--r--app/views/expenses.py224
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 }