usawa

Signed, immutable accounting.
Log | Files | Refs | Submodules | LICENSE

commit 244333daaf88c1f35f08c10266e3978ccd1e34cb
parent 800a625e0a03b6a9223e77d5ee06e25236c997a4
Author: lash <dev@holbrook.no>
Date:   Fri,  1 May 2026 20:06:15 -0600

Implement account object in entrypart

Diffstat:
Mdummy/tests/balance.py | 46+++++++++++++++++++++++-----------------------
Mdummy/tests/entry.py | 44++++++++++++++++++++++----------------------
Mdummy/tests/index.py | 12++++++------
Mdummy/tests/ledger.py | 32++++++++++++++++----------------
Mdummy/tests/resolver.py | 8++++----
Mdummy/tests/server.py | 15++++++++-------
Mdummy/tests/store.py | 36++++++++++++++++++------------------
Mdummy/tests/wallet.py | 2+-
Mdummy/usawa/account.py | 14++++++++++++++
Mdummy/usawa/balance.py | 6+++---
Mdummy/usawa/crypto.py | 12++++++------
Mdummy/usawa/entry.py | 55++++++++++++++++++++++++++++++++++++++-----------------
Mdummy/usawa/ledger.py | 8++++++--
13 files changed, 165 insertions(+), 125 deletions(-)

diff --git a/dummy/tests/balance.py b/dummy/tests/balance.py @@ -25,9 +25,9 @@ class TestBalancer(unittest.TestCase): def test_balancer_parts_simple(self): o = Balancer(self.uidx) - src = EntryPart('FOO', 'income', 'baz', 1337, debit=True) + src = EntryPart('FOO.Income/baz', 1337, debit=True) o.apply_part(src) - dst = EntryPart('FOO', 'asset', 'foo', 1337) + dst = EntryPart('FOO.Asset/foo', 1337) o.apply_part(dst) self.assertTrue(o.balanced()) @@ -35,42 +35,42 @@ class TestBalancer(unittest.TestCase): def test_balancer_parts_exchange(self): o = Balancer(self.uidx) self.uidx.set_rate('BAR', 230000000) - src = EntryPart('BAR', 'income', 'baz', 420000, debit=True) + src = EntryPart('BAR.Income/baz', 420000, debit=True) o.apply_part(src) - dst = EntryPart('FOO', 'asset', 'foo', 9660) + dst = EntryPart('FOO.Asset/foo', 9660) o.apply_part(dst) self.assertTrue(o.balanced()) def test_balance_accumulate_simple(self): o = Balancer(self.uidx) - src = EntryPart('FOO', 'asset', 'baz', -1337, debit=True) + src = EntryPart('FOO.Asset/baz', -1337, debit=True) o.apply_part(src) - dst = EntryPart('FOO', 'asset', 'foo', 1337) + dst = EntryPart('FOO.Asset/foo', 1337) o.apply_part(dst) self.assertTrue(o.balanced()) self.assertEqual(o.value(), 1337) o = Balancer(self.uidx) - src = EntryPart('FOO', 'liability', 'baz', 1337, debit=True) + src = EntryPart('FOO.Liability/baz', 1337, debit=True) o.apply_part(src) - dst = EntryPart('FOO', 'asset', 'foo', 1337) + dst = EntryPart('FOO.Asset/foo', 1337) o.apply_part(dst) self.assertTrue(o.balanced()) self.assertEqual(o.value(), 1337) o = Balancer(self.uidx) - src = EntryPart('FOO', 'liability', 'baz', 1337, debit=True) + src = EntryPart('FOO.Liability/baz', 1337, debit=True) o.apply_part(src) - dst = EntryPart('FOO', 'liability', 'foo', -1337) + dst = EntryPart('FOO.Liability/foo', -1337) o.apply_part(dst) self.assertTrue(o.balanced()) self.assertEqual(o.value(), 1337) o = Balancer(self.uidx) - src = EntryPart('FOO', 'asset', 'baz', -1337, debit=True) + src = EntryPart('FOO.Asset/baz', -1337, debit=True) o.apply_part(src) - dst = EntryPart('FOO', 'liability', 'foo', -1337) + dst = EntryPart('FOO.Liability/foo', -1337) o.apply_part(dst) self.assertTrue(o.balanced()) self.assertEqual(o.value(), 1337) @@ -78,33 +78,33 @@ class TestBalancer(unittest.TestCase): def test_flow_accumulate_simple(self): o = Balancer(self.uidx) - src = EntryPart('FOO', 'asset', 'baz', -1337, debit=True) + src = EntryPart('FOO.Asset/baz', -1337, debit=True) o.apply_part(src) - dst = EntryPart('FOO', 'expense', 'foo', 1337) + dst = EntryPart('FOO.Expense/foo', 1337) o.apply_part(dst) self.assertTrue(o.balanced()) self.assertEqual(o.value(), 1337) o = Balancer(self.uidx) - src = EntryPart('FOO', 'income', 'baz', 1337, debit=True) + src = EntryPart('FOO.Income/baz', 1337, debit=True) o.apply_part(src) - dst = EntryPart('FOO', 'asset', 'foo', 1337) + dst = EntryPart('FOO.Asset/foo', 1337) o.apply_part(dst) self.assertTrue(o.balanced()) self.assertEqual(o.value(), 1337) o = Balancer(self.uidx) - src = EntryPart('FOO', 'income', 'baz', 1337, debit=True) + src = EntryPart('FOO.Income/baz', 1337, debit=True) o.apply_part(src) - dst = EntryPart('FOO', 'expense', 'foo', 1337) + dst = EntryPart('FOO.Expense/foo', 1337) o.apply_part(dst) self.assertTrue(o.balanced()) self.assertEqual(o.value(), 1337) o = Balancer(self.uidx) - src = EntryPart('FOO', 'income', 'baz', 1337, debit=True) + src = EntryPart('FOO.Income/baz', 1337, debit=True) o.apply_part(src) - dst = EntryPart('FOO', 'liability', 'foo', -1337) + dst = EntryPart('FOO.Liability/foo', -1337) o.apply_part(dst) self.assertTrue(o.balanced()) self.assertEqual(o.value(), 1337) @@ -112,15 +112,15 @@ class TestBalancer(unittest.TestCase): def test_balance_running(self): o = Balancer(self.uidx) - src = EntryPart('FOO', 'liability', 'foo', 1337, debit=True) + src = EntryPart('FOO.Liability/foo', 1337, debit=True) o.apply_part(src) self.assertEqual(o.balance(), -1337) - dst = EntryPart('FOO', 'asset', 'bar', 42) + dst = EntryPart('FOO.Asset/bar', 42) o.apply_part(dst) self.assertEqual(o.balance(), -1295) - dst = EntryPart('FOO', 'expense', 'baz', 1295) + dst = EntryPart('FOO.Expense/baz', 1295) o.apply_part(dst) self.assertTrue(o.balanced()) self.assertEqual(o.value(), 1337) diff --git a/dummy/tests/entry.py b/dummy/tests/entry.py @@ -23,8 +23,8 @@ class TestEntry(unittest.TestCase): def test_entry_serialize(self): - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + 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) o.add_part(dst) @@ -46,8 +46,8 @@ class TestEntry(unittest.TestCase): def test_entry_sign_verify(self): - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + 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) o.add_part(dst) @@ -57,8 +57,8 @@ class TestEntry(unittest.TestCase): def test_entry_sign_verify_imported(self): - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + 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) o.add_part(dst) @@ -74,8 +74,8 @@ class TestEntry(unittest.TestCase): def test_entry_acl_verify(self): - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + 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) o.add_part(dst) @@ -93,8 +93,8 @@ class TestEntry(unittest.TestCase): def test_entry_export_import(self): - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + 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) o.add_part(dst) @@ -108,8 +108,8 @@ class TestEntry(unittest.TestCase): def test_entry_attach(self): - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + 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) o.add_part(dst) @@ -127,9 +127,9 @@ class TestEntry(unittest.TestCase): def test_entry_mux(self): - dst_one = EntryPart('FOO', 'asset', 'foo', 1337) - dst_two = EntryPart('FOO', 'asset', 'bar', 42) - src = EntryPart('FOO', 'income', 'baz', 1337+42, debit=True) + dst_one = EntryPart('FOO.Asset/foo', 1337) + 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) o.add_part(dst_one) @@ -139,19 +139,19 @@ class TestEntry(unittest.TestCase): def test_entry_balance(self): - dst_one = EntryPart('FOO', 'asset', 'foo', 1337) - dst_two = EntryPart('FOO', 'asset', 'bar', 42) - src = EntryPart('FOO', 'income', 'baz', 1337+42, debit=True) + dst_one = EntryPart('FOO.Asset/foo', 1337) + 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) o.add_part(dst_one) o.add_part(dst_two) - def test_entry_serialize_full(self): - dst_one = EntryPart('FOO', 'asset', 'foo', 1337) - dst_two = EntryPart('FOO', 'asset', 'bar', 42) - src = EntryPart('FOO', 'income', 'baz', 1337+42, debit=True) + def test_entry_full_serialize(self): + dst_one = EntryPart('FOO.Asset/foo', 1337) + 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) o.add_part(dst_one) diff --git a/dummy/tests/index.py b/dummy/tests/index.py @@ -35,24 +35,24 @@ class TestIndex(unittest.TestCase): store.start() - x = EntryPart(s, 'income', 'foo', 1337, debit=True) - y = EntryPart(s, 'asset', 'foo', 1337) + 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) v.add_part(y) v.sign(wallet) store.add_entry(v, update_ledger=True) - x = EntryPart(s, 'expense', 'bar', 42, debit=True) - y = EntryPart(s, 'liability', 'bar', 42) + 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) v.add_part(y) v.sign(wallet) store.add_entry(v, update_ledger=True) - x = EntryPart(s, 'expense', 'bar', 42, debit=True) - y = EntryPart(s, 'liability', 'bar', 42) + 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) v.add_part(y) diff --git a/dummy/tests/ledger.py b/dummy/tests/ledger.py @@ -61,16 +61,16 @@ class TestLedger(unittest.TestCase): store.start() print(o.to_string()) - x = EntryPart(s, 'income', 'foo', 1337, debit=True) - y = EntryPart(s, 'asset', 'foo', 1337) + 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) v.add_part(y) v.sign(wallet) o.add_entry(v) - x = EntryPart(s, 'expense', 'bar̈́', 42, debit=True) - y = EntryPart(s, 'liability', 'bar', 42) + 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) v.add_part(y) @@ -99,16 +99,16 @@ class TestLedger(unittest.TestCase): wallet = DemoWallet() o.set_wallet(wallet) - x = EntryPart(s, 'income', 'foo', 1337, debit=True) - y = EntryPart(s, 'asset', 'foo', 1337) + 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) v.add_part(y) v.sign(wallet) o.add_entry(v) - x = EntryPart(s, 'expense', 'bar̈́', 42, debit=True) - y = EntryPart(s, 'liability', 'bar', 42) + 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) v.add_part(y) @@ -139,16 +139,16 @@ class TestLedger(unittest.TestCase): wallet = DemoWallet() ledger.set_wallet(wallet) - x = EntryPart(s, 'income', 'foo', 1337, debit=True) - y = EntryPart(s, 'asset', 'foo', 1337) + 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) v.add_part(y) v.sign(wallet) ledger.add_entry(v) - x = EntryPart(s, 'expense', 'bar̈́', 42, debit=True) - y = EntryPart(s, 'liability', 'bar', 42) + 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) v.add_part(y) @@ -172,8 +172,8 @@ class TestLedger(unittest.TestCase): wallet = DemoWallet() ledger.set_wallet(wallet) - x = EntryPart(s, 'income', 'foo', 1337, debit=True) - y = EntryPart(s, 'asset', 'foo', 1337) + 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) v.add_part(y) @@ -181,8 +181,8 @@ class TestLedger(unittest.TestCase): ledger.add_entry(v) ledger.register_callback(cb_no, CallbackType.POST) - x = EntryPart(s, 'income', 'foo', 1337, debit=True) - y = EntryPart(s, 'asset', 'foo', 1337) + 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) v.add_part(y) diff --git a/dummy/tests/resolver.py b/dummy/tests/resolver.py @@ -61,8 +61,8 @@ class TestResolver(unittest.TestCase): uidx = UnitIndex('FOO') wallet = DemoWallet() ledger = Ledger(uidx, wallet=wallet, topic=bytes.fromhex(hash_of_foo)) - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + dst = EntryPart('FOO.Asset/foo', 1337) + src = EntryPart('FOO.Income/foo', 1337, debit=True) entry = Entry(1, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, tx_datereg=self.dtreg) entry.add_part(dst) entry.add_part(src) @@ -70,8 +70,8 @@ class TestResolver(unittest.TestCase): first_entry_key = self.backend.put_entry(entry, 'sha512') ledger.add_entry(entry) - dst = EntryPart('FOO', 'expense', 'bar̈́', 42, debit=True) - src = EntryPart('FOO', 'liability', 'bar', 42) + dst = EntryPart('FOO.Expense/bar', 42) + src = EntryPart('FOO.Liability/bar', 42, debit=True) entry = Entry(ledger.peek(), datetime.datetime.now(), parent=ledger.current()) entry.add_part(dst) entry.add_part(src) diff --git a/dummy/tests/server.py b/dummy/tests/server.py @@ -71,10 +71,10 @@ class TestSocket(unittest.TestCase): def test_socket_entry_get(self): s = 'FOO' - x = EntryPart(s, 'income', 'foo', 1337, debit=True) - y = EntryPart(s, 'asset', 'foo', 1337) + x = EntryPart(s + '.Income/foo', 1337, debit=True) + y = EntryPart(s + '.Asset/foo', 1337) entry = Entry(self.ledger.peek(), datetime.datetime.now(), parent=self.ledger.current()) - entry.add_part(x, debit=True) + entry.add_part(x) entry.add_part(y) entry.sign(self.wallet) self.store.add_entry(entry, update_ledger=True) @@ -111,10 +111,10 @@ class TestSocket(unittest.TestCase): def test_socket_entry_putget(self): s = 'FOO' - x = EntryPart(s, 'income', 'foo', 1337, debit=True) - y = EntryPart(s, 'asset', 'foo', 1337) + x = EntryPart(s + '.Income/foo', 1337, debit=True) + y = EntryPart(s + '.Asset/foo', 1337) entry = Entry(self.ledger.peek(), datetime.datetime.now(), parent=self.ledger.current()) - entry.add_part(x, debit=True) + entry.add_part(x) entry.add_part(y) s = str(uuid.uuid4()) @@ -131,7 +131,8 @@ class TestSocket(unittest.TestCase): client.close() srv.stop() th.join() - Entry.unwrap(r, acl=self.acl) + #Entry.unwrap(r, acl=self.acl) + Entry.unwrap(r) if __name__ == '__main__': diff --git a/dummy/tests/store.py b/dummy/tests/store.py @@ -35,8 +35,8 @@ class TestStore(unittest.TestCase): uidx = UnitIndex('FOO') ledger = Ledger(uidx, serial=42, base=self.parent) store = LedgerStore(self.store, ledger) - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + 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) o.add_part(dst) @@ -54,8 +54,8 @@ class TestStore(unittest.TestCase): uidx = UnitIndex('FOO') ledger = Ledger(uidx, serial=42, base=self.parent) store = LedgerStore(self.store, ledger) - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + 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) o.add_part(dst) @@ -83,8 +83,8 @@ class TestStore(unittest.TestCase): ledger = Ledger(uidx, serial=41, base=self.parent, acl=acl, wallet=wallet) store = LedgerStore(self.store, ledger) - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + 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) o.add_part(dst) @@ -95,8 +95,8 @@ class TestStore(unittest.TestCase): parent = o.sum()[0] description = 'barbarbar' dtreg = datetime.datetime.now() - dst = EntryPart('FOO', 'expense', 'bar', 4200) - src = EntryPart('FOO', 'liability', 'bar', 4200, debit=True) + 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) o.add_part(dst) @@ -132,8 +132,8 @@ class TestStore(unittest.TestCase): ledger = Ledger(uidx, base=self.parent, acl=acl, wallet=wallet) store = LedgerStore(self.store, ledger) - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + 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) o.add_part(dst) @@ -144,8 +144,8 @@ class TestStore(unittest.TestCase): parent = o.sum()[0] description = 'barbarbar' dtreg = datetime.datetime.now() - dst = EntryPart('FOO', 'expense', 'bar', 4200) - src = EntryPart('FOO', 'liability', 'bar', 4200, debit=True) + 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) o.add_part(dst) @@ -166,8 +166,8 @@ class TestStore(unittest.TestCase): uidx = UnitIndex('FOO') ledger = Ledger(uidx, serial=42, base=self.parent) store = LedgerStore(self.store, ledger) - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + 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) o.add_part(dst) @@ -200,8 +200,8 @@ class TestStore(unittest.TestCase): store = LedgerStore(self.store, ledger) wallet = DemoWallet() - dst = EntryPart('FOO', 'asset', 'foo', 1337) - src = EntryPart('FOO', 'income', 'foo', 1337, debit=True) + dst = EntryPart('FOO.Asset/foo', 1337) + src = EntryPart('FOO.Income/foo', 1337, debit=True) o = Entry(1, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), ref=str(uuid.uuid4()), description='foo', tx_datereg=self.dtreg, unitindex=uidx) o.add_part(src) o.add_part(dst) @@ -213,8 +213,8 @@ class TestStore(unittest.TestCase): o.sign(wallet) store.add_entry(o, update_ledger=True) - dst = EntryPart('FOO', 'expense', 'bar', 42) - src = EntryPart('FOO', 'asset', 'bar', -42, debit=True) + dst = EntryPart('FOO.Expense/bar', 42) + src = EntryPart('FOO.Asset/bar', -42, debit=True) now = datetime.datetime.now(datetime.UTC) o = Entry(2, now, parent=ledger.cur, ref=str(uuid.uuid4()), description='bar', unitindex=uidx) o.add_part(src) diff --git a/dummy/tests/wallet.py b/dummy/tests/wallet.py @@ -36,7 +36,7 @@ class TestWallet(unittest.TestCase): b = wallet.export() with self.assertRaises(VerifyError): - wallet = DemoWallet.from_export(b, passphrase='baz') + wallet = DemoWallet.from_export(b, passphrase='baz', opslimit=3) wallet = DemoWallet.from_export(b) wallet.verify(v, r) diff --git a/dummy/usawa/account.py b/dummy/usawa/account.py @@ -77,9 +77,23 @@ class Account: path = '{}.{}/{}'.format(self.sym, self.typ.value.lower(), path) elif display == AccountDisplay.typ: path = '{}/{}'.format(self.typ.value.lower(), path) + elif display != AccountDisplay.path: + raise ValueError('invalid display mode') return path + def get_unit(self): + return self.sym + + + def get_type(self): + return self.typ + + + def get_type_str(self): + return self.typ.value + + def __str__(self): return self.to_path() diff --git a/dummy/usawa/balance.py b/dummy/usawa/balance.py @@ -15,8 +15,8 @@ class Balancer: def apply_part(self, part): - amount = self.uidx.val(part.unit, part.amount) - fn = getattr(self, '_handle_' + part.typ.lower()) + amount = self.uidx.val(part.get_unit(), part.amount) + fn = getattr(self, '_handle_' + part.get_type()) fn(amount[0], part.isdebit) v = abs(amount[0]) logg.debug('amount {} v {}'.format(amount, v)) @@ -26,7 +26,7 @@ class Balancer: self.zsrc += v else: self.zdst += v - logg.debug('after {} {} => {} = {}'.format(part.unit, part.amount, amount[0], self.r)) + logg.debug('after {} {} => {} = {}'.format(part.get_unit(), part.amount, amount[0], self.r)) def balanced(self): diff --git a/dummy/usawa/crypto.py b/dummy/usawa/crypto.py @@ -59,9 +59,9 @@ def key_from_export(v, passphrase="", did=None, opslimit=0, memlimit=0): salt = v[: argon2i.SALTBYTES] ciphertext = v[argon2i.SALTBYTES:] if not opslimit: - opslimit = nacl.pwhash.OPSLIMIT_INTERACTIVE + opslimit = nacl.pwhash.OPSLIMIT_MODERATE if not memlimit: - memlimit = nacl.pwhash.MEMLIMIT_INTERACTIVE + memlimit = nacl.pwhash.MEMLIMIT_MODERATE logg.debug('pwhash ops {} mem {} salt {} pw {}'.format(opslimit, memlimit, salt, passphrase.hex())) @@ -185,10 +185,10 @@ class Wallet: logg.warning("exporting key with no passphrase") salt = os.urandom(argon2i.SALTBYTES) - if not opslimit: - opslimit = nacl.pwhash.OPSLIMIT_INTERACTIVE - if not memlimit: - memlimit = nacl.pwhash.MEMLIMIT_INTERACTIVE + if opslimit == 0: + opslimit = nacl.pwhash.OPSLIMIT_MODERATE + if memlimit == 0: + memlimit = nacl.pwhash.MEMLIMIT_MODERATE logg.debug('pwhash ops {} mem {} salt {} pw {}'.format(opslimit, memlimit, salt, passphrase.hex())) key = argon2i.kdf(nacl.secret.SecretBox.KEY_SIZE, passphrase, salt, opslimit=opslimit, memlimit=memlimit) box = nacl.secret.SecretBox(key) diff --git a/dummy/usawa/entry.py b/dummy/usawa/entry.py @@ -14,6 +14,7 @@ from .error import ACLError, VerifyError from .xml import nsmap from .asset import Asset from .tag import Tags +from .account import Account, AccountDisplay, AccountType logg = logging.getLogger('usawa.entry') @@ -43,18 +44,26 @@ class EntryPart: :type debit: boolean :todo: Make typ enum """ - def __init__(self, unit, typ, account, amount, debit=False): + def __init__(self, account, amount, debit=False): if isinstance(amount, float): raise ValueError('entrydata must pass amount in int including full precision') - self.unit = unit - self.typ = typ + if isinstance(account, str): + account = Account.from_path(account) + elif not isinstance(account, Account): + raise TypeError('account must be account type') self.account = account self.amount = amount self.isdebit = debit - def account_path(self): - return self.unit + '.' + self.typ + '/' + self.account + def account_path(self, with_unit=True): + #return self.unit + '.' + self.typ + '/' + self.account + mode = None + if with_unit: + mode = AccountDisplay.full + else: + mode = AccountDisplay.typ + return self.account.to_path(display=mode) """Create object from an entry part defined as an XML tree. @@ -73,8 +82,9 @@ class EntryPart: typ = tree.get('type') unit = tree.find('unit', namespaces=nsmap()).text amount = int(tree.find('amount', namespaces=nsmap()).text) - account = tree.find('account', namespaces=nsmap()).text - return EntryPart(unit, typ, account, amount, debit=debit) + account_path = tree.find('account', namespaces=nsmap()).text + account = Account.from_path(account_path, sym=unit, typ=getattr(AccountType, typ)) + return EntryPart(account, amount, debit=debit) """Generate XML element from state of entry part. @@ -90,14 +100,15 @@ class EntryPart: if self.isdebit: tag = 'debit' - tree = lxml.etree.Element(tag, type=self.typ.lower(), nsmap=nsmap()) + typ = self.account.get_type_str() + tree = lxml.etree.Element(tag, type=typ.lower(), nsmap=nsmap()) o = lxml.etree.Element('unit') - o.text = self.unit + o.text = self.account.get_unit() tree.append(o) o = lxml.etree.Element('account') - o.text = self.account + o.text = self.account.to_path(display=AccountDisplay.path) tree.append(o) o = lxml.etree.Element('amount') @@ -114,9 +125,9 @@ class EntryPart: """ def to_list(self): d = [ - self.unit, - self.typ, - self.account, + self.account.get_unit(), + self.account.get_type_str(), + self.account_path(with_unit=False), self.amount, ] return d @@ -145,17 +156,27 @@ class EntryPart: v = rencode.loads(data) unit = v[0].decode('utf-8') typ = v[1].decode('utf-8') - account = v[2].decode('utf-8') + account_path = v[2].decode('utf-8') + account = Account.from_path(account_path, sym=unit) amount = v[3] - o = EntryPart(unit, typ, account, amount, debit=debit) + o = EntryPart(account, amount, debit=debit) return o + def get_unit(self): + return self.account.get_unit() + + + def get_type(self): + return self.account.get_type_str().lower() + + def __str__(self): pfx = 'credit' if self.isdebit: pfx = 'debit' - return '[{}] {}:{} {}'.format(pfx, self.typ, self.account, self.amount) + typ = self.account.get_type() + return '[{}] {}:{} {}'.format(pfx, typ, self.account_path(with_unit=False), self.amount) class Entry(UsawaElement): @@ -260,7 +281,7 @@ class Entry(UsawaElement): """ def add_part(self, part): if self.uidx != None: - self.uidx.sym(part.unit) + self.uidx.sym(part.get_unit()) if part.isdebit: self.debit.append(part) else: diff --git a/dummy/usawa/ledger.py b/dummy/usawa/ledger.py @@ -536,12 +536,16 @@ class Ledger(UsawaElement): """ def apply_entryparts(self, entry): for v in entry.debit: + unit = v.get_unit() + typ = v.get_type() amount = v.amount - self.running[v.unit].apply(v.typ, amount) + self.running[unit].apply(typ, amount) for v in entry.credit: + unit = v.get_unit() + typ = v.get_type() amount = v.amount - self.running[v.unit].apply(v.typ, amount) + self.running[unit].apply(typ, amount) logg.debug('applied entry {} src {} dst {}'.format(entry.serial, entry.debit, entry.credit))