Ejemplo n.º 1
0
def bank_account_activities_edit(activity_id):
    activity = BankAccountActivity.q.get(activity_id)

    if activity is None:
        flash(u"Bankbewegung mit ID {} existiert nicht!".format(activity_id),
              'error')
        abort(404)

    form = BankAccountActivityEditForm(
        obj=activity, bank_account_name=activity.bank_account.name)

    if form.validate():
        debit_account = Account.q.filter(
            Account.id == form.account_id.data).one()
        credit_account = activity.bank_account.account

        transaction = finance.simple_transaction(
            description=form.description.data,
            debit_account=debit_account,
            credit_account=credit_account,
            amount=activity.amount,
            author=current_user,
            valid_on=activity.valid_on)
        activity.split = next(split for split in transaction.splits
                              if split.account_id == credit_account.id)
        session.add(activity)
        session.commit()

        end_payment_in_default_memberships()

        return redirect(url_for('.bank_accounts_list'))

    return render_template('finance/bank_account_activities_edit.html',
                           form=form)
Ejemplo n.º 2
0
def transaction_delete(transaction_id):
    transaction = Transaction.q.get(transaction_id)

    if transaction is None:
        flash(u"Transaktion existiert nicht.", 'error')
        abort(404)

    if transaction.confirmed:
        flash(
            u"Diese Transaktion wurde bereits bestätigt und kann daher nicht gelöscht werden.",
            'error')
        abort(400)

    form = FlaskForm()

    if form.is_submitted():
        lib.finance.transaction_delete(transaction)

        session.commit()

        flash(u'Transaktion gelöscht.', 'success')
        return redirect(url_for('.transactions_unconfirmed'))

    form_args = {
        'form': form,
        'cancel_to': url_for('.transactions_unconfirmed'),
        'submit_text': 'Löschen',
        'actions_offset': 0
    }

    return render_template('generic_form.html',
                           page_title="Transaktion löschen",
                           form_args=form_args,
                           form=form)
Ejemplo n.º 3
0
def membership_fee_book(fee_id):
    fee = MembershipFee.q.get(fee_id)

    if fee is None:
        flash(u'Ein Beitrag mit dieser ID existiert nicht!', 'error')
        abort(404)

    form = FeeApplyForm()
    if form.is_submitted():
        affected_users = post_transactions_for_membership_fee(
            fee, current_user)

        session.commit()

        flash("{} neue Buchungen erstellt.".format(len(affected_users)),
              "success")

        return redirect(url_for(".membership_fees"))

    table = UsersDueTable(
        data_url=url_for('.membership_fee_users_due_json', fee_id=fee.id))
    return render_template('finance/membership_fee_book.html',
                           form=form,
                           page_title='Beitrag buchen',
                           table=table)
Ejemplo n.º 4
0
    def test_mail_creation(self):
        users_without_mail = [
            u for u in self.users_to_sync if u.User.email is None
        ]
        if not users_without_mail:
            raise RuntimeError(
                "Fixtures do not provide a syncable user without a mail address"
            )
        mod_user = users_without_mail[0].User
        mod_dn = UserRecord.from_db_user(mod_user, self.user_base_dn).dn
        mod_user.email = '*****@*****.**'
        session.add(mod_user)
        session.commit()

        users_to_sync = fetch_users_to_sync(session,
                                            self.config.required_property)
        exporter = self.build_user_exporter(current_users=self.new_ldap_users,
                                            desired_users=users_to_sync)
        exporter.compile_actions()
        relevant_actions = [
            a for a in exporter.actions if not isinstance(a, IdleAction)
        ]
        print(relevant_actions)
        self.assertEqual(len(relevant_actions), 1)
        self.assertEqual(type(relevant_actions[0]), ModifyAction)
        exporter.execute_all(self.conn)

        newest_users = fetch_current_ldap_users(self.conn,
                                                base_dn=self.user_base_dn)
        modified_ldap_record = self.get_by_dn(newest_users, mod_dn)
        self.assertIn('mail', modified_ldap_record['attributes'])
        self.assertEqual(modified_ldap_record['attributes']['mail'],
                         [mod_user.email])
Ejemplo n.º 5
0
def membership_fee_edit(fee_id):
    fee = MembershipFee.q.get(fee_id)

    if fee is None:
        flash(u'Ein Beitrag mit dieser ID existiert nicht!', 'error')
        abort(404)

    form = MembershipFeeEditForm()

    if not form.is_submitted():
        form = MembershipFeeEditForm(
            name=fee.name,
            regular_fee=fee.regular_fee,
            booking_begin=fee.booking_begin.days,
            booking_end=fee.booking_end.days,
            payment_deadline=fee.payment_deadline.days,
            payment_deadline_final=fee.payment_deadline_final.days,
            begins_on=fee.begins_on,
            ends_on=fee.ends_on,
        )
    elif form.validate_on_submit():
        fee.name = form.name.data
        fee.regular_fee = form.regular_fee.data
        fee.booking_begin = timedelta(days=form.booking_begin.data)
        fee.booking_end = timedelta(days=form.booking_end.data)
        fee.payment_deadline = timedelta(days=form.payment_deadline.data)
        fee.payment_deadline_final = timedelta(
            days=form.payment_deadline_final.data)
        fee.begins_on = form.begins_on.data
        fee.ends_on = form.ends_on.data

        session.commit()
        return redirect(url_for(".membership_fees"))
    return render_template('finance/membership_fee_edit.html', form=form)
Ejemplo n.º 6
0
def bank_account_activities_edit(activity_id):
    activity = BankAccountActivity.q.get(activity_id)

    if activity is None:
        flash(u"Bankbewegung mit ID {} existiert nicht!".format(activity_id), 'error')
        abort(404)

    form = BankAccountActivityEditForm(
        obj=activity, bank_account_name=activity.bank_account.name)

    if form.validate():
        debit_account = Account.q.filter(
            Account.id == form.account_id.data
        ).one()
        credit_account = activity.bank_account.account

        transaction = finance.simple_transaction(
            description=form.description.data, debit_account=debit_account,
            credit_account=credit_account, amount=activity.amount,
            author=current_user, valid_on=activity.valid_on)
        activity.split = next(split for split in transaction.splits
                              if split.account_id == credit_account.id)
        session.add(activity)
        session.commit()

        end_payment_in_default_memberships()

        return redirect(url_for('.bank_accounts_list'))

    return render_template('finance/bank_account_activities_edit.html',
                           form=form)
Ejemplo n.º 7
0
def transactions_create():
    form = TransactionCreateForm()
    if form.validate_on_submit():
        splits = []
        for split_form in form.splits:
            splits.append((
                Account.q.get(split_form.account_id.data),
                split_form.amount.data
            ))
        transaction = finance.complex_transaction(
            description=form.description.data,
            author=current_user,
            splits=splits,
            valid_on=form.valid_on.data,
        )

        end_payment_in_default_memberships()

        session.commit()

        return redirect(url_for('.transactions_show',
                                transaction_id=transaction.id))
    return render_template(
        'finance/transactions_create.html',
        form=form
    )
Ejemplo n.º 8
0
def transaction_confirm_all():
    form = FlaskForm()

    def default_response():
        form_args = {
            'form': form,
            'cancel_to': url_for('.transactions_unconfirmed'),
            'submit_text': 'Alle Bestätigen',
            'actions_offset': 0
        }
        return render_template(
            'generic_form.html',
            page_title="Alle Transaktionen (älter als 1h) bestätigen",
            form_args=form_args,
            form=form)

    if not form.is_submitted():
        return default_response()

    try:
        with handle_errors(session):
            lib.finance.transaction_confirm_all(current_user)
            session.commit()
    except PycroftException:
        return default_response()

    flash("Alle Transaktionen wurden bestätigt.", 'success')
    return redirect(url_for('.transactions_unconfirmed'))
Ejemplo n.º 9
0
def bank_accounts_import_manual():
    form = BankAccountActivitiesImportManualForm()
    form.account.query = BankAccount.q.all()

    if form.validate_on_submit():
        bank_account = form.account.data

        if form.file.data:
            mt940 = form.file.data.read().decode()

            mt940_entry = MT940Error(mt940=mt940,
                                     exception="manual import",
                                     author=current_user,
                                     bank_account=bank_account)
            session.add(mt940_entry)

            session.commit()
            flash(
                u'Datensatz wurde importiert. Buchungen können jetzt importiert werden.'
            )
            return redirect(
                url_for(".fix_import_error", error_id=mt940_entry.id))
        else:
            flash(u"Kein MT940 hochgeladen.", 'error')

    return render_template('finance/bank_accounts_import_manual.html',
                           form=form)
Ejemplo n.º 10
0
    def test_mail_deletion(self):
        users_with_mail = [
            u for u in self.users_to_sync if u.User.email is not None
        ]
        if not users_with_mail:
            raise RuntimeError(
                "Fixtures do not provide a syncable user with a mail address")

        modified_user = users_with_mail[0].User
        mod_dn = Record.from_db_user(modified_user, self.base_dn).dn
        modified_user.email = '*****@*****.**'
        session.add(modified_user)
        session.commit()

        self.users_to_sync = fetch_users_to_sync(session,
                                                 self.config.required_property)
        self.sync_all()

        newest_users = fetch_current_ldap_users(self.conn,
                                                base_dn=self.base_dn)
        newest_users_correct_dn = [
            u for u in newest_users if u['dn'] == mod_dn
        ]
        self.assertEqual(len(newest_users_correct_dn), 1)
        modified_record = newest_users_correct_dn[0]
        self.assertNotIn('mail', modified_record)
Ejemplo n.º 11
0
def newDorm():
    """Make a new dormitory"""

    street = u_input("street: ")
    number = u_input("number: ")
    short_name = u_input("short_name: ")

    try:
        new_dormitory = Dormitory(number=number,
                                  short_name=short_name,
                                  street=street)
    except:
        print("could not create dormitory")

    print new_dormitory

    confirm = raw_input("do you want to save? (y/n): ")

    if confirm == "y":
        try:
            session.add(new_dormitory)
            session.commit()
        except:
            session.rollback()
            raise
Ejemplo n.º 12
0
def deleteDorm():
    """Delete a existing dormitory from the list"""

    dormitories = session.query(Dormitory).all()

    if not len(dormitories):
        print "no dormitories"
        return

    for i in range(len(dormitories)):
        print i
        print dormitories[i]

    while True:
        try:
            delete = int(raw_input("(you have to confirm) delete No. : "))
            break
        except ValueError:
            print "you have to type a number"

    if not delete >= 0 or not delete < len(dormitories):
        print "{} is not a dormitory".format(delete)
        return

    print dormitories[delete]
    confirm = raw_input("do you want to delete this dormitory? (y/n): ")

    if confirm == "y":
        try:
            session.delete(dormitories[delete])
            session.commit()
            print "deleted"
            return
        except:
            session.rollback()
Ejemplo n.º 13
0
def membership_fee_edit(fee_id):
    fee = MembershipFee.q.get(fee_id)

    if fee is None:
        flash(u'Ein Beitrag mit dieser ID existiert nicht!', 'error')
        abort(404)

    form = MembershipFeeEditForm()

    if not form.is_submitted():
        form = MembershipFeeEditForm(
            name=fee.name,
            regular_fee=fee.regular_fee,
            grace_period=fee.grace_period.days,
            payment_deadline=fee.payment_deadline.days,
            payment_deadline_final=fee.payment_deadline_final.days,
            begins_on=fee.begins_on,
            ends_on=fee.ends_on,
        )
    elif form.validate_on_submit():
        fee.name = form.name.data
        fee.regular_fee = form.regular_fee.data
        fee.grace_period = timedelta(days=form.grace_period.data)
        fee.payment_deadline = timedelta(days=form.payment_deadline.data)
        fee.payment_deadline_final = timedelta(days=form.payment_deadline_final.data)
        fee.begins_on = form.begins_on.data
        fee.ends_on = form.ends_on.data

        session.commit()
        return redirect(url_for(".membership_fees"))
    return render_template('finance/membership_fee_edit.html', form=form)
Ejemplo n.º 14
0
def deleteDorm():
    """Delete a existing dormitory from the list"""

    dormitories = session.query(Dormitory).all()

    if not len(dormitories):
        print "no dormitories"
        return

    for i in range(len(dormitories)):
        print i
        print dormitories[i]

    while True:
        try:
            delete = int(raw_input("(you have to confirm) delete No. : "))
            break
        except ValueError:
            print "you have to type a number"

    if not delete >= 0 or not delete < len(dormitories):
        print "{} is not a dormitory".format(delete)
        return

    print dormitories[delete]
    confirm = raw_input("do you want to delete this dormitory? (y/n): ")

    if confirm == "y":
        try:
            session.delete(dormitories[delete])
            session.commit()
            print "deleted"
            return
        except:
            session.rollback()
Ejemplo n.º 15
0
def accounts_create():
    form = FinanceAccountCreateForm()

    if form.validate_on_submit():
        new_account = FinanceAccount(name=form.name.data, type=form.type.data)
        session.add(new_account)
        session.commit()
        return redirect(url_for('.accounts'))

    return render_template('finance/accounts_create.html', form=form,
                           page_title=u"Konto erstellen")
Ejemplo n.º 16
0
def bank_accounts_import():
    form = BankAccountActivitiesImportForm()
    form.account.choices = [ (acc.id, acc.name) for acc in BankAccount.q.all()]
    (transactions, old_transactions) = ([], [])
    if form.validate_on_submit():
        # login with fints
        bank_account = BankAccount.q.get(form.account.data)
        process = True
        try:
            fints = FinTS3PinTanClient(
                bank_account.routing_number,
                form.user.data,
                form.pin.data,
                bank_account.fints_endpoint
            )

            acc = next((a for a in fints.get_sepa_accounts()
                        if a.iban == bank_account.iban), None)
            if acc is None:
                raise KeyError('BankAccount with IBAN {} not found.'.format(
                    bank_account.iban)
                )
            start_date = map_or_default(bank_account.last_updated_at,
                                        datetime.date, date(2018, 1, 1))
            statement = fints.get_statement(acc, start_date, date.today())
            flash(
                "Transaktionen vom {} bis {}.".format(start_date, date.today()))
        except FinTSDialogError:
            flash(u"Ungültige FinTS-Logindaten.", 'error')
            process = False
        except KeyError:
            flash(u'Das gewünschte Konto kann mit diesem Online-Banking-Zugang\
                    nicht erreicht werden.', 'error')
            process = False

        if process:
            (transactions, old_transactions) = finance.process_transactions(
                bank_account, statement)
        else:
            (transactions, old_transactions) = ([], [])

        if process and form.do_import.data is True:
            # save transactions to database
            session.add_all(transactions)
            session.commit()
            flash(u'Bankkontobewegungen wurden importiert.')
            return redirect(url_for(".accounts_show",
                                    account_id=bank_account.account_id))


    return render_template('finance/bank_accounts_import.html', form=form,
                           transactions=transactions,
                           old_transactions=old_transactions)
Ejemplo n.º 17
0
def accounts_create():
    form = AccountCreateForm()

    if form.validate_on_submit():
        new_account = Account(name=form.name.data, type=form.type.data)
        session.add(new_account)
        session.commit()
        return redirect(url_for('.accounts_list'))

    return render_template('finance/accounts_create.html',
                           form=form,
                           page_title=u"Konto erstellen")
Ejemplo n.º 18
0
def account_toggle_legacy(account_id):
    account = Account.q.get(account_id)

    if not account:
        abort(404)

    account.legacy = not account.legacy

    session.commit()

    flash("Der Status des Kontos wurde umgeschaltet.", "success")

    return redirect(url_for('.accounts_show', account_id=account_id))
Ejemplo n.º 19
0
def bank_account_activities_do_match():

    # Generate form again
    matching = match_activities()

    matched = []
    FieldList = []
    for activity, user in matching.items():
        FieldList.append((str(activity.id),
                          BooleanField('{} ({}€) -> {} ({}, {})'.format(
                              activity.reference, activity.amount, user.name,
                              user.id, user.login))))

    class F(forms.ActivityMatchForm):
        pass

    for (name, field) in FieldList:
        setattr(F, name, field)
    form = F()

    # parse data
    if form.validate_on_submit():
        # look for all matches which were checked
        for activity, user in matching.items():
            if form._fields[str(
                    activity.id
            )].data is True and activity.transaction_id is None:
                debit_account = user.account
                credit_account = activity.bank_account.account
                transaction = finance.simple_transaction(
                    description=activity.reference,
                    debit_account=debit_account,
                    credit_account=credit_account,
                    amount=activity.amount,
                    author=current_user,
                    valid_on=activity.valid_on)
                activity.split = next(split for split in transaction.splits
                                      if split.account_id == credit_account.id)

                session.add(activity)

                matched.append((activity, user))

        end_payment_in_default_memberships()

        session.flush()
        session.commit()

    return render_template('finance/bank_accounts_matched.html',
                           matched=matched)
Ejemplo n.º 20
0
def bank_accounts_import():
    form = BankAccountActivitiesImportForm()
    form.account.choices = [(acc.id, acc.name) for acc in BankAccount.q.all()]
    (transactions, old_transactions) = ([], [])
    if form.validate_on_submit():
        # login with fints
        bank_account = BankAccount.q.get(form.account.data)
        process = True
        try:
            fints = FinTS3PinTanClient(bank_account.routing_number,
                                       form.user.data, form.pin.data,
                                       bank_account.fints_endpoint)

            acc = next((a for a in fints.get_sepa_accounts()
                        if a.iban == bank_account.iban), None)
            if acc is None:
                raise KeyError('BankAccount with IBAN {} not found.'.format(
                    bank_account.iban))
            start_date = map_or_default(bank_account.last_updated_at,
                                        datetime.date, date(2018, 1, 1))
            statement = fints.get_statement(acc, start_date, date.today())
            flash("Transaktionen vom {} bis {}.".format(
                start_date, date.today()))
        except FinTSDialogError:
            flash(u"Ungültige FinTS-Logindaten.", 'error')
            process = False
        except KeyError:
            flash(
                u'Das gewünschte Konto kann mit diesem Online-Banking-Zugang\
                    nicht erreicht werden.', 'error')
            process = False

        if process:
            (transactions, old_transactions) = finance.process_transactions(
                bank_account, statement)
        else:
            (transactions, old_transactions) = ([], [])

        if process and form.do_import.data is True:
            # save transactions to database
            session.add_all(transactions)
            session.commit()
            flash(u'Bankkontobewegungen wurden importiert.')
            return redirect(
                url_for(".accounts_show", account_id=bank_account.account_id))

    return render_template('finance/bank_accounts_import.html',
                           form=form,
                           transactions=transactions,
                           old_transactions=old_transactions)
Ejemplo n.º 21
0
def transaction_confirm(transaction_id):
    transaction = Transaction.q.get(transaction_id)

    if transaction is None:
        flash(u"Transaktion existiert nicht.", 'error')
        abort(404)

    if transaction.confirmed:
        flash(u"Diese Transaktion wurde bereits bestätigt.", 'error')
        abort(400)

    lib.finance.transaction_confirm(transaction)

    session.commit()

    flash(u'Transaktion bestätigt.', 'success')
    return redirect(url_for('.transactions_unconfirmed'))
Ejemplo n.º 22
0
def journals_create():
    form = JournalCreateForm()

    if form.validate_on_submit():
        new_journal = Journal(
            name=form.name.data,
            bank=form.bank.data,
            account_number=form.account_number.data,
            routing_number=form.routing_number.data,
            iban=form.iban.data,
            bic=form.bic.data,
            hbci_url=form.hbci_url.data)
        session.add(new_journal)
        session.commit()
        return redirect(url_for('.journals'))

    return render_template('finance/journals_create.html',
                           form=form, page_title=u"Journal erstellen")
Ejemplo n.º 23
0
def journals_create():
    form = JournalCreateForm()

    if form.validate_on_submit():
        new_journal = Journal(name=form.name.data,
                              bank=form.bank.data,
                              account_number=form.account_number.data,
                              routing_number=form.routing_number.data,
                              iban=form.iban.data,
                              bic=form.bic.data,
                              hbci_url=form.hbci_url.data)
        session.add(new_journal)
        session.commit()
        return redirect(url_for('.journals'))

    return render_template('finance/journals_create.html',
                           form=form,
                           page_title=u"Journal erstellen")
Ejemplo n.º 24
0
    def test_mail_deletion(self):
        users_with_mail = [u for u in self.users_to_sync if u.User.email is not None]
        if not users_with_mail:
            raise RuntimeError("Fixtures do not provide a syncable user with a mail address")

        modified_user = users_with_mail[0].User
        mod_dn = Record.from_db_user(modified_user, self.base_dn).dn
        modified_user.email = '*****@*****.**'
        session.add(modified_user)
        session.commit()

        self.users_to_sync = fetch_users_to_sync(session, self.config.required_property)
        self.sync_all()

        newest_users = fetch_current_ldap_users(self.conn, base_dn=self.base_dn)
        newest_users_correct_dn = [u for u in newest_users if u['dn'] == mod_dn]
        self.assertEqual(len(newest_users_correct_dn), 1)
        modified_record = newest_users_correct_dn[0]
        self.assertNotIn('mail', modified_record)
Ejemplo n.º 25
0
def bank_accounts_create():
    form = BankAccountCreateForm()

    if form.validate_on_submit():
        new_bank_account = BankAccount(
            name=form.name.data,
            bank=form.bank.data,
            account_number=form.account_number.data,
            routing_number=form.routing_number.data,
            iban=form.iban.data,
            bic=form.bic.data,
            fints_endpoint=form.fints.data,
            account=Account(name=form.name.data, type='BANK_ASSET'),
        )
        session.add(new_bank_account)
        session.commit()
        return redirect(url_for('.bank_accounts_list'))

    return render_template('finance/bank_accounts_create.html',
                           form=form, page_title=u"Bankkonto erstellen")
Ejemplo n.º 26
0
def membership_fee_create():
    previous_fee = MembershipFee.q.order_by(MembershipFee.id.desc()).first()
    if previous_fee:
        begins_on_default = previous_fee.ends_on + timedelta(1)

        next_month = begins_on_default.replace(day=28) + timedelta(4)
        ends_on_default = begins_on_default.replace(
            day=(next_month - timedelta(days=next_month.day)).day)

        name_default = str(begins_on_default.year) \
                       + "-" + "%02d" % begins_on_default.month

        form = MembershipFeeCreateForm(
            name=name_default,
            regular_fee=previous_fee.regular_fee,
            booking_begin=previous_fee.booking_begin.days,
            booking_end=previous_fee.booking_end.days,
            payment_deadline=previous_fee.payment_deadline.days,
            payment_deadline_final=previous_fee.payment_deadline_final.days,
            begins_on=begins_on_default,
            ends_on=ends_on_default,
        )
    else:
        form = MembershipFeeCreateForm()
    if form.validate_on_submit():
        mfee = MembershipFee(
            name=form.name.data,
            regular_fee=form.regular_fee.data,
            booking_begin=timedelta(days=form.booking_begin.data),
            booking_end=timedelta(days=form.booking_end.data),
            payment_deadline=timedelta(days=form.payment_deadline.data),
            payment_deadline_final=timedelta(
                days=form.payment_deadline_final.data),
            begins_on=form.begins_on.data,
            ends_on=form.ends_on.data,
        )
        session.add(mfee)
        session.commit()
        flash("Beitrag erfolgreich erstellt.", "success")
        return redirect(url_for(".membership_fees"))
    return render_template('finance/membership_fee_create.html', form=form)
Ejemplo n.º 27
0
def transactions_create():
    form = TransactionCreateForm()
    if form.validate_on_submit():
        splits = []
        for split_form in form.splits:
            splits.append((Account.q.get(split_form.account_id.data),
                           split_form.amount.data))
        transaction = finance.complex_transaction(
            description=form.description.data,
            author=current_user,
            splits=splits,
            valid_on=form.valid_on.data,
        )

        end_payment_in_default_memberships()

        session.commit()

        return redirect(
            url_for('.transactions_show', transaction_id=transaction.id))
    return render_template('finance/transactions_create.html', form=form)
Ejemplo n.º 28
0
def bank_accounts_create():
    form = BankAccountCreateForm()

    if form.validate_on_submit():
        new_bank_account = BankAccount(
            name=form.name.data,
            bank=form.bank.data,
            account_number=form.account_number.data,
            routing_number=form.routing_number.data,
            iban=form.iban.data,
            bic=form.bic.data,
            fints_endpoint=form.fints.data,
            account=Account(name=form.name.data, type='BANK_ASSET'),
        )
        session.add(new_bank_account)
        session.commit()
        return redirect(url_for('.bank_accounts_list'))

    return render_template('finance/bank_accounts_create.html',
                           form=form,
                           page_title=u"Bankkonto erstellen")
Ejemplo n.º 29
0
def membership_fee_book(fee_id):
    fee = MembershipFee.q.get(fee_id)

    if fee is None:
        flash(u'Ein Beitrag mit dieser ID existiert nicht!', 'error')
        abort(404)

    form = FeeApplyForm()
    if form.is_submitted():
        affected_users = post_transactions_for_membership_fee(
            fee, current_user)

        session.commit()

        flash("{} neue Buchungen erstellt.".format(len(affected_users)), "success")

        return redirect(url_for(".handle_payments_in_default"))

    table = UsersDueTable(data_url=url_for('.membership_fee_users_due_json', fee_id=fee.id))
    return render_template('finance/membership_fee_book.html', form=form,
                           page_title='Beitrag buchen', table=table)
Ejemplo n.º 30
0
def handle_payments_in_default():
    finance.end_payment_in_default_memberships()

    users_pid_membership_all, users_membership_terminated_all = finance.get_users_with_payment_in_default(
    )

    form = HandlePaymentsInDefaultForm()

    # Using `query_factory` instead of `query`, because wtforms would not process an empty list as `query`
    form.new_pid_memberships.query_factory = lambda: users_pid_membership_all
    form.terminated_member_memberships.query_factory = lambda: users_membership_terminated_all

    if not form.is_submitted():
        form.new_pid_memberships.process_data(users_pid_membership_all)
        form.terminated_member_memberships.process_data(
            users_membership_terminated_all)

    if form.validate_on_submit():
        users_pid_membership = form.new_pid_memberships.data
        users_membership_terminated = form.terminated_member_memberships.data

        take_actions_for_payment_in_default_users(
            users_pid_membership=users_pid_membership,
            users_membership_terminated=users_membership_terminated,
            processor=current_user)
        session.commit()
        flash("Zahlungsrückstände behandelt.", "success")
        return redirect(url_for(".membership_fees"))

    form_args = {
        'form': form,
        'cancel_to': url_for('.membership_fees'),
        'submit_text': 'Anwenden',
        'actions_offset': 0
    }

    return render_template('generic_form.html',
                           page_title="Zahlungsrückstände behandeln",
                           form_args=form_args,
                           form=form)
Ejemplo n.º 31
0
def fix_import_error(error_id):
    error = MT940Error.q.get(error_id)
    form = FixMT940Form()
    (transactions, old_transactions, doubtful_transactions) = ([], [], [])
    new_exception = None

    if request.method != 'POST':
        form.mt940.data = error.mt940

    if form.validate_on_submit():
        statement = []
        try:
            statement += mt940_to_array(form.mt940.data)
        except Exception as e:
            new_exception = str(e)

        if new_exception is None:
            flash('MT940 ist jetzt valide.', 'success')
            (transactions, old_transactions,
             doubtful_transactions) = finance.process_transactions(
                 error.bank_account, statement)

            if form.do_import.data is True:
                # save transactions to database
                session.add_all(transactions)
                session.delete(error)
                session.commit()
                flash(u'Bankkontobewegungen wurden importiert.')
                return redirect(url_for(".bank_accounts_import_errors"))
        else:
            flash('Es existieren weiterhin Fehler.', 'error')

    return render_template('finance/bank_accounts_error_fix.html',
                           error_id=error_id,
                           exception=error.exception,
                           new_exception=new_exception,
                           form=form,
                           transactions=transactions,
                           old_transactions=old_transactions,
                           doubtful_transactions=doubtful_transactions)
Ejemplo n.º 32
0
    def test_mail_deletion(self):
        users_with_mail = [
            u for u in self.users_to_sync if u.User.email is not None
        ]
        if not users_with_mail:
            raise RuntimeError(
                "Fixtures do not provide a syncable user with a mail address")

        modified_user = users_with_mail[0].User
        mod_dn = UserRecord.from_db_user(modified_user, self.user_base_dn).dn
        modified_user.email = '*****@*****.**'
        session.add(modified_user)
        session.commit()

        self.users_to_sync = fetch_users_to_sync(session,
                                                 self.config.required_property)
        self.sync_all()

        newest_users = fetch_current_ldap_users(self.conn,
                                                base_dn=self.user_base_dn)
        modified_record = self.get_by_dn(newest_users, mod_dn)
        assert 'mail' not in modified_record
Ejemplo n.º 33
0
def bank_account_activities_do_match():
    # Generate form again
    matching_user, matching_team = match_activities()

    field_list_user = _create_field_list(matching_user)
    field_list_team = _create_field_list(matching_team)
    form = _create_combined_form(field_list_user, field_list_team)

    matched_user = []
    matched_team = []
    if form.user.validate_on_submit() or form.team.validate_on_submit():
        # parse data
        matched_user = _apply_checked_matches(matching_user, form.user)
        matched_team = _apply_checked_matches(matching_team, form.team)
        end_payment_in_default_memberships(current_user)

        session.flush()
        session.commit()

    return render_template('finance/bank_accounts_matched.html',
                           matched_user=matched_user,
                           matched_team=matched_team)
Ejemplo n.º 34
0
def membership_fee_create():
    previous_fee = MembershipFee.q.order_by(MembershipFee.id.desc()).first()
    if previous_fee:
        begins_on_default = previous_fee.ends_on + timedelta(1)

        next_month = begins_on_default.replace(day=28) + timedelta(4)
        ends_on_default = begins_on_default.replace(
            day=(next_month - timedelta(days=next_month.day)).day
        )

        name_default = str(begins_on_default.year) \
                       + "-" + "%02d" % begins_on_default.month

        form = MembershipFeeCreateForm(
            name=name_default,
            regular_fee=previous_fee.regular_fee,
            grace_period=previous_fee.grace_period.days,
            payment_deadline=previous_fee.payment_deadline.days,
            payment_deadline_final=previous_fee.payment_deadline_final.days,
            begins_on=begins_on_default,
            ends_on=ends_on_default,
        )
    else:
        form = MembershipFeeCreateForm()
    if form.validate_on_submit():
        mfee = MembershipFee(
            name=form.name.data,
            regular_fee=form.regular_fee.data,
            grace_period=timedelta(days=form.grace_period.data),
            payment_deadline=timedelta(days=form.payment_deadline.data),
            payment_deadline_final=timedelta(days=form.payment_deadline_final.data),
            begins_on=form.begins_on.data,
            ends_on=form.ends_on.data,
        )
        session.add(mfee)
        session.commit()
        flash("Beitrag erfolgreich erstellt.", "success")
        return redirect(url_for(".membership_fees"))
    return render_template('finance/membership_fee_create.html', form=form)
Ejemplo n.º 35
0
def edit_membership(membership_id):
    membership = Membership.q.get(membership_id)

    if membership is None:
        flash(u"Gruppenmitgliedschaft mit ID %s existiert nicht!" % (
        membership_id), 'error')
        abort(404)

    form = UserEditGroupMembership()
    if request.method == 'GET':
        form.begin_date.data = membership.start_date
        if membership.start_date < datetime.now():
            form.begin_date.disabled = True

        if membership.end_date is not None:
            form.end_date.data = membership.end_date

    if form.validate_on_submit():
        membership.start_date = datetime.combine(form.begin_date.data, datetime.min.time())
        if form.unlimited.data:
            membership.end_date = None
        else:
            membership.end_date = datetime.combine(form.end_date.data, datetime.min.time())

        session.commit()
        flash(u'Gruppenmitgliedschaft bearbeitet', 'success')
        lib.logging.create_user_log_entry(author=current_user,
            message=u"hat die Mitgliedschaft des Nutzers"
                u" in der Gruppe '%s' bearbeitet." %
                membership.group.name,
            timestamp=datetime.now(),
            user=membership.user)
        return redirect(url_for('.user_show', user_id=membership.user_id))

    return render_template('user/user_edit_membership.html',
                           page_title=u"Mitgliedschaft %s für %s bearbeiten" % (membership.group.name, membership.user.name),
                           membership_id=membership_id,
                           user = membership.user,
                           form = form)
Ejemplo n.º 36
0
def handle_payments_in_default():
    users_pid_membership, users_membership_terminated = finance.handle_payments_in_default()
    users_no_more_pid = finance.end_payment_in_default_memberships()

    changes = [('Neue Zugehörigkeiten in Zahlungsrückstands-Gruppe',
                users_pid_membership),
               ('Beendete Mitgliedschaften', users_membership_terminated),
               ('Beendete Zugehörigkeiten in Zahlungsrückstands-Gruppe',
                users_no_more_pid)]

    form = HandlePaymentsInDefaultForm()

    if form.is_submitted():
        session.commit()
        flash("Zahlungsrückstände behandelt.", "success")
        return redirect(url_for(".membership_fees"))
    else:
        session.rollback()

    return render_template('finance/handle_payments_in_default.html',
                           changes=changes,
                           page_title="Zahlungsrückstände behandeln",
                           form=form)
Ejemplo n.º 37
0
def journals_entries_edit(journal_id, entry_id):
    entry = JournalEntry.q.get(entry_id)
    form = JournalEntryEditForm(obj=entry, journal_name=entry.journal.name)

    if form.validate():
        debit_account = entry.journal.finance_account
        credit_account = FinanceAccount.q.filter(
            FinanceAccount.id == form.finance_account_id.data
        ).one()
        entry.transaction = finance.simple_transaction(
            description=entry.description, debit_account=debit_account,
            credit_account=credit_account, amount=entry.amount,
            author=current_user, valid_date=entry.valid_date)
        entry.description = form.description.data
        session.add(entry)
        session.commit()

        return redirect(url_for('.journals'))

    return render_template(
        'finance/journals_entries_edit.html',
        entry=entry, form=form
    )
Ejemplo n.º 38
0
def handle_payments_in_default():
    users_pid_membership, users_membership_terminated = finance.handle_payments_in_default(
    )
    users_no_more_pid = finance.end_payment_in_default_memberships()

    changes = [('Neue Zugehörigkeiten in Zahlungsrückstands-Gruppe',
                users_pid_membership),
               ('Beendete Mitgliedschaften', users_membership_terminated),
               ('Beendete Zugehörigkeiten in Zahlungsrückstands-Gruppe',
                users_no_more_pid)]

    form = HandlePaymentsInDefaultForm()

    if form.is_submitted():
        session.commit()
        flash("Zahlungsrückstände behandelt.", "success")
        return redirect(url_for(".membership_fees"))
    else:
        session.rollback()

    return render_template('finance/handle_payments_in_default.html',
                           changes=changes,
                           page_title="Zahlungsrückstände behandeln",
                           form=form)
Ejemplo n.º 39
0
    def test_mail_creation(self):
        users_without_mail = [u for u in self.users_to_sync if u.User.email is None]
        if not users_without_mail:
            raise RuntimeError("Fixtures do not provide a syncable user without a mail address")
        mod_user = users_without_mail[0].User
        mod_dn = Record.from_db_user(mod_user, self.base_dn).dn
        mod_user.email = '*****@*****.**'
        session.add(mod_user)
        session.commit()

        users_to_sync = fetch_users_to_sync(session, self.config.required_property)
        exporter = self.build_exporter(current=self.new_ldap_users,
                                       desired=users_to_sync)
        exporter.compile_actions()
        relevant_actions = [a for a in exporter.actions if not isinstance(a, IdleAction)]
        print(relevant_actions)
        self.assertEqual(len(relevant_actions), 1)
        self.assertEqual(type(relevant_actions[0]), ModifyAction)
        exporter.execute_all(self.conn)

        newest_users = fetch_current_ldap_users(self.conn, base_dn=self.base_dn)
        modified_ldap_record = [u for u in newest_users if u['dn'] == mod_dn][0]
        self.assertIn('mail', modified_ldap_record['attributes'])
        self.assertEqual(modified_ldap_record['attributes']['mail'], [mod_user.email])
Ejemplo n.º 40
0
def newDorm():
    """Make a new dormitory"""

    street = u_input("street: ")
    number = u_input("number: ")
    short_name = u_input("short_name: ")

    try:
        new_dormitory = Dormitory(number=number, short_name=short_name,
            street=street)
    except:
        print("could not create dormitory")

    print new_dormitory

    confirm = raw_input("do you want to save? (y/n): ")

    if confirm == "y":
        try:
            session.add(new_dormitory)
            session.commit()
        except:
            session.rollback()
            raise
Ejemplo n.º 41
0
def transaction_confirm_all():
    form = FlaskForm()

    if form.is_submitted():
        _, success = web_execute(lib.finance.transaction_confirm_all,
                                 "Alle Transaktionen wurden bestätigt.",
                                 current_user)

        session.commit()

        return redirect(url_for('.transactions_unconfirmed'))

    form_args = {
        'form': form,
        'cancel_to': url_for('.transactions_unconfirmed'),
        'submit_text': 'Alle Bestätigen',
        'actions_offset': 0
    }

    return render_template(
        'generic_form.html',
        page_title="Alle Transaktionen (älter als 1h) bestätigen",
        form_args=form_args,
        form=form)
Ejemplo n.º 42
0
def journals_entries_edit(journal_id, entry_id):
    entry = JournalEntry.q.get(entry_id)
    form = JournalEntryEditForm(obj=entry, journal_name=entry.journal.name)

    if form.validate():
        debit_account = entry.journal.finance_account
        credit_account = FinanceAccount.q.filter(
            FinanceAccount.id == form.finance_account_id.data).one()
        entry.transaction = finance.simple_transaction(
            description=entry.description,
            debit_account=debit_account,
            credit_account=credit_account,
            amount=entry.amount,
            author=current_user,
            valid_date=entry.valid_date)
        entry.description = form.description.data
        session.add(entry)
        session.commit()

        return redirect(url_for('.journals'))

    return render_template('finance/journals_entries_edit.html',
                           entry=entry,
                           form=form)
Ejemplo n.º 43
0
 def auto_expire():
     """Delete all expired items from the database"""
     WebStorage.q.filter(WebStorage.expiry <= func.current_timestamp()).delete(False)
     session.commit()
Ejemplo n.º 44
0
 def auto_expire():
     """Delete all expired items from the database"""
     WebStorage.q.filter(
         WebStorage.expiry <= func.current_timestamp()).delete(False)
     session.commit()
Ejemplo n.º 45
0
def bank_account_activities_edit(activity_id):
    activity = BankAccountActivity.q.get(activity_id)

    if activity is None:
        flash(u"Bankbewegung mit ID {} existiert nicht!".format(activity_id),
              'error')
        abort(404)

    if activity.transaction_id is not None:
        form = BankAccountActivityReadForm(
            obj=activity, bank_account_name=activity.bank_account.name)

        if activity.transaction_id:
            flash(u"Bankbewegung ist bereits zugewiesen!".format(activity_id),
                  'warning')

        form_args = {
            'form': form,
            'show_submit': False,
            'show_cancel': False,
        }

        return render_template('generic_form.html',
                               page_title="Bankbewegung",
                               form_args=form_args,
                               form=form)

    else:
        form = BankAccountActivityEditForm(
            obj=activity,
            bank_account_name=activity.bank_account.name,
            description=activity.reference)

        if form.validate_on_submit():
            debit_account = Account.q.filter(
                Account.id == form.account_id.data).one()
            credit_account = activity.bank_account.account

            transaction = finance.simple_transaction(
                description=form.description.data,
                debit_account=debit_account,
                credit_account=credit_account,
                amount=activity.amount,
                author=current_user,
                valid_on=activity.valid_on,
                confirmed=current_user.member_of(config.treasurer_group))
            activity.split = next(split for split in transaction.splits
                                  if split.account_id == credit_account.id)
            session.add(activity)

            end_payment_in_default_memberships()

            session.commit()

            flash(u"Transaktion erfolgreich erstellt.", 'success')

            return redirect(url_for('.bank_accounts_list'))

        form_args = {
            'form': form,
            'cancel_to': url_for('.bank_accounts_list'),
            'submit_text': 'Zuweisen',
        }

        return render_template('generic_form.html',
                               page_title="Bankbewegung zuweisen",
                               form_args=form_args,
                               form=form)
Ejemplo n.º 46
0
def bank_accounts_import():
    form = BankAccountActivitiesImportForm()
    form.account.choices = [(acc.id, acc.name) for acc in BankAccount.q.all()]
    (transactions, old_transactions) = ([], [])
    if request.method != 'POST':
        del (form.start_date)
        form.end_date.data = date.today() - timedelta(days=1)

    if form.validate_on_submit():
        bank_account = BankAccount.q.get(form.account.data)

        # set start_date, end_date
        if form.start_date.data is None:
            form.start_date.data = map_or_default(
                bank_account.last_imported_at, datetime.date, date(2018, 1, 1))
        if form.end_date.data is None:
            form.end_date.data = date.today()

        # login with fints
        process = True
        try:
            fints = FinTS3Client(bank_account.routing_number, form.user.data,
                                 form.pin.data, bank_account.fints_endpoint)

            acc = next((a for a in fints.get_sepa_accounts()
                        if a.iban == bank_account.iban), None)
            if acc is None:
                raise KeyError('BankAccount with IBAN {} not found.'.format(
                    bank_account.iban))
            start_date = form.start_date.data
            end_date = form.end_date.data
            statement, with_error = fints.get_filtered_transactions(
                acc, start_date, end_date)
            flash("Transaktionen vom {} bis {}.".format(start_date, end_date))
            if len(with_error) > 0:
                flash(
                    "{} Statements enthielten fehlerhafte Daten und müssen "
                    "vor dem Import manuell korrigiert werden.".format(
                        len(with_error)), 'error')

        except (FinTSDialogError, FinTSClientPINError):
            flash(u"Ungültige FinTS-Logindaten.", 'error')
            process = False
        except KeyError:
            flash(
                u'Das gewünschte Konto kann mit diesem Online-Banking-Zugang\
                    nicht erreicht werden.', 'error')
            process = False

        if process:
            (transactions, old_transactions) = finance.process_transactions(
                bank_account, statement)
        else:
            (transactions, old_transactions) = ([], [])

        if process and form.do_import.data is True:
            # save errors to database
            for error in with_error:
                session.add(
                    MT940Error(mt940=error[0],
                               exception=error[1],
                               author=current_user,
                               bank_account=bank_account))

            # save transactions to database
            session.add_all(transactions)
            session.commit()
            flash(u'Bankkontobewegungen wurden importiert.')
            return redirect(
                url_for(".accounts_show", account_id=bank_account.account_id))

    return render_template('finance/bank_accounts_import.html',
                           form=form,
                           transactions=transactions,
                           old_transactions=old_transactions)