Neuer Kunde anlegen ohne Lizenz

Dieser Commit ist enthalten in:
2025-06-10 00:35:41 +02:00
Ursprung 7f9849d879
Commit 0a4d79ec6d
4 geänderte Dateien mit 131 neuen und 0 gelöschten Zeilen

Datei anzeigen

@@ -2185,6 +2185,61 @@ def edit_customer(customer_id):
return render_template("edit_customer.html", customer=customer, licenses=licenses, username=session.get('username'))
@app.route("/customer/create", methods=["GET", "POST"])
@login_required
def create_customer():
"""Erstellt einen neuen Kunden ohne Lizenz"""
if request.method == "POST":
name = request.form.get('name')
email = request.form.get('email')
is_test = request.form.get('is_test') == 'on'
if not name or not email:
flash("Name und E-Mail sind Pflichtfelder!", "error")
return render_template("create_customer.html", username=session.get('username'))
conn = get_connection()
cur = conn.cursor()
try:
# Prüfen ob E-Mail bereits existiert
cur.execute("SELECT id, name FROM customers WHERE email = %s", (email,))
existing = cur.fetchone()
if existing:
flash(f"Ein Kunde mit der E-Mail '{email}' existiert bereits: {existing[1]}", "error")
return render_template("create_customer.html", username=session.get('username'))
# Kunde erstellen
cur.execute("""
INSERT INTO customers (name, email, created_at, is_test)
VALUES (%s, %s, %s, %s) RETURNING id
""", (name, email, datetime.now(), is_test))
customer_id = cur.fetchone()[0]
conn.commit()
# Audit-Log
log_audit('CREATE', 'customer', customer_id,
new_values={
'name': name,
'email': email,
'is_test': is_test
})
flash(f"Kunde '{name}' wurde erfolgreich angelegt!", "success")
return redirect(f"/customer/edit/{customer_id}")
except Exception as e:
conn.rollback()
flash(f"Fehler beim Anlegen des Kunden: {str(e)}", "error")
return render_template("create_customer.html", username=session.get('username'))
finally:
cur.close()
conn.close()
# GET Request - Formular anzeigen
return render_template("create_customer.html", username=session.get('username'))
@app.route("/customer/delete/<int:customer_id>", methods=["POST"])
@login_required
def delete_customer(customer_id):

Datei anzeigen

@@ -0,0 +1,74 @@
{% extends "base.html" %}
{% block title %}Neuer Kunde{% endblock %}
{% block content %}
<div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>👤 Neuer Kunde anlegen</h2>
<div>
<a href="/" class="btn btn-secondary">📊 Dashboard</a>
<a href="/customers" class="btn btn-secondary">👥 Zurück zur Übersicht</a>
</div>
</div>
<div class="card">
<div class="card-body">
<form method="post" action="/customer/create" accept-charset="UTF-8">
<div class="row g-3">
<div class="col-md-6">
<label for="name" class="form-label">Kundenname <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="name" name="name"
placeholder="Firmenname oder Vor- und Nachname"
accept-charset="UTF-8" required autofocus>
<div class="form-text">Der Name des Kunden oder der Firma</div>
</div>
<div class="col-md-6">
<label for="email" class="form-label">E-Mail <span class="text-danger">*</span></label>
<input type="email" class="form-control" id="email" name="email"
placeholder="kunde@beispiel.de"
accept-charset="UTF-8" required>
<div class="form-text">Kontakt-E-Mail-Adresse des Kunden</div>
</div>
</div>
<div class="form-check mt-3">
<input class="form-check-input" type="checkbox" id="isTest" name="is_test">
<label class="form-check-label" for="isTest">
<i class="fas fa-flask"></i> Als Testdaten markieren
<small class="text-muted">(Kunde wird von der Software ignoriert)</small>
</label>
</div>
<div class="alert alert-info mt-4" role="alert">
<i class="fas fa-info-circle"></i>
<strong>Hinweis:</strong> Nach dem Anlegen des Kunden können Sie direkt Lizenzen für diesen Kunden erstellen.
</div>
<div class="mt-4">
<button type="submit" class="btn btn-primary">💾 Kunde anlegen</button>
<a href="/customers" class="btn btn-secondary">Abbrechen</a>
</div>
</form>
</div>
</div>
</div>
<!-- Flash Messages -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="position-fixed bottom-0 end-0 p-3" style="z-index: 11">
{% for category, message in messages %}
<div class="toast show align-items-center text-white bg-{{ 'danger' if category == 'error' else 'success' }} border-0" role="alert">
<div class="d-flex">
<div class="toast-body">
{{ message }}
</div>
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
</div>
</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% endblock %}

Datei anzeigen

@@ -32,6 +32,7 @@
<i class="bi bi-layout-split"></i> Kombinierte Ansicht
</a>
<a href="/" class="btn btn-secondary">📊 Dashboard</a>
<a href="/customer/create" class="btn btn-primary">👤 Neuer Kunde</a>
<a href="/create" class="btn btn-primary"> Neue Lizenz</a>
<a href="/batch" class="btn btn-primary">🔑 Batch-Lizenzen</a>
<div class="btn-group">

Datei anzeigen

@@ -7,6 +7,7 @@
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>👥 Kunden & Lizenzen</h2>
<div>
<a href="/customer/create" class="btn btn-primary">👤 Neuer Kunde</a>
<a href="/create" class="btn btn-success"> Neue Lizenz</a>
<a href="/batch" class="btn btn-primary">🔑 Batch-Lizenzen</a>
<div class="btn-group">