commit 463f1768a7dea1904b8468989761f443eda3dafb
parent cb2707e8ac8c4777381b30e852abf63b35f88f29
Author: lash <dev@holbrook.no>
Date: Wed, 25 Mar 2026 06:29:16 -0600
Reimplement balancer
Diffstat:
4 files changed, 58 insertions(+), 33 deletions(-)
diff --git a/dummy/tests/balance.py b/dummy/tests/balance.py
@@ -4,7 +4,7 @@ import datetime
import os
from usawa import EntryPart, Entry, UnitIndex
-from usawa.balance import Translator
+from usawa.balance import Balancer
logging.basicConfig(level=logging.DEBUG)
logg = logging.getLogger()
@@ -22,29 +22,23 @@ class TestBalancer(unittest.TestCase):
self.dtreg = datetime.datetime.now()
- def test_translate_ex(self):
- o = Translator(self.uidx, 'FOO')
- o.set_ex('BAR', 230000)
- r = o.val('BAR', 42333)
- print(r)
-
# 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, entry=entry, base='FOO')
+# o = Balancer(self.uidx)
# self.assertTrue(o.balanced())
#
-#
-# def test_balancer_parts_simple(self):
-# o = Balancer(self.uidx, base='FOO')
-# 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())
+
+ def test_balancer_parts_simple(self):
+ 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())
diff --git a/dummy/tests/unit.py b/dummy/tests/unit.py
@@ -54,12 +54,11 @@ class TestUnit(unittest.TestCase):
#r = self.uidx_default.val('BAR', 42333)
with self.assertRaises(ValueError):
self.uidx_default.set_rate('FOO', 230000)
- #self.uidx_default.set_rate('BAR', 230000)
r = self.uidx_default.val('BAR', 4233300)
self.assertEqual(r[0], 9736)
self.assertEqual(r[1], 590000)
- r = self.uidx_default.set_rate('BAR', 1000000)
+ self.uidx_default.set_rate('BAR', 1000000)
r = self.uidx_default.val('BAR', 4233300)
self.assertEqual(r[0], 42333)
self.assertEqual(r[1], 0)
diff --git a/dummy/usawa/balance.py b/dummy/usawa/balance.py
@@ -5,20 +5,50 @@ logg = logging.getLogger('usawa.balancer')
class Balancer:
- def __init__(self, translator):
- self.tr = translator
+ def __init__(self, unitindex):
+ self.uidx = unitindex
self.r = 0
+ self.m = 0
def apply_part(self, part):
- precision = self.uidx.get(part.unit)
- mod = 10 ** (self.max_precision - precision)
- amount = part.amount * mod
- ex = self.ex[part.unit] / 1000000000
- amount *= ex
+ amount = self.uidx.val(part.unit, part.amount)
fn = getattr(self, 'handle_' + part.typ)
- fn(amount, part.isdebit)
- logg.debug('after {} {} (ex {}) = {}'.format(part.unit, amount, ex, self.r))
+ fn(amount[0], part.isdebit)
+ self.m += amount[1]
+ logg.debug('after {} {} => {} = {}'.format(part.unit, part.amount, amount[0], self.r))
+
+
+ def balanced(self):
+ return self.r == 0
+
+
+ def handle_income(self, amount, issrc=False):
+ if issrc:
+ self.r += amount
+ else:
+ self.r -= amount
+
+
+ def handle_expense(self, amount, issrc=False):
+ if issrc:
+ self.r -= amount
+ else:
+ self.r += amount
+
+
+ def handle_asset(self, amount, issrc=False):
+ if issrc:
+ self.r += amount
+ else:
+ self.r -= amount
+
+
+ def handle_liability(self, amount, issrc=False):
+ if issrc:
+ self.r -= amount
+ else:
+ self.r += amount
#class Balancer:
diff --git a/dummy/usawa/unit.py b/dummy/usawa/unit.py
@@ -31,19 +31,20 @@ class UnitIndex:
def __init__(self, base=None, precision=None):
self.detail = {}
self.rate = {}
- self.base = base
+ self.base = None
if base != None:
if precision == None:
precision = UnitIndex.default_precision
self.detail = {base: precision}
- self.exchange = {base: UnitIndex.default_exchange}
+ self.set_rate(base, UnitIndex.default_exchange)
+ self.base = base
def clone(self):
o = UnitIndex()
o.detail = self.detail
o.base = self.base
- o.exchange = copy.copy(self.exchange)
+ o.rate = copy.copy(self.rate)
return o
@@ -51,12 +52,13 @@ class UnitIndex:
if unit == self.base:
raise ValueError('cannot adjust rate for base')
if not isinstance(rate, float):
- rate /= 1000000
+ rate /= 1000000000
self.rate[unit] = rate
def val(self, unit, amount):
r = self.rate[unit] * amount
+ logg.debug('rate {} {} {}'.format(r, amount, self.rate[unit]))
# TODO: embed in rate
base_precision = self.detail[self.base]
adj = base_precision - self.detail[unit]
@@ -67,7 +69,7 @@ class UnitIndex:
r *= (10 ** adj)
v = int(r)
- m = int((r - v) * 1000000)
+ m = int((r - v) * 1000000000)
logg.debug('val {} -> {},{} adj {}'.format(r, v, m, adj))
return (v, m,)
@@ -83,7 +85,7 @@ class UnitIndex:
:param ex: The exchange rate of the unit, relative to the base unit. Default is 1000000000 (1.0).
:type ex: int or float
"""
- def add(self, sym, precision=2, rate=1000000):
+ def add(self, sym, precision=2, rate=1000000000):
self.detail[sym] = precision
self.set_rate(sym, rate)