init-db löscht vor dem Seeding sämtliche CRM-Geschäftsdaten (Kunden, Kontakte, Projekte, Kontaktadressen, Gesprächsnotizen, Projekt-Zuordnungen) in FK-sicherer Reihenfolge und legt danach die Musterdaten komplett neu an. Die Tag-Taxonomie bleibt als Stammdaten erhalten. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
689 lines
33 KiB
Python
689 lines
33 KiB
Python
"""
|
||
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 <vibe@mistral.ai>
|
||
: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()
|