Use Amount objects, use the XML output in bal()
This commit is contained in:
parent
dd260aa021
commit
af6e28d168
2 changed files with 62 additions and 21 deletions
|
@ -40,7 +40,6 @@ class Ledger:
|
|||
_log.info('Waiting for one second... %d/%d', i, timeout)
|
||||
time.sleep(1)
|
||||
|
||||
|
||||
process = self.get_process()
|
||||
|
||||
self.locked = True
|
||||
|
@ -111,20 +110,40 @@ class Ledger:
|
|||
return output
|
||||
|
||||
def bal(self):
|
||||
output = self.send_command('bal --format "%A|%t\\\\n"')
|
||||
output = self.send_command('xml')
|
||||
|
||||
if output is None:
|
||||
raise RuntimeError('bal call returned no output')
|
||||
|
||||
accounts = []
|
||||
|
||||
for line in output.split(b'\n'):
|
||||
try:
|
||||
name, balance = line.decode('utf8').split('|')
|
||||
except ValueError:
|
||||
continue
|
||||
xml = ElementTree.fromstring(output.decode('utf8'))
|
||||
|
||||
accounts.append(Account(name=name, balance=balance))
|
||||
accounts = self._recurse_accounts(xml.find('./accounts'))
|
||||
|
||||
return accounts
|
||||
|
||||
def _recurse_accounts(self, root):
|
||||
accounts = []
|
||||
|
||||
for account in root.findall('./account'):
|
||||
name = account.find('./fullname').text
|
||||
|
||||
amounts = []
|
||||
|
||||
account_amounts = account.findall('./account-total/balance/amount') or \
|
||||
account.findall('./account-amount/amount')
|
||||
|
||||
if account_amounts:
|
||||
for amount in account_amounts:
|
||||
quantity = amount.find('./quantity').text
|
||||
symbol = amount.find('./commodity/symbol').text
|
||||
|
||||
amounts.append(Amount(amount=quantity, symbol=symbol))
|
||||
|
||||
accounts.append(Account(name=name,
|
||||
amounts=amounts,
|
||||
accounts=self._recurse_accounts(account)))
|
||||
|
||||
return accounts
|
||||
|
||||
|
@ -152,7 +171,8 @@ class Ledger:
|
|||
'./post-amount/amount/commodity/symbol').text
|
||||
|
||||
postings.append(
|
||||
Posting(account=account, amount=amount, symbol=symbol))
|
||||
Posting(account=account,
|
||||
amount=Amount(amount=amount, symbol=symbol)))
|
||||
|
||||
entries.append(
|
||||
Transaction(date=date, payee=payee, postings=postings))
|
||||
|
@ -170,33 +190,44 @@ class Transaction:
|
|||
return ('<{self.__class__.__name__} {date}' +
|
||||
' {self.payee} {self.postings}').format(
|
||||
self=self,
|
||||
date=self.date.isoformat())
|
||||
date=self.date.strftime('%Y-%m-%d'))
|
||||
|
||||
|
||||
class Posting:
|
||||
def __init__(self, account=None, amount=None, symbol=None):
|
||||
def __init__(self, account=None, amount=None):
|
||||
self.account = account
|
||||
self.amount = amount
|
||||
|
||||
def __repr__(self):
|
||||
return ('<{self.__class__.__name__} "{self.account}"' +
|
||||
' {self.amount}>').format(self=self)
|
||||
|
||||
|
||||
class Amount:
|
||||
def __init__(self, amount=None, symbol=None):
|
||||
self.amount = amount
|
||||
self.symbol = symbol
|
||||
|
||||
def __repr__(self):
|
||||
return ('<{self.__class__.__name__} "{self.account}"' +
|
||||
' {self.symbol} {self.amount}>').format(self=self)
|
||||
return ('<{self.__class__.__name__} {self.symbol}' +
|
||||
' {self.amount}>').format(self=self)
|
||||
|
||||
|
||||
class Account:
|
||||
def __init__(self, name=None, balance=None):
|
||||
def __init__(self, name=None, amounts=None, accounts=None):
|
||||
self.name = name
|
||||
self.balance = balance
|
||||
self.amounts = amounts
|
||||
self.accounts = accounts
|
||||
|
||||
def __repr__(self):
|
||||
return '<{self.__class__.__name__}: "{self.name}" {self.balance} >'.format(
|
||||
self=self)
|
||||
return ('<{self.__class__.__name__} "{self.name}" {self.amounts}' +
|
||||
' {self.accounts}>').format(self=self)
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
ledger = Ledger(ledger_file='non-profit-test-data.ledger')
|
||||
print(ledger.bal())
|
||||
print(ledger.reg())
|
||||
|
|
|
@ -2,7 +2,7 @@ import logging
|
|||
|
||||
from flask import Flask, g, jsonify, json
|
||||
|
||||
from accounting import Ledger, Account, Posting, Transaction
|
||||
from accounting import Ledger, Account, Posting, Transaction, Amount
|
||||
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
@ -11,12 +11,14 @@ app.config.from_pyfile('config.py')
|
|||
|
||||
ledger = Ledger(ledger_file=app.config['LEDGER_FILE'])
|
||||
|
||||
|
||||
class AccountingEncoder(json.JSONEncoder):
|
||||
def default(self, o):
|
||||
if isinstance(o, Account):
|
||||
return dict(
|
||||
name=o.name,
|
||||
balance=o.balance
|
||||
amounts=o.amounts,
|
||||
accounts=o.accounts
|
||||
)
|
||||
elif isinstance(o, Transaction):
|
||||
return dict(
|
||||
|
@ -28,23 +30,31 @@ class AccountingEncoder(json.JSONEncoder):
|
|||
return dict(
|
||||
account=o.account,
|
||||
amount=o.amount,
|
||||
)
|
||||
elif isinstance(o, Amount):
|
||||
return dict(
|
||||
amount=o.amount,
|
||||
symbol=o.symbol
|
||||
)
|
||||
|
||||
return json.JSONEncoder.default(self, o)
|
||||
|
||||
|
||||
app.json_encoder = AccountingEncoder
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return 'Hello World!'
|
||||
|
||||
|
||||
@app.route('/balance')
|
||||
def balance_report():
|
||||
report_data = ledger.bal()
|
||||
|
||||
return jsonify(balance_report=report_data)
|
||||
|
||||
|
||||
@app.route('/register')
|
||||
def register_report():
|
||||
report_data = ledger.reg()
|
||||
|
|
Loading…
Reference in a new issue