[30388f42] Infrastructure Hardening: Repaired CE/Connector DB schema, fixed frontend styling build, implemented robust echo shield in worker v2.1.1, and integrated Lead Engine into gateway.
This commit is contained in:
130
lead-engine/trading_twins/orchestrator.py
Normal file
130
lead-engine/trading_twins/orchestrator.py
Normal file
@@ -0,0 +1,130 @@
|
||||
import time
|
||||
import threading
|
||||
import logging
|
||||
import datetime
|
||||
from .manager import TradingTwinsManager
|
||||
from .teams_notification import send_approval_card
|
||||
from .email_sender import send_email_via_graph
|
||||
import os
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("TradingTwinsOrchestrator")
|
||||
|
||||
TIMEOUT_SECONDS = 300 # 5 Minuten
|
||||
SIGNATURE_FILE = "trading_twins/signature.html"
|
||||
BANNER_IMAGE = "trading_twins/RoboPlanetBannerWebinarEinladung.png"
|
||||
|
||||
class TradingTwinsOrchestrator:
|
||||
def __init__(self):
|
||||
self.manager = TradingTwinsManager()
|
||||
|
||||
def process_lead(self, customer_email, customer_name, customer_company):
|
||||
"""
|
||||
Startet den gesamten Prozess für einen Lead.
|
||||
"""
|
||||
logger.info(f"Neuer Lead eingegangen: {customer_email}")
|
||||
|
||||
# 1. Job und Slots erstellen (mit Faktor-3 Logik)
|
||||
job_uuid, slots = self.manager.create_proposal_job(
|
||||
customer_email, customer_name, customer_company
|
||||
)
|
||||
logger.info(f"Job erstellt: {job_uuid}. Slots: {slots}")
|
||||
|
||||
# 2. Teams Benachrichtigung senden
|
||||
# Formatieren der Uhrzeit für die Teams-Nachricht
|
||||
send_time = (datetime.datetime.now() + datetime.timedelta(seconds=TIMEOUT_SECONDS)).strftime("%H:%M")
|
||||
|
||||
success = send_approval_card(job_uuid, customer_name, send_time)
|
||||
if not success:
|
||||
logger.error("Konnte Teams-Benachrichtigung nicht senden!")
|
||||
# Fallback? Trotzdem Timer starten oder abbrechen?
|
||||
# Wir machen weiter, da E-Mail-Versand Priorität hat.
|
||||
|
||||
# 3. Timer starten für automatischen Versand
|
||||
timer = threading.Timer(TIMEOUT_SECONDS, self._check_timeout, args=[job_uuid])
|
||||
timer.start()
|
||||
|
||||
return job_uuid
|
||||
|
||||
def _check_timeout(self, job_uuid):
|
||||
"""
|
||||
Wird nach Ablauf des Timers aufgerufen.
|
||||
Prüft den Status und sendet ggf. automatisch.
|
||||
"""
|
||||
logger.info(f"Timer abgelaufen für Job {job_uuid}. Prüfe Status...")
|
||||
|
||||
current_status = self.manager.get_job_status(job_uuid)
|
||||
|
||||
if current_status == 'pending':
|
||||
logger.info(f"Job {job_uuid} ist noch 'pending'. Löse automatischen Versand aus.")
|
||||
self._trigger_email_send(job_uuid)
|
||||
elif current_status == 'approved':
|
||||
logger.info(f"Job {job_uuid} wurde bereits manuell genehmigt.")
|
||||
elif current_status == 'cancelled':
|
||||
logger.info(f"Job {job_uuid} wurde manuell abgebrochen.")
|
||||
else:
|
||||
logger.warning(f"Unbekannter Status für Job {job_uuid}: {current_status}")
|
||||
|
||||
def _trigger_email_send(self, job_uuid):
|
||||
"""
|
||||
Hier wird der tatsächliche E-Mail-Versand angestoßen.
|
||||
"""
|
||||
# Job Details laden
|
||||
job_details = self.manager.get_job_details(job_uuid)
|
||||
if not job_details:
|
||||
logger.error(f"Konnte Job {job_uuid} nicht finden!")
|
||||
return
|
||||
|
||||
# E-Mail Body zusammenbauen
|
||||
try:
|
||||
with open(SIGNATURE_FILE, "r") as f:
|
||||
signature_html = f.read()
|
||||
except FileNotFoundError:
|
||||
logger.warning("Signatur-Datei nicht gefunden!")
|
||||
signature_html = "<br>Viele Grüße<br>Ihr RoboPlanet Team"
|
||||
|
||||
# Dynamische Terminvorschläge formatieren
|
||||
slots_text = ""
|
||||
for slot in job_details['slots']:
|
||||
# Format: "Morgen, 14:00 Uhr" oder Datum
|
||||
start = slot['start']
|
||||
slots_text += f"<li>{start.strftime('%d.%m.%Y um %H:%M Uhr')}</li>"
|
||||
|
||||
email_body = f"""
|
||||
<html>
|
||||
<body>
|
||||
<p>Hallo {job_details['name']},</p>
|
||||
<p>vielen Dank für Ihr Interesse an Trading Twins.</p>
|
||||
<p>Gerne würde ich Ihnen in einem kurzen Gespräch (ca. 15-30 Min) zeigen, wie wir Sie unterstützen können.</p>
|
||||
<p>Hätten Sie an einem dieser Termine Zeit?</p>
|
||||
<ul>
|
||||
{slots_text}
|
||||
</ul>
|
||||
<p>Ich freue mich auf Ihre Rückmeldung.</p>
|
||||
{signature_html}
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
# Banner Check
|
||||
banner_path = BANNER_IMAGE if os.path.exists(BANNER_IMAGE) else None
|
||||
|
||||
# Senden
|
||||
success = send_email_via_graph(
|
||||
to_email=job_details['email'],
|
||||
subject="Ihr Termin für Trading Twins",
|
||||
body_html=email_body,
|
||||
banner_path=banner_path
|
||||
)
|
||||
|
||||
if success:
|
||||
logger.info(f"🚀 E-MAIL WURDE VERSENDET für Job {job_uuid}")
|
||||
self.manager.update_job_status(job_uuid, 'sent')
|
||||
else:
|
||||
logger.error(f"❌ Fehler beim E-Mail-Versand für Job {job_uuid}")
|
||||
self.manager.update_job_status(job_uuid, 'failed')
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Test-Lauf
|
||||
orchestrator = TradingTwinsOrchestrator()
|
||||
orchestrator.process_lead("test@example.com", "Max Mustermann", "Musterfirma GmbH")
|
||||
Reference in New Issue
Block a user