mirror of
https://git.hiabuto.net/C3MA/CCMA.git
synced 2026-08-25 15:05:18 +02:00
feat: add OpenDocument PDF templates
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import tkinter as tk
|
||||
from collections.abc import Callable
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
from tkinter import messagebox, ttk
|
||||
|
||||
from ccma.services.documents import DocumentError, DocumentService, GeneratedDocument
|
||||
from ccma.storage.repository import MemberRepository, RepositoryError
|
||||
|
||||
|
||||
class DocumentTemplateDialog(tk.Toplevel):
|
||||
def __init__(
|
||||
self,
|
||||
master: tk.Misc,
|
||||
repository: MemberRepository,
|
||||
member_id: str,
|
||||
on_generated: Callable[[Path], None],
|
||||
*,
|
||||
claim_id: str | None = None,
|
||||
reminder_id: str | None = None,
|
||||
):
|
||||
super().__init__(master)
|
||||
self.service = DocumentService(repository)
|
||||
self.member_id = member_id
|
||||
self.claim_id = claim_id
|
||||
self.reminder_id = reminder_id
|
||||
self.on_generated = on_generated
|
||||
self.templates = self.service.compatible_templates(
|
||||
has_claim=claim_id is not None,
|
||||
has_reminder=reminder_id is not None,
|
||||
)
|
||||
self.template_by_label = {
|
||||
f"{template.name} ({template.relative_path})": template for template in self.templates
|
||||
}
|
||||
self.title("Dokument aus Template erzeugen")
|
||||
self.transient(master.winfo_toplevel())
|
||||
self.resizable(False, False)
|
||||
self.template_var = tk.StringVar()
|
||||
self.filename_var = tk.StringVar()
|
||||
self._build_ui()
|
||||
self.bind("<Escape>", lambda _event: self.destroy())
|
||||
self.after_idle(self._grab_if_visible)
|
||||
|
||||
def _grab_if_visible(self) -> None:
|
||||
try:
|
||||
if self.winfo_exists() and self.winfo_viewable():
|
||||
self.grab_set()
|
||||
except tk.TclError:
|
||||
pass
|
||||
|
||||
def _build_ui(self) -> None:
|
||||
frame = ttk.Frame(self, padding=18)
|
||||
frame.pack(fill="both", expand=True)
|
||||
ttk.Label(frame, text="OpenDocument-Template").grid(
|
||||
row=0, column=0, sticky="w", pady=5, padx=(0, 12)
|
||||
)
|
||||
template_box = ttk.Combobox(
|
||||
frame,
|
||||
textvariable=self.template_var,
|
||||
values=list(self.template_by_label),
|
||||
state="readonly",
|
||||
width=56,
|
||||
)
|
||||
template_box.grid(row=0, column=1, sticky="ew", pady=5)
|
||||
template_box.bind("<<ComboboxSelected>>", lambda _event: self._template_selected())
|
||||
ttk.Label(frame, text="PDF-Dateiname").grid(
|
||||
row=1, column=0, sticky="w", pady=5, padx=(0, 12)
|
||||
)
|
||||
ttk.Entry(frame, textvariable=self.filename_var, width=58).grid(
|
||||
row=1, column=1, sticky="ew", pady=5
|
||||
)
|
||||
context = "Mitglied"
|
||||
if self.claim_id:
|
||||
context += " · Forderung"
|
||||
if self.reminder_id:
|
||||
context += " · ausgewählte Mahnung"
|
||||
ttk.Label(frame, text=f"Kontext: {context}", style="Mono.TLabel").grid(
|
||||
row=2, column=0, columnspan=2, sticky="w", pady=(8, 0)
|
||||
)
|
||||
ttk.Label(
|
||||
frame,
|
||||
text="Das PDF wird unter files/documents in der Mitgliederakte abgelegt.",
|
||||
style="Muted.TLabel",
|
||||
).grid(row=3, column=0, columnspan=2, sticky="w", pady=(4, 0))
|
||||
buttons = ttk.Frame(frame)
|
||||
buttons.grid(row=4, column=0, columnspan=2, sticky="e", pady=(18, 0))
|
||||
ttk.Button(buttons, text="Abbrechen", command=self.destroy).pack(side="left", padx=(0, 8))
|
||||
self.generate_button = ttk.Button(
|
||||
buttons,
|
||||
text="PDF erzeugen",
|
||||
style="Accent.TButton",
|
||||
command=self._generate,
|
||||
)
|
||||
self.generate_button.pack(side="left")
|
||||
if self.template_by_label:
|
||||
self.template_var.set(next(iter(self.template_by_label)))
|
||||
self._template_selected()
|
||||
else:
|
||||
self.generate_button.configure(state="disabled")
|
||||
ttk.Label(
|
||||
frame,
|
||||
text="Für diesen Kontext ist kein passendes Template vorhanden.",
|
||||
style="Warning.TLabel",
|
||||
).grid(row=5, column=0, columnspan=2, sticky="w", pady=(12, 0))
|
||||
|
||||
def _template_selected(self) -> None:
|
||||
template = self.template_by_label.get(self.template_var.get())
|
||||
if template:
|
||||
self.filename_var.set(f"{date.today().isoformat()} - {template.name}.pdf")
|
||||
|
||||
def _generate(self) -> None:
|
||||
template = self.template_by_label.get(self.template_var.get())
|
||||
if template is None:
|
||||
messagebox.showerror("Template auswählen", "Bitte ein Template auswählen.", parent=self)
|
||||
return
|
||||
self.generate_button.configure(state="disabled")
|
||||
self.configure(cursor="watch")
|
||||
self.update_idletasks()
|
||||
try:
|
||||
generated: GeneratedDocument = self.service.generate(
|
||||
template,
|
||||
self.member_id,
|
||||
output_name=self.filename_var.get(),
|
||||
claim_id=self.claim_id,
|
||||
reminder_id=self.reminder_id,
|
||||
)
|
||||
except (DocumentError, RepositoryError, OSError) as exc:
|
||||
messagebox.showerror("Dokument konnte nicht erzeugt werden", str(exc), parent=self)
|
||||
self.generate_button.configure(state="normal")
|
||||
self.configure(cursor="")
|
||||
return
|
||||
self.destroy()
|
||||
self.on_generated(generated.path)
|
||||
messagebox.showinfo("Dokument erzeugt", f"PDF gespeichert:\n{generated.path}", parent=self.master)
|
||||
Reference in New Issue
Block a user