From: Christian Heller Date: Wed, 22 Jan 2025 13:55:20 +0000 (+0100) Subject: Add balance view. X-Git-Url: https://plomlompom.com/repos/%7B%7B%20web_path%20%7D%7D/static/%7B%7Bdb.prefix%7D%7D/%7B%7Bprefix%7D%7D/balance2?a=commitdiff_plain;h=f7a484f9127edd297a4535dde570d869fb454993;p=plomledger Add balance view. --- diff --git a/ledger.py b/ledger.py index 0687377..c7f3116 100755 --- a/ledger.py +++ b/ledger.py @@ -48,6 +48,27 @@ class Wealth: return sink +class Account: + """Combine name, position in tree of own, and wealth of self + children.""" + + def __init__(self, parent: Optional['Account'], basename: str) -> None: + self.local_wealth = Wealth() + self.basename = basename + self.children: list[Account] = [] + self.parent = parent + if self.parent: + self.parent.children += [self] + + @property + def wealth(self) -> Wealth: + """Total of .local_wealth with that of .children.""" + total = Wealth() + total += self.local_wealth + for child in self.children: + total += child.wealth + return total + + class DatLine: """Line of .dat file parsed into comments and machine-readable data.""" @@ -164,22 +185,22 @@ class Booking: dat_line.booking_line = TransferLine(self, dat_line.code) self._transfer_lines += [dat_line.booking_line] changes = Wealth() + sink_account = None self.account_changes: dict[str, Wealth] = {} - self.sink_account = None for transfer_line in [tl for tl in self._transfer_lines if not tl.errors]: if transfer_line.account not in self.account_changes: self.account_changes[transfer_line.account] = Wealth() if transfer_line.amount is None: - if self.sink_account: + if sink_account: transfer_line.errors += ['too many sinks'] - self.sink_account = transfer_line.account + sink_account = transfer_line.account continue change = Wealth({transfer_line.currency: transfer_line.amount}) self.account_changes[transfer_line.account] += change changes += change - if self.sink_account: - self.account_changes[self.sink_account] += changes.as_sink + if sink_account: + self.account_changes[sink_account] += changes.as_sink elif not changes.sink_empty: self._transfer_lines[-1].errors += ['needed sink missing'] self.id_ = id_ @@ -204,7 +225,10 @@ class Handler(PlomHttpHandler): def do_GET(self) -> None: # pylint: disable=invalid-name,missing-function-docstring - if self.pagename == 'booking': + if self.pagename == 'balance': + self.send_rendered(Path('balance.tmpl'), + {'roots': self.server.balance_roots}) + elif self.pagename == 'booking': self.send_rendered( Path('booking.tmpl'), {'dat_lines': @@ -245,6 +269,31 @@ class Server(PlomHttpServer): """Return only those .data_lines with .code or .comment.""" return [dl for dl in self.dat_lines if not dl.is_empty] + @property + def balance_roots(self) -> list[Account]: + """Return tree of calculated Accounts over all .bookings.""" + account_names = set() + for booking in self.bookings: + for account_name in booking.account_changes: + account_names.add(account_name) + full_names_to_accounts: dict[str, Account] = {} + for full_name in sorted(list(account_names)): + step_names = full_name.split(':') + path = '' + for step_name in step_names: + parent_name = path[:] + path = ':'.join([path, step_name]) if path else step_name + if path not in full_names_to_accounts: + full_names_to_accounts[path] = Account( + full_names_to_accounts[parent_name] if parent_name + else None, + step_name) + for booking in self.bookings: + for account_name in booking.account_changes: + full_names_to_accounts[account_name].local_wealth +=\ + booking.account_changes[account_name] + return [ac for ac in full_names_to_accounts.values() if not ac.parent] + if __name__ == "__main__": if not LEDGER_DAT: diff --git a/templates/_base.tmpl b/templates/_base.tmpl index 74ed6b1..75f33af 100644 --- a/templates/_base.tmpl +++ b/templates/_base.tmpl @@ -12,7 +12,7 @@ td.invalid, tr.warning td.invalid { background-color: #ff0000; } -home · raw +home · raw · balance
{% block content %}{% endblock %} diff --git a/templates/_macros.tmpl b/templates/_macros.tmpl index 2a349b5..106e443 100644 --- a/templates/_macros.tmpl +++ b/templates/_macros.tmpl @@ -1,6 +1,4 @@ {% macro css_value_line() %} -tr.warning td { background-color: #ff8888; } -td.invalid, tr.warning td.invalid { background-color: #ff0000; } td.amt { text-align: right } td.amt, td.curr { font-family: monospace; font-size: 1.3em; } td.curr { text-align: center; } diff --git a/templates/balance.tmpl b/templates/balance.tmpl new file mode 100644 index 0000000..da13b34 --- /dev/null +++ b/templates/balance.tmpl @@ -0,0 +1,25 @@ +{% extends '_base.tmpl' %} + + +{% macro account_with_children(account, indent) %} + +{% for _ in range(indent) %}     {% endfor %}{{account.basename}} + +{% for curr, amt in account.wealth.moneys.items() %} +{{amt}}{{curr}} +{% endfor %} + + +{% for child in account.children %} +{{ account_with_children(child, indent=indent+1) }} +{% endfor %} +{% endmacro %} + + +{% block content %} + +{% for root in roots %} +{{ account_with_children(root, indent=0) }} +{% endfor %} +
+{% endblock %}