ctx['id'] = id_
ctx['dat_lines'] = [dl if raw else dl.as_dict
for dl in booking.booked_lines]
+ ctx['sink_error'] = booking.sink_error
ctx['valid'] = self.server.ledger.bookings_valid_up_incl(id_)
if not raw:
ctx['all_accounts'] = sorted(self.server.ledger.accounts.keys())
"""Return error if registered on attempt to parse into BookingLine."""
return '; '.join(self.booked.errors) if self.booked else ''
- @property
- def is_questionable(self) -> bool:
- """Return whether line be questionable per associated _Booking."""
- return bool(self.booking and self.booking.is_questionable)
-
@property
def raw_nbsp(self) -> str:
"""Return .raw but ensure whitespace as , and at least one."""
# calculate .account_changes
changes = _Wealth()
sink_account = None
+ self.sink_error = ''
self.account_changes: dict[str, _Wealth] = {}
for transfer_line in [tl for tl in self._transfer_lines
if not tl.errors]:
self.account_changes[transfer_line.account] = _Wealth()
if transfer_line.amount is None:
if sink_account:
- transfer_line.errors += ['too many sinks']
- sink_account = transfer_line.account
+ self.sink_error = 'too many sinks'
+ else:
+ sink_account = transfer_line.account
continue
change = _Wealth({transfer_line.currency: transfer_line.amount})
self.account_changes[transfer_line.account] += change
if sink_account:
self.account_changes[sink_account] += changes.as_sink
elif not changes.sink_empty:
- self._transfer_lines[-1].errors += ['needed sink missing']
+ self.sink_error = 'needed sink missing'
def recalc_prev_next(self, bookings: list[Self]) -> None:
"""Assuming .id_ to be index in bookings, link prev + next bookings."""
@property
def is_questionable(self) -> bool:
- """Whether lines count any errors."""
+ """Whether lines count any errors, or add up to a .sink_error."""
+ if self.sink_error:
+ return True
for _ in [bl for bl in [self.intro_line] + self._transfer_lines
if bl.errors]:
return True
{% macro css_errors() %}
-td.invalid, tr.warning td.invalid { background-color: #ff0000; }
+span.sink_error, td.invalid, tr.warning td.invalid { background-color: #ff0000; }
{% endmacro %}
{% macro css_ledger_index_col() %}
-table.ledger tr > td:first-child { background-color: white; text-align: right; }
+table.ledger tr > td:first-child { text-align: right; }
{% endmacro %}
{% if (not raw) and dat_line.prev_line_empty %}
<tr ><td> </td></tr>
{% endif %}
- <tr class="alternating{% if dat_line.is_questionable %} warning{% endif %}">
+ <tr class="alternating">
- <td{% if dat_line.is_intro %} id="{{dat_line.booking_id}}"{% endif %}>
+ <td{% if dat_line.is_intro %} id="{{dat_line.booking_id}}"{% endif %} {% if dat_line.booking.sink_error %}class="invalid"{% endif %}>
{% if dat_line.is_intro %}
<a href="#{{dat_line.booking_id}}">[#]</a>
{{ table_dat_lines_action_button(dat_line, "moveup", "^", dat_line.booking.can_move(1)) }}
-{% macro edit_bar(target, id) %}
+{% macro edit_bar(target, id, sink_error) %}
<span class="disable_on_change">
<a href="/bookings/{{id-1}}">prev</a> · <a href="/bookings/{{id+1}}">next</a>
</span>
<a href="/edit_{{target}}/{{id}}">switch to {{target}}</a> · <a href="/balance?up_incl={{id}}">balance after</a> · <a href="/ledger_structured/#{{id}}">in ledger</a>
</span>
<hr />
+{% if sink_error %}
+<span class="sink_error">balancing error: {{ sink_error }}</span>
+<hr />
+{% endif %}
{% endmacro %}
{% block content %}
<form action="/edit_raw/{{id}}" method="POST">
-{{ macros.edit_bar("structured", id) }}
+{{ macros.edit_bar("structured", id, sink_error) }}
<textarea name="booking" cols=100 rows=100 oninput="taint()">
{% for dat_line in dat_lines %}{{ dat_line.raw }}
{% endfor %}</textarea>
{% block content %}
<form action="/edit_structured/{{id}}" method="POST">
-{{ macros.edit_bar("raw", id) }}
+{{ macros.edit_bar("raw", id, sink_error) }}
<input type="button" onclick="mirror()" value="mirror" class="disable_on_change">
<input type="button" onclick="fill_sink()" value="fill sink" class="disable_on_change">
|