Added /transaction endpoint
This commit is contained in:
parent
63c7b70000
commit
6f2c875c7b
5 changed files with 125 additions and 2 deletions
|
@ -111,6 +111,30 @@ class Ledger:
|
|||
|
||||
return output
|
||||
|
||||
def add_transaction(self, transaction):
|
||||
transaction_template = ('\n{date} {t.payee}\n'
|
||||
'{postings}')
|
||||
|
||||
posting_template = (' {account} {p.amount.symbol}'
|
||||
' {p.amount.amount}\n')
|
||||
|
||||
output = b''
|
||||
|
||||
output += transaction_template.format(
|
||||
date=transaction.date.strftime('%Y-%m-%d'),
|
||||
t=transaction,
|
||||
postings=''.join([posting_template.format(
|
||||
p=p,
|
||||
account=p.account + ' ' * (
|
||||
80 - (len(p.account) + len(p.amount.symbol) +
|
||||
len(p.amount.amount) + 1 + 2)
|
||||
)) for p in transaction.postings])).encode('utf8')
|
||||
|
||||
with open(self.ledger_file, 'ab') as f:
|
||||
f.write(output)
|
||||
|
||||
_log.debug('written to file: %s', output)
|
||||
|
||||
def bal(self):
|
||||
output = self.send_command('xml')
|
||||
|
||||
|
|
20
accounting/decorators.py
Normal file
20
accounting/decorators.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from functools import wraps
|
||||
|
||||
from flask import jsonify
|
||||
|
||||
from accounting.exceptions import AccountingException
|
||||
|
||||
|
||||
def jsonify_exceptions(func):
|
||||
'''
|
||||
Wraps a Flask endpoint and catches any AccountingException-based
|
||||
exceptions which are returned to the client as JSON.
|
||||
'''
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kw):
|
||||
try:
|
||||
return func(*args, **kw)
|
||||
except AccountingException as exc:
|
||||
return jsonify(error=exc)
|
||||
|
||||
return wrapper
|
6
accounting/exceptions.py
Normal file
6
accounting/exceptions.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
class AccountingException(Exception):
|
||||
'''
|
||||
Used as a base for exceptions that are returned to the caller via the
|
||||
jsonify_exceptions decorator
|
||||
'''
|
||||
pass
|
|
@ -1,3 +1,5 @@
|
|||
from datetime import datetime
|
||||
|
||||
from flask import json
|
||||
|
||||
from accounting import Amount, Transaction, Posting, Account
|
||||
|
@ -30,6 +32,11 @@ class AccountingEncoder(json.JSONEncoder):
|
|||
amount=o.amount,
|
||||
symbol=o.symbol
|
||||
)
|
||||
elif isinstance(o, Exception):
|
||||
return dict(
|
||||
__type__=o.__class__.__name__,
|
||||
args=o.args
|
||||
)
|
||||
|
||||
return json.JSONEncoder.default(self, o)
|
||||
|
||||
|
@ -46,4 +53,7 @@ class AccountingDecoder(json.JSONDecoder):
|
|||
|
||||
_type = d.pop('__type__')
|
||||
|
||||
if _type == 'Transaction':
|
||||
d['date'] = datetime.strptime(d['date'], '%Y-%m-%d')
|
||||
|
||||
return types[_type](**d)
|
||||
|
|
|
@ -2,10 +2,12 @@ import sys
|
|||
import logging
|
||||
import argparse
|
||||
|
||||
from flask import Flask, g, jsonify, json, request
|
||||
from flask import Flask, jsonify, request
|
||||
|
||||
from accounting import Ledger, Account, Posting, Transaction, Amount
|
||||
from accounting import Ledger
|
||||
from accounting.transport import AccountingEncoder, AccountingDecoder
|
||||
from accounting.exceptions import AccountingException
|
||||
from accounting.decorators import jsonify_exceptions
|
||||
|
||||
|
||||
app = Flask('accounting')
|
||||
|
@ -32,6 +34,67 @@ def balance_report():
|
|||
return jsonify(balance_report=report_data)
|
||||
|
||||
|
||||
@app.route('/transaction', methods=['POST'])
|
||||
@jsonify_exceptions
|
||||
def transaction():
|
||||
'''
|
||||
REST/JSON endpoint for transactions.
|
||||
|
||||
Current state:
|
||||
|
||||
Takes a POST request with a ``transactions`` JSON payload and writes it to
|
||||
the ledger file.
|
||||
|
||||
Requires the ``transactions`` payload to be __type__-annotated:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"transactions": [
|
||||
{
|
||||
"__type__": "Transaction",
|
||||
"date": "2013-01-01",
|
||||
"payee": "Kindly T. Donor",
|
||||
"postings": [
|
||||
{
|
||||
"__type__": "Posting",
|
||||
"account": "Income:Foo:Donation",
|
||||
"amount": {
|
||||
"__type__": "Amount",
|
||||
"amount": "-100",
|
||||
"symbol": "$"
|
||||
}
|
||||
},
|
||||
{
|
||||
"__type__": "Posting",
|
||||
"account": "Assets:Checking",
|
||||
"amount": {
|
||||
"__type__": "Amount",
|
||||
"amount": "100",
|
||||
"symbol": "$"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
becomes::
|
||||
|
||||
2013-01-01 Kindly T. Donor
|
||||
Income:Foo:Donation $ -100
|
||||
Assets:Checking $ 100
|
||||
'''
|
||||
transactions = request.json.get('transactions')
|
||||
|
||||
if not transactions:
|
||||
raise AccountingException('No transaction data provided')
|
||||
|
||||
for transaction in transactions:
|
||||
ledger.add_transaction(transaction)
|
||||
|
||||
return jsonify(foo='bar')
|
||||
|
||||
|
||||
@app.route('/parse-json', methods=['POST'])
|
||||
def parse_json():
|
||||
r'''
|
||||
|
|
Loading…
Reference in a new issue