Files
Brancheneinstufung2/list_generator.py
2025-05-26 19:04:37 +00:00

231 lines
11 KiB
Python

import csv
from datetime import datetime
import collections
import os.path
from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# --- Konfiguration ---
CSV_FILENAME = 'Namensliste.csv'
GOOGLE_DOC_TITLE = f"Gruppenlisten Kinderhaus St. Martin Neuching (Service Acc) - {datetime.now().strftime('%Y-%m-%d_%H-%M')}"
TARGET_FOLDER_ID = "18DNQaH9zbcBzwhckJI-4Uah-WXTXg6bg"
EINRICHTUNG = "Kinderhaus St. Martin Neuching"
FOTODATUM = "02. - 05.06.2025"
GRUPPENNAME_SUFFIX = "gruppe"
FOTOGRAF_NAME = "Kinderfotos Erding"
FOTOGRAF_ADRESSE = "Gartenstr. 10 85445 Oberding"
FOTOGRAF_WEB = "www.kinderfotos-erding.de"
FOTOGRAF_TEL = "08122-8470867"
SCOPES = [
'https://www.googleapis.com/auth/documents',
'https://www.googleapis.com/auth/drive.file' # Notwendig für Erstellung im Ordner
# Alternativ: 'https://www.googleapis.com/auth/drive' für vollen Drive-Zugriff
]
SERVICE_ACCOUNT_FILE = 'service_account.json'
# --- Ende Konfiguration ---
def get_services_with_service_account(): # Umbenannt für Klarheit
"""Erstellt Docs und Drive API-Dienste mit einem Service Account."""
creds = None
docs_service = None
drive_service = None
try:
creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
except Exception as e:
print(f"Fehler beim Laden der Service Account Credentials aus '{SERVICE_ACCOUNT_FILE}': {e}")
return None, None
try:
docs_service = build('docs', 'v1', credentials=creds)
print("Google Docs API Service erfolgreich erstellt.")
except Exception as e_docs:
print(f"Konnte Google Docs API Service nicht erstellen: {e_docs}")
try:
# Prüfen, ob Drive Scope vorhanden ist, bevor Drive Service gebaut wird
has_drive_scope = any(s in SCOPES for s in ['https://www.googleapis.com/auth/drive.file', 'https://www.googleapis.com/auth/drive'])
if has_drive_scope:
drive_service = build('drive', 'v3', credentials=creds)
print("Google Drive API Service erfolgreich erstellt.")
else:
print("WARNUNG: Kein Drive Scope in SCOPES definiert. Drive Service wird nicht erstellt.")
print(" Dokumente können nicht in spezifischen Ordnern erstellt werden.")
except Exception as e_drive:
print(f"Konnte Google Drive API Service nicht erstellen: {e_drive}")
return docs_service, drive_service # Gibt beide Services zurück
def create_and_fill_doc(docs_service, drive_service, folder_id, doc_title): # Name beibehalten
"""
Erstellt ein Dokument (idealerweise im Ordner) und befüllt es mit CSV-Daten,
wobei Tabellen als tabulatorgetrennter Text formatiert werden.
"""
document_id = None
# 1. Dokument erstellen (Logik bleibt gleich)
if drive_service and folder_id:
file_metadata = {
'name': doc_title,
'mimeType': 'application/vnd.google-apps.document',
'parents': [folder_id]
}
try:
created_file = drive_service.files().create(body=file_metadata, fields='id').execute()
document_id = created_file.get('id')
print(f"Google Doc via Drive API in Ordner '{folder_id}' erstellt, ID: {document_id}")
except HttpError as err_drive_create:
print(f"Fehler beim Erstellen des Dokuments mit Drive API im Ordner: {err_drive_create}")
if err_drive_create.resp.status == 403:
print(" -> Dies deutet oft auf fehlende Scopes ('drive.file' oder 'drive') hin oder darauf, dass die Drive API nicht im Projekt aktiviert ist.")
print(" Versuche, Dokument im Root des Servicekontos mit Docs API zu erstellen...")
except Exception as e_drive_create_general:
print(f"Allg. Fehler beim Erstellen des Dokuments mit Drive API: {e_drive_create_general}")
print(" Versuche, Dokument im Root des Servicekontos mit Docs API zu erstellen...")
if not document_id:
if not docs_service:
print("FEHLER: Docs API Service nicht verfügbar, kann kein Dokument erstellen.")
return None
try:
doc_body_for_create = {'title': doc_title}
doc = docs_service.documents().create(body=doc_body_for_create).execute()
document_id = doc.get('documentId')
print(f"Google Doc via Docs API (im Root des Servicekontos) erstellt, ID: {document_id}")
if folder_id:
print(f" BITTE manuell in den Ordner '{folder_id}' verschieben.")
except Exception as e_docs_create:
print(f"Konnte Dokument auch nicht mit Docs API erstellen: {e_docs_create}")
return None
if not document_id:
print("Konnte keine Dokumenten-ID für die Befüllung erhalten.")
return None
# 2. Daten aus CSV lesen (Logik bleibt gleich)
kinder_nach_gruppen = collections.defaultdict(list)
try:
with open(CSV_FILENAME, mode='r', encoding='utf-8-sig', newline='') as csvfile:
reader = csv.DictReader(csvfile, delimiter=';')
for row in reader:
vorname = row.get('Vorname', '').strip()
nachname = row.get('Nachname', '').strip()
gruppe_original = row.get('Gruppe', '').strip()
if not vorname or not nachname or not gruppe_original: continue
kinder_nach_gruppen[gruppe_original].append({'Nachname': nachname, 'Vorname': vorname})
except Exception as e:
print(f"FEHLER beim Lesen der CSV-Datei für Befüllung: {e}")
return document_id
if not kinder_nach_gruppen:
print("Keine Daten aus der CSV-Datei für Befüllung geladen.")
return document_id
for gruppe_key in kinder_nach_gruppen:
kinder_nach_gruppen[gruppe_key].sort(key=lambda x: (x['Nachname'].lower(), x['Vorname'].lower()))
sorted_gruppen_namen = sorted(kinder_nach_gruppen.keys())
stand_zeit = datetime.now().strftime("%d.%m.%Y %H:%M Uhr")
# 3. Dokument befüllen - JETZT MIT VEREINFACHTER TEXTFORMATIERUNG
requests = []
for i, gruppe_original in enumerate(sorted_gruppen_namen):
kinder_liste = kinder_nach_gruppen[gruppe_original]
anzahl_kinder = len(kinder_liste)
gruppe_display_name = gruppe_original + GRUPPENNAME_SUFFIX
# Baue den gesamten Textblock für diese Seite/Gruppe
page_text_lines = []
# Seiten-Header
page_text_lines.append(f"{EINRICHTUNG}\t\t\t{FOTOGRAF_NAME}") # Tabs für rudimentäre Ausrichtung
page_text_lines.append(FOTODATUM)
page_text_lines.append("") # Leerzeile
# "Tabellen"-Daten als Text
page_text_lines.append("Nachname\tVorname\tGruppe") # Kopfzeile mit Tabs
for kind in kinder_liste:
page_text_lines.append(f"{kind['Nachname']}\t{kind['Vorname']}\t{gruppe_display_name}")
page_text_lines.append("") # Leerzeile nach der "Tabelle"
# Footer-Text
page_text_lines.append(f"{anzahl_kinder} angemeldete Kinder")
page_text_lines.append("")
page_text_lines.append("Dies ist die Liste der bereits angemeldeten Kinder. Bitte die Eltern der noch fehlenden")
page_text_lines.append("Kinder an die Anmeldung erinnern.")
page_text_lines.append("")
page_text_lines.append(f"Stand {stand_zeit}")
page_text_lines.append("")
page_text_lines.append(FOTOGRAF_NAME)
page_text_lines.append(FOTOGRAF_ADRESSE)
page_text_lines.append(FOTOGRAF_WEB)
page_text_lines.append(FOTOGRAF_TEL)
full_page_text = "\n".join(page_text_lines) + "\n" # Alle Zeilen mit Newline verbinden
# Einfügen des gesamten Textblocks für die Seite
if i == 0:
requests.append({'insertText': {'location': {'index': 1}, 'text': full_page_text}})
else:
# Nach einem PageBreak sollte der nächste Textblock angehängt werden
requests.append({'insertText': {'endOfSegmentLocation': {}, 'text': full_page_text}})
# Seitenumbruch nach jeder Gruppe, außer der letzten
if i < len(sorted_gruppen_namen) - 1:
requests.append({'insertPageBreak': {'endOfSegmentLocation': {}}})
# Batch-Update ausführen
if requests:
if not docs_service:
print("FEHLER: Docs API Service nicht verfügbar, kann Dokument nicht befüllen.")
return document_id
try:
print(f"Sende Batch Update für Dokument ID '{document_id}' (vereinfachte Textformatierung)...")
docs_service.documents().batchUpdate(
documentId=document_id, body={'requests': requests}
).execute()
print("Dokument erfolgreich befüllt (mit tabulatorgetrenntem Text).")
print("Sie können den Text in Google Docs markieren und über 'Einfügen' > 'Tabelle' > 'Tabelle aus Text erstellen' umwandeln.")
except HttpError as err:
print(f"Fehler beim Befüllen des Dokuments ID '{document_id}': {err}")
error_details = "Keine Fehlerdetails im Content."
if err.content:
try: error_details = err.content.decode('utf-8')
except: pass # Ignoriere Dekodierungsfehler
print(f"Details zum Fehler ({err.resp.status} {err._get_reason()}): {error_details}")
return document_id
return document_id
# --- Main execution block ---
if __name__ == "__main__":
print(f"Info: Verwendetes Fotodatum: {FOTODATUM}")
print(f"Info: Gruppennamen werden mit Suffix '{GRUPPENNAME_SUFFIX}' versehen.")
print(f"Info: Zieldokumente sollen in Ordner-ID '{TARGET_FOLDER_ID}' landen.")
docs_api_service, drive_api_service = get_services_with_service_account() # Definition oben im Skript
if docs_api_service:
final_doc_id = create_and_fill_doc( # Definition oben im Skript
docs_api_service,
drive_api_service,
TARGET_FOLDER_ID,
GOOGLE_DOC_TITLE
)
if final_doc_id:
print(f"\n--- SKRIPT BEENDET ---")
print(f"Dokument-ID: {final_doc_id}")
print(f"Link: https://docs.google.com/document/d/{final_doc_id}/edit")
if not drive_api_service or not TARGET_FOLDER_ID:
print("Das Dokument wurde im Root-Verzeichnis des Servicekontos erstellt.")
print("HINWEIS: Die 'Tabellen' wurden als tabulatorgetrennter Text eingefügt.")
print(" Öffnen Sie das Dokument und formatieren Sie den Text bei Bedarf als Tabelle.")
else:
print("\n--- FEHLGESCHLAGEN ---")
print("Konnte Dokument nicht erstellen oder befüllen.")
else:
print("Konnte Google Docs API Service nicht initialisieren. Skript wird beendet.")