diff --git a/drcr/general_journal/views.py b/drcr/general_journal/views.py index 5763866..d5fbb9b 100644 --- a/drcr/general_journal/views.py +++ b/drcr/general_journal/views.py @@ -20,7 +20,7 @@ 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 .models import Amount, BalanceAssertion, GeneralJournalPosting, GeneralJournalTransaction from datetime import datetime @@ -40,15 +40,15 @@ def general_journal_new(): 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)) + for account, sign, amount_str in zip(request.form.getlist('account'), request.form.getlist('sign'), request.form.getlist('amount')): + amount = Amount.parse(amount_str) if sign == 'cr': - quantity = -quantity + amount = -amount posting = GeneralJournalPosting( account=account, - quantity=quantity, - commodity='$' # TODO: Commodities + quantity=amount.quantity, + commodity=amount.commodity ) transaction.postings.append(posting) diff --git a/drcr/models.py b/drcr/models.py index fc37258..0afcda8 100644 --- a/drcr/models.py +++ b/drcr/models.py @@ -25,8 +25,7 @@ class Transaction: 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 + if any(p.commodity != self.postings[0].commodity for p in self.postings[1:]): raise AssertionError('Transaction contains multiple commodities') if sum(p.quantity for p in self.postings) != 0: @@ -49,14 +48,50 @@ class Amount: self.quantity = quantity self.commodity = commodity + @classmethod + def parse(self, amount_str): + if ' ' not in amount_str: + # Default commodity + quantity = round(float(amount_str) * (10**AMOUNT_DPS)) + return Amount(quantity, '$') # TODO: Customisable default commodity + + quantity_str = amount_str[:amount_str.index(' ')] + quantity = round(float(quantity_str) * (10**AMOUNT_DPS)) + + commodity = amount_str[amount_str.index(' ')+1:] + return Amount(quantity, commodity) + def __abs__(self): return Amount(abs(self.quantity), self.commodity) + def __neg__(self): + return Amount(-self.quantity, self.commodity) + def format(self): - return '{0}{1:,.{dps}f}'.format(self.commodity, self.quantity / (10**AMOUNT_DPS), dps=AMOUNT_DPS) + if len(self.commodity) == 1: + return '{0}{1:,.{dps}f}'.format(self.commodity, self.quantity / (10**AMOUNT_DPS), dps=AMOUNT_DPS) + else: + return '{1:,.{dps}f} {0}'.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) + + def as_cost(self): + """Convert commodity to reporting currency in cost basis""" + + if self.commodity == '$': + return self + + # TODO: Refactor this + + if '{{' in self.commodity: + cost = float(self.commodity[self.commodity.index('{{')+2:self.commodity.index('}}')]) + return Amount(round(cost * (10**AMOUNT_DPS)), '$') + elif '{' in self.commodity: + cost = float(self.commodity[self.commodity.index('{')+1:self.commodity.index('}')]) + return Amount(round(cost * self.quantity), '$') # FIXME: Custom reporting currency + else: + raise Exception('No cost base for commodity {}'.format(self.commodity)) class TrialBalancer: """ @@ -70,10 +105,10 @@ class TrialBalancer: for transaction in transactions: for posting in transaction.postings: if posting.account not in self.accounts: - self.accounts[posting.account] = Amount(0, '$') # FIXME: Other commodities + self.accounts[posting.account] = Amount(0, '$') - # FIXME: Handle commodities - self.accounts[posting.account].quantity += posting.quantity + # FIXME: Handle commodities better + self.accounts[posting.account].quantity += posting.amount().as_cost().quantity def transfer_balance(self, source_account, destination_account, description=None): """Transfer the balance of the source account to the destination account""" diff --git a/drcr/templates/general_journal/general_journal_edit.html b/drcr/templates/general_journal/general_journal_edit.html index 4a119ef..8724316 100644 --- a/drcr/templates/general_journal/general_journal_edit.html +++ b/drcr/templates/general_journal/general_journal_edit.html @@ -54,7 +54,7 @@
$
- +
@@ -74,7 +74,7 @@
$
- +
diff --git a/drcr/templates/transactions.html b/drcr/templates/transactions.html index 9e70035..1320f5a 100644 --- a/drcr/templates/transactions.html +++ b/drcr/templates/transactions.html @@ -37,7 +37,7 @@ {% for transaction in transactions %} {% if transaction.postings|length == 2 %} {% for posting in transaction.postings if posting.account == account %} - {% set _ = running_total.__setattr__('quantity', running_total.quantity + posting.quantity) %} + {% set _ = running_total.__setattr__('quantity', running_total.quantity + posting.amount().as_cost().quantity) %} {{ transaction.dt.strftime('%Y-%m-%d') }} {{ transaction.description }} @@ -58,7 +58,7 @@ {% for posting in transaction.postings if posting.account == account %} - {% set _ = running_total.__setattr__('quantity', running_total.quantity + posting.quantity) %} + {% set _ = running_total.__setattr__('quantity', running_total.quantity + posting.amount().as_cost().quantity) %} {{ 'Dr' if posting.quantity >= 0 else 'Cr' }}