# -*- 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.DateField('Beginn', F.req, format='%m.%Y', default=lambda: today()) end = F.DateField('Ende', F.req, format='%m.%Y', 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') prev = F.QuerySelectField('Vorgänger', get_label='description', allow_blank=True) 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('/') @login_required @assert_authorisation('id') @templated def show(id): """Show a specific constant expense.""" return { 'exp': ConstExpense.get(id) } @mod.route('/edit/', 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/') @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 }