Merge branch 'dev' into feature/read-only-store

dev gained the editable mail templates, which live in the store like everything
else -- so they follow the same read-only rules: the options dialog skips saving
them, save_mail_template() reports the store instead of a raw PermissionError,
and a store that cannot keep its own copy simply renders from the shipped
default.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Marcel Peterkau
2026-08-28 21:26:40 +02:00
co-authored by Claude Opus 5
24 changed files with 2276 additions and 168 deletions
+16
View File
@@ -38,6 +38,7 @@ from ccma.ui.labels import display_label, storage_key
from ccma.ui.messages import MessageAction, MessageBannerList, TabMessage
from ccma.ui.payment_dialog import PaymentCreateDialog, PaymentEditDialog
from ccma.ui.scrolling import ScrollableFrame
from ccma.ui.welcome_mail_dialog import WelcomeMailDialog
# Shared column sizing for the ledger-style tables (Forderungen/Zahlungen/Spenden): date-
# and amount-like columns get the same fixed width, status columns get a third more
@@ -355,6 +356,13 @@ class MemberTab(ttk.Frame):
self.claims.grid(row=1, column=0, sticky="nsew")
self.claims.bind("<Double-1>", lambda _event: self._open_selected_claim())
self.claims.bind("<Return>", lambda _event: self._open_selected_claim())
claim_actions = ttk.Frame(contribution_tab)
claim_actions.grid(row=2, column=0, sticky="e", pady=(8, 0))
ttk.Button(
claim_actions,
text="Willkommens- und Erstrechnungsmail",
command=self._send_welcome_mail,
).pack(side="left")
contribution_override_tab.columnconfigure(0, weight=1)
contribution_override_tab.rowconfigure(1, weight=1)
@@ -1185,6 +1193,14 @@ class MemberTab(ttk.Frame):
except OSError as exc:
messagebox.showerror("Datei konnte nicht geöffnet werden", str(exc), parent=self)
def _send_welcome_mail(self) -> None:
WelcomeMailDialog(self, self.repository, self.member_id, self._welcome_mail_sent)
def _welcome_mail_sent(self) -> None:
self._refresh_documents()
self._refresh_events()
self.on_changed()
def _create_document(self) -> None:
DocumentTemplateDialog(
self,