home · contact · privacy
Disallow movement into different date. master
authorChristian Heller <c.heller@plomlompom.de>
Wed, 29 Jan 2025 07:47:45 +0000 (08:47 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Wed, 29 Jan 2025 07:47:45 +0000 (08:47 +0100)
ledger.py
templates/_macros.tmpl
templates/balance.tmpl
templates/ledger_raw.tmpl
templates/ledger_structured.tmpl

index b9577dc008e4cf38b08fe5b9e37a102cf675844c..f179efeb87e5271bea6bb1565532908a368e7788 100755 (executable)
--- a/ledger.py
+++ b/ledger.py
@@ -104,7 +104,12 @@ class DatLine:
     @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
+        return self.booking.id_ if self.booking else -1
+
+    @property
+    def booking(self) -> Optional['Booking']:
+        """If .booking_line, matching Booking, else None."""
+        return self.booking_line.booking if self.booking_line else None
 
     @property
     def error(self) -> str:
@@ -203,9 +208,13 @@ class Booking:
     """Represents lines of individual booking."""
     # pylint: disable=too-few-public-methods
 
-    def __init__(self, id_: int, dat_lines: list[DatLine]) -> None:
-        self.intro_line = IntroLine(self, dat_lines[0].code)
-        dat_lines[0].booking_line = self.intro_line
+    def __init__(self,
+                 id_: int,
+                 dat_lines: list[DatLine],
+                 prev_booking: Optional[Self]
+                 ) -> None:
+        self.intro = IntroLine(self, dat_lines[0].code)
+        dat_lines[0].booking_line = self.intro
         self._transfer_lines = []
         for i, dat_line in enumerate(dat_lines[1:]):
             dat_line.booking_line = TransferLine(self, dat_line.code, i + 1)
@@ -231,11 +240,25 @@ class Booking:
             self._transfer_lines[-1].errors += ['needed sink missing']
         self.id_ = id_
         self.dat_lines = dat_lines
+        self.prev = prev_booking
+        if self.prev:
+            self.prev.next = self
+        self.next: Optional[Self] = None
+
+    def can_move(self, up: bool) -> bool:
+        """Whether movement rules would allow self to move up or down."""
+        if (up and ((not self.prev)
+                    or self.prev.intro.date != self.intro.date)):
+            return False
+        if ((not up) and ((not self.next)
+                          or self.next.intro.date != self.intro.date)):
+            return False
+        return True
 
     @property
     def is_questionable(self) -> bool:
         """Whether lines count any errors."""
-        for _ in [bl for bl in [self.intro_line] + self._transfer_lines
+        for _ in [bl for bl in [self.intro] + self._transfer_lines
                   if bl.errors]:
             return True
         return False
@@ -313,8 +336,6 @@ class Handler(PlomHttpHandler):
             id_ = int(self.path_toks[2])
             if self.pagename.startswith('edit_'):
                 ctx['id'] = id_
-        elif self.pagename.startswith('ledger_'):
-            ctx['max_id'] = self.server.bookings[-1].id_
         if self.pagename == 'balance':
             id_ = int(self.params.first('up_incl') or '-1')
             valid, balance_roots = self.server.balance_roots(id_)
@@ -375,11 +396,13 @@ class Server(PlomHttpServer):
             if dat_line.code:
                 booking_lines += [dat_line]
             elif booking_lines:
-                booking = Booking(len(self.bookings), booking_lines)
-                if last_date > booking.intro_line.date:
-                    booking.intro_line.errors += ['date < previous valid date']
+                booking = Booking(
+                        len(self.bookings), booking_lines,
+                        self.bookings[-1] if self.bookings else None)
+                if last_date > booking.intro.date:
+                    booking.intro.errors += ['date < previous valid date']
                 else:
-                    last_date = booking.intro_line.date
+                    last_date = booking.intro.date
                 self.bookings += [booking]
                 booking_lines = []
 
@@ -431,7 +454,7 @@ class Server(PlomHttpServer):
         if to_end or copied is self.bookings[-1]:
             intro = DatLine(
                 f'{dt_date.today().isoformat()} '
-                f'{copied.intro_line.target} ; {copied.dat_lines[0].comment}')
+                f'{copied.intro.target} ; {copied.dat_lines[0].comment}')
             self.dat_lines += [empty_line, intro] + copied.dat_lines[1:]
             prev_id = self.bookings[-1].id_
         else:
index f8f932545ec6c553d330574196a19662826d9291..6cbeb0102e14a587fb321425600d33cec4095ac2 100644 (file)
@@ -11,7 +11,7 @@ td.invalid, tr.warning td.invalid { background-color: #ff0000; }
 table.ledger tr > td:first-child { background-color: white; }
 {% endmacro %}
 
-{% macro table_dat_lines(dat_lines, max_id, raw) %}
+{% macro table_dat_lines(dat_lines, raw) %}
 <form action="/ledger_{% if raw %}raw{% else %}structured{% endif %}" method="POST">
 <table class="ledger">
 {% for dat_line in dat_lines %}
@@ -20,9 +20,9 @@ table.ledger tr > td:first-child { background-color: white; }
   {% endif %}
   <tr class="alternating{% if dat_line.is_questionable %} warning{% endif %}">
   {% if dat_line.is_intro %}
-    <td id="{{dat_line.booking_id}}"><a href="#{{dat_line.booking_id}}">[#]</a><input type="submit" name="move_{{dat_line.booking_id}}_up" value="^"{% if dat_line.booking_id == 0 %} disabled{% endif %}/></td>
+    <td id="{{dat_line.booking_id}}"><a href="#{{dat_line.booking_id}}">[#]</a><input type="submit" name="move_{{dat_line.booking_id}}_up" value="^"{% if not dat_line.booking.can_move(1) %} disabled{% endif %}/></td>
   {% elif dat_line.booking_line.idx == 1 %}
-    <td><a href="/balance?up_incl={{dat_line.booking_id}}">[b]</a><input type="submit" name="move_{{dat_line.booking_id}}_down" value="v"{% if dat_line.booking_id == max_id %} disabled{% endif %}/></td>
+    <td><a href="/balance?up_incl={{dat_line.booking_id}}">[b]</a><input type="submit" name="move_{{dat_line.booking_id}}_down" value="v"{% if not dat_line.booking.can_move(0) %} disabled{% endif %}/></td>
   {% elif dat_line.booking_line.idx == 2 %}
     <td><input type="submit" name="copy_{{dat_line.booking_id}}_here" value="c" /><input type="submit" name="copy_{{dat_line.booking_id}}_to_end" value="C" /></td>
   {% else %}
index a8a3b7f32b27ada408a9b8efb038335e8fd60b8d..acf81fc5838ae643d5c922410e1e67cf792b8167 100644 (file)
@@ -62,7 +62,7 @@ span.indent { letter-spacing: 3em; }
 {% endblock css %}
 
 {% block content %}
-<p>balance after <a href="/bookings/{{booking.id_}}">booking {{booking.id_}} ({{booking.intro_line.date}}: {{booking.intro_line.target}})</a></p>
+<p>balance after <a href="/bookings/{{booking.id_}}">booking {{booking.id_}} ({{booking.intro.date}}: {{booking.intro.target}})</a></p>
 <table{% if not valid %} class="warning"{% endif %}>
 {% for root in roots %}
 {{ account_with_children(root, indent=0) }}
index d1e13f0f929a0255522f752e8b66188b85d7eb42..7f803abea0232ce7a4fca371b81c0ffba369d638 100644 (file)
@@ -9,6 +9,6 @@ table.ledger > tbody > tr > td:first-child input[type=submit] { font-size: 0.5em
 {% endblock %}
 
 {% block content %}
-{{ macros.table_dat_lines(dat_lines, max_id, raw=true) }}
+{{ macros.table_dat_lines(dat_lines, raw=true) }}
 {% endblock %}
 
index 8d9b88cadf024a7ed0247363ff9fea42689dd75c..da1f46fcc38001d1a705f0d04239548a111341c6 100644 (file)
@@ -11,5 +11,5 @@ table.ledger > tbody > tr > td:first-child { white-space: nowrap; }
 {% endblock %}
 
 {% block content %}
-{{ macros.table_dat_lines(dat_lines, max_id, raw=false) }}
+{{ macros.table_dat_lines(dat_lines, raw=false) }}
 {% endblock %}