home · contact · privacy
Refactor do_GET routes. master
authorChristian Heller <c.heller@plomlompom.de>
Sun, 2 Feb 2025 21:54:58 +0000 (22:54 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Sun, 2 Feb 2025 21:54:58 +0000 (22:54 +0100)
ledger.py

index fb2abcfa2ccd1701d99da09933bacb57cd5343b6..f994721f1ce346a2bacfab20f9f852a6e0da3cec 100755 (executable)
--- a/ledger.py
+++ b/ledger.py
@@ -6,7 +6,7 @@ from decimal import Decimal, InvalidOperation as DecimalInvalidOperation
 from os import environ
 from pathlib import Path
 from sys import exit as sys_exit
-from typing import Optional, Self
+from typing import Any, Optional, Self
 from plomlib.web import PlomHttpHandler, PlomHttpServer, PlomQueryMap
 
 
@@ -15,6 +15,15 @@ SERVER_PORT = 8084
 SERVER_HOST = '127.0.0.1'
 PATH_TEMPLATES = Path('templates')
 
+PREFIX_LEDGER = 'ledger_'
+PREFIX_EDIT = 'edit_'
+TOK_STRUCT = 'structured'
+TOK_RAW = 'raw'
+EDIT_STRUCT = f'{PREFIX_EDIT}{TOK_STRUCT}'
+EDIT_RAW = f'{PREFIX_EDIT}{TOK_RAW}'
+LEDGER_STRUCT = f'{PREFIX_LEDGER}{TOK_STRUCT}'
+LEDGER_RAW = f'{PREFIX_LEDGER}{TOK_RAW}'
+
 
 class Wealth:
     """Collects amounts mapped to currencies."""
@@ -313,16 +322,19 @@ class Handler(PlomHttpHandler):
     # pylint: disable=missing-class-docstring
     mapper = PlomQueryMap
 
+    def _send_rendered(self, tmpl_name: str, ctx: dict[str, Any]) -> None:
+        self.send_rendered(Path(f'{tmpl_name}.tmpl'), ctx)
+
     def do_POST(self) -> None:
         # pylint: disable=invalid-name,missing-function-docstring
-        prefix_file, prefix_ledger = 'file_', 'ledger_'
+        prefix_file = 'file_'
         if (file_prefixed := self.postvars.keys_prefixed(prefix_file)):
             getattr(self.server, file_prefixed[0][len(prefix_file):])()
-        elif (self.pagename.startswith('edit_')
+        elif (self.pagename.startswith(PREFIX_EDIT)
               and self.postvars.first('apply')):
             booking = self.server.bookings[int(self.path_toks[2])]
             new_lines = []
-            if self.pagename == 'edit_structured':
+            if self.pagename == EDIT_STRUCT:
                 line_keys = self.postvars.keys_prefixed('line_')
                 lineno_to_inputs: dict[int, list[str]] = {}
                 for key in line_keys:
@@ -356,9 +368,9 @@ class Handler(PlomHttpHandler):
             new_id = self.server.rewrite_booking(booking.id_, new_lines)
             self.redirect(Path('/bookings').joinpath(f'{new_id}'))
             return
-        elif self.pagename.startswith(prefix_ledger):
+        elif self.pagename.startswith(PREFIX_LEDGER):
             action, id_str, dir_ =\
-                self.postvars.keys_prefixed(prefix_ledger)[0].split('_')[1:]
+                self.postvars.keys_prefixed(PREFIX_LEDGER)[0].split('_')[1:]
             new_id = getattr(self.server, f'{action}_booking')(
                 int(id_str), dir_ == 'up' if action == 'move' else 'to_end')
             self.redirect(Path(self.path).joinpath(f'#{new_id}'))
@@ -368,35 +380,64 @@ class Handler(PlomHttpHandler):
     def do_GET(self) -> None:
         # pylint: disable=invalid-name,missing-function-docstring
         ctx = {'tainted': self.server.tainted, 'path': self.path}
-        if self.pagename == 'bookings' or self.pagename.startswith('edit_'):
-            id_ = int(self.path_toks[2])
-            if self.pagename.startswith('edit_'):
-                ctx['id'] = id_
-        if self.pagename == 'balance':
-            id_ = int(self.params.first('up_incl') or '-1')
-            valid, balance_roots = self.server.balance_roots(id_)
-            self.send_rendered(Path('balance.tmpl'),
-                               ctx | {'roots': balance_roots,
-                                      'valid': valid,
-                                      'booking': self.server.bookings[id_]})
-        elif self.pagename == 'bookings':
+        if self.pagename == 'bookings':
             self.redirect(
-                    Path('/').joinpath('edit_structured').joinpath(str(id_)))
-        elif self.pagename == 'edit_structured':
-            ctx['dat_lines'] = [
-                    dl.as_dict for dl
-                    in self.server.bookings[ctx['id']].booked_lines]
-            self.send_rendered(Path('edit_structured.tmpl'), ctx)
-        elif self.pagename == 'edit_raw':
-            ctx['dat_lines'] = self.server.bookings[ctx['id']].booked_lines
-            self.send_rendered(Path('edit_raw.tmpl'), ctx)
-        elif self.pagename == 'ledger_raw':
-            self.send_rendered(Path('ledger_raw.tmpl'),
-                               ctx | {'dat_lines': self.server.dat_lines})
+                Path('/').joinpath(EDIT_STRUCT).joinpath(self.path_toks[2]))
+        elif self.pagename == 'balance':
+            self.get_balance(ctx)
+        elif self.pagename.startswith(PREFIX_EDIT):
+            self.get_edit(ctx, self.pagename == EDIT_RAW)
+        elif self.pagename.startswith(PREFIX_LEDGER):
+            self.get_ledger(ctx, self.pagename == LEDGER_RAW)
         else:
-            self.send_rendered(
-                    Path('ledger_structured.tmpl'),
-                    ctx | {'dat_lines': self.server.dat_lines_sans_empty})
+            self.get_ledger(ctx, False)
+
+    def get_balance(self, ctx) -> None:
+        """Display tree of calculated Accounts over .bookings[:up_incl+1]."""
+        id_ = int(self.params.first('up_incl') or '-1')
+        valid = True
+        account_names = set()
+        to_balance = (self.server.bookings[:id_ + 1] if id_ >= 0
+                      else self.server.bookings)
+        for booking in to_balance:
+            valid = valid if not booking.is_questionable else False
+            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 to_balance:
+            for account_name in booking.account_changes:
+                full_names_to_accounts[account_name].local_wealth +=\
+                        booking.account_changes[account_name]
+        ctx['roots'] = [ac for ac in full_names_to_accounts.values()
+                        if not ac.parent]
+        ctx['valid'] = valid
+        ctx['booking'] = self.server.bookings[id_]
+        self._send_rendered('balance', ctx)
+
+    def get_edit(self, ctx, raw: bool) -> None:
+        """Display edit form for individual Booking."""
+        id_ = int(self.path_toks[2])
+        ctx['id'] = id_
+        ctx['dat_lines'] = [dl if raw else dl.as_dict for dl
+                            in self.server.bookings[id_].booked_lines]
+        self._send_rendered(EDIT_RAW if raw else EDIT_STRUCT, ctx)
+
+    def get_ledger(self, ctx: dict[str, Any], raw: bool) -> None:
+        """Display ledger of all Bookings."""
+        ctx['dat_lines'] = [dl for dl in self.server.dat_lines
+                            if raw or not dl.is_empty]
+        self._send_rendered(LEDGER_RAW if raw else LEDGER_STRUCT, ctx)
 
 
 class Server(PlomHttpServer):
@@ -543,40 +584,6 @@ class Server(PlomHttpServer):
         self._recalc_dat_lines()
         return new_id
 
-    @property
-    def dat_lines_sans_empty(self) -> list[DatLine]:
-        """Return only those .data_lines with .code or .comment."""
-        return [dl for dl in self.dat_lines if not dl.is_empty]
-
-    def balance_roots(self, up_incl: int) -> tuple[bool, list[Account]]:
-        """Return tree of calculated Accounts over .bookings[:up_incl+1]."""
-        account_names = set()
-        valid = True
-        to_balance = (self.bookings[:up_incl + 1] if up_incl >= 0
-                      else self.bookings)
-        for booking in to_balance:
-            valid = valid if not booking.is_questionable else False
-            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 to_balance:
-            for account_name in booking.account_changes:
-                full_names_to_accounts[account_name].local_wealth +=\
-                        booking.account_changes[account_name]
-        return valid, [ac for ac in full_names_to_accounts.values()
-                       if not ac.parent]
-
 
 if __name__ == "__main__":
     if not LEDGER_DAT: