feat(cli): init-db setzt CRM-Geschäftsdaten zurück und legt neue Musterdaten an
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>
This commit is contained in:
1 parent
f6588dec79
commit
70f6101761
1 file changed
+560
-158
+560
-158
@@ -2,17 +2,23 @@
|
||||
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 init-db -- Schema anlegen/migrieren + Musterdaten
|
||||
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.
|
||||
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.0
|
||||
:version: 1.1
|
||||
"""
|
||||
from datetime import date, timedelta
|
||||
|
||||
import click
|
||||
from flask import Flask
|
||||
|
||||
@@ -33,10 +39,10 @@ def register_cli_commands(app: Flask):
|
||||
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("Lösche vorhandene CRM-Geschäftsdaten ...")
|
||||
_purge_crm_daten()
|
||||
click.echo("Lege Musterdaten an ...")
|
||||
_seed_musterdaten()
|
||||
|
||||
click.echo("Fertig.")
|
||||
|
||||
@@ -83,180 +89,576 @@ def _seed_app_roles():
|
||||
session.commit()
|
||||
|
||||
|
||||
def _seed_muster_kunden():
|
||||
def _purge_crm_daten():
|
||||
"""
|
||||
Legt die drei Muster-Kunden an, falls die kunden-Tabelle noch leer ist.
|
||||
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 Kunde
|
||||
from crm.model import (
|
||||
CallLogTag, CallLog, Kontaktadresse, ProjektUser,
|
||||
Projekt, Kontakt, 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.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()
|
||||
|
||||
|
||||
def _seed_muster_projekte():
|
||||
# ---------------------------------------------------------------------------
|
||||
# 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 für jeden Muster-Kunden 1 bis 3 Muster-Projekte an, falls die
|
||||
projekte-Tabelle noch leer ist.
|
||||
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, Projekt
|
||||
from crm.model import Kunde, Kontakt, Projekt, Kontaktadresse, CallLog
|
||||
|
||||
session = dbapp.session
|
||||
if session.query(Projekt).count() > 0:
|
||||
return
|
||||
# Fester Seed für reproduzierbare Musterdaten (Datum, Uhrzeit, Dauer).
|
||||
rng = random.Random(456)
|
||||
|
||||
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)
|
||||
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.commit()
|
||||
session.flush()
|
||||
|
||||
|
||||
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)
|
||||
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"],
|
||||
)
|
||||
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()
|
||||
session.add(adresse)
|
||||
session.flush()
|
||||
|
||||
|
||||
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):
|
||||
# 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
|
||||
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.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(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.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)
|
||||
)
|
||||
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)
|
||||
session.add(log)
|
||||
session.commit()
|
||||
|
||||
|
||||
Reference in new issue
Block a user