diff --git a/drcr/models.py b/drcr/models.py index f4900cb..e70e989 100644 --- a/drcr/models.py +++ b/drcr/models.py @@ -21,6 +21,16 @@ class Transaction: self.dt = dt self.description = description self.postings = postings or [] + + def assert_valid(self): + """Assert that debits equal credits, and commodities are compatible""" + + if any(p.commodity != '$' for p in self.postings): + # FIXME: Allow non-$ commodities + raise AssertionError('Transaction contains multiple commodities') + + if sum(p.quantity for p in self.postings) != 0: + raise AssertionError('Transaction debits and credits do not balance') class Posting: def __init__(self, description=None, account=None, quantity=None, commodity=None): @@ -44,3 +54,6 @@ class Amount: def format(self): return '{0}{1:,.{dps}f}'.format(self.commodity, self.quantity / (10**AMOUNT_DPS), dps=AMOUNT_DPS) + + def quantity_string(self): + return '{:.{dps}f}'.format(self.quantity / (10**AMOUNT_DPS), dps=AMOUNT_DPS) diff --git a/drcr/statements/models.py b/drcr/statements/models.py index f713e69..780021d 100644 --- a/drcr/statements/models.py +++ b/drcr/statements/models.py @@ -54,6 +54,15 @@ class StatementLine(Base): Posting(account=unclassified_name, quantity=-self.quantity, commodity=self.commodity) ] ) + + def is_complex(self): + if len(self.postings) > 1: + return True + + if any(len(p.transaction.postings) > 2 for p in self.postings): + return True + + return False class StatementLineTransaction(Base, Transaction): __tablename__ = 'statement_line_transactions' diff --git a/drcr/statements/views.py b/drcr/statements/views.py index a41d467..e08bf53 100644 --- a/drcr/statements/views.py +++ b/drcr/statements/views.py @@ -16,6 +16,7 @@ from flask import abort, redirect, render_template, request +from .. import AMOUNT_DPS from ..database import db_session from ..webapp import app from .models import StatementLine, StatementLinePosting, StatementLineTransaction @@ -74,14 +75,31 @@ def statement_line_edit_transaction(): # Queue for deletion db_session.delete(posting.transaction) - transaction = StatementLineTransaction( - dt=statement_line.dt, - description=request.form['description'], - postings=[ + if len(request.form.getlist('charge-account')) == 1: + # Simple transaction + postings = [ StatementLinePosting(statement_line=statement_line, account=statement_line.source_account, quantity=statement_line.quantity, commodity=statement_line.commodity), StatementLinePosting(account=request.form['charge-account'], quantity=-statement_line.quantity, commodity=statement_line.commodity) ] + else: + # Complex transaction, multiple postings + postings = [ + StatementLinePosting(statement_line=statement_line, account=statement_line.source_account, quantity=statement_line.quantity, commodity=statement_line.commodity) + ] + + for charge_account, charge_amount_str in zip(request.form.getlist('charge-account'), request.form.getlist('charge-amount')): + charge_quantity = round(float(charge_amount_str) * (10**AMOUNT_DPS)) + if statement_line.quantity >= 0: + # If source is debit, charge is credit + charge_quantity = -charge_quantity + postings.append(StatementLinePosting(account=charge_account, quantity=charge_quantity, commodity=statement_line.commodity)) + + transaction = StatementLineTransaction( + dt=statement_line.dt, + description=request.form['description'], + postings=postings ) + transaction.assert_valid() db_session.add(transaction) db_session.commit() diff --git a/drcr/templates/statement_line_edit_transaction.html b/drcr/templates/statement_line_edit_transaction.html index 0634b70..0696b7f 100644 --- a/drcr/templates/statement_line_edit_transaction.html +++ b/drcr/templates/statement_line_edit_transaction.html @@ -34,7 +34,7 @@
-