changes
This commit is contained in:
+38
-4
@@ -3236,13 +3236,48 @@ def admin_invoices():
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
flash("Rechnung angelegt.", "success")
|
flash("Rechnung angelegt.", "success")
|
||||||
|
|
||||||
|
# NEU HINZUGEFÜGT: Die Logik für das Update (Aktualisieren) Formular
|
||||||
|
elif action == "update" and invoice_id:
|
||||||
|
invoice_number = _sanitize_text(request.form.get("invoice_number") or "", 120)
|
||||||
|
period = _sanitize_text(request.form.get("period") or "", 20)
|
||||||
|
due_date = _sanitize_text(request.form.get("due_date") or "", 20)
|
||||||
|
status = _sanitize_text(request.form.get("status") or "Zu prüfen", 40)
|
||||||
|
amount_text = _sanitize_text(request.form.get("amount_eur") or "0", 20)
|
||||||
|
|
||||||
|
try:
|
||||||
|
amount = float(amount_text.replace(',', '.'))
|
||||||
|
except ValueError:
|
||||||
|
amount = 0.0
|
||||||
|
|
||||||
|
update_data = {
|
||||||
|
"invoice_number": invoice_number,
|
||||||
|
"period": period,
|
||||||
|
"amount_eur": amount,
|
||||||
|
"status": status,
|
||||||
|
"due_date": due_date
|
||||||
|
}
|
||||||
|
|
||||||
|
# PDF nur überschreiben, wenn auch ein neues hochgeladen wurde
|
||||||
|
pdf_file = request.files.get("invoice_pdf")
|
||||||
|
if pdf_file and pdf_file.filename:
|
||||||
|
pdf_path = _save_invoice_pdf(pdf_file, invoice_number)
|
||||||
|
if pdf_path:
|
||||||
|
update_data["pdf_path"] = pdf_path
|
||||||
|
|
||||||
|
col.update_one(
|
||||||
|
{"_id": ObjectId(invoice_id)},
|
||||||
|
{"$set": update_data}
|
||||||
|
)
|
||||||
|
flash("Rechnung erfolgreich aktualisiert.", "success")
|
||||||
|
|
||||||
elif action == "delete" and invoice_id:
|
elif action == "delete" and invoice_id:
|
||||||
col.delete_one({"_id": ObjectId(invoice_id)})
|
col.delete_one({"_id": ObjectId(invoice_id)})
|
||||||
flash("Rechnung gelöscht.", "success")
|
flash("Rechnung gelöscht.", "success")
|
||||||
else:
|
else:
|
||||||
flash("Ungültige Aktion.", "error")
|
flash("Ungültige Aktion.", "error")
|
||||||
except Exception:
|
except Exception as e:
|
||||||
|
print(f"Fehler bei admin_invoices: {e}") # Ins Log schreiben
|
||||||
flash("Rechnungsverwaltung fehlgeschlagen.", "error")
|
flash("Rechnungsverwaltung fehlgeschlagen.", "error")
|
||||||
finally:
|
finally:
|
||||||
if client:
|
if client:
|
||||||
@@ -3268,7 +3303,7 @@ def admin_invoices():
|
|||||||
if not isinstance(item.get("booking_data"), dict):
|
if not isinstance(item.get("booking_data"), dict):
|
||||||
item["booking_data"] = {}
|
item["booking_data"] = {}
|
||||||
|
|
||||||
except PyMongoError:
|
except Exception: # Geändert von PyMongoError zu general Exception für Sicherheit
|
||||||
flash("Rechnungen konnten nicht geladen werden.", "error")
|
flash("Rechnungen konnten nicht geladen werden.", "error")
|
||||||
finally:
|
finally:
|
||||||
if client:
|
if client:
|
||||||
@@ -3284,7 +3319,7 @@ def admin_invoices():
|
|||||||
if not isinstance(prov.get("booking_data"), dict):
|
if not isinstance(prov.get("booking_data"), dict):
|
||||||
prov["booking_data"] = {}
|
prov["booking_data"] = {}
|
||||||
|
|
||||||
except PyMongoError:
|
except Exception:
|
||||||
flash("Instanz-Anfragen konnten nicht geladen werden.", "error")
|
flash("Instanz-Anfragen konnten nicht geladen werden.", "error")
|
||||||
finally:
|
finally:
|
||||||
if 'req_client' in locals() and req_client:
|
if 'req_client' in locals() and req_client:
|
||||||
@@ -3293,7 +3328,6 @@ def admin_invoices():
|
|||||||
users = _list_users_for_admin()
|
users = _list_users_for_admin()
|
||||||
return render_template("admin_invoices.html", invoices=invoices, users=users, provision_requests=instance_requests)
|
return render_template("admin_invoices.html", invoices=invoices, users=users, provision_requests=instance_requests)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/datenschutz')
|
@app.route('/datenschutz')
|
||||||
def datenschutz():
|
def datenschutz():
|
||||||
return render_template("datenschutz.html")
|
return render_template("datenschutz.html")
|
||||||
|
|||||||
@@ -27,7 +27,16 @@
|
|||||||
<input type="text" name="period" placeholder="Zeitraum (MM/YYYY)" required>
|
<input type="text" name="period" placeholder="Zeitraum (MM/YYYY)" required>
|
||||||
<input type="text" name="amount_eur" placeholder="Betrag in EUR" required>
|
<input type="text" name="amount_eur" placeholder="Betrag in EUR" required>
|
||||||
<input type="text" name="due_date" placeholder="Fälligkeit (YYYY-MM-DD)">
|
<input type="text" name="due_date" placeholder="Fälligkeit (YYYY-MM-DD)">
|
||||||
<input type="text" name="status" placeholder="Status (Zu prüfen, Geprüft, Bezahlt)">
|
|
||||||
|
<!-- NEU: Dropdown für Status beim Erstellen -->
|
||||||
|
<select name="status">
|
||||||
|
<option value="Zu prüfen">Zu prüfen</option>
|
||||||
|
<option value="In Bearbeitung">In Bearbeitung</option>
|
||||||
|
<option value="Geprüft">Geprüft</option>
|
||||||
|
<option value="Bezahlt">Bezahlt</option>
|
||||||
|
<option value="Storniert">Storniert</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
<input type="file" name="invoice_pdf" accept="application/pdf">
|
<input type="file" name="invoice_pdf" accept="application/pdf">
|
||||||
<button type="submit">Rechnung anlegen</button>
|
<button type="submit">Rechnung anlegen</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -38,12 +47,14 @@
|
|||||||
<h3>{{ item.invoice_number }}</h3>
|
<h3>{{ item.invoice_number }}</h3>
|
||||||
<p><strong>Nutzer:</strong> {{ item.username }} | <strong>Zeitraum:</strong> {{ item.period }}</p>
|
<p><strong>Nutzer:</strong> {{ item.username }} | <strong>Zeitraum:</strong> {{ item.period }}</p>
|
||||||
<p><strong>Betrag:</strong> {{ '%.2f'|format(item.amount_eur) }} EUR | <strong>Status:</strong> {{ item.status }} | <strong>Fälligkeit:</strong> {{ item.due_date }}</p>
|
<p><strong>Betrag:</strong> {{ '%.2f'|format(item.amount_eur) }} EUR | <strong>Status:</strong> {{ item.status }} | <strong>Fälligkeit:</strong> {{ item.due_date }}</p>
|
||||||
|
|
||||||
{% if item.source == 'booking_payment' %}
|
{% if item.source == 'booking_payment' %}
|
||||||
<p><strong>Buchung:</strong> {{ item.booking_package_label or item.booking_package }} | <strong>Flow:</strong> {{ item.booking_flow }}</p>
|
<p><strong>Buchung:</strong> {{ item.booking_package_label or item.booking_package }} | <strong>Flow:</strong> {{ item.booking_flow }}</p>
|
||||||
<p><strong>Zugewiesener Admin:</strong> {{ item.assigned_admin_display_name or item.assigned_admin_username or 'Nicht gesetzt' }}{% if item.assigned_admin_email %} | <strong>E-Mail:</strong> {{ item.assigned_admin_email }}{% endif %}</p>
|
<p><strong>Zugewiesener Admin:</strong> {{ item.assigned_admin_display_name or item.assigned_admin_username or 'Nicht gesetzt' }}{% if item.assigned_admin_email %} | <strong>E-Mail:</strong> {{ item.assigned_admin_email }}{% endif %}</p>
|
||||||
<p><strong>Unterlagen:</strong> {{ item.paperwork_status or 'Offen' }}{% if item.consent_accepted %} | Einwilligung bestätigt{% endif %}</p>
|
<p><strong>Unterlagen:</strong> {{ item.paperwork_status or 'Offen' }}{% if item.consent_accepted %} | Einwilligung bestätigt{% endif %}</p>
|
||||||
<p><strong>Kontaktdaten:</strong> {{ item.booking_data.get('contact_person', '-') }} | {{ item.booking_data.get('contact_email', '-') }} | {{ item.booking_data.get('billing_city', '-') }}</p>
|
<p><strong>Kontaktdaten:</strong> {{ item.booking_data.get('contact_person', '-') }} | {{ item.booking_data.get('contact_email', '-') }} | {{ item.booking_data.get('billing_city', '-') }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<div style="margin: 0.5rem 0; padding: 0.5rem; background: #f4f8fa; border-radius: 8px;">
|
<div style="margin: 0.5rem 0; padding: 0.5rem; background: #f4f8fa; border-radius: 8px;">
|
||||||
{% if item.pdf_path %}
|
{% if item.pdf_path %}
|
||||||
<p style="margin:0.2rem 0;"><strong>Rechnungs-PDF:</strong>
|
<p style="margin:0.2rem 0;"><strong>Rechnungs-PDF:</strong>
|
||||||
@@ -61,6 +72,7 @@
|
|||||||
<p style="margin:0.2rem 0; color: #777;"><strong>Hauptvertrag:</strong> Noch nicht in MongoDB hochgeladen</p>
|
<p style="margin:0.2rem 0; color: #777;"><strong>Hauptvertrag:</strong> Noch nicht in MongoDB hochgeladen</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form method="post" class="inline-form" enctype="multipart/form-data">
|
<form method="post" class="inline-form" enctype="multipart/form-data">
|
||||||
<input type="hidden" name="action" value="update">
|
<input type="hidden" name="action" value="update">
|
||||||
<input type="hidden" name="invoice_id" value="{{ item.id }}">
|
<input type="hidden" name="invoice_id" value="{{ item.id }}">
|
||||||
@@ -68,10 +80,20 @@
|
|||||||
<input type="text" name="period" value="{{ item.period }}" placeholder="Zeitraum">
|
<input type="text" name="period" value="{{ item.period }}" placeholder="Zeitraum">
|
||||||
<input type="text" name="amount_eur" value="{{ item.amount_eur }}" placeholder="Betrag">
|
<input type="text" name="amount_eur" value="{{ item.amount_eur }}" placeholder="Betrag">
|
||||||
<input type="text" name="due_date" value="{{ item.due_date }}" placeholder="Fälligkeit">
|
<input type="text" name="due_date" value="{{ item.due_date }}" placeholder="Fälligkeit">
|
||||||
<input type="text" name="status" value="{{ item.status }}" placeholder="Status">
|
|
||||||
|
<!-- NEU: Dropdown für Status beim Aktualisieren (mit dynamischer Vorauswahl) -->
|
||||||
|
<select name="status">
|
||||||
|
<option value="Zu prüfen" {% if item.status == 'Zu prüfen' %}selected{% endif %}>Zu prüfen</option>
|
||||||
|
<option value="In Bearbeitung" {% if item.status == 'In Bearbeitung' %}selected{% endif %}>In Bearbeitung</option>
|
||||||
|
<option value="Geprüft" {% if item.status == 'Geprüft' %}selected{% endif %}>Geprüft</option>
|
||||||
|
<option value="Bezahlt" {% if item.status == 'Bezahlt' %}selected{% endif %}>Bezahlt</option>
|
||||||
|
<option value="Storniert" {% if item.status == 'Storniert' %}selected{% endif %}>Storniert</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
<input type="file" name="invoice_pdf" accept="application/pdf">
|
<input type="file" name="invoice_pdf" accept="application/pdf">
|
||||||
<button type="submit">Aktualisieren</button>
|
<button type="submit">Aktualisieren</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="action" value="delete">
|
<input type="hidden" name="action" value="delete">
|
||||||
<input type="hidden" name="invoice_id" value="{{ item.id }}">
|
<input type="hidden" name="invoice_id" value="{{ item.id }}">
|
||||||
@@ -93,8 +115,8 @@
|
|||||||
.inline-form { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.45rem; margin-top: 0.6rem; }
|
.inline-form { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 0.45rem; margin-top: 0.6rem; }
|
||||||
input, select { width: 100%; border: 1px solid #c9d8e3; border-radius: 10px; padding: 0.52rem; font: inherit; background: #fff; }
|
input, select { width: 100%; border: 1px solid #c9d8e3; border-radius: 10px; padding: 0.52rem; font: inherit; background: #fff; }
|
||||||
a { color: #0a4c74; font-weight: 700; }
|
a { color: #0a4c74; font-weight: 700; }
|
||||||
button { border: 1px solid #0a4c74; background: linear-gradient(120deg, #0c5a86 0%, #08486c 100%); color: #fff; padding: 0.45rem 0.8rem; border-radius: 999px; font-weight: 700; }
|
button { border: 1px solid #0a4c74; background: linear-gradient(120deg, #0c5a86 0%, #08486c 100%); color: #fff; padding: 0.45rem 0.8rem; border-radius: 999px; font-weight: 700; cursor: pointer; }
|
||||||
button.danger { border-color: #d04a49; background: #fff; color: #922e2e; margin-top: 0.55rem; }
|
button.danger { border-color: #d04a49; background: #fff; color: #922e2e; margin-top: 0.55rem; }
|
||||||
@media (max-width: 980px) { .layout { grid-template-columns: 1fr; } .inline-form { grid-template-columns: 1fr; } }
|
@media (max-width: 980px) { .layout { grid-template-columns: 1fr; } .inline-form { grid-template-columns: 1fr; } }
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user