|
@@ -0,0 +1,113 @@
|
|
|
+#!/usr/bin/python3
|
|
|
+from datetime import datetime
|
|
|
+from dateutil.parser import parse as parse_time
|
|
|
+import itertools
|
|
|
+import gnucash
|
|
|
+import sys
|
|
|
+
|
|
|
+def _unwrap_list(root, blacklist):
|
|
|
+ for i in map(lambda x: [
|
|
|
+ (':'.join([x[0], c.name]), True) for c in root.get_children()
|
|
|
+ ] if x[1] else [ x ], blacklist):
|
|
|
+ for j in i: yield j
|
|
|
+
|
|
|
+def _accounts(root, path, blacklist, whitelist):
|
|
|
+ #print('blacklist1: {}'.format(blacklist))
|
|
|
+ #print(f'whitelist1 ({root.name}: {whitelist}')
|
|
|
+
|
|
|
+ if root.name in [ w[0] for w in whitelist ] and \
|
|
|
+ root.name not in [ b[0] for b in blacklist ]:
|
|
|
+ yield path, root
|
|
|
+ blacklist = [b for b in itertools.chain(
|
|
|
+ _unwrap_list(root, filter(lambda x: (x[0] == root.name), blacklist)),
|
|
|
+ filter(lambda x: not (x[0] == root.name), blacklist)
|
|
|
+ )]
|
|
|
+ whitelist = [b for b in itertools.chain(
|
|
|
+ _unwrap_list(root, filter(lambda x: (x[0] == root.name), whitelist)),
|
|
|
+ filter(lambda x: not (x[0] == root.name), whitelist)
|
|
|
+ )]
|
|
|
+ path = [*path, root.name]
|
|
|
+ prefix = '{}:'.format(root.name)
|
|
|
+ #print('root: {}'.format(root.name))
|
|
|
+ #print('prefix: {}'.format(prefix))
|
|
|
+ #print('path: {}'.format(':'.join(path)))
|
|
|
+ blacklist = [
|
|
|
+ b for b in map(
|
|
|
+ lambda x: (x[0][len(prefix):], x[1]), filter(
|
|
|
+ lambda x: x[0].startswith(prefix), blacklist
|
|
|
+ )
|
|
|
+ )
|
|
|
+ ]
|
|
|
+ whitelist = [
|
|
|
+ b for b in map(
|
|
|
+ lambda x: (x[0][len(prefix):], x[1]), filter(
|
|
|
+ lambda x: x[0].startswith(prefix), whitelist
|
|
|
+ )
|
|
|
+ )
|
|
|
+ ]
|
|
|
+ #print('blacklist: {}'.format(blacklist))
|
|
|
+ for a in root.get_children():
|
|
|
+ for p, c in _accounts(a, path, blacklist, whitelist):
|
|
|
+ yield p, c
|
|
|
+
|
|
|
+def _path(account):
|
|
|
+ if account.get_parent() is not None: return ':'.join([_path(account.get_parent()), account.name])
|
|
|
+ else: return account.name
|
|
|
+
|
|
|
+def _iter(root, blacklist, whitelist, _from, _to):
|
|
|
+ for p, a in _accounts(root, [], blacklist, whitelist):
|
|
|
+ apath = _path(a)
|
|
|
+ s = dict()
|
|
|
+
|
|
|
+ for t in a.GetSplitList():
|
|
|
+ tpath = _path(t.account)
|
|
|
+ if datetime.fromtimestamp(_to) > t.parent.GetDate() >= datetime.fromtimestamp(_from):
|
|
|
+ #if apath.startswith('Root Account:Trading'):
|
|
|
+ # if tpath.startswith('Root Account:Trading:CURRENCY'):
|
|
|
+ # s+=t.GetValue().num()
|
|
|
+ #elif tpath == apath:
|
|
|
+ if tpath == apath:
|
|
|
+ #print(t.parent.GetDescription())
|
|
|
+ desc = t.parent.GetDescription()
|
|
|
+ if desc not in s:
|
|
|
+ s[desc] = 0
|
|
|
+ #print(t.parent.GetNotes())
|
|
|
+ s[desc]+=t.GetValue().num()
|
|
|
+ #if apath.startswith('Assets'): s+= t.GetValue().num()
|
|
|
+ #elif apath.startswith('Liabilities'): s-= t.GetValue().num()
|
|
|
+ #if apath.startswith('Income'): s+= t.GetValue().num()
|
|
|
+ yield p, a.name, s
|
|
|
+ #for t in a.GetSplitList():
|
|
|
+ # print(t.parent.GetDate(), type(t.parent.GetDate()))
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ args = sys.argv
|
|
|
+ session = gnucash.Session(args[1])
|
|
|
+ try:
|
|
|
+ blacklist = [
|
|
|
+ # name, also_children
|
|
|
+ ('Root Account:Assets', True),
|
|
|
+ ('Root Account:Liabilities', True),
|
|
|
+ ('Root Account:Equity', True),
|
|
|
+ ('Root Account:Income', True),
|
|
|
+ ]
|
|
|
+ whitelist = [
|
|
|
+ # name, also_children
|
|
|
+ ('Root Account:Expenses:NZD:Food:Groceries', True),
|
|
|
+ ]
|
|
|
+ _from = int(parse_time(args[2]).timestamp())# 1554030000 # 1 April 2019 as seconds since epoch
|
|
|
+ _to = int(parse_time(args[3]).timestamp())
|
|
|
+ _interval = int(args[4])*60*60*24
|
|
|
+ for f, t in [ (i, i+_interval) for i in range(_from, _to, _interval)]:
|
|
|
+ ts = datetime.fromtimestamp(f)
|
|
|
+ to = datetime.fromtimestamp(t)
|
|
|
+ tot = 0
|
|
|
+ for p,n,s in _iter(session.book.get_root_account(), blacklist, whitelist, f, t):
|
|
|
+ account_name = ':'.join([*p, n])
|
|
|
+ for k in sorted(s.keys()):
|
|
|
+ print(f'{ts} {k:35s}: {s[k]/100:>06.2f}')
|
|
|
+ tot += s[k]
|
|
|
+ if tot > 0:
|
|
|
+ print(f'{to} {str("TOTAL"):35s}: {tot/100:>06.2f}')
|
|
|
+ finally:
|
|
|
+ session.end()
|