commit 41db8d1466c7df7dc80e2133c4dbdf3980993051
parent 1af8e7036cc73edb4c4050ea2ca20010a26c9b88
Author: lash <dev@holbrook.no>
Date: Wed, 25 Mar 2026 19:26:20 -0600
Enable multiple parts in entry cli
Diffstat:
6 files changed, 110 insertions(+), 74 deletions(-)
diff --git a/dummy/tests/entry.py b/dummy/tests/entry.py
@@ -26,7 +26,7 @@ class TestEntry(unittest.TestCase):
dst = EntryPart('FOO', 'asset', 'foo', 1337)
src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
o = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
s = o.serialize()
@@ -49,7 +49,7 @@ class TestEntry(unittest.TestCase):
dst = EntryPart('FOO', 'asset', 'foo', 1337)
src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
o = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
wallet = DemoWallet()
data = o.wrap(wallet=wallet)
@@ -60,7 +60,7 @@ class TestEntry(unittest.TestCase):
dst = EntryPart('FOO', 'asset', 'foo', 1337)
src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
o = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
wallet = DemoWallet()
(digest, sig, msg) = o.sign(wallet)
@@ -77,7 +77,7 @@ class TestEntry(unittest.TestCase):
dst = EntryPart('FOO', 'asset', 'foo', 1337)
src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
o = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
wallet = DemoWallet()
data = o.wrap(wallet)
@@ -96,7 +96,7 @@ class TestEntry(unittest.TestCase):
dst = EntryPart('FOO', 'asset', 'foo', 1337)
src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
o = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
wallet = DemoWallet()
o.sign(wallet)
@@ -111,7 +111,7 @@ class TestEntry(unittest.TestCase):
dst = EntryPart('FOO', 'asset', 'foo', 1337)
src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
o = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
fp = os.path.join(testdir, 'test.xml')
@@ -131,7 +131,7 @@ class TestEntry(unittest.TestCase):
dst_two = EntryPart('FOO', 'asset', 'bar', 42)
src = EntryPart('FOO', 'income', 'baz', 1337+42, debit=True)
o = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst_one)
o.add_part(dst_two)
wallet = DemoWallet()
@@ -143,7 +143,7 @@ class TestEntry(unittest.TestCase):
dst_two = EntryPart('FOO', 'asset', 'bar', 42)
src = EntryPart('FOO', 'income', 'baz', 1337+42, debit=True)
o = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg, unitindex=self.uidx)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst_one)
o.add_part(dst_two)
diff --git a/dummy/tests/ledger.py b/dummy/tests/ledger.py
@@ -64,7 +64,7 @@ class TestLedger(unittest.TestCase):
x = EntryPart(s, 'income', 'foo', 1337, debit=True)
y = EntryPart(s, 'asset', 'foo', 1337)
v = Entry(o.peek(), datetime.datetime.now(), parent=o.current())
- v.add_part(x, debit=True)
+ v.add_part(x)
v.add_part(y)
v.sign(wallet)
o.add_entry(v)
@@ -72,7 +72,7 @@ class TestLedger(unittest.TestCase):
x = EntryPart(s, 'expense', 'bar̈́', 42, debit=True)
y = EntryPart(s, 'liability', 'bar', 42)
v = Entry(o.peek(), datetime.datetime.now(), parent=o.current())
- v.add_part(x, debit=True)
+ v.add_part(x)
v.add_part(y)
v.sign(wallet)
o.add_entry(v)
@@ -102,7 +102,7 @@ class TestLedger(unittest.TestCase):
x = EntryPart(s, 'income', 'foo', 1337, debit=True)
y = EntryPart(s, 'asset', 'foo', 1337)
v = Entry(o.peek(), datetime.datetime.now(), parent=o.current())
- v.add_part(x, debit=True)
+ v.add_part(x)
v.add_part(y)
v.sign(wallet)
o.add_entry(v)
@@ -110,7 +110,7 @@ class TestLedger(unittest.TestCase):
x = EntryPart(s, 'expense', 'bar̈́', 42, debit=True)
y = EntryPart(s, 'liability', 'bar', 42)
v = Entry(o.peek(), datetime.datetime.now(), parent=o.current())
- v.add_part(x, debit=True)
+ v.add_part(x)
v.add_part(y)
v.sign(wallet)
o.add_entry(v)
@@ -142,7 +142,7 @@ class TestLedger(unittest.TestCase):
x = EntryPart(s, 'income', 'foo', 1337, debit=True)
y = EntryPart(s, 'asset', 'foo', 1337)
v = Entry(ledger.peek(), datetime.datetime.now(), parent=ledger.current())
- v.add_part(x, debit=True)
+ v.add_part(x)
v.add_part(y)
v.sign(wallet)
ledger.add_entry(v)
@@ -150,7 +150,7 @@ class TestLedger(unittest.TestCase):
x = EntryPart(s, 'expense', 'bar̈́', 42, debit=True)
y = EntryPart(s, 'liability', 'bar', 42)
v = Entry(ledger.peek(), datetime.datetime.now(), parent=ledger.current())
- v.add_part(x, debit=True)
+ v.add_part(x)
v.add_part(y)
v.sign(wallet)
ledger.add_entry(v)
@@ -175,7 +175,7 @@ class TestLedger(unittest.TestCase):
x = EntryPart(s, 'income', 'foo', 1337, debit=True)
y = EntryPart(s, 'asset', 'foo', 1337)
v = Entry(ledger.peek(), datetime.datetime.now(), parent=ledger.current())
- v.add_part(x, debit=True)
+ v.add_part(x)
v.add_part(y)
v.sign(wallet)
ledger.add_entry(v)
@@ -184,7 +184,7 @@ class TestLedger(unittest.TestCase):
x = EntryPart(s, 'income', 'foo', 1337, debit=True)
y = EntryPart(s, 'asset', 'foo', 1337)
v = Entry(ledger.peek(), datetime.datetime.now(), parent=ledger.current())
- v.add_part(x, debit=True)
+ v.add_part(x)
v.add_part(y)
v.sign(wallet)
with self.assertRaises(VerifyError):
diff --git a/dummy/tests/store.py b/dummy/tests/store.py
@@ -38,7 +38,7 @@ class TestStore(unittest.TestCase):
dst = EntryPart('FOO', 'asset', 'foo', 1337)
src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
o = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg, unitindex=uidx)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
wallet = DemoWallet()
o.sign(wallet)
@@ -57,7 +57,7 @@ class TestStore(unittest.TestCase):
dst = EntryPart('FOO', 'asset', 'foo', 1337)
src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
o = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg, unitindex=uidx)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
fp = os.path.join(testdir, 'test.xml')
@@ -86,7 +86,7 @@ class TestStore(unittest.TestCase):
dst = EntryPart('FOO', 'asset', 'foo', 1337)
src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
o = Entry(ledger.next_serial(), datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg, unitindex=uidx)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
o.sign(wallet)
store.add_entry(o)
@@ -98,7 +98,7 @@ class TestStore(unittest.TestCase):
dst = EntryPart('FOO', 'expense', 'bar', 4200)
src = EntryPart('FOO', 'liability', 'bar', 4200, debit=True)
o = Entry(ledger.next_serial(), datetime.datetime.strptime('2025-11-12', '%Y-%m-%d'), parent=parent, ref=ref, description=description, tx_datereg=dtreg, unitindex=uidx)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
o.sign(wallet)
store.add_entry(o)
@@ -135,7 +135,7 @@ class TestStore(unittest.TestCase):
dst = EntryPart('FOO', 'asset', 'foo', 1337)
src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
o = Entry(ledger.next_serial(), datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg, unitindex=uidx)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
o.sign(wallet)
store.add_entry(o)
@@ -147,7 +147,7 @@ class TestStore(unittest.TestCase):
dst = EntryPart('FOO', 'expense', 'bar', 4200)
src = EntryPart('FOO', 'liability', 'bar', 4200, debit=True)
o = Entry(ledger.next_serial(), datetime.datetime.strptime('2025-11-12', '%Y-%m-%d'), parent=parent, ref=ref, description=description, tx_datereg=dtreg, unitindex=uidx)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
o.sign(wallet)
store.add_entry(o)
@@ -169,7 +169,7 @@ class TestStore(unittest.TestCase):
dst = EntryPart('FOO', 'asset', 'foo', 1337)
src = EntryPart('FOO', 'income', 'foo', 1337, debit=True)
o = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg, unitindex=uidx)
- o.add_part(src, debit=True)
+ o.add_part(src)
o.add_part(dst)
o.add_tag('foo')
o.add_pair('bar', 'baz')
diff --git a/dummy/usawa/account.py b/dummy/usawa/account.py
@@ -26,7 +26,9 @@ def from_account_path(p, sym=None, typ=None):
if typ == None:
o = check_path_parts(o[1])
typ = o[0]
- path = o[1]
+ path = o[1]
+ else:
+ path = o[1].split('/')
return (sym, typ, path,)
diff --git a/dummy/usawa/entry.py b/dummy/usawa/entry.py
@@ -226,10 +226,10 @@ class Entry(UsawaElement):
:type debit: boolean
:raises KeyError: Symbol does not exist in unit index.
"""
- def add_part(self, part, debit=False):
+ def add_part(self, part):
if self.uidx != None:
self.uidx.sym(part.unit)
- if debit:
+ if part.isdebit:
self.debit.append(part)
else:
self.credit.append(part)
@@ -297,7 +297,7 @@ class Entry(UsawaElement):
src = EntryPart.from_tree(src_tree, debit=True)
dst = EntryPart.from_tree(dst_tree)
entry.add_part(dst)
- entry.add_part(src, debit=True)
+ entry.add_part(src)
for v in o.findall('attachment', namespaces=nsmap()):
asset = Asset.from_tree(v)
@@ -375,13 +375,11 @@ class Entry(UsawaElement):
@staticmethod
def deserialize(data):
v = rencode.loads(data)
- #parent = v[0].hex()
parent = v[1]
serial = v[2]
ref = v[3].decode('utf-8')
date_reg = datetime.datetime.strptime(v[4].decode('utf-8'), '%Y%m%d%H%M%S')
date = datetime.datetime.strptime(v[5].decode('utf-8'), '%Y%m%d')
- #unit = v[5].decode('utf-8')
description = v[6].decode('utf-8')
dst_data = v[7]
src_data = v[8]
@@ -389,12 +387,10 @@ class Entry(UsawaElement):
o = Entry(serial, date, ref=ref, description=description, parent=parent, tx_datereg=date_reg)
super(Entry, o).deserialize(v[0])
for v in src_data:
- #src = EntryPart(v[0].decode('utf-8'), v[1].decode('utf-8'), v[2].decode('utf-8'), v[3], debit=True)
src = EntryPart.deserialize(v, debit=True)
- o.add_part(src, debit=True)
+ o.add_part(src)
for v in dst_data:
- #dst = EntryPart(v[0].decode('utf-8'), v[1].decode('utf-8'), v[2].decode('utf-8'), v[3])
dst = EntryPart.deserialize(v)
o.add_part(dst)
diff --git a/dummy/usawa/runnable/entry.py b/dummy/usawa/runnable/entry.py
@@ -2,6 +2,8 @@ import argparse
import logging
import uuid
import datetime
+import signal
+import sys
from whee.valkey import ValkeyStore
@@ -24,10 +26,11 @@ class Context:
# entry parts
self.description = None
- self.src = [None, None, None]
- self.dst = [None, None, None]
+ #self.src = [None, None, None]
+ #self.dst = [None, None, None]
+ self.src = []
+ self.dst = []
self.amount = None
- self.part = []
self.output = None
self.f = None
if args.d:
@@ -35,7 +38,7 @@ class Context:
else:
self.txdate = datetime.datetime.utcnow()
self.attach = []
-
+
# set up ledger
s = args.l
if not s:
@@ -47,8 +50,8 @@ class Context:
raise ValueError('ledger file required')
self.ledger = Ledger.from_file(s)
self.uidx = self.ledger.uidx
- self.src[2] = self.uidx.base
- self.dst[2] = self.uidx.base
+ #self.src[2] = self.uidx.base
+ #self.dst[2] = self.uidx.base
# set up accounts hierarchy, if applicable
self.accounts = None
@@ -75,6 +78,10 @@ class Context:
self.store.put_draft(self.entry)
self.ref = self.entry.get_ref()
+ self.base = self.uidx.base
+ self.k = 'src'
+ self.havedst = False
+ self.i = 0
def parse_type(self, v):
@@ -109,18 +116,27 @@ class Context:
return uidx.from_floatstring(sym, v)
+ def parse_side(self, v):
+ for k in ['src', 'dst']:
+ if k.startswith(v):
+ return k
+ raise ValueError('invalid side: ' + v)
+
+
def add_part(self, part):
logg.info('add part {}'.format(part))
self.part.append(part)
def validate(self):
- for v in self.src:
- if v == None:
- raise ValueError('invalid src')
- for v in self.dst:
- if v == None:
- raise ValueError('invalid dst')
+ #for k in self.src:
+ # if v == None:
+ if len(self.src) == 0:
+ raise ValueError('no src')
+ #for v in self.dst:
+ # if v == None:
+ if len(self.dst) == 0:
+ raise ValueError('no dst')
if self.ref == None:
raise ValueError('invalid ref')
@@ -142,6 +158,11 @@ if args.v:
ctx = Context(args)
+def croak(*args, **kwargs):
+ sys.exit(1)
+
+signal.signal(signal.SIGINT, croak)
+signal.signal(signal.SIGTERM, croak)
def input_or_default(prompt, default=None, postfix=': ', validate_fn=None):
if default != None:
@@ -156,54 +177,66 @@ def input_or_default(prompt, default=None, postfix=': ', validate_fn=None):
return v
-def do_interactive(ctx):
- v = input_or_default('Entry description', ctx.description)
- ctx.description = v
+def do_interactive_one(ctx):
+ ctx.description = input_or_default('Entry description', ctx.description)
+ ctx.ref = input_or_default('External ref', ctx.ref)
- amounts = {
- 'src': None,
- 'dst': None,
- }
- for k in ['src', 'dst']:
- o = vars(ctx)
- #v = input('Entry {} type: '.format(k))
+def do_interactive_two(ctx, entry):
- v = input_or_default('Entry {} unit'.format(k), o[k][2])
+ r = True
+ while r:
+ try:
+ r = enter_part(ctx, entry)
+ except Exception as e:
+ logg.error('err {}'.format(e))
+ pass
+
+
+def enter_part(ctx, entry):
+ if ctx.i > 0:
+ if ctx.havedst:
+ ctx.k = ''
+ else:
+ ctx.k = 'dst'
+ v = input_or_default('Entry side', ctx.k)
+ if v == '':
+ return False
+ ctx.k = ctx.parse_side(v)
+ if v == 'dst':
+ ctx.havedst = True
+
+ v = input_or_default('Entry {} unit'.format(ctx.k), ctx.base)
unit = ctx.parse_unit(v)
- o[k][2] = unit
+ if ctx.base != unit:
+ ctx.base = unit
- v = input_or_default('Entry {} type'.format(k), o[k][0])
+ v = input_or_default('Entry {} type'.format(ctx.k))
typ = ctx.parse_type(v)
- o[k][0] = typ
- v = input_or_default('Entry {} account'.format(k), o[k][1])
+ v = input_or_default('Entry {} account'.format(ctx.k))
account = ctx.parse_account(v, sym=unit, typ=typ)
- o[k][1] = account
amount = None
- if k =='dst':
- amount = amounts['src']
- v = input_or_default('Entry {} amount'.format(k), amount)
+ v = input_or_default('Entry {} amount'.format(ctx.k), amount)
amount = ctx.parse_amount(ctx.uidx, unit, v)
- amount *= -1
- amounts[k] = str(amount)
- part = EntryPart(unit, typ.value, account.to_path(display=AccountDisplay.path), amount, debit=k=='src')
- ctx.add_part(part)
+ isdebit = ctx.k=='src'
+ part = EntryPart(unit, typ.value, account.to_path(display=AccountDisplay.path), amount, debit=isdebit)
+ entry.add_part(part)
- ctx.ref = input_or_default('External ref', ctx.ref)
+ ctx.i += 1
+
+ return True
entry = None
if ctx.state == 0:
- do_interactive(ctx)
- ctx.validate()
- entry = Entry.empty(ref=ctx.ref)
+ do_interactive_one(ctx)
+ entry = Entry.empty(ref=ctx.ref, unitindex=ctx.uidx)
entry = ctx.store.get_draft(entry)
- entry.description = description
- entry.add_part(ctx.part[0], debit=True)
- entry.add_part(ctx.part[1])
+ entry.description = ctx.description
+ do_interactive_two(ctx, entry)
else:
entry = ctx.entry
@@ -225,5 +258,10 @@ if ctx.commit:
entry.serial = ctx.ledger.next_serial()
+#v = input_or_default('Commit? (type YES, any other input is no)', '')
+#if v == 'YES':
+ #ctx.store.put_entry(entry)
+# pass
+#else:
ctx.store.put_draft(entry)
print(entry)