From: Christian Heller Date: Thu, 13 Mar 2025 12:11:45 +0000 (+0100) Subject: Remove "copy here", refactor and bugfix Booking addition/rewriting. X-Git-Url: https://plomlompom.com/repos/%7B%7B%20web_path%20%7D%7D/decks/%7B%7B%20deck_id%20%7D%7D/booking?a=commitdiff_plain;p=ledgplom Remove "copy here", refactor and bugfix Booking addition/rewriting. --- diff --git a/src/run.py b/src/run.py index 911a5e3..68aa534 100755 --- a/src/run.py +++ b/src/run.py @@ -455,17 +455,17 @@ class Handler(PlomHttpHandler): return Path('/bookings').joinpath(f'{new_id}') def post_ledger_action(self) -> Path: - """Based on trigger postvar call .server.(move|copy)_booking.""" + """Parse postvar to call .server.(move|copy|add_empty_new)_booking.""" if 'add_booking' in self.postvars.as_dict: id_ = self.server.add_empty_booking() else: keys_prefixed = self.postvars.keys_prefixed(PREFIX_LEDGER) - action, id_str, dir_ = keys_prefixed[0].split('_', maxsplit=3)[1:] + action, id_str = keys_prefixed[0].split('_', maxsplit=2)[1:] id_ = int(id_str) - if action == 'move': - id_ = self.server.move_booking(id_, dir_ == 'up') + if action.startswith('move'): + id_ = self.server.move_booking(id_, action == 'moveup') return Path(self.path).joinpath(f'#{id_}') - id_ = self.server.copy_booking(id_, dir_ == 'to_end') + id_ = self.server.copy_booking(id_) return Path(EDIT_STRUCT).joinpath(f'{id_}') def do_GET(self) -> None: @@ -569,7 +569,6 @@ class Server(PlomHttpServer): booked_lines: list[DatLine] = [] gap_lines: list[DatLine] = [] booking: Optional[Booking] = None - last_date = '' for dat_line in self.dat_lines + [DatLine('')]: if dat_line.code: if gap_lines: @@ -582,23 +581,30 @@ class Server(PlomHttpServer): else: if booked_lines: booking = Booking(len(self.bookings), booked_lines[:]) - if last_date > booking.date: - booking.intro_line.errors += [ - 'date < previous valid date'] - else: - last_date = booking.date booking.apply_to_account_dict(self.accounts) self.bookings += [booking] booked_lines.clear() for acc_name, desc in dat_line.comment_instructions.items(): Account.ensure_in_dict(acc_name, self.accounts) 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 _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( @@ -656,48 +662,54 @@ class Server(PlomHttpServer): self._recalc_dat_lines() 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] booked_start, booked_end, gap_start_found = -1, 0, False for i, line in enumerate(new_lines): - if booked_start < 0 and line.code.strip(): - booked_start = i - elif booked_start >= 0 and not line.code.strip(): - gap_start_found = True - if not gap_start_found: - booked_end += 1 + if booked_start < 0 and line.code.strip(): # ignore any initial + booked_start = i # empty lines + elif booked_start >= 0 and not line.code.strip(): # past start, + gap_start_found = True # yet empty? gap + if not gap_start_found: # end index is always after current line, + booked_end += 1 # provided we're not yet in the gap elif line.code.strip(): new_lines[i] = DatLine(f'; {line.code}') before_gap = new_lines[:booked_start] new_booked_lines = (new_lines[booked_start:booked_end] if booked_start > -1 else []) - after_gap = old_booking.gap_lines_copied + new_lines[booked_end:] - if not new_booked_lines: - del self.bookings[old_id] - for booking in self.bookings[old_id:]: - booking.id_ -= 1 - summed_gap = before_gap + after_gap - if old_booking.id_ == 0: - self.initial_gap_lines += summed_gap - else: - assert old_booking.prev is not None - old_booking.prev.gap_lines += summed_gap - for neighbour in old_booking.prev, old_booking.next: - if neighbour: - neighbour.recalc_prev_next(self.bookings) - self._recalc_dat_lines() + 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) return old_id if old_id < len(self.bookings) else 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: - new_booking = Booking(old_id, new_booked_lines, after_gap) - self.bookings[old_id] = new_booking - new_booking.recalc_prev_next(self.bookings) - else: + 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: + if (not i_booking.prev) and i_booking.date > new_date: new_idx = i_booking.id_ break if i_booking.next.date > new_date: @@ -709,50 +721,44 @@ class Server(PlomHttpServer): # 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.date == new_date][0].id_ - new_booking = Booking(new_idx, new_booked_lines, after_gap) - self.bookings[old_id] = new_booking + if b != updated and b.date == new_date][0].id_ self._move_booking(old_id, new_idx) - if new_booking.id_ == 0: + if updated.id_ == 0: self.initial_gap_lines += before_gap else: - assert new_booking.prev is not None - new_booking.prev.gap_lines += before_gap + assert updated.prev is not None + updated.prev.gap_lines += before_gap self._recalc_dat_lines() - return new_booking.id_ - - def add_empty_booking(self) -> int: - """Add new Booking to end of ledger.""" - booking = Booking(len(self.bookings), - [DatLine(f'{dt_date.today().isoformat()} ?')]) + self._check_date_order() + return updated.id_ + + def _add_new_booking( + self, + target: str, + dat_lines_transaction: list[DatLine], + intro_comment: str = '' + ) -> int: + booking = Booking( + len(self.bookings), + [DatLine(f'{dt_date.today().isoformat()} {target}' + + ' ; '.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() return booking.id_ - def copy_booking(self, id_: int, to_end: bool) -> int: - """Add copy of Booking of id_ to_end of ledger, or after copied.""" - copied = self.bookings[id_] - new_id = len(self.bookings) if to_end else copied.id_ + 1 - if to_end: - intro_comment = copied.booked_lines[0].comment - intro = DatLine( - f'{dt_date.today().isoformat()} {copied.target}' - + (f' ; {intro_comment}' if intro_comment else '')) - new_booking = Booking(new_id, - [intro] + copied.booked_lines_copied[1:], - copied.gap_lines_copied) - self.bookings += [new_booking] - else: - new_booking = Booking(new_id, - copied.booked_lines_copied, - copied.gap_lines_copied) - self.bookings[new_id:new_id] = [new_booking] - for b in self.bookings[new_id + 1:]: - b.id_ += 1 - new_booking.recalc_prev_next(self.bookings) - self._recalc_dat_lines() - return new_id + def add_empty_booking(self) -> int: + """Add new Booking to end of ledger.""" + return self._add_new_booking('?', []) + + def copy_booking(self, copied_id: int) -> int: + """Add copy of Booking of copied_id to_end of ledger.""" + copied = self.bookings[copied_id] + return self._add_new_booking(copied.target, + copied.booked_lines_copied[1:], + copied.booked_lines[0].comment) if __name__ == "__main__": diff --git a/src/templates/_macros.tmpl b/src/templates/_macros.tmpl index fe783f7..97eddaf 100644 --- a/src/templates/_macros.tmpl +++ b/src/templates/_macros.tmpl @@ -19,13 +19,13 @@ td.invalid, tr.warning td.invalid { background-color: #ff0000; } {% macro css_ledger_index_col() %} -table.ledger tr > td:first-child { background-color: white; } +table.ledger tr > td:first-child { background-color: white; text-align: right; } {% endmacro %} -{% macro table_dat_lines_action_button(dat_line, verb, direction, label, enabled=true) %} - +{% macro table_dat_lines_action_button(dat_line, action, label, enabled=true) %} + {% endmacro %} {% macro table_dat_lines(dat_lines, raw) %} @@ -42,13 +42,12 @@ table.ledger tr > td:first-child { background-color: white; } {% if dat_line.is_intro %} [#] - {{ table_dat_lines_action_button(dat_line, "move", "up", "^", dat_line.booking.can_move(1)) }} + {{ table_dat_lines_action_button(dat_line, "moveup", "^", dat_line.booking.can_move(1)) }} {% elif dat_line.booking_line.idx == 1 %} [b] - {{ table_dat_lines_action_button(dat_line, "move", "down", "v", dat_line.booking.can_move(0)) }} + {{ table_dat_lines_action_button(dat_line, "movedown", "v", dat_line.booking.can_move(0)) }} {% elif dat_line.booking_line.idx == 2 %} - {{ table_dat_lines_action_button(dat_line, "copy", "here", "c") }} - {{ table_dat_lines_action_button(dat_line, "copy", "to_end", "C") }} + {{ table_dat_lines_action_button(dat_line, "copy", "C") }} {% endif %} diff --git a/src/templates/ledger_structured.tmpl b/src/templates/ledger_structured.tmpl index da1f46f..da853e5 100644 --- a/src/templates/ledger_structured.tmpl +++ b/src/templates/ledger_structured.tmpl @@ -5,8 +5,9 @@ {{ macros.css_td_money() }} {{ macros.css_errors() }} {{ macros.css_ledger_index_col() }} -table.ledger > tbody > tr > td.date, table.ledger > tbody > tr > td:first-child { font-family: monospace; font-size: 1.3em; text-align: center; } table.ledger > tbody > tr > td { vertical-align: middle; } +table.ledger > tbody > tr > td.date, table.ledger > tbody > tr > td:first-child { font-family: monospace; font-size: 1.3em; } +table.ledger > tbody > tr > td.date { text-align: center; } table.ledger > tbody > tr > td:first-child { white-space: nowrap; } {% endblock %}