usawa

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

commit f4084d5aba741fd2e8ca98f77ebf0fcb6da4aaa2
parent cd9355a09d69b47a8ee57d7d0a3650a54aaab50c
Author: lash <dev@holbrook.no>
Date:   Thu, 23 Apr 2026 08:21:22 -0600

Allow empty extref, include extref in xml

Diffstat:
Mdummy/usawa/balance.py | 2+-
Mdummy/usawa/cli/entry.py | 9+++++----
Mdummy/usawa/context.py | 1+
Mdummy/usawa/entry.py | 27++++++++++++++++++++-------
Mdummy/usawa/ledger.py | 1+
Mdummy/usawa/runnable/asset.py | 2+-
Mdummy/usawa/store.py | 4++--
7 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/dummy/usawa/balance.py b/dummy/usawa/balance.py @@ -16,7 +16,7 @@ class Balancer: def apply_part(self, part): amount = self.uidx.val(part.unit, part.amount) - fn = getattr(self, '_handle_' + part.typ) + fn = getattr(self, '_handle_' + part.typ.lower()) fn(amount[0], part.isdebit) v = abs(amount[0]) logg.debug('amount {} v {}'.format(amount, v)) diff --git a/dummy/usawa/cli/entry.py b/dummy/usawa/cli/entry.py @@ -97,13 +97,14 @@ def parse_txdate(ctx, v): return datetime.date.fromisoformat(v) -def input_or_default(prompt, default=None, postfix=': ', validate_fn=None): +def input_or_default(prompt, default=None, allow_empty=False, postfix=': ', validate_fn=None): if default != None: postfix = ' [{}]'.format(default) + postfix v = input(prompt + postfix) if len(v) == 0: - if default == None: - raise ValueError('empty value and no default') + if not allow_empty: + if default == None: + raise ValueError('empty value and no default') v = default if validate_fn != None: validate_fn(v) @@ -399,7 +400,7 @@ class EntrySession: self.entry.description = v v = input_or_default('Internal ref', self.entry.ref) self.entry.ref = v - v = input_or_default('External ref', self.entry.ref) + v = input_or_default('External ref', allow_empty=True) self.entry.extref = v v = input_or_default('Transaction date(time)', self.entry.dt) if isinstance(v, str): diff --git a/dummy/usawa/context.py b/dummy/usawa/context.py @@ -76,6 +76,7 @@ class UsawaContext: self.load_wallet() if self.replay: + #self.store.load(unitindex=self.uidx) self.store.load() self.ledger.truncate() logg.debug('replayed ledger {}'.format(self.ledger.to_string())) diff --git a/dummy/usawa/entry.py b/dummy/usawa/entry.py @@ -426,11 +426,16 @@ class Entry(UsawaElement): #except TypeError: # pass tags = [] - for s in v[10]: - tags.append(s.decode('utf-8')) +# for s in v[10]: +# try: +# tags.append(s.decode('utf-8')) +# except AttributeError as e: +# logg.debug('fail tag decode, use raw: {}'.format(s.hex())) +# tags.append(s) o = Entry(serial, date, ref=ref, description=description, parent=parent, tx_datereg=date_reg, tags=tags, unitindex=unitindex) super(Entry, o).deserialize(v[0]) - o.balancer = Balancer(unitindex) + if unitindex != None: + o.balancer = Balancer(unitindex) for v in src_data: src = EntryPart.deserialize(v, debit=True) o.add_part(src) @@ -608,10 +613,11 @@ class Entry(UsawaElement): o = lxml.etree.Element('ref') o.text = self.ref data.append(o) - - o = lxml.etree.Element('extref') - o.text = self.ref - data.append(o) + + if self.extref: + o = lxml.etree.Element('extref') + o.text = self.extref + data.append(o) o = lxml.etree.Element('serial') o.text = str(self.serial) @@ -698,6 +704,13 @@ class Entry(UsawaElement): return b.encode('utf-8') + def get_canon(self): + b = self.canon() + h = hashlib.sha512() + h.update(b) + z = h.digest() + return(z.hex(), b,) + def tag(self, tag): if self.tags == None: diff --git a/dummy/usawa/ledger.py b/dummy/usawa/ledger.py @@ -510,6 +510,7 @@ class Ledger(UsawaElement): #oldsum = self.cur #self.cur = entry.sum()[0] (k, v) = entry.get_lookup(self.lookup_algo) + #(k, v) = entry.get_canon() #self.lookup_algo) logg.debug('addentr entry for algo {}: {} {}'.format(self.lookup_algo, k, v)) #entry.parent = oldsum # TODO: parent being changed after sealed and signed, why? diff --git a/dummy/usawa/runnable/asset.py b/dummy/usawa/runnable/asset.py @@ -53,7 +53,7 @@ def main(): try: ctx.store.add_asset(asset, overwrite=args.force) except FileExistsError: - logg.error('record already exists for {}'.format(digest)) + logg.error('record already exists for {}'.format(digest.hex())) sys.exit(1) if w != None: k = digest diff --git a/dummy/usawa/store.py b/dummy/usawa/store.py @@ -366,7 +366,7 @@ class LedgerStore(EntryStore, AssetStore, KeyStore): :raises FileNotFoundError: If an entry cannot be found. """ - def load(self, acl=None, until=0): + def load(self, acl=None, until=0, unitindex=None): logg.debug('load ledger from store {} until {}'.format(self.ledger, until)) v = 0 while True: @@ -376,7 +376,7 @@ class LedgerStore(EntryStore, AssetStore, KeyStore): if until == v: break v = self.ledger.peek() - o = self.get_entry(v, acl=acl) + o = self.get_entry(v, acl=acl, unitindex=unitindex) self.ledger.next_serial() except FileNotFoundError as e: logg.debug('entry serial {} not found, terminating ({})'.format(v, e))