SERVER_HOST = '127.0.0.1'
PATH_TEMPLATES = Path('templates')
+PREFIX_DEF = 'def '
PREFIX_LEDGER = 'ledger_'
PREFIX_EDIT = 'edit_'
PREFIX_FILE = 'file_'
class Account:
"""Combine name, position in tree of own, and wealth of self + children."""
- def __init__(self, parent: Optional['Account'], basename: str) -> None:
+ def __init__(self, parent: Optional['Account'], basename: str, desc: str
+ ) -> None:
self.local_wealth = Wealth()
self.basename = basename
+ self.desc = desc
self.children: list[Self] = []
self.parent = parent
if self.parent:
total += child.wealth
return total
- @staticmethod
- def by_paths(acc_names: list[str]) -> dict[str, 'Account']:
- """From bookings generate dict of all refered Accounts by paths."""
- paths_to_accs: dict[str, Account] = {}
- for full_name in acc_names:
- path = ''
- for step_name in full_name.split(':'):
- parent_name = path[:]
- path = ':'.join([path, step_name]) if path else step_name
- if path not in paths_to_accs:
- paths_to_accs[path] = Account(
- paths_to_accs[parent_name] if parent_name else None,
- step_name)
- return paths_to_accs
-
- @staticmethod
- def names_over_bookings(bookings: list['Booking']) -> list[str]:
- """Sorted list of all account names refered to in bookings."""
- names = set()
- for booking in bookings:
- for account_name in booking.account_changes:
- names.add(account_name)
- return sorted(list(names))
-
class DatLine(Dictable):
"""Line of .dat file parsed into comments and machine-readable data."""
to_balance = (self.server.bookings[:id_ + 1] if id_ >= 0
else self.server.bookings)
valid = 0 == len([b for b in to_balance if b.is_questionable])
- acc_dict = Account.by_paths(Account.names_over_bookings(to_balance))
+ acc_dict = self.server.empty_accounts_by_path(id_)
for booking in to_balance:
booking.apply_to_account_dict(acc_dict)
ctx['roots'] = [ac for ac in acc_dict.values() if not ac.parent]
"""Display edit form for individual Booking."""
id_ = int(self.path_toks[2])
booking = self.server.bookings[id_]
- acc_names = Account.names_over_bookings(self.server.bookings)
to_balance = self.server.bookings[:id_ + 1]
- accounts_after = Account.by_paths(acc_names)
- accounts_before = Account.by_paths(acc_names)
+ accounts_after = self.server.empty_accounts_by_path()
+ accounts_before = self.server.empty_accounts_by_path()
for b in to_balance:
if b != booking:
b.apply_to_account_dict(accounts_before)
ctx['valid'] = 0 == len([b for b in to_balance if b.is_questionable])
ctx['roots'] = observed_tree
if not raw:
- ctx['all_accounts'] = acc_names
+ ctx['all_accounts'] = accounts_after.keys()
self._send_rendered(EDIT_RAW if raw else EDIT_STRUCT, ctx)
def get_ledger(self, ctx: dict[str, Any], raw: bool) -> None:
self.bookings += [booking]
booked_lines.clear()
gap_lines += [dat_line]
+ self.paths_to_descs = {}
+ for comment in [dl.comment for dl in self.dat_lines if dl.comment]:
+ if comment.startswith(PREFIX_DEF):
+ parts = [part.strip() for part
+ in comment[len(PREFIX_DEF):].split(';')]
+ first_part_parts = parts[0].split(maxsplit=1)
+ account_name = first_part_parts[0]
+ desc = first_part_parts[1] if len(first_part_parts) > 1 else ''
+ if desc:
+ self.paths_to_descs[account_name] = desc
for booking in self.bookings:
booking.recalc_prev_next(self.bookings)
if booking:
def _hash_dat_lines(self) -> int:
return hash(tuple(dl.raw for dl in self.dat_lines))
+ def empty_accounts_by_path(self,
+ up_incl: int = -1
+ ) -> dict[str, 'Account']:
+ """Dict of Accounts refered in .bookings till up_incl by paths."""
+ booked_names = set()
+ for booking in (self.bookings[:up_incl + 1] if up_incl >= 0
+ else self.bookings):
+ for account_name in booking.account_changes:
+ booked_names.add(account_name)
+ paths_to_accs: dict[str, Account] = {}
+ for full_name in booked_names:
+ path = ''
+ for step_name in full_name.split(':'):
+ parent_name = path[:]
+ path = ':'.join([path, step_name]) if path else step_name
+ if path not in paths_to_accs:
+ paths_to_accs[path] = Account(
+ paths_to_accs[parent_name] if parent_name else None,
+ step_name,
+ self.paths_to_descs.get(path, ''))
+ return paths_to_accs
+
@property
def tainted(self) -> bool:
"""If .dat_lines different to those of last .load()."""