""" Flask CLI-Befehle zur Datenbank-Initialisierung und zum Reset. Befehle (aufgerufen via Flask CLI): flask --app wsgi:app init-db -- Schema anlegen/migrieren + Musterdaten flask --app wsgi:app reset-db -- alles bis auf SysAdmin löschen init-db legt das Schema an bzw. migriert es und setzt danach die CRM-Geschäftsdaten zurück: Sämtliche Kunden samt aller abhängigen Daten (Kontakte, Projekte, Kontaktadressen, Gesprächsnotizen, Projekt-Zuordnungen) werden gelöscht und die Musterdaten werden komplett neu angelegt. Die Tag-Taxonomie (tags) bleibt erhalten, da es sich um Stammdaten handelt. reset-db fragt standardmäßig zur Bestätigung; mit --yes wird die Abfrage übersprungen. :author: Mistral Vibe :date: 2026-09-02 :version: 1.1 """ from datetime import date, timedelta 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() click.echo("Lösche vorhandene CRM-Geschäftsdaten ...") _purge_crm_daten() click.echo("Lege Musterdaten an ...") _seed_musterdaten() 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 _purge_crm_daten(): """ Löscht sämtliche CRM-Geschäftsdaten vor dem Neuanlegen der Musterdaten. Die Löschreihenfolge beachtet die Fremdschlüsselbeziehungen: erst die n:m-Verknüpfungen der Gesprächsnotizen, dann die Notizen selbst, danach die Kontaktadressen, die Projekt-Nutzer-Zuordnungen, die Projekte, die Kontakte und zuletzt die Kunden. Die Tag-Taxonomie (tags) bleibt erhalten, da Tags Stammdaten und keine Musterdaten sind. """ from crm.model import ( CallLogTag, CallLog, Kontaktadresse, ProjektUser, Projekt, Kontakt, Kunde, ) session = dbapp.session session.query(CallLogTag).delete(synchronize_session=False) session.query(CallLog).delete(synchronize_session=False) session.query(Kontaktadresse).delete(synchronize_session=False) session.query(ProjektUser).delete(synchronize_session=False) session.query(Projekt).delete(synchronize_session=False) session.query(Kontakt).delete(synchronize_session=False) session.query(Kunde).delete(synchronize_session=False) session.commit() # --------------------------------------------------------------------------- # Musterdaten: drei Kunden, jeder mit eigenen Kontakten und je drei # Telefon-Akquise-Projekten. Die Daten sind bewusst so aufgebaut, dass # jeder Kontakte- und Kontaktadressen-Name genau einmal in der gesamten # Datenbank vorkommt und kein Projektname bei zwei Kunden existiert. # Die Kontaktadressen sind die Akquise-Ziele (angerufene Firmen), die # Gesprächsnotizen werden daraus automatisch abgeleitet. # --------------------------------------------------------------------------- _MUSTERDATEN = [ { "name": "Nordwerk Metallbau GmbH & Co. KG", "strasse": "Hamburger Str. 118", "plz": "21079", "ort": "Hamburg", "land": "Deutschland", "kontakte": [ { "anrede": "Herr", "name": "Dipl.-Ing. Markus Haverkamp", "position": "Einkaufsleiter", "telefon": "+49 40 790 214 66", "email": "haverkamp@nordwerk-metallbau.de", "notiz": "Entscheider für Rahmenverträge; telefonisch am besten nach 15 Uhr erreichbar.", }, { "anrede": "Frau", "name": "Katrin Ohmsen", "position": "Vertriebsleitung", "telefon": "+49 40 790 214 12", "email": "ohmsen@nordwerk-metallbau.de", "notiz": "Steuert die laufenden Kampagnen mit uns; erwartet jeden Freitag ein kurzes Zwischen-Reporting.", }, ], "projekte": [ { "projektname": "Akquise Stahlträgerprogramm 2026 – Dachstühle und Hallenbau", "zweck": "Telefonische Neukundenansprache bei Bauunternehmen in Norddeutschland, um das überarbeitete Stahlträgerprogramm zu positionieren. Ziel: 400 geführte Gespräche bis Jahresende, davon 60 Angebotsanfragen.", "verantwortlicher": "Miriam Falkner", "startdatum": date(2026, 8, 3), "kontaktadressen": [ { "anrede": "Herr", "name": "Torben Block", "firma": "Block Bauunternehmung GmbH", "position": "Einkaufsleiter", "telefon": "+49 40 6899 2140", "email": "t.block@block-bau-hamburg.de", "strasse": "Wandsbeker Chaussee 210", "plz": "22089", "ort": "Hamburg", "land": "Deutschland", "notiz": "Tauscht die Rahmenverträge jährlich aus; entscheidet gemeinsam mit der Kalkulation.", }, { "anrede": "Frau", "name": "Silke Reimers", "firma": "Reimers Dachbaustoffe Nord", "position": "Leiterin Kalkulation", "telefon": "+49 431 556 872", "email": "s.reimers@reimers-dachbaustoffe.de", "strasse": "Kieler Str. 31", "plz": "24116", "ort": "Kiel", "land": "Deutschland", "notiz": "Plant mehrere Hallenprojekte für das kommende Jahr.", }, { "anrede": "Herr", "name": "Gero Timmermann", "firma": "Timmermann Hallenbau", "position": "Geschäftsführer", "telefon": "+49 511 987 4432", "email": "g.timmermann@timmermann-hallenbau.de", "strasse": "Am Lindener Hafen 12", "plz": "30453", "ort": "Hannover", "land": "Deutschland", "notiz": "Hat großes Interesse an Schnellmontage-Systemen signalisiert.", }, ], }, { "projektname": "Neukundengewinnung Zulieferer Ostösterreich", "zweck": "Kaltakquise bei Stahl- und Metallzulieferern in Wien, Niederösterreich und Oberösterreich zur Erschließung neuer Lieferbeziehungen. Ziel: 250 Kontakte, davon 40 qualifizierte Terminvorschläge für den Außendienst.", "verantwortlicher": "Dominik Reiss", "startdatum": date(2026, 8, 17), "kontaktadressen": [ { "anrede": "Herr", "name": "Wolfgang Gruber", "firma": "Gruber Stahlhandel", "position": "Vertriebsleiter", "telefon": "+43 1 982 76 11", "email": "w.gruber@gruber-stahlhandel.at", "strasse": "Laxenburger Str. 84", "plz": "1100", "ort": "Wien", "land": "Österreich", "notiz": "Bezieht Trägerprofile bislang aus Deutschland; offen für österreichische Bezugsquellen.", }, { "anrede": "Frau", "name": "Martina Ehgartner", "firma": "Ehgartner Metallwerke", "position": "Einkaufsleitung", "telefon": "+43 732 455 210", "email": "m.ehgartner@ehgartner-metallwerke.at", "strasse": "Wiener Str. 145", "plz": "4020", "ort": "Linz", "land": "Österreich", "notiz": "Kauft halbjährlich größere Kontingente; Verträge laufen über die Zentrale.", }, { "anrede": "Herr", "name": "Kurt Strubreiter", "firma": "Strubreiter Blechtechnik", "position": "Inhaber", "telefon": "+43 2628 741 33", "email": "office@strubreiter-blechtechnik.at", "strasse": "Betriebsstr. 7", "plz": "2700", "ort": "Wiener Neustadt", "land": "Österreich", "notiz": "Familienbetrieb; entscheidet kurzfristig, wenn die Konditionen stimmen.", }, ], }, { "projektname": "Cross-Selling Schutzgitter und Tore im Bestand", "zweck": "Nachverkauf im Bestandskundenstamm: Kunden der Jahre 2022 bis 2025 werden telefonisch auf das neue Sortiment an Schutzgittern und Industrietoren angesprochen. Ziel: 300 Bestandskunden kontaktiert, Angebotsversand innerhalb von 48 Stunden.", "verantwortlicher": "Aylin Kocabiyik", "startdatum": date(2026, 9, 1), "kontaktadressen": [ { "anrede": "Frau", "name": "Petra Wilhelmi", "firma": "Wilhelmi Logistikzentrum", "position": "Technische Leiterin", "telefon": "+49 421 338 7762", "email": "p.wilhelmi@wilhelmi-logistik.de", "strasse": "Universitätsallee 25", "plz": "28359", "ort": "Bremen", "land": "Deutschland", "notiz": "Sanierung der Tore für nächstes Jahr geplant; Budget muss noch beantragt werden.", }, { "anrede": "Herr", "name": "Heino Sievers", "firma": "Sievers Agrartechnik", "position": "Kundendienstleiter", "telefon": "+49 441 763 519", "email": "h.sievers@sievers-agrartechnik.de", "strasse": "Boschdamm 18", "plz": "26122", "ort": "Oldenburg", "land": "Deutschland", "notiz": "Sucht Ersatzteile für ältere Hallentore; auch Interesse an Wartungsverträgen.", }, { "anrede": "Herr", "name": "Dietrich Voskamp", "firma": "Voskamp Landbau", "position": "Betriebsleiter", "telefon": "+49 541 229 834", "email": "d.voskamp@voskamp-landbau.de", "strasse": "Natruper-Tor-Wall 70", "plz": "49074", "ort": "Osnabrück", "land": "Deutschland", "notiz": "Erweitert den Maschinenpark; über Neuanschaffungen entscheidet der Sohn mit.", }, ], }, ], }, { "name": "Vitalis Apothekenverbund eG", "strasse": "Kaisersstr. 77", "plz": "76133", "ort": "Karlsruhe", "land": "Deutschland", "kontakte": [ { "anrede": "Frau", "name": "Dr. Ingrid Halbach", "position": "Mitglied der Geschäftsleitung", "telefon": "+49 721 508 3390", "email": "halbach@vitalis-apotheken.de", "notiz": "Apothekerin; legt besonderen Wert auf seriös formulierte Gesprächsleitfäden.", }, { "anrede": "Herr", "name": "Jörn Kiebitz", "position": "Leiter Filialmarketing", "telefon": "+49 721 508 3377", "email": "kiebitz@vitalis-apotheken.de", "notiz": "Liefert die Filial- und Zielgruppenlisten für unsere Kampagnen; Ansprechpartner für Abstimmungstermine.", }, ], "projekte": [ { "projektname": "Terminierung Arzneimittelberatung – Vitalis Filialen Süd", "zweck": "Telefonische Terminierung kostenpflichtiger Arzneimittelberatungen für Mitgliedsapotheken in Baden-Württemberg und Bayern. Ziel: 120 bestätigte Beratungstermine pro Monat bei maximal drei Absagen je Termin.", "verantwortlicher": "Tobias Lenzen", "startdatum": date(2026, 9, 7), "kontaktadressen": [ { "anrede": "Frau", "name": "Dr. Marlene Vogt", "firma": "Vogt-Apotheke Stuttgart-West", "position": "Inhaberin", "telefon": "+49 711 563 448", "email": "m.vogt@vogt-apotheke-stuttgart.de", "strasse": "Kernerstr. 31", "plz": "70182", "ort": "Stuttgart", "land": "Deutschland", "notiz": "Führt die Beratungen selbst durch; Terminvorschläge möglichst vormittags.", }, { "anrede": "Herr", "name": "Ingo Pasternak", "firma": "Pasternak Apotheke", "position": "Filialleiter", "telefon": "+49 89 448 2120", "email": "i.pasternak@pasternak-apotheke.de", "strasse": "Leopoldstr. 90", "plz": "80802", "ort": "München", "land": "Deutschland", "notiz": "Stellvertretung zu Servicezwecken; Zeitfenster dienstags und donnerstags.", }, { "anrede": "Frau", "name": "Regine Axt", "firma": "Axt Rathaus-Apotheke", "position": "Approbierte Apothekerin", "telefon": "+49 721 976 512", "email": "r.axt@axt-apotheke.de", "strasse": "Am Stadtgarten 2", "plz": "76133", "ort": "Karlsruhe", "land": "Deutschland", "notiz": "Neu in der Mitgliedschaft; wünscht ein Einführungsgespräch.", }, ], }, { "projektname": "Rückgewinnung inaktiver Bonuskarten-Kunden", "zweck": "Reaktivierung von rund 5.000 nicht mehr aktiven Bonuskarten-Kunden per Telefon mit anschließender Follow-up-Mail. Ziel: 8 Prozent Rückkehrquote im ersten Quartal, Nachverkauf über die Filialen.", "verantwortlicher": "Camilla Brugger", "startdatum": date(2026, 8, 24), "kontaktadressen": [ { "anrede": "Herr", "name": "Falk Rüdiger", "firma": "Sonnen-Apotheke Freiburg", "position": "Inhaber", "telefon": "+49 761 388 224", "email": "f.ruediger@sonnen-apotheke-freiburg.de", "strasse": "Salzstr. 60", "plz": "79098", "ort": "Freiburg", "land": "Deutschland", "notiz": "Wertet die Rückkehrquote monatlich aus; erwartet Zahlen zum Quartalsende.", }, { "anrede": "Frau", "name": "Heidrun Clauß", "firma": "Clauß Apotheke am Markt", "position": "Inhaberin", "telefon": "+49 351 469 887", "email": "h.clauss@clauss-apotheke.de", "strasse": "Wilsdruffer Str. 24", "plz": "01067", "ort": "Dresden", "land": "Deutschland", "notiz": "Ist mit der bisherigen Rücklaufquote unzufrieden und drängt auf eine neue Ansprache.", }, { "anrede": "Herr", "name": "Marek Sawatzki", "firma": "Sawatzki Apotheke Leipzig-Süd", "position": "Fachapotheker", "telefon": "+49 341 225 904", "email": "m.sawatzki@sawatzki-apotheke.de", "strasse": "Karl-Liebknecht-Str. 105", "plz": "04275", "ort": "Leipzig", "land": "Deutschland", "notiz": "Möchte besonders die junge Zielgruppe wieder ansprechen.", }, ], }, { "projektname": "Up-Selling Homöopathie-Eigenmarke bei Mitgliedsapotheken", "zweck": "Telefonische Empfehlung der Eigenmarke 'Vitalis Natur' an alle 180 Mitgliedsapotheken. Ziel: Listung in mindestens 60 Apotheken bis zum Ende des ersten Quartals, durchschnittliches Bestellvolumen von 1.200 Euro je Listung.", "verantwortlicher": "Nils Gröber", "startdatum": date(2026, 9, 14), "kontaktadressen": [ { "anrede": "Frau", "name": "Brunhilde Kessler", "firma": "Kessler Engelpforte-Apotheke", "position": "Inhaberin", "telefon": "+49 611 344 210", "email": "b.kessler@kessler-apotheke.de", "strasse": "Kirchgasse 32", "plz": "65183", "ort": "Wiesbaden", "land": "Deutschland", "notiz": "Listet bislang nur zwei Eigenmarken-Produkte; offen für eine Sortimentserweiterung.", }, { "anrede": "Herr", "name": "Ali Demirci", "firma": "Demirci Apotheke Köln", "position": "Apotheker", "telefon": "+49 221 559 731", "email": "a.demirci@demirci-apotheke.de", "strasse": "Neumarkt 3", "plz": "50667", "ort": "Köln", "land": "Deutschland", "notiz": "Fragt nach Verkaufsunterlagen für das Beratungsgespräch.", }, { "anrede": "Frau", "name": "Yasmin Trautmann", "firma": "Trautmann Apotheke", "position": "Fachapothekerin", "telefon": "+49 69 664 128", "email": "y.trautmann@trautmann-apotheke.de", "strasse": "Berger Str. 175", "plz": "60385", "ort": "Frankfurt", "land": "Deutschland", "notiz": "Möchte erst die Ergebnisse einer Testlistung abwarten.", }, ], }, ], }, { "name": "Alpina Holzwerke Sepp Achmüller GmbH", "strasse": "Sepp-Achmüller-Str. 4", "plz": "6330", "ort": "Kufstein", "land": "Österreich", "kontakte": [ { "anrede": "Herr", "name": "Sepp Achmüller jun.", "position": "Geschäftsführer", "telefon": "+43 5372 6234 18", "email": "achmiller@alpina-holzwerke.at", "notiz": "Prüft jede Kampagne vor dem Start persönlich ab; Budgetfreigabe erst nach Vorlage einer Musterabrechnung.", }, { "anrede": "Frau", "name": "Elisabeth Steger", "position": "Vertriebsleiterin", "telefon": "+43 5372 6234 22", "email": "steger@alpina-holzwerke.at", "notiz": "Stimmt Zielgruppen und Anrufregionen mit uns ab; bevorzugt die Abstimmung per Mail.", }, ], "projekte": [ { "projektname": "Kampagne Thermofenster Linienserie Alpin", "zweck": "Telefonische Kampagne bei Baufirmen, Architekten und Holzbaubetrieben für die neue Thermofenster-Serie 'Alpin'. Ziel: 300 geführte Gespräche und 45 Mess- beziehungsweise Angebotstermine.", "verantwortlicher": "Sandra Wittke", "startdatum": date(2026, 8, 10), "kontaktadressen": [ { "anrede": "Herr", "name": "Jakob Rainer", "firma": "Rainer Holzbau", "position": "Geschäftsführer", "telefon": "+43 512 344 087", "email": "j.rainer@rainer-holzbau.at", "strasse": "Museumstr. 13", "plz": "6020", "ort": "Innsbruck", "land": "Österreich", "notiz": "Setzt auf Passivhaus-Komponenten; U-Werte müssen im Angebot ausgewiesen sein.", }, { "anrede": "Frau", "name": "Notburga Wörgötter", "firma": "Wörgötter Zimmerei", "position": "Kalkulation und Einkauf", "telefon": "+43 662 834 556", "email": "n.woergoetter@woergoetter-zimmerei.at", "strasse": "Schallmooser Hauptstr. 44", "plz": "5020", "ort": "Salzburg", "land": "Österreich", "notiz": "Benötigt Muster für die Messepräsentation im November.", }, { "anrede": "Herr", "name": "Quirin Hofer", "firma": "Hofer Bau & Planung", "position": "Architekt", "telefon": "+49 871 339 421", "email": "q.hofer@hofer-bau-planung.de", "strasse": "Ostengasse 15", "plz": "84028", "ort": "Landshut", "land": "Deutschland", "notiz": "Plant ein mehrgeschossiges Holzbauprojekt; Fensterelemente sind noch nicht vergeben.", }, ], }, { "projektname": "Wiedervorlage-Bestellungen Winterholz-Vorkauf", "zweck": "Frühzeitige telefonische Vorkaufskampagne für Winterholz: Bestandskunden aus dem Bauhandel anrufen, Bedarf aufnehmen und Wiedervorlagen für die Bestellzeit setzen. Ziel: 65 Prozent Vorab-Buchung des Winterkontingents.", "verantwortlicher": "Jonas Ade", "startdatum": date(2026, 9, 21), "kontaktadressen": [ { "anrede": "Herr", "name": "Werner Prantner", "firma": "Prantner Baustoffe", "position": "Verkauf", "telefon": "+49 8631 554 22", "email": "w.prantner@prantner-baustoffe.de", "strasse": "Simbacher Str. 14", "plz": "84137", "ort": "Vilsbiburg", "land": "Deutschland", "notiz": "Bestellt traditionell erst im November; testet dieses Jahr erstmals den Vorkauf.", }, { "anrede": "Frau", "name": "Cäcilia Pfeiff", "firma": "Pfeiff Holzmarkt", "position": "Inhaberin", "telefon": "+43 732 915 447", "email": "c.pfeiff@pfeiff-holzmarkt.at", "strasse": "Rudolfstr. 12", "plz": "4020", "ort": "Linz", "land": "Österreich", "notiz": "Braucht eine verbindliche Lieferzusage bis Anfang Dezember.", }, { "anrede": "Herr", "name": "Ambros Hinterseer", "firma": "Hinterseer Sägewerke", "position": "Disposition", "telefon": "+43 5356 622 18", "email": "a.hinterseer@hinterseer-saegewerke.at", "strasse": "Jochberger Str. 9", "plz": "6360", "ort": "Kitzbühel", "land": "Österreich", "notiz": "Koordiniert den Transport selbst; Übergabetermine müssen exakt stehen.", }, ], }, { "projektname": "Lead-Qualifizierung Sägewerksbetriebe Bayern/Tirol", "zweck": "Anrufcampagne zur Lead-Qualifizierung bei mittelständischen Sägewerken in Bayern und Tirol: Recherche der Ansprechpartner und Bewertung nach Einkaufsvolumen. Ziel: 200 qualifizierte Leads bis Mitte des zweiten Quartals.", "verantwortlicher": "Pia Merkert", "startdatum": date(2026, 9, 28), "kontaktadressen": [ { "anrede": "Herr", "name": "Hubert Mühlbacher", "firma": "Mühlbacher Holz", "position": "Einkaufsleiter", "telefon": "+49 851 987 350", "email": "h.muehlbacher@muehlbacher-holz.de", "strasse": "Innstr. 40", "plz": "94032", "ort": "Passau", "land": "Deutschland", "notiz": "Fragt nach Zertifikaten und Lieferkonditionen bereits im Erstgespräch.", }, { "anrede": "Frau", "name": "Resi Peringer", "firma": "Peringer Säge", "position": "Disposition", "telefon": "+43 5285 644 21", "email": "r.peringer@peringer-saege.at", "strasse": "Dorfstr. 22", "plz": "6290", "ort": "Mayrhofen", "land": "Österreich", "notiz": "Familienbetrieb in dritter Generation; die Entscheidung liegt beim Senior.", }, { "anrede": "Herr", "name": "Konrad Eder", "firma": "Eder Holzwerk", "position": "Betriebsleiter", "telefon": "+49 8031 554 67", "email": "k.eder@eder-holzwerk.de", "strasse": "Chiemseestr. 28", "plz": "83022", "ort": "Rosenheim", "land": "Deutschland", "notiz": "Erweitert die Produktionskapazität; sucht Lieferanten mit hoher Flexibilität.", }, ], }, ], }, ] # Betreff-Vorlagen für die automatisch erzeugten Gesprächsnotizen. Passen # zum Ablauf einer Telefon-Akquise (Erstkontakt -> Termin -> Angebot). _BETREFFVORLAGEN = [ "Erstkontakt und Bedarfsaufnahme", "Produktvorstellung am Telefon", "Terminvorschlag Außendienst", "Angebot nachreichen", "Nachfassung zum Angebot", "Wiedervorlage nach Sommerpause", "Rückruf vereinbart", ] # Notiz-Vorlagen für die automatisch erzeugten Gesprächsnotizen. Formuliert # wie typische Ergebnisse eines Akquise-Telefonats; ein leerer Eintrag # steht für ein Telefonat ohne Notiz. _NOTIZVORLAGEN = [ "Gesprächspartner zeigt grundsätzliches Interesse und bittet um die Preisliste als PDF. Das Angebot geht per Mail raus.", "Kein akuter Bedarf, aber Erweiterungsplanung für das kommende Jahr. Wiedervorlage im Frühjahr gesetzt.", "Vor-Ort-Termin zur Besichtigung vereinbart; Unterlagen werden vorab per Mail gesendet.", "Zentrale verweist auf die Beschaffungsabteilung, der konkrete Ansprechpartner wird noch erfragt.", "Muster werden angefragt; Rückruf zugesagt, sobald die Kollegin aus dem Urlaub zurück ist.", "Angebot wurde durchgesprochen, das Budget ist noch nicht freigegeben. Nächster Anruf nach der Freigabe.", "", ] def _seed_musterdaten(): """ Legt die vollständigen Musterdaten an: drei Kunden mit kundenspezifischen Kontakten, je drei Telefon-Akquise-Projekte pro Kunde, projektbezogene Kontaktadressen (Akquise-Ziele) und daraus abgeleitete Gesprächsnotizen. Aufruf nur nach _purge_crm_daten(), da die Funktion die Daten ohne Existenzprüfung neu anlegt. Die Gesprächsnotizen verweisen auf die Kontaktadresse, zu der sie gehören (kontaktadresse_id ist Pflichtfeld), und übernehmen Name und Telefonnummer des Ziels. """ import random from crm.model import Kunde, Kontakt, Projekt, Kontaktadresse, CallLog session = dbapp.session # Fester Seed für reproduzierbare Musterdaten (Datum, Uhrzeit, Dauer). rng = random.Random(456) for kundendaten in _MUSTERDATEN: kunde = Kunde( name=kundendaten["name"], strasse=kundendaten["strasse"], plz=kundendaten["plz"], ort=kundendaten["ort"], land=kundendaten["land"], ) session.add(kunde) # flush liefert die Auto-Increment-ID für die abhängigen Sätze. session.flush() for kontaktdaten in kundendaten["kontakte"]: kontakt = Kontakt( kunden_id=kunde.id, anrede=kontaktdaten["anrede"], name=kontaktdaten["name"], position=kontaktdaten["position"], telefon=kontaktdaten["telefon"], email=kontaktdaten["email"], notiz=kontaktdaten["notiz"], ) session.add(kontakt) for projektdaten in kundendaten["projekte"]: projekt = Projekt( kunden_id=kunde.id, projektname=projektdaten["projektname"], zweck=projektdaten["zweck"], verantwortlicher=projektdaten["verantwortlicher"], startdatum=projektdaten["startdatum"], ) session.add(projekt) session.flush() for adressdaten in projektdaten["kontaktadressen"]: adresse = Kontaktadresse( projekt_id=projekt.id, anrede=adressdaten["anrede"], name=adressdaten["name"], firma=adressdaten["firma"], position=adressdaten["position"], telefon=adressdaten["telefon"], email=adressdaten["email"], strasse=adressdaten["strasse"], plz=adressdaten["plz"], ort=adressdaten["ort"], land=adressdaten["land"], notiz=adressdaten["notiz"], ) session.add(adresse) session.flush() # Je Kontaktadresse ein bis zwei Gesprächsnotizen, die das # Akquise-Telefonat mit diesem Ziel dokumentieren. for _ in range(rng.randint(1, 2)): log = CallLog() log.projekt_id = projekt.id log.kontaktadresse_id = adresse.id log.datum = date(2026, 9, rng.randint(1, 26)) log.uhrzeit_beginn = "{h:02d}:{min:02d}".format( h=rng.randint(8, 17), min=rng.randint(0, 59) ) log.dauer = str(rng.randint(5, 45)) log.betreff = rng.choice(_BETREFFVORLAGEN) log.name_ansprechpartner = adresse.name log.telefon = adresse.telefon log.notiz = rng.choice(_NOTIZVORLAGEN) log.wiedervorlage_datum = log.datum + timedelta( days=rng.randint(7, 28) ) 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()