mirror of
https://git.hiabuto.net/C3MA/CCMA.git
synced 2026-08-25 15:05:18 +02:00
feat: extend inventory and administration workflows
This commit is contained in:
@@ -88,8 +88,10 @@ class ClaimTab(ttk.Frame):
|
||||
footer.columnconfigure(0, weight=1)
|
||||
self.hold_button = ttk.Button(footer, text="Mahnsperre setzen", command=self._toggle_hold)
|
||||
self.hold_button.grid(row=0, column=0, sticky="w")
|
||||
self.edit_button = ttk.Button(footer, text="Forderung bearbeiten", command=self._edit_claim)
|
||||
self.edit_button.grid(row=0, column=1, sticky="e", padx=(0, 8))
|
||||
self.cancel_button = ttk.Button(footer, text="Forderung stornieren", command=self._cancel_claim)
|
||||
self.cancel_button.grid(row=0, column=1, sticky="e")
|
||||
self.cancel_button.grid(row=0, column=2, sticky="e")
|
||||
|
||||
def _build_ledger(self) -> None:
|
||||
ledger = ttk.Frame(self, padding=12)
|
||||
@@ -185,6 +187,7 @@ class ClaimTab(ttk.Frame):
|
||||
self.summary_vars["balance"].set(f"{money_text(balance)} EUR")
|
||||
self.summary_vars["status"].set(CLAIM_STATUS_LABELS.get(status, status.upper()))
|
||||
self.cancel_button.configure(state="disabled" if status == "cancelled" else "normal")
|
||||
self.edit_button.configure(state="disabled" if status == "cancelled" else "normal")
|
||||
self.hold_button.configure(text="Mahnsperre aufheben" if hold.get("active") else "Mahnsperre setzen")
|
||||
self._render_ledger()
|
||||
|
||||
@@ -478,6 +481,16 @@ class ClaimTab(ttk.Frame):
|
||||
return
|
||||
self._changed()
|
||||
|
||||
def _edit_claim(self) -> None:
|
||||
ClaimEditDialog(
|
||||
self,
|
||||
self.repository,
|
||||
self.member_id,
|
||||
self.claim_id,
|
||||
self.claim,
|
||||
self._changed,
|
||||
)
|
||||
|
||||
def _changed(self) -> None:
|
||||
self.refresh()
|
||||
self.on_changed()
|
||||
@@ -502,6 +515,68 @@ class _Dialog(tk.Toplevel):
|
||||
ttk.Button(buttons, text="Speichern", style="Accent.TButton", command=command).pack(side="left")
|
||||
|
||||
|
||||
class ClaimEditDialog(_Dialog):
|
||||
def __init__(self, master, repository, member_id, claim_id, claim, on_saved):
|
||||
super().__init__(master, "Forderung bearbeiten", on_saved)
|
||||
self.repository = repository
|
||||
self.member_id = member_id
|
||||
self.claim_id = claim_id
|
||||
items = claim_items(claim)
|
||||
base_item = next(
|
||||
(item for item in items if str(item.get("type", "")) == "base"),
|
||||
items[0] if items else {},
|
||||
)
|
||||
self.variables = {
|
||||
"title": tk.StringVar(value=str(claim.get("title", ""))),
|
||||
"due_date": tk.StringVar(
|
||||
value=format_date_for_display(str(claim.get("due_date", "")))
|
||||
),
|
||||
"base_amount": tk.StringVar(
|
||||
value=str(base_item.get("amount", claim.get("amount", "")))
|
||||
),
|
||||
"description": tk.StringVar(value=str(base_item.get("description", ""))),
|
||||
}
|
||||
fields = (
|
||||
("Titel", "title"),
|
||||
(f"Fällig am ({date_input_hint()})", "due_date"),
|
||||
("Grundbetrag", "base_amount"),
|
||||
("Beschreibung der Grundposition", "description"),
|
||||
)
|
||||
for row, (label, key) in enumerate(fields):
|
||||
ttk.Label(self.frame, text=label).grid(
|
||||
row=row, column=0, sticky="w", pady=5, padx=(0, 12)
|
||||
)
|
||||
ttk.Entry(self.frame, textvariable=self.variables[key], width=52).grid(
|
||||
row=row, column=1, sticky="ew", pady=5
|
||||
)
|
||||
ttk.Label(
|
||||
self.frame,
|
||||
text=(
|
||||
"Der Grundbetrag ändert nur die Grundposition. Weitere Positionen, "
|
||||
"zum Beispiel Mahngebühren, bleiben erhalten."
|
||||
),
|
||||
style="Mono.TLabel",
|
||||
wraplength=520,
|
||||
).grid(row=len(fields), column=0, columnspan=2, sticky="w", pady=(8, 0))
|
||||
self._buttons(len(fields) + 1, self._save)
|
||||
|
||||
def _save(self) -> None:
|
||||
try:
|
||||
self.repository.update_claim(
|
||||
self.member_id,
|
||||
self.claim_id,
|
||||
title=self.variables["title"].get(),
|
||||
due_date=self.variables["due_date"].get(),
|
||||
base_amount=self.variables["base_amount"].get(),
|
||||
description=self.variables["description"].get(),
|
||||
)
|
||||
except RepositoryError as exc:
|
||||
messagebox.showerror("Forderung konnte nicht gespeichert werden", str(exc), parent=self)
|
||||
return
|
||||
self.destroy()
|
||||
self.on_saved()
|
||||
|
||||
|
||||
class ItemDialog(_Dialog):
|
||||
def __init__(self, master, repository, member_id, claim_id, on_saved):
|
||||
super().__init__(master, "Forderungsposition hinzufügen", on_saved)
|
||||
@@ -634,7 +709,11 @@ class AllocatePaymentDialog(_Dialog):
|
||||
self.repository, self.member_id, self.claim_id = repository, member_id, claim_id
|
||||
data = repository.get_contributions(member_id)
|
||||
self.payment_by_label = {}
|
||||
for payment in data.payments:
|
||||
for payment in sorted(
|
||||
data.payments,
|
||||
key=lambda item: (str(item.get("date", "")), str(item.get("created_at", ""))),
|
||||
reverse=True,
|
||||
):
|
||||
payment_id = str(payment.get("payment_id", ""))
|
||||
available = decimal_value(payment.get("amount", "0")) - payment_allocated_total(data, payment_id)
|
||||
if available <= 0:
|
||||
@@ -655,10 +734,23 @@ class AllocatePaymentDialog(_Dialog):
|
||||
width=60,
|
||||
)
|
||||
combo.grid(row=0, column=1, pady=5)
|
||||
ttk.Label(self.frame, text="Betrag").grid(row=1, column=0, sticky="w", pady=5, padx=(0, 12))
|
||||
ttk.Entry(self.frame, textvariable=self.amount_var).grid(row=1, column=1, sticky="ew", pady=5)
|
||||
if not self.payment_by_label:
|
||||
ttk.Label(
|
||||
self.frame,
|
||||
text="Für dieses Mitglied gibt es keine Zahlung mit freiem Restbetrag.",
|
||||
style="Mono.TLabel",
|
||||
).grid(row=1, column=0, columnspan=2, sticky="w", pady=(3, 5))
|
||||
amount_row = 2
|
||||
else:
|
||||
amount_row = 1
|
||||
ttk.Label(self.frame, text="Betrag").grid(
|
||||
row=amount_row, column=0, sticky="w", pady=5, padx=(0, 12)
|
||||
)
|
||||
ttk.Entry(self.frame, textvariable=self.amount_var).grid(
|
||||
row=amount_row, column=1, sticky="ew", pady=5
|
||||
)
|
||||
combo.bind("<<ComboboxSelected>>", lambda _event: self._select(balance))
|
||||
self._buttons(2, self._save)
|
||||
self._buttons(amount_row + 1, self._save)
|
||||
|
||||
def _select(self, balance):
|
||||
_payment_id, available = self.payment_by_label[self.payment_var.get()]
|
||||
|
||||
Reference in New Issue
Block a user