commit 9596246ed4ae2428e404f21b132c681d839cc7a6
parent 895a86e94f07ceffb2cd63eb1a67aaf659c59680
Author: lash <dev@holbrook.no>
Date: Sat, 4 Apr 2026 18:02:25 -0600
Implement accumulator in balancer, correct adjustments
Diffstat:
2 files changed, 112 insertions(+), 35 deletions(-)
diff --git a/dummy/tests/balance.py b/dummy/tests/balance.py
@@ -13,6 +13,7 @@ testdir = os.path.realpath(os.path.dirname(__file__))
class TestBalancer(unittest.TestCase):
+
def setUp(self):
self.parent = bytes.fromhex('0cf9180a764aba863a67b6d72f0918bc131c6772642cb2dce5a34f0a702f9470ddc2bf125c12198b1995c233c34b4afd346c54a2334c350a948a51b6e8b4e6b6')
self.ref = '1bda7dfa-b8fd-400d-8b42-1d2861ad7f70'
@@ -22,16 +23,6 @@ class TestBalancer(unittest.TestCase):
self.dtreg = datetime.datetime.now()
-# def test_balancer_process(self):
-# dst = EntryPart('FOO', 'asset', 'foo', 1337)
-# src = EntryPart('FOO', 'income', 'baz', 1337, debit=True)
-# entry = Entry(42, datetime.datetime.strptime('2025-11-11', '%Y-%m-%d'), parent=self.parent, ref=self.ref, description=self.description, tx_datereg=self.dtreg)
-# entry.add_part(src)
-# entry.add_part(dst)
-# o = Balancer(self.uidx)
-# self.assertTrue(o.balanced())
-#
-
def test_balancer_parts_simple(self):
o = Balancer(self.uidx)
src = EntryPart('FOO', 'income', 'baz', 1337, debit=True)
@@ -41,7 +32,7 @@ class TestBalancer(unittest.TestCase):
self.assertTrue(o.balanced())
- def test_balancer_parts_simple(self):
+ def test_balancer_parts_exchange(self):
o = Balancer(self.uidx)
self.uidx.set_rate('BAR', 230000000)
src = EntryPart('BAR', 'income', 'baz', 420000, debit=True)
@@ -51,14 +42,89 @@ class TestBalancer(unittest.TestCase):
self.assertTrue(o.balanced())
- def test_balancer_parts_simple(self):
+ def test_balance_accumulate_simple(self):
o = Balancer(self.uidx)
- self.uidx.set_rate('BAR', 230000000)
- src = EntryPart('BAR', 'income', 'baz', 420000, debit=True)
+ src = EntryPart('FOO', 'asset', 'baz', -1337, debit=True)
o.apply_part(src)
- dst = EntryPart('FOO', 'asset', 'foo', 9660)
+ 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)
+ o.apply_part(src)
+ 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)
+ o.apply_part(src)
+ 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)
+ o.apply_part(src)
+ dst = EntryPart('FOO', 'liability', 'foo', -1337)
+ o.apply_part(dst)
+ self.assertTrue(o.balanced())
+ self.assertEqual(o.value(), 1337)
+
+
+ def test_flow_accumulate_simple(self):
+ o = Balancer(self.uidx)
+ src = EntryPart('FOO', 'asset', 'baz', -1337, debit=True)
+ o.apply_part(src)
+ 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)
+ o.apply_part(src)
+ 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)
+ o.apply_part(src)
+ 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)
+ o.apply_part(src)
+ dst = EntryPart('FOO', 'liability', 'foo', -1337)
+ o.apply_part(dst)
+ self.assertTrue(o.balanced())
+ self.assertEqual(o.value(), 1337)
+
+
+ def test_balance_running(self):
+ o = Balancer(self.uidx)
+ src = EntryPart('FOO', 'liability', 'foo', 1337, debit=True)
+ o.apply_part(src)
+ self.assertEqual(o.balance(), -1337)
+
+ dst = EntryPart('FOO', 'asset', 'bar', 42)
+ o.apply_part(dst)
+ self.assertEqual(o.balance(), -1295)
+
+ dst = EntryPart('FOO', 'expense', 'baz', 1295)
+ o.apply_part(dst)
+ self.assertTrue(o.balanced())
+ self.assertEqual(o.value(), 1337)
+
if __name__ == '__main__':
unittest.main()
diff --git a/dummy/usawa/balance.py b/dummy/usawa/balance.py
@@ -9,13 +9,14 @@ class Balancer:
self.uidx = unitindex
self.r = 0
self.m = 0
+ self.z = 0
def apply_part(self, part):
amount = self.uidx.val(part.unit, part.amount)
- fn = getattr(self, 'handle_' + part.typ)
- fn(amount[0], part.isdebit)
- self.m += amount[1]
+ fn = getattr(self, '_handle_' + part.typ)
+ v = fn(amount[0], part.isdebit)
+ self.z += abs(amount[0])
logg.debug('after {} {} => {} = {}'.format(part.unit, part.amount, amount[0], self.r))
@@ -23,29 +24,39 @@ class Balancer:
return self.r == 0
- def handle_income(self, amount, issrc=False):
- if issrc:
- self.r += amount
- else:
- self.r -= amount
+ def balance(self):
+ return self.r
+
+
+ def value(self):
+ return int(self.z / 2)
+
+
+ def _handle_income(self, amount, issrc=False):
+ if not issrc:
+ raise TypeError('income can only be src')
+ self.r -= amount
+ return amount
- def handle_expense(self, amount, issrc=False):
+ def _handle_expense(self, amount, issrc=False):
if issrc:
- self.r -= amount
- else:
- self.r += amount
+ raise TypeError('expense can only be dst')
+ self.r += amount
+ return amount
- def handle_asset(self, amount, issrc=False):
+ def _handle_asset(self, amount, issrc=False):
if issrc:
- self.r += amount
- else:
- self.r -= amount
+ if amount >= 0:
+ raise ValueError('positive asset can only be dst')
+ self.r += amount
+ return amount
- def handle_liability(self, amount, issrc=False):
+ def _handle_liability(self, amount, issrc=False):
if issrc:
- self.r -= amount
- else:
- self.r += amount
+ if amount < 0:
+ raise ValueError('negative liability can only be dst')
+ self.r -= amount
+ return amount