home · contact · privacy
Move interpretation of .code lines into new BookingLine construct.
authorChristian Heller <c.heller@plomlompom.de>
Mon, 20 Jan 2025 11:35:39 +0000 (12:35 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Mon, 20 Jan 2025 11:35:39 +0000 (12:35 +0100)
ledger.py
templates/index.tmpl

index 2a1fdd6a196dcfa11624dfe208e8cd5674f9f11b..8a50435fb30162e98157f13afdf58957b42ffe22 100755 (executable)
--- a/ledger.py
+++ b/ledger.py
@@ -22,26 +22,17 @@ class DatLine:
         halves = [t.rstrip() for t in line.split(';', maxsplit=1)]
         self.comment = halves[1] if len(halves) > 1 else ''
         self.code = halves[0]
-        self.type = 'no_data'
-        self.booking: Optional[Booking] = None
-        if self.code:
-            self.type = 'invalid'
-            if self.code[0].isspace():
-                toks = self.code.lstrip().split()
-                self.acc = toks[0]
-                if 1 == len(toks):
-                    self.amt, self.curr = '', ''
-                    self.type = 'value'
-                elif 3 == len(toks):
-                    amt_dec = Decimal(toks[1])
-                    exp = amt_dec.as_tuple().exponent
-                    assert isinstance(exp, int)
-                    self.amt = (f'{amt_dec:.1f}…' if exp < -2
-                                else f'{amt_dec:.2f}')
-                    self.curr = toks[2]
-                    self.type = 'value'
-            else:
-                self.type = 'intro'
+        self.booking_line: Optional[BookingLine] = None
+
+    @property
+    def type(self) -> str:
+        """Provide categorization of .code part."""
+        return self.booking_line.type if self.booking_line else 'no_data'
+
+    @property
+    def booking_id(self) -> int:
+        """If .booking_line, its .booking_id, else -1."""
+        return self.booking_line.booking_id if self.booking_line else -1
 
     @property
     def is_empty(self) -> bool:
@@ -56,15 +47,41 @@ class DatLine:
         return self.raw.replace(' ', '&nbsp;')
 
 
+class BookingLine:
+    """Parsed code part of a DatLine belonging to a Booking."""
+
+    def __init__(self, booking_id: int, code: str) -> None:
+        self.booking_id = booking_id
+        self.type = 'invalid'
+        self.acc, self.amt, self.curr = '', '', ''
+        if code[0].isspace():
+            toks = code.lstrip().split()
+            self.acc = toks[0]
+            if 1 == len(toks):
+                self.type = 'value'
+            elif 3 == len(toks):
+                amt_dec = Decimal(toks[1])
+                exp = amt_dec.as_tuple().exponent
+                assert isinstance(exp, int)
+                self.amt = (f'{amt_dec:.1f}…' if exp < -2
+                            else f'{amt_dec:.2f}')
+                self.curr = toks[2]
+                self.type = 'value'
+        else:
+            self.type = 'intro'
+
+
 class Booking:
     """Represents lines of individual booking."""
     # pylint: disable=too-few-public-methods
 
-    def __init__(self, id_: int, idx_start: int, b_lines: list[str]) -> None:
+    def __init__(self, id_: int, idx_start: int, dat_lines: list[DatLine]
+                 ) -> None:
         self.id_ = id_
         self.idx_start = idx_start
-        self.b_lines = b_lines
-        self.idx_end = self.idx_start + len(self.b_lines)
+        self.idx_end = self.idx_start + len(dat_lines)
+        for dat_line in dat_lines:
+            dat_line.booking_line = BookingLine(self.id_, dat_line.code)
 
 
 class Handler(PlomHttpHandler):
@@ -98,19 +115,17 @@ class Server(PlomHttpServer):
                 DatLine(line)
                 for line in path_dat.read_text(encoding='utf8').splitlines()]
         self.bookings: list[Booking] = []
-        code_lines = [dl.code for dl in self.dat_lines]
         last_booking_start = -1
-        b_lines: list[str] = []
-        for idx, code in enumerate(code_lines + ['']):
-            if code:
-                if not b_lines:
+        booking_lines: list[DatLine] = []
+        for idx, dat_line in enumerate(self.dat_lines + [DatLine('')]):
+            if dat_line.code:
+                if not booking_lines:
                     last_booking_start = idx
-                b_lines += [code]
-            elif b_lines:
+                booking_lines += [dat_line]
+            elif booking_lines:
                 self.bookings += [Booking(len(self.bookings),
-                                          last_booking_start, b_lines)]
-                b_lines.clear()
-                self.dat_lines[last_booking_start].booking = self.bookings[-1]
+                                          last_booking_start, booking_lines)]
+                booking_lines.clear()
 
     @property
     def dat_lines_sans_empty(self) -> list[DatLine]:
index bf83499d2381ea804f48e94cfb250719521f1d52..301b2d4f7e971928a6cdca4c467a4fdcfce3e46a 100644 (file)
@@ -15,14 +15,14 @@ td.curr { text-align: center; }
   {% if "intro" == l.type and loop.index > 1 %}<tr><td colspan=5>&nbsp;</td></tr>{% endif %}
   <tr class="{{l.type}}">
   {% if l.type == "intro" %}
-    <td id="{{l.booking.id_}}"><a href="#{{l.booking.id_}}">#</a></td>
+    <td id="{{l.booking_id}}"><a href="#{{l.booking_id}}">#</a></td>
   {% else %}
     <td></td>
   {% endif %}
   {% if l.type == "value" %}
-    <td class="amt">{{l.amt}}</td><td class="curr">{{l.curr|truncate(4,true,"…")}}</td><td>{{l.acc}}</td>
+    <td class="amt">{{l.booking_line.amt}}</td><td class="curr">{{l.booking_line.curr|truncate(4,true,"…")}}</td><td>{{l.booking_line.acc}}</td>
   {% elif l.type == "intro" %}
-    <td class="code" colspan=3><a href="/booking/{{l.booking.id_}}">{{l.code}}</a></td>
+    <td class="code" colspan=3><a href="/booking/{{l.booking_id}}">{{l.code}}</a></td>
   {% else %}
     <td colspan=3>{{l.code}}</td>
   {% endif %}