diff options
Diffstat (limited to 'kosten/app/views/consts.py')
-rw-r--r-- | kosten/app/views/consts.py | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/kosten/app/views/consts.py b/kosten/app/views/consts.py new file mode 100644 index 0000000..5d6598d --- /dev/null +++ b/kosten/app/views/consts.py @@ -0,0 +1,174 @@ +# -*- coding: utf-8 -*- +from . import Blueprint, flash, db, \ + current_user, login_required, \ + assert_authorisation, templated, redirect, request, \ + today + +from ..model import Category, ConstExpense +from .. import forms as F + +from sqlalchemy import sql +from functools import partial + +mod = Blueprint('consts', __name__) +assert_authorisation = partial(assert_authorisation, ConstExpense.get) + +def one_year(d): + """Returns the date d', such that [d, d'] spans exactly one year. + In effect, this is d + 11 months (NB: not 12!)""" + if d.month == 1: + return d.replace(month = 12) + else: + return d.replace(month = d.month - 1, year = d.year + 1) + +# +# Form +# +class ConstForm(F.Form): + start = F.MonthField('Beginn', F.req, + default=lambda: today()) + + end = F.MonthField('Ende', F.req, + default=lambda: one_year(today()), + description='(einschließlich)') + + months = F.IntegerField('Zahlungsrythmus', F.req, + description='Monate') + + expense = F.DecimalField('Betrag', F.req, + description='EUR', + places=2) + + description = F.StringField('Beschreibung', F.req) + + category = F.QuerySelectField('Kategorie', + get_label='name', + get_pk=lambda c: c.id) + + prev = F.QuerySelectField('Vorgänger', + get_label='description', + allow_blank=True, + get_pk=lambda p: p.id) + + def __init__(self, cur=None, obj=None): + obj = cur if obj is None else obj + super().__init__(obj=obj) + self.category.query = Category.of(current_user).order_by(Category.name) + + # init prev_list + CE = ConstExpense + + filter = (CE.next == None) + + if cur and cur.id is not None: # not empty + filter = sql.or_(CE.next == cur, filter) + filter = sql.and_(filter, CE.id != cur.id) + + self.prev.query = CE.of(current_user).filter(filter).order_by(CE.description) + +# +# Views +# +@mod.route('/') +@login_required +@templated +def list (): + """List all constant expenses.""" + d = today().replace(day = 1) + + expenses = ConstExpense.of(current_user).order_by(ConstExpense.description).all() + + current = [] + old = [] + future = [] + last_month = [] + + for e in expenses: + if e.start <= d: + if e.end >= d: + current.append(e) + else: + if (d.month == 1 and e.end.month == 12 and e.end.year == d.year - 1) \ + or (e.end.year == d.year and e.end.month == d.month - 1): + last_month.append(e) + else: + old.append(e) + else: + future.append(e) + + return { 'current': current, 'old': old, 'future': future, 'last_month': last_month } + + +@mod.route('/<int:id>') +@login_required +@assert_authorisation('id') +@templated +def show(id): + """Show a specific constant expense.""" + return { 'exp': ConstExpense.get(id) } + + +@mod.route('/edit/<int:id>', methods=('GET', 'POST')) +@login_required +@assert_authorisation('id') +@templated +def edit(id): + """Edit a specific constant expense. This includes deletion.""" + exp = ConstExpense.get(id) + form = ConstForm(exp) + + if form.is_submitted(): + if 'deleteB' in request.form: + db.session.delete(exp) + db.session.commit() + return redirect('.list') + + elif form.flash_validate(): # change + form.populate_obj(exp) + db.session.commit() + flash("Eintrag geändert.") + return redirect('.show', id = id) + + return { 'form': form } + + +@mod.route('/add/', methods=('GET', 'POST')) +@login_required +@templated +def add(): + """Add a new constant expense.""" + exp = ConstExpense() + + form = ConstForm() + + if form.validate_on_submit(): + form.populate_obj(exp) + exp.user = current_user + db.session.add(exp) + db.session.commit() + flash("Eintrag hinzugefügt.") + return redirect('.show', id = exp.id) + + return { 'form': form } + + +@mod.route('/add/from/<int:other>') +@login_required +@assert_authorisation('other') +@templated('.add') +def add_from(other): + """Copy `other` and create a new expense based on it.""" + exp = ConstExpense() # needed to initialize 'CE.next' + + other = ConstExpense.get(other) + + # get form with data from other + form = ConstForm(obj = other) + + # replace some fields to be more meaningful + start = max(form.end.data, today()) + form.start.data = start + form.end.data = one_year(start) + if not other.next: form.prev.data = other + + return { 'form': form } |