From: Christian Heller <c.heller@plomlompom.de> Date: Fri, 5 Jan 2024 00:59:45 +0000 (+0100) Subject: Improve accounting scripts. X-Git-Url: https://plomlompom.com/repos/%7B%7Bprefix%7D%7D/%7B%7B%20web_path%20%7D%7D/static/foo.html?a=commitdiff_plain;h=fde1097e391b9ec0c261f1e91bd203232b3fbcb3;p=misc Improve accounting scripts. --- diff --git a/ledger.py b/ledger.py index 36cca98..0ef3d44 100755 --- a/ledger.py +++ b/ledger.py @@ -6,7 +6,7 @@ from urllib.parse import parse_qs, urlparse from plomlib import PlomDB, PlomException, run_server, PlomHandler server_port = 8082 -db_path = '/home/plom/org/ledger2023.dat' +db_path = '/home/plom/org/ledger2024.dat' html_head = """ <style> @@ -56,10 +56,8 @@ add_form_footer = """ </form> """ add_free_html = """<br /> -<textarea name="booking" rows=10 cols=80> -{% for line in lines %}{{ line }} -{% endfor %} -</textarea> +<textarea name="booking" rows=10 cols=80>{% for line in lines %}{{ line }}{% if not loop.last %} +{% endif %}{% endfor %}</textarea> """ add_structured_html = """ <input type="submit" name="add_taxes" value="add taxes" tabindex="5" /> @@ -371,26 +369,30 @@ class LedgerDB(PlomDB): elif b.date_string > date: start_at = b.start_line break + lines += [''] # DEBUG is new return self.write_lines_in_total_lines_at(self.real_lines, start_at, lines) def update(self, start, end, lines, date): - total_lines = self.real_lines[:start] + self.real_lines[end:] + remaining_lines = self.real_lines[:start] + self.real_lines[end:] n_original_lines = end - start - start_at = len(total_lines) + start_at = len(remaining_lines) for b in self.bookings: if b.date_string == date: - if start_at == len(total_lines) or b.start_line == start: + if start_at == len(remaining_lines) or b.start_line == start: start_at = b.start_line if b.start_line > start: start_at -= n_original_lines elif b.date_string > date: break - if start_at == len(total_lines): + # print("DEBUG update start_at", start_at, "len(remaining_lines)", len(remaining_lines), "len(self.real_lines)", len(self.real_lines), "end", end) + if start_at != 0 and end != len(self.real_lines) and start_at == len(remaining_lines): + # Add empty predecessor line if appending. lines = [''] + lines - return self.write_lines_in_total_lines_at(total_lines, start_at, lines) + return self.write_lines_in_total_lines_at(remaining_lines, start_at, lines) def write_lines_in_total_lines_at(self, total_lines, start_at, lines): - total_lines = total_lines[:start_at] + lines + [''] + total_lines[start_at:] + # total_lines = total_lines[:start_at] + lines + [''] + total_lines[start_at:] + total_lines = total_lines[:start_at] + lines + total_lines[start_at:] _, _ = parse_lines(lines) text = '\n'.join(total_lines) self.write_db(text) @@ -581,7 +583,7 @@ class LedgerDB(PlomDB): else: line += f"\t\t" for currency, amount in account_sums[path + node].items(): - if currency != 'â¬' and amount > 0: + if currency != 'â¬' and amount != 0: line += f"{amount:5.2f} {currency}\t" lines += [line] indent += " " @@ -672,13 +674,23 @@ class LedgerDB(PlomDB): if b.start_line > start: next_booking = b break - start_at = next_booking.start_line + len(next_booking.lines) - (end - start) + 1 - self.make_move(start, end, start_at-1) + # start_at = next_booking.start_line + len(next_booking.lines) - (end - start) + 1 + # self.make_move(start, end, start_at-1) + start_at = next_booking.start_line + len(next_booking.lines) - (end - start) + print("DEBUG", start, end, start_at) + self.make_move(start, end, start_at) return redir_nth def make_move(self, start, end, start_at): + # FIXME currently broken due to changed self.write_lines_in_total_lines_at, easy fix would be lines += [""] maybe? lines = self.get_lines(start, end) - total_lines = self.real_lines[:start-1] + self.real_lines[end:] # +1 because we reduce the original position's two empty border lines to in-between line + if start == 0: + total_lines = self.real_lines[end+1:] + lines = [''] + lines + start_at += 1 + else: + total_lines = self.real_lines[:start-1] + self.real_lines[end:] # -1 because we reduce the original position's two empty limit lines to one in-between line + lines += [''] self.write_lines_in_total_lines_at(total_lines, start_at, lines) def booking_lines_from_postvars(self, postvars): @@ -722,7 +734,8 @@ class LedgerDB(PlomDB): temp_bookings, _ = parse_lines(temp_lines) for currency in temp_bookings[0].sink: amount = temp_bookings[0].sink[currency] - lines += [f'Assets {amount:.2f} {currency}'] + # lines += [f'Assets {amount:.2f} {currency}'] + lines += [f'Assets {amount} {currency}'] except PlomException: pass elif 'add_taxes' in postvars.keys(): @@ -756,6 +769,7 @@ class LedgerHandler(PlomHandler): postvars = parse_qs(self.rfile.read(length).decode(), keep_blank_values=1) start = int(postvars['start'][0]) end = int(postvars['end'][0]) + print("DEBUG start, end", start, end) db = LedgerDB(prefix) add_empty_line = None lines = [] @@ -785,6 +799,7 @@ class LedgerHandler(PlomHandler): nth = db.get_nth_for_booking_of_start_line(start) else: new_start = db.update(start, end, lines, target_date) + print("DEBUG save", new_start, start, end, lines) nth = db.get_nth_for_booking_of_start_line(new_start) if new_start > start: nth -= 1 diff --git a/plomlib.py b/plomlib.py index a94eb54..1d83295 100644 --- a/plomlib.py +++ b/plomlib.py @@ -33,7 +33,7 @@ class PlomDB: return # collect modification times of numbered .bak files - print('DEBUG BACKUP') + # print('DEBUG BACKUP') bak_prefix = f'{self.db_file}.bak.' # backup_dates = [] mtimes_to_paths = {} @@ -41,44 +41,47 @@ class PlomDB: if path.startswith(os.path.basename(bak_prefix))]: path = os.path.dirname(bak_prefix) + f'/{path}' mod_time = os.path.getmtime(path) - print(f'DEBUG pre-exists: {path} {mod_time}') + # print(f'DEBUG pre-exists: {path} {mod_time}') mtimes_to_paths[str(datetime.fromtimestamp(mod_time))] = path - # backup_dates += [str(datetime.fromtimestamp(mod_time))] - for mtime in sorted(mtimes_to_paths.keys()): - print(f'DEBUG mtimes_to_paths: {mtime}:{mtimes_to_paths[mtime]}') + # for mtime in sorted(mtimes_to_paths.keys()): + # print(f'DEBUG mtimes_to_paths: {mtime}:{mtimes_to_paths[mtime]}') # collect what numbered .bak files to save: the older, the fewer; for each # timedelta, keep the newest file that's older ages_to_keep = [timedelta(minutes=4**i) for i in range(0, 8)] - print(f'DEBUG ages_to_keep: {ages_to_keep}') + # print(f'DEBUG ages_to_keep: {ages_to_keep}') now = datetime.now() to_save = {} for age in ages_to_keep: limit = now - age for mtime in reversed(sorted(mtimes_to_paths.keys())): - print(f'DEBUG checking if {mtime} < {limit} ({now} - {age})') - if datetime.strptime(mtime, '%Y-%m-%d %H:%M:%S.%f') < limit: - print('DEBUG it is, adding!') + # print(f'DEBUG checking if {mtime} < {limit} ({now} - {age})') + if len(mtime) < 20: + mtime_test = mtime + '.000000' + else: + mtime_test = mtime + if datetime.strptime(mtime_test, '%Y-%m-%d %H:%M:%S.%f') < limit: + # print('DEBUG it is, adding!') to_save[mtime] = mtimes_to_paths[mtime] break for path in [path for path in mtimes_to_paths.values() if path not in to_save.values()]: - print(f'DEBUG removing {path} cause not in to_save') + # print(f'DEBUG removing {path} cause not in to_save') os.remove(path) i = 0 for mtime in sorted(to_save.keys()): source = to_save[mtime] target = f'{bak_prefix}{i}' - print(f'DEBUG to_save {source} -> {target}') + # print(f'DEBUG to_save {source} -> {target}') if source != target: shutil.move(source, target) i += 1 # put copy of current state at end of bak list - print(f'DEBUG saving current state to {bak_prefix}{i}') + # print(f'DEBUG saving current state to {bak_prefix}{i}') shutil.copy(self.db_file, f'{bak_prefix}{i}') def write_text_to_db(self, text, mode='w'): diff --git a/todo.py b/todo.py index 478a41e..7b8b83e 100644 --- a/todo.py +++ b/todo.py @@ -309,7 +309,7 @@ class TodoDB(PlomDB): task_rows.sort(key=lambda r: False if not r['todo'] else True, reverse=True) elif task_sort == 'comment': task_rows.sort(key=lambda r: '' if not r['todo'] else r['todo'].comment, reverse=True) - return j2env.get_template('day.html').render(db=self, action=self.prefix+'/day', prev_date=prev_date_str, next_date=next_date_str, task_rows=task_rows) + return j2env.get_template('day.html').render(db=self, action=self.prefix+'/day', prev_date=prev_date_str, next_date=next_date_str, task_rows=task_rows, sort=task_sort) def show_calendar(self, start_date_str, end_date_str): self.t_filter_and = ['calendar'] @@ -333,14 +333,18 @@ class TodoDB(PlomDB): days_to_show[current_date].weekday = datetime.strptime(current_date, DATE_FORMAT).strftime('%A')[:2] return j2env.get_template('calendar.html').render(db=self, days=days_to_show, action=self.prefix+'/calendar', today=str(datetime.now())[:10], start_date=start_date_str, end_date=end_date_str) - def show_todo(self, task_uuid, selected_date): + def show_todo(self, task_uuid, selected_date, referer): + if selected_date not in self.days.keys(): + self.days[selected_date] = self.add_day() if task_uuid in self.days[selected_date].todos: todo = self.days[selected_date].todos[task_uuid] else: todo = self.days[selected_date].add_todo(task_uuid) - return j2env.get_template('todo.html').render(db=self, todo=todo, action=self.prefix+'/todo') + return j2env.get_template('todo.html').render(db=self, todo=todo, action=self.prefix+'/todo', referer=referer) def update_todo_mini(self, task_uuid, date, day_effort, done, importance): + if date not in self.days.keys(): + self.days[date] = self.add_day() if task_uuid in self.days[date].todos.keys(): todo = self.days[date].todos[task_uuid] else: @@ -363,9 +367,9 @@ class TodoDB(PlomDB): todo.comment = comment todo.day_tags = self.collect_tags(day_tags_joined, day_tags_checked) - def show_task(self, id_): + def show_task(self, id_, referer=''): task = self.tasks[id_] if id_ else self.add_task() - return j2env.get_template('task.html').render(db=self, task=task, action=self.prefix+'/task') + return j2env.get_template('task.html').render(db=self, task=task, action=self.prefix+'/task', referer=referer) def update_task(self, id_, title, default_effort, tags_joined, tags_checked, links): task = self.tasks[id_] if id_ in self.tasks.keys() else self.add_task(id_) @@ -455,16 +459,20 @@ class TodoHandler(PlomHandler): del db.selected_day.todos[uuid] if 'choose' in postvars.keys(): for i, uuid in enumerate(postvars['t_uuid']): - uuids = postvars['choose'] + postvars['done'] if 'done' in postvars.keys() else [] - if uuid in uuids or postvars['day_effort'][i] != '' or postvars['importance'][i] != '1.0': + uuids = postvars['choose'] + uuids += postvars['done'] if 'done' in postvars.keys() else [] + if uuid in uuids or postvars['day_effort'][i] != '' or (postvars['importance'][i] not in {'1.0', ''}): done = 'done' in postvars and uuid in postvars['done'] db.update_todo_mini(uuid, db.selected_date, postvars['day_effort'][i], done, postvars['importance'][i]) if 'day_comment' in postvars.keys(): db.selected_day.comment = postvars['day_comment'][0] params_to_encode += [('selected_date', db.selected_date)] - encoded_params = urlencode(params_to_encode) - homepage = f'{parsed_url.path}?{encoded_params}' + if 'referer' in postvars.keys() and len(postvars['referer'][0]) > 0: + homepage = postvars['referer'][0] + else: + encoded_params = urlencode(params_to_encode) + homepage = f'{parsed_url.path}?{encoded_params}' db.write() self.redirect(homepage) @@ -501,6 +509,7 @@ class TodoHandler(PlomHandler): selected_date = t_filter_and = t_filter_not = None hide_unchosen = hide_done = False + referer = params.get('referer', [''])[0] if parsed_url.path in {app_config['prefix'] + '/day', app_config['prefix'] + '/tasks'}: selected_date = get_param('selected_date') if parsed_url.path in {app_config['prefix'] + '/day', app_config['prefix'] + '/tasks', app_config['prefix'] + '/task'}: @@ -516,10 +525,10 @@ class TodoHandler(PlomHandler): elif parsed_url.path == app_config['prefix'] + '/todo': todo_date = params.get('date', [None])[0] task_uuid = params.get('task', [None])[0] - page = db.show_todo(task_uuid, todo_date) + page = db.show_todo(task_uuid, todo_date, referer) elif parsed_url.path == app_config['prefix'] + '/task': id_ = params.get('id', [None])[0] - page = db.show_task(id_) + page = db.show_task(id_, referer) elif parsed_url.path == app_config['prefix'] + '/tasks': page = db.show_tasks() elif parsed_url.path == app_config['prefix'] + '/add_task': diff --git a/todo_templates/day.html b/todo_templates/day.html index 7dd8f66..4f5f1fc 100644 --- a/todo_templates/day.html +++ b/todo_templates/day.html @@ -6,6 +6,7 @@ table.alternating tr:nth-child(even) { table.alternating tr:nth-child(odd) { background-color: #ffffff; } +th.desc { background: linear-gradient(to bottom, white, grey); } td.checkbox, td.number { height: 0.1em; padding: 0em; text-align: center; } td.checkbox { width: 0.1em } td button { height: 1.5em; padding: 0em; margin: 0em } @@ -31,17 +32,24 @@ comment: <input name="day_comment" value="{{ db.selected_day.comment|e }}"> <input type="hidden" name="selected_date" value="{{ db.selected_date }}" /> </p> <table class="alternating"> -<tr><th><a href="?sort=title">task</a></th><th><a href="?sort=chosen">choose?</a></th><th><a href="?sort=done">done?</a></th><th><a href="?sort=default_effort">effort</a></th><th><a href="?sort=importance">importance</a></th><th>edit?</th><th>day tags</th><th><a href="?sort=comment">comment</a></th></tr> +<tr> +<th {% if sort=='title' %}class="desc"{% endif %}><a href="?sort=title">task</a></th> +<th {% if sort=='chosen' %}class="desc"{% endif %}><a href="?sort=chosen">todo</a></th> +<th {% if sort=='done' %}class="desc"{% endif %}><a href="?sort=done">done</a></th> +<th {% if sort=='default_effort' %}class="desc"{% endif %}><a href="?sort=default_effort">effort</a></th> +<th {% if sort=='importance' %}class="desc"{% endif %}><a href="?sort=importance">importance</a></th> +<th>edit?</th><th>day tags</th> +<th {% if sort=='comment' %}class="desc"{% endif %}><a href="?sort=comment">comment</a></th></tr> {% for row in task_rows %} <tr> <input name="t_uuid" value="{{ row.uuid }}" type="hidden" > -<td><details><summary>] <a href="{{db.prefix}}/task?id={{ row.uuid }}" />{{ row.task.current_title|e }}</a></summary>tags: {% for tag in row.task.tags | sort %}<a href="{{db.prefix}}/day?t_and={{tag|e}}">{{ tag }}</a> {% endfor %}</details></td> +<td><details><summary>] <a href="{{db.prefix}}/task?id={{ row.uuid }}&referer=day" />{{ row.task.current_title|e }}</a></summary>tags: {% for tag in row.task.tags | sort %}<a href="{{db.prefix}}/day?t_and={{tag|e}}">{{ tag }}</a> {% endfor %}</details></td> {% if row.todo %} <td class="checkbox"><input name="choose" type="checkbox" value="{{ row.uuid }}" checked></td> <td class="checkbox"><input name="done" type="checkbox" value="{{ row.uuid }}" {% if row.todo.done %}checked{% endif %}></td> <td class="number"><input class="day_effort_input" name="day_effort" type="number" step=0.1 size=8 value="{% if row.todo.day_effort is not none %}{{ row.todo.day_effort }}{% endif %}" placeholder={{ row.task.current_default_effort }} ></td> <td class="number"><input name="importance" type="number" step=0.1 size=8 value="{{row.todo.importance}}" ></td> -<td><a href="{{db.prefix}}/todo?task={{row.uuid}}&date={{db.selected_date}}">edit</a></td> +<td><a href="{{db.prefix}}/todo?task={{row.uuid}}&date={{db.selected_date}}&referer=day">edit</a></td> <td>{% for tag in row.todo.day_tags | sort %}<a href="{{db.prefix}}/tags?t_and={{tag|e}}">{{ tag }}</a> {% endfor %}</td> <td>{{ row.todo.comment|e }}</td> {% else %} @@ -49,7 +57,7 @@ comment: <input name="day_comment" value="{{ db.selected_day.comment|e }}"> <td class="checkbox"><input name="done" type="checkbox" value="{{ row.uuid }}"></td> <td class="number"><input class="day_effort_input" name="day_effort" type="number" step=0.1 size=8 placeholder={{ row.task.current_default_effort }} ></td> <td class="number"><input name="importance" type="number" step=0.1 size=8 value="1.0" ></td> -<td><a href="{{db.prefix}}/todo?task={{row.uuid}}&date={{db.selected_date}}">edit</a></td> +<td><a href="{{db.prefix}}/todo?task={{row.uuid}}&date={{db.selected_date}}&referer=day">edit</a></td> <td></td> <td></td> <td></td> diff --git a/todo_templates/task.html b/todo_templates/task.html index ef2402d..b0ed3e8 100644 --- a/todo_templates/task.html +++ b/todo_templates/task.html @@ -11,6 +11,7 @@ textarea { width: 100% }; <form id="form_to_watch" action="{{action|e}}" method="POST"> <h3>edit task</h3> <input type="hidden" name="id" value="{{ task.id_ }}" /> +<input type="hidden" name="referer" value="{{ referer }}" /> <table> <tr><th>title</th><td class="input"><input name="title" type="text" value="{{ task.title|e }}" /><details><summary>history</summary><ul>{% for k,v in task.title_history.items() | sort(attribute='0', reverse=True) %}<li>{{ k }}: {{ v|e }}{% endfor %}</ul></details></td></tr> <tr><th>default effort</th><td class="input"><input type="number" name="default_effort" value="{{ task.default_effort }}" step=0.1 size=8 required /><details><summary>history</summary><ul>{% for k,v in task.default_effort_history.items() | sort(attribute='0', reverse=True) %}<li>{{ k }}: {{ v|e }}{% endfor %}</ul></details></td></tr> diff --git a/todo_templates/todo.html b/todo_templates/todo.html index 4bf83e3..af48a47 100644 --- a/todo_templates/todo.html +++ b/todo_templates/todo.html @@ -12,6 +12,7 @@ textarea { width: 100% }; <h3>edit todo</h3> <input type="hidden" name="task_uuid" value="{{ todo.task.id_ }}" /> <input type="hidden" name="date" value="{{ todo.day.date }}" /> +<input type="hidden" name="referer" value="{{ referer }}" /> <table> <tr><th>task</th><td><a href="{{db.prefix}}/task?id={{ todo.task.id_ }}">{{ todo.task.title|e }}</a></td></tr> <tr><th>default effort</th><td>{{ todo.default_effort }}</td></tr>