import csv from datetime import datetime import collections import os.path # Für Service Account Authentifizierung from google.oauth2 import service_account # Wichtig! 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')}" 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 für die Google Docs API SCOPES = ['https://www.googleapis.com/auth/documents'] SERVICE_ACCOUNT_FILE = 'service_account.json' # Ihre Service Account Schlüsseldatei # --- Ende Konfiguration --- def get_docs_service_with_service_account(): """Erstellt den API-Dienst mit einem Service Account.""" creds = 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 try: service = build('docs', 'v1', credentials=creds) return service except HttpError as err: print(f"Ein Fehler beim Erstellen des Docs Service mit Service Account ist aufgetreten: {err}") return None except Exception as e: print(f"Ein unerwarteter Fehler beim Erstellen des Docs Service: {e}") return None def create_google_doc_from_csv(service): """Liest CSV, verarbeitet Daten und erstellt/befüllt das Google Doc.""" 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: print(f"Warnung: Zeile übersprungen wegen fehlender Daten: {row}") continue kinder_nach_gruppen[gruppe_original].append({ 'Nachname': nachname, 'Vorname': vorname }) except FileNotFoundError: print(f"FEHLER: Die Datei '{CSV_FILENAME}' wurde nicht gefunden.") return None except Exception as e: print(f"FEHLER beim Lesen der CSV-Datei: {e}") return None if not kinder_nach_gruppen: print("Keine Daten aus der CSV-Datei geladen.") return None # Kinder innerhalb jeder Gruppe sortieren for gruppe_key in kinder_nach_gruppen: # Geändert von 'gruppe' zu 'gruppe_key' um Verwechslung zu vermeiden kinder_nach_gruppen[gruppe_key].sort(key=lambda x: (x['Nachname'].lower(), x['Vorname'].lower())) # ***** KORREKTUR HIER: sorted_gruppen_namen definieren ***** sorted_gruppen_namen = sorted(kinder_nach_gruppen.keys()) stand_zeit = datetime.now().strftime("%d.%m.%Y %H:%M Uhr") # 1. Neues Google Doc erstellen try: doc_body = {'title': GOOGLE_DOC_TITLE} doc = service.documents().create(body=doc_body).execute() document_id = doc.get('documentId') print(f"Google Doc erstellt mit ID: {document_id}") print(f"Link: https://docs.google.com/document/d/{document_id}/edit") except HttpError as err: print(f"Fehler beim Erstellen des Google Dokuments: {err}") return None requests = [] for i, gruppe_original in enumerate(sorted_gruppen_namen): # ... (kinder_liste, anzahl_kinder, gruppe_display_name) ... # --- Seiten-Header --- header_text_for_page = ( f"{EINRICHTUNG}\t\t\t{FOTOGRAF_NAME}\n" f"{FOTODATUM}\n\n" ) if i == 0: # Nur für die allererste Seite einen expliziten Index requests.append({'insertText': {'location': {'index': 1}, 'text': header_text_for_page}}) else: # Für Folgeseiten nach einem PageBreak requests.append({'insertText': {'endOfSegmentLocation': {}, 'text': header_text_for_page}}) # --- Tabelle --- num_rows_for_table = len(kinder_liste) + 1 num_cols_for_table = 3 # Tabelle wird nach dem Header eingefügt. # Wenn Header mit EOS eingefügt wurde, wird Tabelle auch mit EOS eingefügt. requests.append({ 'insertTable': { 'endOfSegmentLocation': {}, # Fügt Tabelle am aktuellen Ende an 'rows': num_rows_for_table, 'columns': num_cols_for_table } }) table_text_content = [] table_text_content.append("Nachname\tVorname\tGruppe") for kind in kinder_liste: table_text_content.append(f"{kind['Nachname']}\t{kind['Vorname']}\t{gruppe_display_name}") full_table_text = "\n".join(table_text_content) + "\n" # Füge den gesamten Tabelleninhalt ein. # Dies sollte in die zuletzt mit EOS erstellte Tabelle gehen. requests.append({ 'insertText': { 'endOfSegmentLocation': {}, 'text': full_table_text } }) # --- Footer --- footer_text_for_page = ( f"\n{anzahl_kinder} angemeldete Kinder\n\n" "Dies ist die Liste der bereits angemeldeten Kinder. Bitte die Eltern der noch fehlenden\n" "Kinder an die Anmeldung erinnern.\n\n" f"Stand {stand_zeit}\n\n" f"{FOTOGRAF_NAME}\n{FOTOGRAF_ADRESSE}\n{FOTOGRAF_WEB}\n{FOTOGRAF_TEL}\n" ) requests.append({ 'insertText': { 'endOfSegmentLocation': {}, 'text': footer_text_for_page } }) # --- Seitenumbruch --- if i < len(sorted_gruppen_namen) - 1: requests.append({'insertPageBreak': {'endOfSegmentLocation': {}}}) # Batch-Update ausführen if requests: try: print("Sende Batch Update an Google Docs API...") print("Anzahl der Requests:", len(requests)) # Debug: Gib die ersten paar Requests aus, um zu sehen, ob sie logisch aussehen # for req_idx, req_content in enumerate(requests[:6]): # print(f"Request [{req_idx}]: {req_content}") service.documents().batchUpdate( documentId=document_id, body={'requests': requests} ).execute() print("Dokument erfolgreich befüllt.") except HttpError as err: print(f"Fehler beim Befüllen des Google Dokuments: {err}") error_details = "Keine Fehlerdetails im Content." if err.content: try: error_details = err.content.decode('utf-8') except Exception as e_decode: error_details = f"Fehler beim Dekodieren der Fehlerdetails: {e_decode}" print(f"Details zum Fehler ({err.resp.status} {err._get_reason()}): {error_details}") # Wenn es immer noch schiefgeht, alle Requests ausgeben: # print("Alle gesendeten Requests:") # for req_idx, req_content in enumerate(requests): # print(f"Request [{req_idx}]: {req_content}") return document_id if __name__ == '__main__': print(f"Info: Verwendetes Fotodatum: {FOTODATUM}") print(f"Info: Gruppennamen werden mit Suffix '{GRUPPENNAME_SUFFIX}' versehen.") docs_service = get_docs_service_with_service_account() if docs_service: document_id = create_google_doc_from_csv(docs_service) if document_id: print("\n--- WICHTIG ---") print(f"Das Dokument wurde vom Servicekonto erstellt: {SERVICE_ACCOUNT_FILE}") print(f"Sie finden es unter: https://docs.google.com/document/d/{document_id}/edit") print("Wenn Sie das Dokument in Ihrem Haupt-Google-Drive-Konto sehen und bearbeiten möchten,") print("müssen Sie entweder:") print("1. Das Servicekonto (die E-Mail-Adresse des Servicekontos, steht in der JSON-Datei)") print(" als Bearbeiter zu dem Google Drive Ordner hinzufügen, in dem das Dokument erstellt werden soll (bevor das Skript läuft, oder das Dokument verschieben).") print("2. Oder das Skript erweitern, um das Dokument nach der Erstellung explizit mit Ihrem") print(" Benutzerkonto zu teilen (siehe auskommentierten Code-Teil mit `drive_service.permissions().create`).") print(" Dafür benötigt das Servicekonto auch den Scope 'https://www.googleapis.com/auth/drive'.")