changes to he pdf sending
This commit is contained in:
+47
-40
@@ -2206,7 +2206,19 @@ def build_module_config_string(package_list: list) -> str:
|
|||||||
]
|
]
|
||||||
return " ".join(config_parts)
|
return " ".join(config_parts)
|
||||||
|
|
||||||
def background_booking_provisioning(app_instance, prov_id, subdomain, package_list, user_id, school_name, user_email, username, address, price, software_name):
|
def background_booking_provisioning(
|
||||||
|
app_instance,
|
||||||
|
prov_id,
|
||||||
|
subdomain,
|
||||||
|
package_list,
|
||||||
|
user_id,
|
||||||
|
school_name,
|
||||||
|
user_email,
|
||||||
|
username,
|
||||||
|
address,
|
||||||
|
price,
|
||||||
|
software_name="Invario Inventarsystem"
|
||||||
|
):
|
||||||
"""Hintergrund-Worker, der die Tenant-Bereitstellung über das Host-Watcher-Triggersystem auslöst."""
|
"""Hintergrund-Worker, der die Tenant-Bereitstellung über das Host-Watcher-Triggersystem auslöst."""
|
||||||
with app_instance.app_context():
|
with app_instance.app_context():
|
||||||
req_client, req_col = _get_collection("instance_requests")
|
req_client, req_col = _get_collection("instance_requests")
|
||||||
@@ -2214,7 +2226,7 @@ def background_booking_provisioning(app_instance, prov_id, subdomain, package_li
|
|||||||
# 1. Status auf "in_progress" setzen
|
# 1. Status auf "in_progress" setzen
|
||||||
req_col.update_one({"_id": ObjectId(prov_id)}, {"$set": {"provision_status": "in_progress"}})
|
req_col.update_one({"_id": ObjectId(prov_id)}, {"$set": {"provision_status": "in_progress"}})
|
||||||
|
|
||||||
# 2. Naechsten Port und Admin-Passwort ermitteln
|
# 2. Nächsten Port und Admin-Passwort ermitteln
|
||||||
inst_client_check, inst_col_check = _get_collection("instances")
|
inst_client_check, inst_col_check = _get_collection("instances")
|
||||||
try:
|
try:
|
||||||
existing_instances = list(inst_col_check.find({}, {"https_port": 1, "port": 1}))
|
existing_instances = list(inst_col_check.find({}, {"https_port": 1, "port": 1}))
|
||||||
@@ -2232,7 +2244,7 @@ def background_booking_provisioning(app_instance, prov_id, subdomain, package_li
|
|||||||
# Generiere den korrekten Modul-String
|
# Generiere den korrekten Modul-String
|
||||||
module_config_str = build_module_config_string(package_list)
|
module_config_str = build_module_config_string(package_list)
|
||||||
|
|
||||||
# 3. Trigger-Datei fuer den Host-Watcher schreiben
|
# 3. Trigger-Datei für den Host-Watcher schreiben
|
||||||
os.makedirs(TRIGGER_DIR, exist_ok=True)
|
os.makedirs(TRIGGER_DIR, exist_ok=True)
|
||||||
trigger_file = os.path.join(TRIGGER_DIR, f"{subdomain}.json")
|
trigger_file = os.path.join(TRIGGER_DIR, f"{subdomain}.json")
|
||||||
|
|
||||||
@@ -2248,13 +2260,13 @@ def background_booking_provisioning(app_instance, prov_id, subdomain, package_li
|
|||||||
with open(trigger_file, "w") as f:
|
with open(trigger_file, "w") as f:
|
||||||
json.dump(trigger_payload, f)
|
json.dump(trigger_payload, f)
|
||||||
|
|
||||||
print(f"[INFO] Trigger-Datei fuer Host-Watcher erstellt: {trigger_file} mit Payload: {trigger_payload}")
|
print(f"[INFO] Trigger-Datei für Host-Watcher erstellt: {trigger_file} mit Payload: {trigger_payload}")
|
||||||
|
|
||||||
# 4. Instanz-Eintrag in der Datenbank registrieren
|
# 4. Instanz-Eintrag in der Datenbank registrieren
|
||||||
domain = f"{subdomain}.invario-software.de"
|
domain = f"{subdomain}.invario-software.de"
|
||||||
instance_doc = {
|
instance_doc = {
|
||||||
"owner_id": user_id,
|
"owner_id": user_id,
|
||||||
"owner_username": username, # <--- HIER HINZUGEFÜGT
|
"owner_username": username,
|
||||||
"school_name": school_name,
|
"school_name": school_name,
|
||||||
"subdomain": subdomain,
|
"subdomain": subdomain,
|
||||||
"domain": domain,
|
"domain": domain,
|
||||||
@@ -2272,9 +2284,11 @@ def background_booking_provisioning(app_instance, prov_id, subdomain, package_li
|
|||||||
finally:
|
finally:
|
||||||
inst_client.close()
|
inst_client.close()
|
||||||
|
|
||||||
# 5. Bestaetigungs-E-Mail versenden
|
# 5. Bestätigungs-E-Mail inkl. Vertrag & Anhängen versenden
|
||||||
try:
|
try:
|
||||||
if user_email:
|
if user_email:
|
||||||
|
formatted_date = datetime.today().strftime('%d.%m.%Y')
|
||||||
|
|
||||||
send_accreditation_email(
|
send_accreditation_email(
|
||||||
recipient=user_email,
|
recipient=user_email,
|
||||||
domain=domain,
|
domain=domain,
|
||||||
@@ -2283,9 +2297,10 @@ def background_booking_provisioning(app_instance, prov_id, subdomain, package_li
|
|||||||
school_name=school_name,
|
school_name=school_name,
|
||||||
address=address,
|
address=address,
|
||||||
price=price,
|
price=price,
|
||||||
date=_utc_now_iso(),
|
date=formatted_date,
|
||||||
software_name=software_name,
|
software_name=software_name
|
||||||
)
|
)
|
||||||
|
|
||||||
except Exception as mail_err:
|
except Exception as mail_err:
|
||||||
print(f"[WARNING] E-Mail-Versand fehlgeschlagen: {mail_err}")
|
print(f"[WARNING] E-Mail-Versand fehlgeschlagen: {mail_err}")
|
||||||
|
|
||||||
@@ -2302,10 +2317,10 @@ def background_booking_provisioning(app_instance, prov_id, subdomain, package_li
|
|||||||
"updated_at": _utc_now_iso()
|
"updated_at": _utc_now_iso()
|
||||||
}}
|
}}
|
||||||
)
|
)
|
||||||
print(f"[SUCCESS] Provisioning-Trigger erfolgreich gesendet fuer {subdomain}")
|
print(f"[SUCCESS] Provisioning-Trigger erfolgreich gesendet für {subdomain}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[ERROR] Async Provisioning fehlgeschlagen fuer {subdomain}:")
|
print(f"[ERROR] Async Provisioning fehlgeschlagen für {subdomain}:")
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
req_col.update_one({"_id": ObjectId(prov_id)}, {"$set": {"provision_status": "failed", "last_error": str(e)}})
|
req_col.update_one({"_id": ObjectId(prov_id)}, {"$set": {"provision_status": "failed", "last_error": str(e)}})
|
||||||
finally:
|
finally:
|
||||||
@@ -2350,7 +2365,6 @@ def booking_payment():
|
|||||||
|
|
||||||
flow_config = BOOKING_FLOW_MAP[booking_flow]
|
flow_config = BOOKING_FLOW_MAP[booking_flow]
|
||||||
|
|
||||||
# Auslesen aller Formularfelder (inkl. tenant_slug und Rechnungsdaten)
|
|
||||||
form_data = {
|
form_data = {
|
||||||
"contact_person": _sanitize_text(request.values.get("contact_person") or "", 120),
|
"contact_person": _sanitize_text(request.values.get("contact_person") or "", 120),
|
||||||
"school_name": _sanitize_text(request.values.get("school_name") or "", 160),
|
"school_name": _sanitize_text(request.values.get("school_name") or "", 160),
|
||||||
@@ -2426,21 +2440,8 @@ def booking_payment():
|
|||||||
assigned_admin_display_name = assigned_admin.get("display_name") if assigned_admin else ""
|
assigned_admin_display_name = assigned_admin.get("display_name") if assigned_admin else ""
|
||||||
assigned_admin_email = (assigned_admin.get("email") if assigned_admin else "") or BOOKING_ADMIN_EMAIL_FALLBACK
|
assigned_admin_email = (assigned_admin.get("email") if assigned_admin else "") or BOOKING_ADMIN_EMAIL_FALLBACK
|
||||||
|
|
||||||
message = (
|
|
||||||
f"{flow_config['message_prefix']} {selected_package} {flow_config['message_suffix']}\n"
|
|
||||||
f"Ansprechpartner: {form_data['contact_person']}\n"
|
|
||||||
f"Schule: {form_data['school_name']} (Dienstst.-Nr: {form_data['school_number']})\n"
|
|
||||||
f"E-Mail: {form_data['contact_email']}\n"
|
|
||||||
f"Telefon: {form_data['contact_phone'] or '-'}\n"
|
|
||||||
f"Schulträger/Amt: {form_data['billing_organization']}\n"
|
|
||||||
f"Rechnungsadresse: {form_data['billing_street']}, {form_data['billing_zip']} {form_data['billing_city']}\n"
|
|
||||||
f"Kassenzeichen: {form_data['billing_reference'] or '-'}\n"
|
|
||||||
f"Gewünschte Subdomain: {form_data['tenant_slug']}\n"
|
|
||||||
f"Notizen: {form_data['notes'] or '-'}"
|
|
||||||
)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# FLOW 1: Beratung / Gesprächs-Buchung
|
# FLOW 1: Consultation / Chat
|
||||||
if booking_flow == "consultation":
|
if booking_flow == "consultation":
|
||||||
client, col = _get_collection("chat_messages")
|
client, col = _get_collection("chat_messages")
|
||||||
try:
|
try:
|
||||||
@@ -2449,7 +2450,7 @@ def booking_payment():
|
|||||||
"username": session.get("username"),
|
"username": session.get("username"),
|
||||||
"sender": session.get("display_name") or session.get("username"),
|
"sender": session.get("display_name") or session.get("username"),
|
||||||
"sender_role": "user",
|
"sender_role": "user",
|
||||||
"message": message,
|
"message": f"Gesprächswunsch bezüglich: {selected_package}",
|
||||||
"created_at": _utc_now_iso(),
|
"created_at": _utc_now_iso(),
|
||||||
"booking_flow": booking_flow,
|
"booking_flow": booking_flow,
|
||||||
"booking_package": package_raw,
|
"booking_package": package_raw,
|
||||||
@@ -2465,18 +2466,16 @@ def booking_payment():
|
|||||||
flash(f"Gesprächstermin für {selected_package} wurde an das Team gesendet.", "success")
|
flash(f"Gesprächstermin für {selected_package} wurde an das Team gesendet.", "success")
|
||||||
return redirect(url_for("user_chat"))
|
return redirect(url_for("user_chat"))
|
||||||
|
|
||||||
# FLOW 2: Kostenpflichtige Direkt-Buchung mit Provisioning via Watcher
|
# FLOW 2: Direktbuchung mit Provisioning via Host-Watcher
|
||||||
if booking_flow == "payment":
|
if booking_flow == "payment":
|
||||||
booking_number = f"BOOK-{datetime.utcnow().strftime('%Y%m%d%H%M%S')}"
|
booking_number = f"BOOK-{datetime.utcnow().strftime('%Y%m%d%H%M%S')}"
|
||||||
|
|
||||||
# Schul-URL aus dem Formular bevorzugen
|
|
||||||
raw_base = form_data.get("tenant_slug") or form_data.get("school_name") or session.get("username") or booking_number
|
raw_base = form_data.get("tenant_slug") or form_data.get("school_name") or session.get("username") or booking_number
|
||||||
base = _slugify_subdomain(raw_base).lower()[:51]
|
base = _slugify_subdomain(raw_base).lower()[:51]
|
||||||
|
|
||||||
# Prüfung auf doppelte Subdomains via MongoDB 'instances' Collection
|
inst_check_client, inst_col_check = _get_collection("instances")
|
||||||
inst_check_client, inst_check_col = _get_collection("instances")
|
|
||||||
try:
|
try:
|
||||||
existing_docs = list(inst_check_col.find({}, {"subdomain": 1}))
|
existing_docs = list(inst_col_check.find({}, {"subdomain": 1}))
|
||||||
existing_subdomains = [d.get("subdomain") for d in existing_docs if d.get("subdomain")]
|
existing_subdomains = [d.get("subdomain") for d in existing_docs if d.get("subdomain")]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[WARNING] Konnte bestehende Subdomains nicht prüfen: {e}")
|
print(f"[WARNING] Konnte bestehende Subdomains nicht prüfen: {e}")
|
||||||
@@ -2523,29 +2522,37 @@ def booking_payment():
|
|||||||
username = session.get("username")
|
username = session.get("username")
|
||||||
user_email = session.get("email") or form_data.get("contact_email")
|
user_email = session.get("email") or form_data.get("contact_email")
|
||||||
address_process = f"{form_data['billing_street']}, {form_data['billing_zip']} {form_data['billing_city']}"
|
address_process = f"{form_data['billing_street']}, {form_data['billing_zip']} {form_data['billing_city']}"
|
||||||
|
price_str = f"{total_price:.2f}".replace('.', ',')
|
||||||
|
|
||||||
# Startet den asynchronen Provisioning-Thread
|
# Startet den asynchronen Provisioning-Thread mit exakten Parametern
|
||||||
thread = threading.Thread(
|
thread = threading.Thread(
|
||||||
target=background_booking_provisioning,
|
target=background_booking_provisioning,
|
||||||
args=(app_obj, prov_id, subdomain, package_list, user_id, form_data["school_name"], user_email, username, address_process, total_price, selected_package)
|
args=(
|
||||||
|
app_obj,
|
||||||
|
prov_id,
|
||||||
|
subdomain,
|
||||||
|
package_list,
|
||||||
|
user_id,
|
||||||
|
form_data["school_name"],
|
||||||
|
user_email,
|
||||||
|
username,
|
||||||
|
address_process,
|
||||||
|
price_str,
|
||||||
|
selected_package
|
||||||
|
)
|
||||||
)
|
)
|
||||||
thread.start()
|
thread.start()
|
||||||
print(f"[INFO] Background Provisioning Trigger gestartet für Subdomain: {subdomain}")
|
print(f"[INFO] Background Provisioning Trigger gestartet für Subdomain: {subdomain}")
|
||||||
|
|
||||||
# ANPASSUNG FÜR BESSERE WARTEZEIT:
|
|
||||||
# Wir geben Metadaten mit, wie lange das Setup ca. dauern wird.
|
|
||||||
if is_json_request:
|
if is_json_request:
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"success": True,
|
"success": True,
|
||||||
"slug": subdomain,
|
"slug": subdomain,
|
||||||
"message": "Instanz wird eingerichtet...",
|
"message": "Instanz wird eingerichtet...",
|
||||||
"estimated_seconds": 45, # Erwartete Dauer in Sekunden (anpassbar)
|
"estimated_seconds": 45,
|
||||||
"status_poll_interval_ms": 3000 # Wie oft soll das Frontend fragen? (3 Sek)
|
"status_poll_interval_ms": 3000
|
||||||
}), 200
|
}), 200
|
||||||
|
|
||||||
# Falls es KEIN AJAX-Request war:
|
|
||||||
# Wir hängen den Parameter "wait_for_slug" an, damit die "my_instance_management"-Seite weiß,
|
|
||||||
# dass sie sofort ein Lade-Overlay für diesen spezifischen Tenant öffnen muss.
|
|
||||||
flash(f"Buchung für {selected_package} wurde erfasst. Deine Instanz wird jetzt automatisch eingerichtet.", "success")
|
flash(f"Buchung für {selected_package} wurde erfasst. Deine Instanz wird jetzt automatisch eingerichtet.", "success")
|
||||||
return redirect(url_for("my_instance_management", wait_for_slug=subdomain))
|
return redirect(url_for("my_instance_management", wait_for_slug=subdomain))
|
||||||
|
|
||||||
|
|||||||
@@ -202,12 +202,11 @@ def generate_main_contract_pdf(
|
|||||||
software_name: str = "Invario Inventarsystem"
|
software_name: str = "Invario Inventarsystem"
|
||||||
):
|
):
|
||||||
"""Generiert den Hauptvertrag mit zentrierter und aufeinander abgestimmter Kopf- und Fußzeilen-Formatierung."""
|
"""Generiert den Hauptvertrag mit zentrierter und aufeinander abgestimmter Kopf- und Fußzeilen-Formatierung."""
|
||||||
from datetime import datetime
|
|
||||||
pdf = FPDF()
|
pdf = FPDF()
|
||||||
pdf.add_page()
|
pdf.add_page()
|
||||||
pdf.set_auto_page_break(auto=True, margin=15)
|
pdf.set_auto_page_break(auto=True, margin=15)
|
||||||
|
|
||||||
# --- KOPFBEREICH (ZENTRIERT & BÜNDIG UNTEREINANDER) ---
|
# --- KOPFBEREICH ---
|
||||||
pdf.set_font("Helvetica", style="B", size=13)
|
pdf.set_font("Helvetica", style="B", size=13)
|
||||||
pdf.cell(0, 6, "Vertrag über die Nutzung der Software-Lizenz", ln=True, align="C")
|
pdf.cell(0, 6, "Vertrag über die Nutzung der Software-Lizenz", ln=True, align="C")
|
||||||
pdf.cell(0, 6, f'"{software_name}"', ln=True, align="C")
|
pdf.cell(0, 6, f'"{software_name}"', ln=True, align="C")
|
||||||
@@ -231,7 +230,7 @@ def generate_main_contract_pdf(
|
|||||||
pdf.cell(0, 5, "- Auftraggeber / Schule -", ln=True, align="C")
|
pdf.cell(0, 5, "- Auftraggeber / Schule -", ln=True, align="C")
|
||||||
pdf.ln(8)
|
pdf.ln(8)
|
||||||
|
|
||||||
# --- PARAGRAPHEN (1 BIS 8) ---
|
# --- PARAGRAPHEN ---
|
||||||
pdf.set_font("Helvetica", style="B", size=10)
|
pdf.set_font("Helvetica", style="B", size=10)
|
||||||
pdf.cell(0, 6, "1. Vertragsgegenstand", ln=True)
|
pdf.cell(0, 6, "1. Vertragsgegenstand", ln=True)
|
||||||
pdf.set_font("Helvetica", size=10)
|
pdf.set_font("Helvetica", size=10)
|
||||||
@@ -309,28 +308,25 @@ def generate_main_contract_pdf(
|
|||||||
)
|
)
|
||||||
pdf.ln(6)
|
pdf.ln(6)
|
||||||
|
|
||||||
# --- FUSSBEREICH / UNTERSCHRIFTEN (ZENTRIERT & SYMMETRISCH) ---
|
# --- UNTERSCHRIFTEN ---
|
||||||
pdf.set_font("Helvetica", style="B", size=10)
|
pdf.set_font("Helvetica", style="B", size=10)
|
||||||
pdf.cell(0, 6, "Unterschriften und Einverständnis", ln=True, align="C")
|
pdf.cell(0, 6, "Unterschriften und Einverständnis", ln=True, align="C")
|
||||||
pdf.set_font("Helvetica", size=9)
|
pdf.set_font("Helvetica", size=9)
|
||||||
pdf.multi_cell(0, 4, "Mit der Unterzeichnung bestätigen die Parteien den Abschluss des Hauptvertrages inklusive der beigefügten Anlagen (AGB, EULA und AVV).", align="C")
|
pdf.multi_cell(0, 4, "Mit der Unterzeichnung bestätigen die Parteien den Abschluss des Hauptvertrages inklusive der beigefügten Anlagen (AGB, EULA und AVV).", align="C")
|
||||||
pdf.ln(8)
|
pdf.ln(8)
|
||||||
|
|
||||||
# Exakte Zentrierung der zwei Unterschriften-Blöcke
|
|
||||||
col_width = 85
|
col_width = 85
|
||||||
start_x = (210 - (col_width * 2)) / 2 # Berechnet den exakten linken Rand für Symmetrie (20mm)
|
start_x = (210 - (col_width * 2)) / 2
|
||||||
|
|
||||||
pdf.set_font("Helvetica", size=9)
|
pdf.set_font("Helvetica", size=9)
|
||||||
|
|
||||||
pdf.set_x(start_x)
|
pdf.set_x(start_x)
|
||||||
pdf.cell(col_width, 5, "Für den Auftraggeber", align="C", ln=False)
|
pdf.cell(col_width, 5, "Für den Auftraggeber", align="C", ln=False)
|
||||||
pdf.cell(col_width, 5, "Für den Anbieter", align="C", ln=True)
|
pdf.cell(col_width, 5, "Für den Anbieter", align="C", ln=True)
|
||||||
|
|
||||||
pdf.ln(8)
|
pdf.ln(8)
|
||||||
|
|
||||||
pdf.set_x(start_x)
|
pdf.set_x(start_x)
|
||||||
pdf.cell(col_width, 5, f"{datetime.today().strftime('%d.%m.%Y')} ________________________", align="C", ln=False)
|
pdf.cell(col_width, 5, f"{date} ________________________", align="C", ln=False)
|
||||||
pdf.cell(col_width, 5, f"{datetime.today().strftime('%d.%m.%Y')} ___________ _____________", align="C", ln=True)
|
pdf.cell(col_width, 5, f"{date} ___________ _____________", align="C", ln=True)
|
||||||
|
|
||||||
pdf.set_x(start_x)
|
pdf.set_x(start_x)
|
||||||
pdf.cell(col_width, 5, "(Verantwortlicher)", align="C", ln=False)
|
pdf.cell(col_width, 5, "(Verantwortlicher)", align="C", ln=False)
|
||||||
@@ -339,27 +335,31 @@ def generate_main_contract_pdf(
|
|||||||
pdf.output(output_path)
|
pdf.output(output_path)
|
||||||
return output_path
|
return output_path
|
||||||
|
|
||||||
|
|
||||||
def send_accreditation_email(
|
def send_accreditation_email(
|
||||||
recipient: str,
|
recipient: str,
|
||||||
domain: str,
|
domain: str,
|
||||||
username: str,
|
username: str,
|
||||||
password: str,
|
password: str,
|
||||||
invoice_pdf_path: str,
|
|
||||||
contract_pdf_path: str,
|
|
||||||
school_name: str = "[Name der Schule / des Auftraggebers]",
|
school_name: str = "[Name der Schule / des Auftraggebers]",
|
||||||
address: str = "[Straße, Hausnummer] [PLZ, Ort]",
|
address: str = "[Straße, Hausnummer] [PLZ, Ort]",
|
||||||
price: str = "250,00",
|
price: str = "250,00",
|
||||||
date: str = "[Ort, Datum]"
|
date: str = "[Ort, Datum]",
|
||||||
|
software_name: str = "Invario Inventarsystem"
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Generiert den Hauptvertrag und sendet diesen zusammen mit Rechnung, AGB und AVV per E-Mail."""
|
"""Generiert den Hauptvertrag temporär und versendet ihn zusammen mit AGB & AVV per E-Mail."""
|
||||||
|
|
||||||
# 1. Hauptvertrag generieren
|
# Clean Sanitization für Dateinamen
|
||||||
|
safe_school_name = "".join([c for c in school_name if c.isalnum() or c in (' ', '_', '-')]).rstrip()
|
||||||
|
contract_filename = f"Hauptvertrag_Invario_{safe_school_name}.pdf"
|
||||||
|
contract_pdf_path = os.path.join(tempfile.gettempdir(), contract_filename)
|
||||||
|
|
||||||
|
# 1. Hauptvertrag dynamisch erzeugen
|
||||||
generate_main_contract_pdf(
|
generate_main_contract_pdf(
|
||||||
school_name=school_name,
|
school_name=school_name,
|
||||||
address=address,
|
address=address,
|
||||||
price=price,
|
price=price,
|
||||||
date=date,
|
date=date,
|
||||||
|
software_name=software_name,
|
||||||
output_path=contract_pdf_path
|
output_path=contract_pdf_path
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -367,13 +367,13 @@ def send_accreditation_email(
|
|||||||
agb_pdf_path = os.path.join("static", "download", "AGB Invario.pdf")
|
agb_pdf_path = os.path.join("static", "download", "AGB Invario.pdf")
|
||||||
avv_pdf_path = os.path.join("static", "download", "AVV Invario.pdf")
|
avv_pdf_path = os.path.join("static", "download", "AVV Invario.pdf")
|
||||||
|
|
||||||
# 3. E-Mail Texte
|
# 3. E-Mail Inhalte
|
||||||
subject = "Ihre Zugangsdaten und Unterlagen für Invario"
|
subject = "Ihre Zugangsdaten und Unterlagen für Invario"
|
||||||
|
|
||||||
text_note = (
|
text_note = (
|
||||||
f"Sehr geehrte/r {username},\n\n"
|
f"Sehr geehrte/r {username},\n\n"
|
||||||
"Vielen Dank für Ihre Akkreditierung bei Invario. "
|
"Vielen Dank für Ihre Akkreditierung bei Invario. "
|
||||||
"Im Anhang finden Sie Ihre Rechnung, den Hauptvertrag sowie die AGB und den AVV.\n\n"
|
"Im Anhang finden Sie Ihren Hauptvertrag sowie die AGB und den AVV.\n\n"
|
||||||
f"Ihre Zugangsdaten:\n"
|
f"Ihre Zugangsdaten:\n"
|
||||||
f"Domain: https://{domain}\n"
|
f"Domain: https://{domain}\n"
|
||||||
f"Benutzername: {username}\n"
|
f"Benutzername: {username}\n"
|
||||||
@@ -385,7 +385,7 @@ def send_accreditation_email(
|
|||||||
<div style="font-family: Arial, Helvetica, sans-serif; color: #333333;">
|
<div style="font-family: Arial, Helvetica, sans-serif; color: #333333;">
|
||||||
<h2 style="color: #2c3e50; margin-top: 0;">Willkommen bei Invario!</h2>
|
<h2 style="color: #2c3e50; margin-top: 0;">Willkommen bei Invario!</h2>
|
||||||
<p style="font-size: 15px; line-height: 1.6;">
|
<p style="font-size: 15px; line-height: 1.6;">
|
||||||
Vielen Dank für Ihre Akkreditierung. Im Anhang finden Sie Ihre Rechnung, den Hauptvertrag sowie die AGB und den AVV.
|
Vielen Dank für Ihre Akkreditierung. Im Anhang finden Sie Ihren Hauptvertrag sowie die AGB und den AVV.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3 style="color: #2c3e50;">Ihre Zugangsdaten:</h3>
|
<h3 style="color: #2c3e50;">Ihre Zugangsdaten:</h3>
|
||||||
@@ -401,25 +401,29 @@ def send_accreditation_email(
|
|||||||
</div>
|
</div>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# 4. Alle existierenden Anhänge sammeln
|
# 4. Vorhandene Anhänge einsammeln
|
||||||
attachments = []
|
attachments = []
|
||||||
|
|
||||||
# Generierter Hauptvertrag & Rechnung
|
if os.path.exists(contract_pdf_path):
|
||||||
if contract_pdf_path and os.path.exists(contract_pdf_path):
|
|
||||||
attachments.append(contract_pdf_path)
|
attachments.append(contract_pdf_path)
|
||||||
if invoice_pdf_path and os.path.exists(invoice_pdf_path):
|
|
||||||
attachments.append(invoice_pdf_path)
|
|
||||||
|
|
||||||
# Statische Dokumente aus static/download/
|
|
||||||
if os.path.exists(agb_pdf_path):
|
if os.path.exists(agb_pdf_path):
|
||||||
attachments.append(agb_pdf_path)
|
attachments.append(agb_pdf_path)
|
||||||
else:
|
else:
|
||||||
print(f"Warnung: AGB unter {agb_pdf_path} nicht gefunden.")
|
print(f"[WARNING] AGB unter {agb_pdf_path} nicht gefunden.")
|
||||||
|
|
||||||
if os.path.exists(avv_pdf_path):
|
if os.path.exists(avv_pdf_path):
|
||||||
attachments.append(avv_pdf_path)
|
attachments.append(avv_pdf_path)
|
||||||
else:
|
else:
|
||||||
print(f"Warnung: AVV unter {avv_pdf_path} nicht gefunden.")
|
print(f"[WARNING] AVV unter {avv_pdf_path} nicht gefunden.")
|
||||||
|
|
||||||
# 5. E-Mail mit allen 4 Anhängen versenden
|
# 5. E-Mail versenden & temporäre Datei aufräumen
|
||||||
return send(recipient, subject, text_body=text_note, html_body=html_note, attachments=attachments)
|
try:
|
||||||
|
success = send(recipient, subject, text_body=text_note, html_body=html_note, attachments=attachments)
|
||||||
|
return success
|
||||||
|
finally:
|
||||||
|
if os.path.exists(contract_pdf_path):
|
||||||
|
try:
|
||||||
|
os.remove(contract_pdf_path)
|
||||||
|
except OSError as e:
|
||||||
|
print(f"[WARNING] Konnte temporären Vertrag nicht löschen: {e}")
|
||||||
Reference in New Issue
Block a user