diff --git a/accounting/decorators.py b/accounting/decorators.py index da4cb55ff6a82ab310eb4b62dc6ce7a957d84fa1..634767e9e95554ef212f93c738075cb9352de0b4 100644 --- a/accounting/decorators.py +++ b/accounting/decorators.py @@ -19,7 +19,11 @@ def jsonify_exceptions(func): try: return func(*args, **kw) except AccountingException as exc: - return jsonify(error=exc) + response = jsonify(error=exc) + + response.status_code = exc.http_code + + return response return wrapper diff --git a/accounting/exceptions.py b/accounting/exceptions.py index 6d751cafd0c4da6ced7276144741ee4a6b1513f0..42b179f902319019c7e3f92256cc2c0b6bd59d86 100644 --- a/accounting/exceptions.py +++ b/accounting/exceptions.py @@ -7,6 +7,7 @@ class AccountingException(Exception): Used as a base for exceptions that are returned to the caller via the jsonify_exceptions decorator ''' + http_code = 500 def __init__(self, message, **kw): self.message = message for key, value in kw.items(): @@ -14,12 +15,12 @@ class AccountingException(Exception): class TransactionNotFound(AccountingException): - pass + http_code = 404 class LedgerNotBalanced(AccountingException): - pass + http_code = 400 class TransactionIDCollision(AccountingException): - pass + http_code = 400 diff --git a/accounting/storage/ledgercli.py b/accounting/storage/ledgercli.py index 919d8f722d6e62d0455c9e84097dc76aae2cec60..eb864453c9bf2e93ed2a5dc0a2340cb69deda96e 100644 --- a/accounting/storage/ledgercli.py +++ b/accounting/storage/ledgercli.py @@ -173,6 +173,18 @@ class Ledger(Storage): with open(self.ledger_file, 'ab') as f: f.write(output) + # Check to see that no errors were introduced + try: + self.get_transactions() + except AccountingException as exc: + # TODO: Do a hard reset on the repository using Repository.reset, + # this is on hold because of + # https://github.com/libgit2/pygit2/issues/271. + # This solution will work in the meantime + self.delete_transaction(transaction.id) + setattr(exc, 'transaction', transaction) + raise exc + self.commit_changes('Added transaction %s' % transaction.id) _log.info('Added transaction %s', transaction.id) diff --git a/accounting/tests/test_transactions.py b/accounting/tests/test_transactions.py index 03ea2fcbf19c5d0883f63ea7e814cb96e965054c..f7d9bd1df9ca8221e3f793a21fb476509791e67d 100644 --- a/accounting/tests/test_transactions.py +++ b/accounting/tests/test_transactions.py @@ -9,6 +9,7 @@ import copy import uuid from datetime import datetime +from decimal import Decimal from flask import json @@ -17,7 +18,7 @@ from accounting.web import app, init_ledger from accounting.transport import AccountingEncoder, AccountingDecoder from accounting.models import Transaction, Posting, Amount -logging.basicConfig(level=logging.DEBUG) +#logging.basicConfig(level=logging.DEBUG) class TransactionTestCase(unittest.TestCase): @@ -263,13 +264,36 @@ class TransactionTestCase(unittest.TestCase): ] ) - self._post_json('/transaction', transaction) + response = self._post_json('/transaction', transaction, expect=400) - response = self._get_json('/transaction') + self.assertEqual(response['error']['type'], 'LedgerNotBalanced') - import pdb; pdb.set_trace() + def test_update_transaction_amounts(self): + transaction = self._add_simple_transaction() + response = self._get_json( + '/transaction/' + transaction.id) + + transaction = response['transaction'] + + for posting in transaction.postings: + posting.amount.amount *= Decimal(1.50) + + response = self._post_json('/transaction/' + transaction.id, + {'transaction': transaction}) + + self.assertEqual(response['status'], 'OK') + + response = self._get_json('/transaction/' + transaction.id) + + self.assertEqual(response['transaction'], transaction) + + def test_delete_nonexistent_transaction(self): + response = self._open_json('DELETE', '/transaction/I-do-not-exist', + expect=404) + + self.assertEqual(response['error']['type'], 'TransactionNotFound') - def test_update_transaction_amounts(self): pass + def test_post_transaction_with_metadata(self): pass if __name__ == '__main__': diff --git a/accounting/transport.py b/accounting/transport.py index e838be9edc151161607571de97cda4843c1dbb78..ac155b7ce11622c0667b9dc6c06f8c12b4d50e60 100644 --- a/accounting/transport.py +++ b/accounting/transport.py @@ -44,7 +44,8 @@ class AccountingEncoder(json.JSONEncoder): elif isinstance(o, AccountingException): return dict( type=o.__class__.__name__, - message=o.message + message=o.message, + transaction=getattr(o, 'transaction', None) ) return json.JSONEncoder.default(self, o)