diff --git a/src/ccma/assets/CHANGELOG.json b/src/ccma/assets/CHANGELOG.json index 35db039..817a2e0 100644 --- a/src/ccma/assets/CHANGELOG.json +++ b/src/ccma/assets/CHANGELOG.json @@ -26,7 +26,8 @@ "Der Hausmeister meldet eine überfällige Forderung nicht mehr doppelt als eigene Überfällig- und Mahnungsmeldung; bei Mitgliedern mit aktivem Lastschriftmandat erscheint statt einer Mahnung ein Hinweis, dass der Lastschrifteinzug geprüft werden sollte.", "Die Spaltenbreiten in den Tabellen für Forderungen, Zahlungen, Spenden und Hausmeister-Vorgänge sind jetzt einheitlich: Datum-, Betrag- und Statusspalten haben eine feste Breite, nur die abschließende Beschreibungs- bzw. Referenzspalte passt sich dynamisch an die Fensterbreite an.", "Die Chronik im Mitgliedsfenster nimmt standardmäßig ein Drittel der Fensterbreite ein.", - "Der GnuCash-Import öffnet sich mit 80 % der Bildschirmgröße und erlaubt die Mehrfachauswahl von Buchungen per Klick, Strg+Klick oder Umschalt+Klick; Buchungen, die einer bereits vorhandenen Zahlung entsprechen, können beim Import übersprungen oder mit der Beschreibung aus GnuCash aktualisiert werden." + "Der GnuCash-Import öffnet sich mit 80 % der Bildschirmgröße und erlaubt die Mehrfachauswahl von Buchungen per Klick, Strg+Klick oder Umschalt+Klick; Buchungen, die einer bereits vorhandenen Zahlung entsprechen, können beim Import übersprungen oder mit der Beschreibung aus GnuCash aktualisiert werden.", + "Beim Anklicken einer noch nicht zugeordneten Forderung oder Spende im Zahlungsfenster wird der Betrag automatisch mit dem sinnvollen Vorschlag vorausgefüllt." ] }, { diff --git a/src/ccma/ui/payment_dialog.py b/src/ccma/ui/payment_dialog.py index ff41443..2a60c65 100644 --- a/src/ccma/ui/payment_dialog.py +++ b/src/ccma/ui/payment_dialog.py @@ -42,12 +42,14 @@ class _AllocationTable: claim_allocations: dict[str, str], donation_allocations: dict[str, str], on_change: Callable[[], None], + get_payment_amount: Callable[[], Decimal], ): self.repository = repository self.member_id = member_id self.claim_allocations = claim_allocations self.donation_allocations = donation_allocations self.on_change = on_change + self.get_payment_amount = get_payment_amount # Fixed snapshot of what this payment already covered when the dialog opened. # Capacities are computed against this baseline rather than the live, editable # dicts above -- otherwise "Maximal zuordenbar" would inflate every time the @@ -182,7 +184,23 @@ class _AllocationTable: return kind, target_id = self._target(selected[0]) allocations = self.claim_allocations if kind == "claim" else self.donation_allocations - self.amount_var.set(allocations.get(target_id, "0.00")) + current = allocations.get(target_id) + if current: + # Already allocated: show the existing amount so it can be reviewed/edited. + self.amount_var.set(current) + return + # Not yet allocated: suggest whichever is smaller -- what this claim/donation + # still needs, or what's left of the payment -- so the common case is just + # "click the row, then Zuordnung setzen". + capacity = (self.claim_capacity if kind == "claim" else self.donation_capacity)[target_id] + free = max(self._payment_amount() - self.total_allocated(), Decimal("0")) + self.amount_var.set(money_text(min(capacity, free))) + + def _payment_amount(self) -> Decimal: + try: + return self.get_payment_amount() + except ValueError: + return Decimal("0") def _set(self) -> None: selected = self.tree.selection() @@ -314,6 +332,7 @@ class PaymentCreateDialog(tk.Toplevel): claim_allocations=self.claim_allocations, donation_allocations=self.donation_allocations, on_change=self._refresh_totals, + get_payment_amount=self._current_payment_amount, ) ttk.Label(self, textvariable=self.total_var, style="Mono.TLabel").grid( @@ -328,10 +347,13 @@ class PaymentCreateDialog(tk.Toplevel): ).pack(side="left") self._refresh_totals() + def _current_payment_amount(self) -> Decimal: + return decimal_value(self.variables["amount"].get()) + def _refresh_totals(self) -> None: allocated = self.allocation_table.total_allocated() if self.allocation_table else Decimal("0") try: - payment_amount = decimal_value(self.variables["amount"].get()) + payment_amount = self._current_payment_amount() free = payment_amount - allocated self.total_var.set(f"Zugeordnet: {money_text(allocated)} EUR · Frei: {money_text(free)} EUR") except (ValueError, InvalidOperation): @@ -448,6 +470,7 @@ class PaymentEditDialog(tk.Toplevel): claim_allocations=self.claim_allocations, donation_allocations=self.donation_allocations, on_change=self._refresh_totals, + get_payment_amount=self._current_payment_amount, ) ttk.Label(self, textvariable=self.total_var, style="Mono.TLabel").grid( @@ -474,10 +497,13 @@ class PaymentEditDialog(tk.Toplevel): except tk.TclError: return + def _current_payment_amount(self) -> Decimal: + return decimal_value(self.variables["amount"].get()) + def _refresh_totals(self) -> None: allocated = self.allocation_table.total_allocated() if self.allocation_table else Decimal("0") try: - payment_amount = decimal_value(self.variables["amount"].get()) + payment_amount = self._current_payment_amount() free = payment_amount - allocated self.total_var.set( f"Zugeordnet: {money_text(allocated)} EUR · Frei: {money_text(free)} EUR"