home · contact · privacy
Fix insufficient account updating, refactor. master
authorChristian Heller <c.heller@plomlompom.de>
Thu, 13 Mar 2025 23:09:38 +0000 (00:09 +0100)
committerChristian Heller <c.heller@plomlompom.de>
Thu, 13 Mar 2025 23:09:38 +0000 (00:09 +0100)
src/run.py

index b69e0fc52e3a7cb211f175e78d025de4b71b4999..abb849d490a1e5c016691b202464abb52ae00d5b 100755 (executable)
@@ -159,7 +159,6 @@ class DatLine(Dictable):
         self.comment = halves[1] if len(halves) > 1 else ''
         self.code = halves[0]
         self.booking_line: Optional[BookingLine] = None
-        self.hide_comment_in_ledger = False
 
     @property
     def comment_instructions(self) -> dict[str, str]:
@@ -544,12 +543,12 @@ class Server(PlomHttpServer):
 
     def load(self) -> None:
         """Read into ledger file at .path_dat."""
-        self.accounts, self.bookings, self.initial_gap_lines = {}, [], []
         self.dat_lines = [
             DatLine(line)
             for line in self._path_dat.read_text(encoding='utf8').splitlines()]
         self.last_save_hash = self._hash_dat_lines()
-        booked_lines: list[DatLine] = []
+        self.bookings, self.initial_gap_lines = [], []
+        booked: list[DatLine] = []
         gap_lines: list[DatLine] = []
         booking: Optional[Booking] = None
         for dat_line in self.dat_lines + [DatLine('')]:
@@ -560,27 +559,46 @@ class Server(PlomHttpServer):
                     else:
                         self.initial_gap_lines = gap_lines[:]
                     gap_lines.clear()
-                booked_lines += [dat_line]
+                booked += [dat_line]
             else:
-                if booked_lines:
-                    booking = Booking(len(self.bookings), booked_lines[:])
-                    self._apply_booking_to_accounts(booking)
-                    self.bookings += [booking]
-                    booked_lines.clear()
+                if booked:
+                    self.bookings += [Booking(len(self.bookings), booked[:])]
+                    booked.clear()
+        if booking:
+            booking.gap_lines = gap_lines[:-1]
+        self._sync(recalc_datlines=False)
+
+    def _sync(self, recalc_datlines=True, check_dates=True):
+        if recalc_datlines:
+            self.dat_lines = self.initial_gap_lines[:]
+            for booking in self.bookings:
+                self.dat_lines += booking.booked_lines
+                self.dat_lines += booking.gap_lines
+        for idx, booking in enumerate(self.bookings[1:]):
+            booking.prev = self.bookings[idx]
+        for idx, booking in enumerate(self.bookings[:-1]):
+            booking.next = self.bookings[idx + 1]
+        self.bookings[-1].next = None
+        if check_dates:
+            last_date = ''
+            err_msg = 'date < previous valid date'
+            for booking in self.bookings:
+                if err_msg in booking.intro_line.errors:
+                    booking.intro_line.errors.remove(err_msg)
+                if last_date > booking.date:
+                    booking.intro_line.errors += [err_msg]
+                else:
+                    last_date = booking.date
+        self._recalc_prev_line_empty()
+        self.accounts = {}
+        for dat_line in self.dat_lines:
             for acc_name, desc in dat_line.comment_instructions.items():
                 self.ensure_account(acc_name)
                 self.accounts[acc_name].desc = desc
-        self._check_date_order()
         for booking in self.bookings:
-            booking.recalc_prev_next(self.bookings)
-        if booking:
-            booking.gap_lines = gap_lines[:-1]
-        self._recalc_prev_line_empty()
-
-    def _apply_booking_to_accounts(self, booking: Booking) -> None:
-        for acc_name, wealth in booking.account_changes.items():
-            self.ensure_account(acc_name)
-            self.accounts[acc_name].add_wealth_diff(booking.id_, wealth)
+            for acc_name, wealth in booking.account_changes.items():
+                self.ensure_account(acc_name)
+                self.accounts[acc_name].add_wealth_diff(booking.id_, wealth)
 
     def ensure_account(self, full_path: str) -> None:
         """If full_path not in self.accounts, add its tree with Accounts."""
@@ -592,17 +610,6 @@ class Server(PlomHttpServer):
                         step_name)
             parent_path = path
 
-    def _check_date_order(self) -> None:
-        last_date = ''
-        err_msg = 'date < previous valid date'
-        for booking in self.bookings:
-            if err_msg in booking.intro_line.errors:
-                booking.intro_line.errors.remove(err_msg)
-            if last_date > booking.date:
-                booking.intro_line.errors += [err_msg]
-            else:
-                last_date = booking.date
-
     def save(self) -> None:
         """Save current state to ._path_dat."""
         self._path_dat.write_text(
@@ -633,14 +640,7 @@ class Server(PlomHttpServer):
             if prev_line or line.code + line.comment_in_ledger:  # jump over
                 prev_line = line                                 # empty start
 
-    def _recalc_dat_lines(self) -> None:
-        self.dat_lines = self.initial_gap_lines[:]
-        for booking in self.bookings:
-            self.dat_lines += booking.booked_lines
-            self.dat_lines += booking.gap_lines
-        self._recalc_prev_line_empty()
-
-    def _move_booking(self, idx_from, idx_to) -> None:
+    def _move_booking(self, idx_from: int, idx_to: int):
         moving = self.bookings[idx_from]
         if idx_from >= idx_to:                   # moving upward, deletion must
             del self.bookings[idx_from]          # precede insertion to keep
@@ -650,34 +650,15 @@ class Server(PlomHttpServer):
         min_idx, max_idx = min(idx_from, idx_to), max(idx_from, idx_to)
         for idx, booking in enumerate(self.bookings[min_idx:max_idx + 1]):
             booking.id_ = min_idx + idx
-            booking.recalc_prev_next(self.bookings)
 
-    def move_booking(self, old_id: int, up: bool) -> int:
+    def move_booking(self, idx_from: int, up: bool) -> int:
         """Move Booking of old_id one step up or downwards"""
-        new_id = old_id + (-1 if up else 1)
-        self._move_booking(old_id,                     # moving down implies
-                           new_id + (0 if up else 1))  # jumping over next item
-        self._recalc_dat_lines()
+        new_id = idx_from + (-1 if up else 1)
+        idx_to = new_id + (0 if up else 1)  # down-move imlies jump over next
+        self._move_booking(new_id, idx_to)
+        self._sync()
         return new_id
 
-    def _remove_booking(
-            self,
-            to_remove: Booking,
-            summed_gap: list[DatLine]
-            ) -> None:
-        del self.bookings[to_remove.id_]
-        for booking in self.bookings[to_remove.id_:]:
-            booking.id_ -= 1
-        if to_remove.id_ == 0:
-            self.initial_gap_lines += summed_gap
-        else:
-            assert to_remove.prev is not None
-            to_remove.prev.gap_lines += summed_gap
-        for neighbour in to_remove.prev, to_remove.next:
-            if neighbour:
-                neighbour.recalc_prev_next(self.bookings)
-        self._recalc_dat_lines()
-
     def rewrite_booking(self, old_id: int, new_lines: list[DatLine]) -> int:
         """Rewrite Booking with new_lines, move if changed date."""
         old_booking = self.bookings[old_id]
@@ -697,37 +678,42 @@ class Server(PlomHttpServer):
         after_gap = old_booking.gap_lines_copied  # new gap be old gap _plus_
         after_gap += new_lines[booked_end:]       # any new gap lines
         if not new_booked_lines:  # interpret empty posting as deletion request
-            self._remove_booking(old_booking, before_gap + after_gap)
+            del self.bookings[old_id]
+            for booking in self.bookings[old_id:]:
+                booking.id_ -= 1
+            leftover_gap = before_gap + after_gap
+            if old_id == 0:
+                self.initial_gap_lines += leftover_gap
+            else:
+                self.bookings[old_id - 1].gap_lines += leftover_gap
+            self._sync(check_dates=False)
             return old_id if old_id < len(self.bookings) else 0
+        if old_id == 0:
+            self.initial_gap_lines += before_gap
+        else:
+            self.bookings[old_id - 1].gap_lines += before_gap
+        new_date = new_booked_lines[0].code.lstrip().split(maxsplit=1)[0]
         updated = Booking(old_id, new_booked_lines, after_gap)
         self.bookings[old_id] = updated
-        updated.recalc_prev_next(self.bookings)
-        new_date = new_booked_lines[0].code.lstrip().split(maxsplit=1)[0]
         if new_date != old_booking.date:  # if changed date, move to there
-            i_booking = self.bookings[0]
-            new_idx = None
-            while i_booking.next:
-                if (not i_booking.prev) and i_booking.date > new_date:
-                    new_idx = i_booking.id_
-                    break
-                if i_booking.next.date > new_date:
-                    break
-                i_booking = i_booking.next
-            if new_idx is None:
-                new_idx = i_booking.id_ + 1
-            # ensure that, if we land in group of like-dated Bookings, we
-            # land on the edge closest to our last position
-            if i_booking.date == new_date and old_id < i_booking.id_:
-                new_idx = [b for b in self.bookings
-                           if b != updated and b.date == new_date][0].id_
-            self._move_booking(old_id, new_idx)
-        if updated.id_ == 0:
-            self.initial_gap_lines += before_gap
-        else:
-            assert updated.prev is not None
-            updated.prev.gap_lines += before_gap
-        self._recalc_dat_lines()
-        self._check_date_order()
+            if self.bookings[0].date > new_date:
+                new_id = 0
+            elif self.bookings[-1].date < new_date:
+                new_id = self.bookings[-1].id_ + 1
+            else:
+                of_date_1st = i_booking = self.bookings[0]
+                while i_booking.next:
+                    if of_date_1st.date != i_booking.date:
+                        of_date_1st = i_booking
+                    if i_booking.next.date > new_date:
+                        break
+                    i_booking = i_booking.next
+                # ensure that, if we land in group of like-dated Bookings, we
+                # land on the edge closest to our last position
+                new_id = (of_date_1st.id_ if old_id < i_booking.id_
+                          else i_booking.id_ + 1)
+            self._move_booking(old_id, new_id)
+        self._sync(check_dates=False)
         return updated.id_
 
     def _add_new_booking(
@@ -742,9 +728,7 @@ class Server(PlomHttpServer):
                      + ' ; '.join([''] + [s for s in [intro_comment] if s]))
              ] + dat_lines_transaction)
         self.bookings += [booking]
-        booking.recalc_prev_next(self.bookings)
-        self._recalc_dat_lines()
-        self._check_date_order()
+        self._sync()
         return booking.id_
 
     def add_empty_booking(self) -> int: