home · contact · privacy
Interpret ;def comments for account descriptions.
authorChristian Heller <c.heller@plomlompom.de>
Sun, 9 Feb 2025 06:08:18 +0000 (07:08 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Sun, 9 Feb 2025 06:08:18 +0000 (07:08 +0100)
src/run.py
src/templates/_macros.tmpl
src/templates/balance.tmpl

index 6f09306a0892cd54b0a3b01bf5f538277ef00352..b3e2c5c4436835576e8b1e02e70e735b94a172ec 100755 (executable)
@@ -22,6 +22,7 @@ SERVER_PORT = 8084
 SERVER_HOST = '127.0.0.1'
 PATH_TEMPLATES = Path('templates')
 
+PREFIX_DEF = 'def '
 PREFIX_LEDGER = 'ledger_'
 PREFIX_EDIT = 'edit_'
 PREFIX_FILE = 'file_'
@@ -107,9 +108,11 @@ class Wealth():
 class Account:
     """Combine name, position in tree of own, and wealth of self + children."""
 
-    def __init__(self, parent: Optional['Account'], basename: str) -> None:
+    def __init__(self, parent: Optional['Account'], basename: str, desc: str
+                 ) -> None:
         self.local_wealth = Wealth()
         self.basename = basename
+        self.desc = desc
         self.children: list[Self] = []
         self.parent = parent
         if self.parent:
@@ -124,30 +127,6 @@ class Account:
             total += child.wealth
         return total
 
-    @staticmethod
-    def by_paths(acc_names: list[str]) -> dict[str, 'Account']:
-        """From bookings generate dict of all refered Accounts by paths."""
-        paths_to_accs: dict[str, Account] = {}
-        for full_name in acc_names:
-            path = ''
-            for step_name in full_name.split(':'):
-                parent_name = path[:]
-                path = ':'.join([path, step_name]) if path else step_name
-                if path not in paths_to_accs:
-                    paths_to_accs[path] = Account(
-                        paths_to_accs[parent_name] if parent_name else None,
-                        step_name)
-        return paths_to_accs
-
-    @staticmethod
-    def names_over_bookings(bookings: list['Booking']) -> list[str]:
-        """Sorted list of all account names refered to in bookings."""
-        names = set()
-        for booking in bookings:
-            for account_name in booking.account_changes:
-                names.add(account_name)
-        return sorted(list(names))
-
 
 class DatLine(Dictable):
     """Line of .dat file parsed into comments and machine-readable data."""
@@ -456,7 +435,7 @@ class Handler(PlomHttpHandler):
         to_balance = (self.server.bookings[:id_ + 1] if id_ >= 0
                       else self.server.bookings)
         valid = 0 == len([b for b in to_balance if b.is_questionable])
-        acc_dict = Account.by_paths(Account.names_over_bookings(to_balance))
+        acc_dict = self.server.empty_accounts_by_path(id_)
         for booking in to_balance:
             booking.apply_to_account_dict(acc_dict)
         ctx['roots'] = [ac for ac in acc_dict.values() if not ac.parent]
@@ -468,10 +447,9 @@ class Handler(PlomHttpHandler):
         """Display edit form for individual Booking."""
         id_ = int(self.path_toks[2])
         booking = self.server.bookings[id_]
-        acc_names = Account.names_over_bookings(self.server.bookings)
         to_balance = self.server.bookings[:id_ + 1]
-        accounts_after = Account.by_paths(acc_names)
-        accounts_before = Account.by_paths(acc_names)
+        accounts_after = self.server.empty_accounts_by_path()
+        accounts_before = self.server.empty_accounts_by_path()
         for b in to_balance:
             if b != booking:
                 b.apply_to_account_dict(accounts_before)
@@ -509,7 +487,7 @@ class Handler(PlomHttpHandler):
         ctx['valid'] = 0 == len([b for b in to_balance if b.is_questionable])
         ctx['roots'] = observed_tree
         if not raw:
-            ctx['all_accounts'] = acc_names
+            ctx['all_accounts'] = accounts_after.keys()
         self._send_rendered(EDIT_RAW if raw else EDIT_STRUCT, ctx)
 
     def get_ledger(self, ctx: dict[str, Any], raw: bool) -> None:
@@ -559,6 +537,16 @@ class Server(PlomHttpServer):
                     self.bookings += [booking]
                     booked_lines.clear()
                 gap_lines += [dat_line]
+        self.paths_to_descs = {}
+        for comment in [dl.comment for dl in self.dat_lines if dl.comment]:
+            if comment.startswith(PREFIX_DEF):
+                parts = [part.strip() for part
+                         in comment[len(PREFIX_DEF):].split(';')]
+                first_part_parts = parts[0].split(maxsplit=1)
+                account_name = first_part_parts[0]
+                desc = first_part_parts[1] if len(first_part_parts) > 1 else ''
+                if desc:
+                    self.paths_to_descs[account_name] = desc
         for booking in self.bookings:
             booking.recalc_prev_next(self.bookings)
         if booking:
@@ -573,6 +561,28 @@ class Server(PlomHttpServer):
     def _hash_dat_lines(self) -> int:
         return hash(tuple(dl.raw for dl in self.dat_lines))
 
+    def empty_accounts_by_path(self,
+                               up_incl: int = -1
+                               ) -> dict[str, 'Account']:
+        """Dict of Accounts refered in .bookings till up_incl by paths."""
+        booked_names = set()
+        for booking in (self.bookings[:up_incl + 1] if up_incl >= 0
+                        else self.bookings):
+            for account_name in booking.account_changes:
+                booked_names.add(account_name)
+        paths_to_accs: dict[str, Account] = {}
+        for full_name in booked_names:
+            path = ''
+            for step_name in full_name.split(':'):
+                parent_name = path[:]
+                path = ':'.join([path, step_name]) if path else step_name
+                if path not in paths_to_accs:
+                    paths_to_accs[path] = Account(
+                        paths_to_accs[parent_name] if parent_name else None,
+                        step_name,
+                        self.paths_to_descs.get(path, ''))
+        return paths_to_accs
+
     @property
     def tainted(self) -> bool:
         """If .dat_lines different to those of last .load()."""
index aef28ae1f61365a2bb73003a6d89e91ee1119930..c93ceb952b27caf335f0c522cea3926e9e57e373 100644 (file)
@@ -145,6 +145,7 @@ function taint() {
 {% endfor %}
 </table>
 </td>
+<td></td>
 </tr>
 {% for child in account.children %}
   {{ booking_balance_account_with_children(child) }}
@@ -155,7 +156,7 @@ function taint() {
 {% macro booking_balance(valid, roots) %}
 <hr />
 <table{% if not valid %} class="warning"{% endif %}>
-<tr class="alternating"><th>account</th><th>before</th><th>diff</th><th>after</th></tr>
+<tr class="alternating"><th>account</th><th>before</th><th>diff</th><th>after</th><th>description</th></tr>
 {% for root in roots %}
 {{ booking_balance_account_with_children(root) }}
 {% endfor %}
index 6bbb6484d58015a0121429e5b88fdac5257646f3..59ff4c6f3d885c89942ac0e8622f5f69cf34ac3d 100644 (file)
@@ -32,6 +32,7 @@
   {% endif %}
   </td>
   <td class="acc"><span class="indent">{% for i in range(indent) %}&nbsp;{% endfor %}</span>{% if account.parent %}:{% endif %}{{account.basename}}{% if account.children %}:{% endif %}</td>
+  <td>{{account.desc}}</td>
   </tr>
   {% for child in account.children %}
     {{ account_with_children(child, indent=indent+1) }}