Added transaction IDs and metadata

This commit is contained in:
Joar Wandborg 2013-12-11 15:12:08 +01:00
parent 266aa455f9
commit 032175cd26
5 changed files with 94 additions and 29 deletions

View file

@ -119,23 +119,37 @@ class Ledger:
writing a ledger transaction based on the Transaction instance in
``transaction``.
'''
if not transaction.metadata.get('Id'):
transaction.generate_id()
transaction_template = ('\n{date} {t.payee}\n'
'{tags}'
'{postings}')
metadata_template = ' ;{0}: {1}\n'
# TODO: Generate metadata for postings
posting_template = (' {account} {p.amount.symbol}'
' {p.amount.amount}\n')
output = b''
# XXX: Even I hardly understands what this does, however I indent it it
# stays unreadable.
output += transaction_template.format(
date=transaction.date.strftime('%Y-%m-%d'),
t=transaction,
tags=''.join([
metadata_template.format(k, v) \
for k, v in transaction.metadata.items()]),
postings=''.join([posting_template.format(
p=p,
account=p.account + ' ' * (
80 - (len(p.account) + len(p.amount.symbol) +
len(str(p.amount.amount)) + 1 + 2)
)) for p in transaction.postings])).encode('utf8')
)) for p in transaction.postings
])
).encode('utf8')
with open(self.ledger_file, 'ab') as f:
f.write(output)
@ -209,12 +223,41 @@ class Ledger:
symbol = posting.find(
'./post-amount/amount/commodity/symbol').text
# Get the posting metadata
metadata = {}
values = posting.findall('./metadata/value')
if values:
for value in values:
key = value.get('key')
value = value.find('./string').text
_log.debug('metadata: %s: %s', key, value)
metadata.update({key: value})
postings.append(
Posting(account=account,
metadata=metadata,
amount=Amount(amount=amount, symbol=symbol)))
# Get the transaction metadata
metadata = {}
values = transaction.findall('./metadata/value')
if values:
for value in values:
key = value.get('key')
value = value.find('./string').text
_log.debug('metadata: %s: %s', key, value)
metadata.update({key: value})
# Add a Transaction instance to the list
entries.append(
Transaction(date=date, payee=payee, postings=postings))
Transaction(date=date, payee=payee, postings=postings,
metadata=metadata))
return entries

View file

@ -54,6 +54,23 @@ def _recurse_accounts(accounts, level=0):
_recurse_accounts(account.accounts, level+1)
def get_register():
response = requests.get(HOST + '/register')
register = response.json(cls=AccountingDecoder)
for transaction in register['register_report']:
print('{date} {t.payee:.<69}'.format(
date=transaction.date.strftime('%Y-%m-%d'),
t=transaction))
for posting in transaction.postings:
print(' ' + posting.account +
' ' * (80 - len(posting.account) - len(posting.amount.symbol) -
len(str(posting.amount.amount)) - 1 - 1) +
posting.amount.symbol + ' ' + str(posting.amount.amount))
def main(argv=None, prog=None):
global HOST
if argv is None:
@ -62,11 +79,12 @@ def main(argv=None, prog=None):
parser = argparse.ArgumentParser(prog=prog)
parser.add_argument('-p', '--paypal', type=Decimal)
parser.add_argument('-b', '--balance', action='store_true')
parser.add_argument('-r', '--register', action='store_true')
parser.add_argument('-v', '--verbosity',
default='WARNING',
help=('Filter logging output. Possible values:' +
' CRITICAL, ERROR, WARNING, INFO, DEBUG'))
parser.add_argument('-b', '--balance', action='store_true')
parser.add_argument('--host', default='http://localhost:5000')
args = parser.parse_args(argv)
@ -78,6 +96,8 @@ def main(argv=None, prog=None):
insert_paypal_transaction(args.paypal)
elif args.balance:
get_balance()
elif args.register:
get_register()
if __name__ == '__main__':
sys.exit(main())

View file

@ -1,11 +1,20 @@
import uuid
from decimal import Decimal
class Transaction:
def __init__(self, date=None, payee=None, postings=None):
def __init__(self, date=None, payee=None, postings=None, metadata=None,
_generate_id=False):
self.date = date
self.payee = payee
self.postings = postings
self.metadata = metadata if metadata is not None else {}
if _generate_id:
self.generate_id()
def generate_id(self):
self.metadata.update({'Id': uuid.uuid4()})
def __repr__(self):
return ('<{self.__class__.__name__} {date}' +
@ -15,9 +24,10 @@ class Transaction:
class Posting:
def __init__(self, account=None, amount=None):
def __init__(self, account=None, amount=None, metadata=None):
self.account = account
self.amount = amount
self.metadata = metadata if metadata is not None else {}
def __repr__(self):
return ('<{self.__class__.__name__} "{self.account}"' +

View file

@ -18,13 +18,15 @@ class AccountingEncoder(json.JSONEncoder):
__type__=o.__class__.__name__,
date=o.date.strftime('%Y-%m-%d'),
payee=o.payee,
postings=o.postings
postings=o.postings,
metadata=o.metadata
)
elif isinstance(o, Posting):
return dict(
__type__=o.__class__.__name__,
account=o.account,
amount=o.amount,
metadata=o.metadata
)
elif isinstance(o, Amount):
return dict(

View file

@ -1,26 +1,29 @@
2010/01/01 Kindly T. Donor
;Id: Ids can be anything
Income:Foo:Donation $-100.00
;Invoice: Projects/Foo/Invoices/Invoice20100101.pdf
Assets:Checking $100.00
2011/03/15 Another J. Donor
;Id: but mind you if they collide.
Income:Foo:Donation $-400.00
;Approval: Projects/Foo/earmark-record.txt
Assets:Checking $400.00
2011/04/20 (1) Baz Hosting Services, LLC
;Id: always make sure your IDs are unique
Expenses:Foo:Hosting $250.00
;Receipt: Projects/Foo/Expenses/hosting/AprilHostingReceipt.pdf
Assets:Checking $-250.00
2011/05/10 Donation to General Fund
;Id: if you have two transactions with the same ID, bad things may happen
Income:Donation $-50.00
;Invoice: Financial/Invoices/Invoice20110510.pdf
Assets:Checking $50.00
2011/04/20 (2) Baz Hosting Services, LLC
;Id: this is probably unique
Expenses:Blah:Hosting $250.00
;Receipt: Projects/Blah/Expenses/hosting/AprilHostingReceipt.pdf
;Invoice: Projects/Blah/Expenses/hosting/april-invoice.pdf
@ -28,29 +31,16 @@
;Statement: Financial/BankStuff/bank-statement.pdf
2011-04-25 A transaction with ISO date
;Id: I'm a snowflake!
Income:Karma KARMA-10
Assets:Karma Account KARMA 10
2013-01-01 Kindly T. Donor
Income:Foo:Donation $ -100
Assets:Checking $ 100
2013-03-15 Another J. Donor
Income:Foo:Donation $ -400
Assets:Checking $ 400
2013-12-11 PayPal donation
;Id: bd7f6781-fdc6-4111-b3ad-bee2247e426d
Income:Donations:PayPal $ -20.17
Assets:Checking $ 20.17
2013-12-11 PayPal donation
Income:Donations:PayPal $ -100
Assets:Checking $ 100
2013-12-11 PayPal donation
Income:Donations:PayPal $ -1000
Assets:Checking $ 1000
2013-12-11 PayPal donation
Income:Donations:PayPal $ -0.25
Assets:Checking $ 0.25
2013-12-11 PayPal donation
Income:Donations:PayPal $ -0.252
Assets:Checking $ 0.252
;Id: 31048b9d-a5b6-41d7-951a-e7128e7c53c0
Income:Donations:PayPal $ -20.18
Assets:Checking $ 20.18