+ booking_lines += [{
+ 'i': i,
+ 'acc': account,
+ 'amt': amount,
+ 'curr': currency if currency else '€',
+ 'comment': comments[i],
+ 'comm_cols': len(comments[i])}]
+ content += tmpl.render(
+ action=action,
+ date=date,
+ desc=desc,
+ head_comment=head_comment,
+ booking_lines=booking_lines,
+ datalist_sets=datalist_sets,
+ start=start,
+ end=end)
+ return content
+
+ def move_up(self, start, end):
+ prev_booking = None
+ for redir_nth, b in enumerate(self.bookings):
+ if b.start_line >= start:
+ break
+ prev_booking = b
+ start_at = prev_booking.start_line
+ self.make_move(start, end, start_at)
+ return redir_nth - 1
+
+ def move_down(self, start, end):
+ next_booking = None
+ for redir_nth, b in enumerate(self.bookings):
+ 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)
+ return redir_nth
+
+ def make_move(self, start, end, start_at):
+ lines = self.get_lines(start, end)
+ total_lines = self.real_lines[:start] + self.real_lines[end:]
+ self.write_lines_in_total_lines_at(total_lines, start_at, lines)
+
+ def booking_lines_from_postvars(self, postvars):
+ add_empty_line = None
+ date = postvars['date'][0]
+ description = postvars['description'][0]
+ start_comment = postvars['line_0_comment'][0]
+ start_line = f'{date} {description}'
+ if start_comment.rstrip() != '':
+ start_line += f' ; {start_comment}'
+ lines = [start_line]
+ if 'line_0_add' in postvars.keys():
+ add_empty_line = 0
+ i = j = 1
+ while f'line_{i}_comment' in postvars.keys():
+ if f'line_{i}_delete' in postvars.keys():
+ i += 1
+ continue
+ elif f'line_{i}_delete_after' in postvars.keys():
+ break
+ elif f'line_{i}_add' in postvars.keys():
+ add_empty_line = j
+ account = postvars[f'line_{i}_account'][0]
+ amount = postvars[f'line_{i}_amount'][0]
+ currency = postvars[f'line_{i}_currency'][0]
+ comment = postvars[f'line_{i}_comment'][0]
+ i += 1
+ new_main = f' {account} {amount}'
+ if '' == new_main.rstrip() == comment.rstrip(): # don't write empty lines, ignore currency if nothing else set
+ continue
+ if len(amount.rstrip()) > 0:
+ new_main += f' {currency}'
+ j += 1
+ new_line = new_main
+ if comment.rstrip() != '':
+ new_line += f' ; {comment}'
+ lines += [new_line]
+ if 'add_sink' in postvars.keys():
+ temp_lines = lines.copy() + ['_']
+ try:
+ 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}']
+ except PlomException:
+ pass
+ if 'add_taxes' in postvars.keys():
+ lines += self.add_taxes(lines, finish=False)
+ elif 'add_taxes2' in postvars.keys():
+ lines += self.add_taxes(lines, finish=True)
+ return lines, add_empty_line
+
+
+
+class LedgerHandler(PlomHandler):
+
+ def app_init(self, handler):
+ default_path = '/ledger'
+ handler.add_route('GET', default_path, self.forward_gets)
+ handler.add_route('POST', default_path, self.forward_posts)
+ return 'ledger', default_path
+
+ def do_POST(self):
+ self.try_do(self.forward_posts)
+
+ def forward_posts(self):
+ prefix = self.apps['ledger'] if hasattr(self, 'apps') else ''
+ parsed_url = urlparse(self.path)
+ length = int(self.headers['content-length'])
+ postvars = parse_qs(self.rfile.read(length).decode(), keep_blank_values=1)
+ print("DEBUG", postvars['start'], postvars['end'])
+ start = int(postvars['start'][0])
+ end = int(postvars['end'][0])
+ db = LedgerDB(prefix)
+ add_empty_line = None
+ lines = []
+ # get inputs
+ if prefix + '/add_structured' == parsed_url.path and not 'revert' in postvars.keys():
+ lines, add_empty_line = db.booking_lines_from_postvars(postvars)
+ elif prefix + '/add_free' == parsed_url.path and not 'revert' in postvars.keys():
+ lines = postvars['booking'][0].splitlines()
+ # validate where appropriate
+ if ('save' in postvars.keys()) or ('check' in postvars.keys()):
+ _, _ = parse_lines(lines)
+ # if saving, process where to and where to redirect after
+ if 'save' in postvars.keys():
+ last_date = str(datetime.now())[:10]
+ if len(db.bookings) > 0:
+ last_date = db.bookings[-1].date_string
+ target_date = last_date[:]
+ first_line_tokens = lines[0].split() if len(lines) > 0 else ''
+ first_token = first_line_tokens[0] if len(first_line_tokens) > 0 else ''
+ try:
+ datetime.strptime(first_token, '%Y-%m-%d')
+ target_date = first_token
+ except ValueError:
+ pass
+ if start == end == 0:
+ start = db.insert_at_date(lines, target_date)
+ nth = db.get_nth_for_booking_of_start_line(start)
+ else:
+ new_start = db.update(start, end, lines, target_date)
+ nth = db.get_nth_for_booking_of_start_line(new_start)
+ if new_start > start:
+ nth -= 1
+ self.redirect(prefix + f'/#{nth}')
+ # otherwise just re-build editing form
+ else:
+ if prefix + '/add_structured' == parsed_url.path:
+ edit_content = db.add_structured(start, end, temp_lines=lines, add_empty_line=add_empty_line)
+ else:
+ edit_content = db.add_free(start, end)
+ header = jinja2.Template(html_head).render(prefix=prefix)
+ self.send_HTML(header + edit_content)
+
+ def do_GET(self):
+ self.try_do(self.forward_gets)
+
+ def forward_gets(self):
+ prefix = self.apps['ledger'] if hasattr(self, 'apps') else ''
+ parsed_url = urlparse(self.path)
+ params = parse_qs(parsed_url.query)
+ start = int(params.get('start', ['0'])[0])
+ end = int(params.get('end', ['0'])[0])
+ db = LedgerDB(prefix=prefix)
+ if parsed_url.path == prefix + '/balance':
+ stop = params.get('stop', [None])[0]
+ page = db.balance_as_html(stop)
+ elif parsed_url.path == prefix + '/add_free':
+ page = db.add_free(start, end)
+ elif parsed_url.path == prefix + '/add_structured':
+ page = db.add_structured(start, end)
+ elif parsed_url.path == prefix + '/copy_free':
+ page = db.add_free(start, end, copy=True)
+ elif parsed_url.path == prefix + '/copy_structured':
+ page = db.add_structured(start, end, copy=True)
+ elif parsed_url.path == prefix + '/move_up':
+ nth = db.move_up(start, end)
+ self.redirect(prefix + f'/#{nth}')
+ return
+ elif parsed_url.path == prefix + '/move_down':
+ nth = db.move_down(start, end)
+ self.redirect(prefix + f'/#{nth}')
+ return
+ else:
+ page = db.ledger_as_html()
+ header = jinja2.Template(html_head).render(prefix=prefix)
+ self.send_HTML(header + page)
+
+
+
+if __name__ == "__main__":
+ run_server(server_port, LedgerHandler)