""" Flask CLI-Befehle zur Datenbank-Initialisierung und zum Reset. Befehle (aufgerufen via Flask CLI): flask --app wsgi:app init-db -- Schema + Musterdaten anlegen flask --app wsgi:app reset-db -- alles bis auf SysAdmin löschen init-db ist idempotent: bereits vorhandene Rollen/Kunden werden nicht doppelt angelegt. reset-db fragt standardmäßig zur Bestätigung; mit --yes wird die Abfrage übersprungen. :author: Mistral Vibe :date: 2026-09-02 :version: 1.0 """ import click from flask import Flask from db import dbapp, dbauth def register_cli_commands(app: Flask): """Registriert die CLI-Befehle init-db und reset-db auf der Flask-App.""" @app.cli.command("init-db") def init_db(): """Initialisiert die Datenbanken und legt Musterdaten an.""" click.echo("Initialisiere auth.db ...") from auth.model import checkdb as auth_checkdb auth_checkdb.checkupdates() _seed_app_roles() click.echo("Initialisiere kbp_crm.db ...") from crm.model import checkdb as crm_checkdb crm_checkdb.checkupdates() _seed_muster_kunden() _seed_muster_projekte() _seed_muster_kontaktadressen() _seed_muster_calllogs() click.echo("Fertig.") @app.cli.command("reset-db") @click.option("--yes", is_flag=True, help="Bestätigungsabfrage überspringen") def reset_db(yes): """Setzt die Datenbanken zurück, behält den SysAdmin.""" if not yes: click.confirm( "Wirklich alle Daten löschen? Der SysAdmin bleibt erhalten.", abort=True, ) click.echo("Setze kbp_crm.db zurück ...") _reset_appdb() click.echo("Setze auth.db zurück (SysAdmin bleibt) ...") _reset_authdb() _seed_app_roles() click.echo("Fertig.") def _seed_app_roles(): """ Legt die App-Rollen Mitarbeiter und KundenManager idempotent an und ordnet sie der ersten Application zu. AppAdmin existiert bereits (wird in auth/model/checkdb._db_V01_01 angelegt). """ from auth.model import Application, Role session = dbauth.session application = Application.query.first() rollen = [ ("User", "Mitarbeiter"), ("KundenManager", "Kunden-Manager"), ] for roleid, rolename in rollen: role = Role.query.filter(Role.roleid == roleid).first() if role is None: role = Role() role.roleid = roleid role.name = rolename session.add(role) if application is not None and role not in application.roles: application.roles.append(role) session.commit() def _seed_muster_kunden(): """ Legt die drei Muster-Kunden an, falls die kunden-Tabelle noch leer ist. """ from crm.model import Kunde session = dbapp.session if session.query(Kunde).count() > 0: return muster = [ Kunde(name="Musterfirma GmbH", strasse="Musterstraße 1", plz="12345", ort="Musterstadt", land="Deutschland"), Kunde(name="Beispiel AG", strasse="Beispielweg 2", plz="54321", ort="Beispielstadt", land="Deutschland"), Kunde(name="Test Unternehmen", strasse="Testallee 3", plz="67890", ort="Testdorf", land="Österreich"), ] for kunde in muster: session.add(kunde) session.commit() def _seed_muster_projekte(): """ Legt für jeden Muster-Kunden 1 bis 3 Muster-Projekte an, falls die projekte-Tabelle noch leer ist. """ import random from crm.model import Kunde, Projekt session = dbapp.session if session.query(Projekt).count() > 0: return kunden = session.query(Kunde).order_by(Kunde.id).all() vorlagen = [ ("Website-Relaunch", "Neugestaltung der Unternehmenswebsite"), ("E-Commerce Plattform", "Online-Shop Entwicklung"), ("CRM-System", "Kundenbeziehungsmanagement"), ("Mobile App", "iOS- und Android-Entwicklung"), ("SEO-Optimierung", "Suchmaschinenoptimierung"), ] verantwortliche = [ "Max Mustermann", "Anna Schmidt", "Peter Müller", "Lisa Bauer", "Thomas Becker", ] rng = random.Random(42) vorlagen_idx = 0 for kunde in kunden: anzahl = rng.randint(1, 3) for _ in range(anzahl): name, zweck = vorlagen[vorlagen_idx % len(vorlagen)] vorlagen_idx += 1 projekt = Projekt() projekt.kunden_id = kunde.id projekt.projektname = name projekt.zweck = zweck projekt.verantwortlicher = rng.choice(verantwortliche) projekt.startdatum = "2024-0{monat}-1{tag}".format( monat=rng.randint(1, 9), tag=rng.randint(0, 9) ) session.add(projekt) session.commit() def _seed_muster_kontaktadressen(): """ Legt für jedes Muster-Projekt 1 bis 3 Kontaktadressen an, falls die kontaktadressen-Tabelle noch leer ist. """ import random from crm.model import Projekt, Kontaktadresse session = dbapp.session if session.query(Kontaktadresse).count() > 0: return projekte = session.query(Projekt).order_by(Projekt.id).all() vorlagen = [ ("Herr", "Thomas Becker", "Becker Webdesign GmbH", "Geschäftsführer"), ("Frau", "Sandra Klein", "Klein Marketing", "Marketingleiterin"), ("Herr", "Michael Wagner", "Wagner Online Shop", "IT-Leiter"), ("Frau", "Julia Hoffmann", "Hoffmann Consulting", "Beraterin"), ("Herr", "Stefan Roth", "Roth IT Solutions", "Technischer Leiter"), ] orte = [ ("Industriestr. 12", "45131", "Essen", "Deutschland"), ("Königsallee 5", "40212", "Düsseldorf", "Deutschland"), ("Hauptstr. 88", "50667", "Köln", "Deutschland"), ("Marienplatz 3", "80331", "München", "Deutschland"), ] rng = random.Random(123) vorlagen_idx = 0 for projekt in projekte: anzahl = rng.randint(1, 3) for _ in range(anzahl): anrede, name, firma, position = vorlagen[vorlagen_idx % len(vorlagen)] vorlagen_idx += 1 strasse, plz, ort, land = rng.choice(orte) ka = Kontaktadresse() ka.projekt_id = projekt.id ka.anrede = anrede ka.name = name ka.firma = firma ka.position = position ka.telefon = "+49 {vorwahl} {nummer}".format( vorwahl=rng.randint(100, 999), nummer=rng.randint(100000, 999999) ) ka.email = name.lower().replace(" ", ".") + "@example.de" ka.strasse = strasse ka.plz = plz ka.ort = ort ka.land = land ka.notiz = "" session.add(ka) session.commit() def _seed_muster_calllogs(): """ Legt für jedes Muster-Projekt 2 bis 5 Gesprächsnotizen an, falls die call_logs-Tabelle noch leer ist. """ import random from crm.model import Projekt, CallLog session = dbapp.session if session.query(CallLog).count() > 0: return projekte = session.query(Projekt).order_by(Projekt.id).all() betreffvorlagen = [ "Anforderungen klären", "Feedback zum Design", "Technische Anforderungen", "Schulungstermin", "Feature-Request", "Budgetgespräch", "Projekt-Review", ] notizvorlagen = [ "Kunde möchte responsive Design und neue Farbgestaltung. Budget noch offen.", "Design-Entwürfe wurden positiv aufgenommen. Kleine Änderungen an der Navigation nötig.", "Payment-Gateway und Versand-Schnittstellen müssen integriert werden.", "Schulung für 10 Mitarbeiter geplant. Raum noch zu buchen.", "Kunde wünscht Push-Benachrichtigungen und Offline-Modus.", "", ] ansprechpartner = ["Herr Schmidt", "Frau Müller", "Herr Weber", "Frau Bauer", "Herr König"] rng = random.Random(456) for projekt in projekte: anzahl = rng.randint(2, 5) for _ in range(anzahl): log = CallLog() log.projekt_id = projekt.id monat = rng.randint(1, 9) tag = rng.randint(1, 28) log.datum = "2024-0{m}-{t}".format(m=monat, t=tag) if monat < 10 else "2024-{m}-{t}".format(m=monat, t=tag) log.uhrzeit_beginn = "{h:02d}:{min:02d}".format( h=rng.randint(8, 17), min=rng.randint(0, 59) ) log.dauer = str(rng.randint(15, 90)) log.betreff = rng.choice(betreffvorlagen) log.name_ansprechpartner = rng.choice(ansprechpartner) log.telefon = "+49 {v} {n}".format( v=rng.randint(100, 999), n=rng.randint(100000, 999999) ) log.notiz = rng.choice(notizvorlagen) wiedervorlage_monat = monat + 1 if monat < 12 else 1 log.wiedervorlage_datum = "2024-0{m}-{t}".format(m=wiedervorlage_monat, t=tag) if wiedervorlage_monat < 10 else "2024-{m}-{t}".format(m=wiedervorlage_monat, t=tag) log.erledigt = rng.choice([True, False]) session.add(log) session.commit() def _reset_appdb(): """ Setzt die CRM-Datenbank zurück: alle Tabellen löschen und neu anlegen (Schema + Systeminfo, keine Musterdaten). """ from crm.model import checkdb as crm_checkdb dbapp.drop_all(bind_key="appdb") dbapp.session.remove() crm_checkdb.checkupdates() def _reset_authdb(): """ Setzt die Auth-Datenbank zurück: alle Tabellen löschen und neu anlegen. Dadurch entsteht der frische Initialzustand mit SysAdmin-User, SysAdmin- und AppAdmin-Rolle sowie der Application (entspricht auth/model/checkdb._db_V01_01). """ from auth.model import checkdb as auth_checkdb dbauth.drop_all(bind_key="auth") dbauth.session.remove() auth_checkdb.checkupdates()