Replace the GnuCash import checkbox column with native multi-select

Selecting bookings to import now uses the Treeview's own multi-selection
(click, Ctrl+click, Shift+click for ranges) instead of a dedicated
checkbox column that had to be clicked precisely -- more standard and
much faster for marking many rows at once.

Bookings matching an existing payment's date+amount are no longer
blocked from selection; they're still flagged (red row, "Bereits
vorhanden"). If any selected booking is such a duplicate, importing now
asks whether to skip those or instead adopt the booking's description
onto the already-recorded payment. That relabeling is handled by a new
repository.update_payment_reference, which only touches the reference
and gnucash_transaction_id fields, leaving date/amount/allocations
untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Marcel Peterkau
2026-08-14 23:43:55 +02:00
co-authored by Claude Sonnet 5
parent e25accd35b
commit 195ae0e228
3 changed files with 196 additions and 50 deletions
+38
View File
@@ -1426,6 +1426,44 @@ class MemberRepository:
)
return payment
def update_payment_reference(
self,
member_id: str,
payment_id: str,
*,
reference: str,
gnucash_transaction_id: str = "",
actor_name: str = "Vorstand",
) -> dict:
"""Relabel an existing payment without touching its date, amount, or
allocations -- used e.g. when a GnuCash import recognizes a booking as
matching an already-recorded payment and the board wants to adopt the
(better) description from the statement instead of re-importing it."""
data = self.get_contributions(member_id)
payment = next(
(item for item in data.payments if str(item.get("payment_id", "")) == payment_id),
None,
)
if payment is None:
raise RepositoryError("Zahlung nicht gefunden.")
gnucash_id = gnucash_transaction_id.strip()
if gnucash_id and gnucash_id != str(payment.get("gnucash_transaction_id", "")):
self._assert_gnucash_id_available(gnucash_id, exclude_payment_id=payment_id)
payment["reference"] = reference.strip()
if gnucash_id:
payment["gnucash_transaction_id"] = gnucash_id
payment["updated_at"] = datetime.now().astimezone().isoformat(timespec="seconds")
self.save_contributions(member_id, data)
self.append_event(
member_id,
event_type="payment_changed",
summary=f"Zahlung geändert: Referenz aktualisiert ({payment['reference']})",
actor_type="user",
actor_name=actor_name,
references={"payment_id": payment_id},
)
return payment
def delete_payment(self, member_id: str, payment_id: str) -> None:
data = self.get_contributions(member_id)
payment = next(