# DrCr: Web-based double-entry bookkeeping framework # Copyright (C) 2022 Lee Yingtong Li (RunasSudo) # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . from flask import abort, redirect, render_template, request from .. import AMOUNT_DPS from ..database import db_session from ..models import TrialBalancer from ..webapp import all_transactions, app from .models import BalanceAssertion, GeneralJournalPosting, GeneralJournalTransaction from datetime import datetime @app.route('/general-journal') def general_journal(): return render_template('general_journal/general_journal.html', transactions=sorted(GeneralJournalTransaction.query.all(), key=lambda t: t.dt)) @app.route('/general-journal/new', methods=['GET', 'POST']) def general_journal_new(): if request.method == 'GET': return render_template('general_journal/general_journal_edit.html', transaction=None) # New transaction transaction = GeneralJournalTransaction( dt=datetime.strptime(request.form['dt'], '%Y-%m-%d'), description=request.form['description'], postings=[] ) for account, sign, amount in zip(request.form.getlist('account'), request.form.getlist('sign'), request.form.getlist('amount')): quantity = round(float(amount) * (10**AMOUNT_DPS)) if sign == 'cr': quantity = -quantity posting = GeneralJournalPosting( account=account, quantity=quantity, commodity='$' # TODO: Commodities ) transaction.postings.append(posting) transaction.assert_valid() db_session.add(transaction) db_session.commit() return redirect('/general-journal') @app.route('/balance-assertions') def balance_assertions(): assertions = BalanceAssertion.query.all() # Check assertion status transactions = all_transactions() assertion_status = {} for assertion in assertions: # FIXME: This is very inefficient balancer = TrialBalancer() balancer.apply_transactions([t for t in transactions if t.dt <= assertion.dt]) # TODO: Commodities if balancer.accounts[assertion.account].quantity == assertion.quantity: assertion_status[assertion] = True else: assertion_status[assertion] = False return render_template('general_journal/balance_assertions.html', assertions=assertions, assertion_status=assertion_status) @app.route('/balance-assertions/new', methods=['GET', 'POST']) def balance_assertions_new(): if request.method == 'GET': return render_template('general_journal/balance_assertions_edit.html', assertion=None) quantity = round(float(request.form['amount']) * (10**AMOUNT_DPS)) if request.form['sign'] == 'cr': quantity = -quantity # New balance assertion assertion = BalanceAssertion( dt=datetime.strptime(request.form['dt'], '%Y-%m-%d'), description=request.form['description'], account=request.form['account'], quantity=quantity, commodity='$' ) db_session.add(assertion) db_session.commit() return redirect('/balance-assertions') @app.route('/balance-assertions/edit', methods=['GET', 'POST']) def balance_assertions_edit(): assertion = db_session.get(BalanceAssertion, request.args['id']) if not assertion: abort(404) if request.method == 'GET': return render_template('general_journal/balance_assertions_edit.html', assertion=assertion) quantity = round(float(request.form['amount']) * (10**AMOUNT_DPS)) if request.form['sign'] == 'cr': quantity = -quantity # Edit balance assertion assertion.dt = datetime.strptime(request.form['dt'], '%Y-%m-%d') assertion.description = request.form['description'] assertion.account = request.form['account'] assertion.quantity = quantity db_session.commit() return redirect('/balance-assertions')