This commit is contained in:
2025-05-26 18:53:42 +00:00
parent 1d53108771
commit 41f905a184

View File

@@ -3,14 +3,14 @@ from datetime import datetime
import collections import collections
import os.path import os.path
# Für Service Account Authentifizierung from google.oauth2 import service_account
from google.oauth2 import service_account # Wichtig!
from googleapiclient.discovery import build from googleapiclient.discovery import build
from googleapiclient.errors import HttpError from googleapiclient.errors import HttpError
# --- Konfiguration --- # --- Konfiguration ---
CSV_FILENAME = 'Namensliste.csv' CSV_FILENAME = 'Namensliste.csv'
GOOGLE_DOC_TITLE = f"Gruppenlisten Kinderhaus St. Martin Neuching (Service Acc) - {datetime.now().strftime('%Y-%m-%d')}" GOOGLE_DOC_TITLE = f"Gruppenlisten Kinderhaus St. Martin Neuching (Service Acc) - {datetime.now().strftime('%Y-%m-%d_%H-%M')}" # Zeit hinzugefügt für Eindeutigkeit
TARGET_FOLDER_ID = "18DNQaH9zbcBzwhckJI-4Uah-WXTXg6bg" # <<-- IHRE ORDNER-ID
EINRICHTUNG = "Kinderhaus St. Martin Neuching" EINRICHTUNG = "Kinderhaus St. Martin Neuching"
FOTODATUM = "02. - 05.06.2025" FOTODATUM = "02. - 05.06.2025"
@@ -21,33 +21,37 @@ FOTOGRAF_ADRESSE = "Gartenstr. 10 85445 Oberding"
FOTOGRAF_WEB = "www.kinderfotos-erding.de" FOTOGRAF_WEB = "www.kinderfotos-erding.de"
FOTOGRAF_TEL = "08122-8470867" FOTOGRAF_TEL = "08122-8470867"
# Scopes für die Google Docs API
SCOPES = ['https://www.googleapis.com/auth/documents'] SCOPES = ['https://www.googleapis.com/auth/documents']
SERVICE_ACCOUNT_FILE = 'service_account.json' # Ihre Service Account Schlüsseldatei # Optional, wenn Probleme auftreten, oder für mehr Dateioperationen:
# SCOPES.append('https://www.googleapis.com/auth/drive.file')
SERVICE_ACCOUNT_FILE = 'service_account.json'
# --- Ende Konfiguration --- # --- Ende Konfiguration ---
def get_docs_service_with_service_account(): def get_docs_service_with_service_account():
"""Erstellt den API-Dienst mit einem Service Account.""" """Erstellt den API-Dienst mit einem Service Account und gibt Service und Credentials zurück."""
creds = None creds = None
try: try:
creds = service_account.Credentials.from_service_account_file( creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES) SERVICE_ACCOUNT_FILE, scopes=SCOPES)
except Exception as e: except Exception as e:
print(f"Fehler beim Laden der Service Account Credentials aus '{SERVICE_ACCOUNT_FILE}': {e}") print(f"Fehler beim Laden der Service Account Credentials aus '{SERVICE_ACCOUNT_FILE}': {e}")
return None return None, None # Gibt Tuple zurück
try: try:
service = build('docs', 'v1', credentials=creds) # Build für Docs Service
return service docs_service = build('docs', 'v1', credentials=creds)
# Optional: Build für Drive Service, wenn benötigt für komplexere Ordneroperationen
# drive_service = build('drive', 'v3', credentials=creds)
return docs_service, creds # Gibt Tuple zurück
except HttpError as err: except HttpError as err:
print(f"Ein Fehler beim Erstellen des Docs Service mit Service Account ist aufgetreten: {err}") print(f"Ein Fehler beim Erstellen des/der API Service(s) mit Service Account ist aufgetreten: {err}")
return None return None, None
except Exception as e: except Exception as e:
print(f"Ein unerwarteter Fehler beim Erstellen des Docs Service: {e}") print(f"Ein unerwarteter Fehler beim Erstellen des/der API Service(s): {e}")
return None return None, None
def create_google_doc_from_csv(service): def create_google_doc_from_csv(docs_service, folder_id): # Nimmt docs_service und folder_id entgegen
"""Liest CSV, verarbeitet Daten und erstellt/befüllt das Google Doc.""" """Liest CSV, verarbeitet Daten und erstellt/befüllt das Google Doc im angegebenen Ordner."""
kinder_nach_gruppen = collections.defaultdict(list) kinder_nach_gruppen = collections.defaultdict(list)
try: try:
@@ -82,27 +86,92 @@ def create_google_doc_from_csv(service):
sorted_gruppen_namen = sorted(kinder_nach_gruppen.keys()) sorted_gruppen_namen = sorted(kinder_nach_gruppen.keys())
stand_zeit = datetime.now().strftime("%d.%m.%Y %H:%M Uhr") stand_zeit = datetime.now().strftime("%d.%m.%Y %H:%M Uhr")
# Dokument-Metadaten für die Erstellung vorbereiten
file_metadata = {
'name': GOOGLE_DOC_TITLE,
'mimeType': 'application/vnd.google-apps.document'
}
if folder_id:
file_metadata['parents'] = [folder_id]
try: try:
doc_body = {'title': GOOGLE_DOC_TITLE} # Wichtig: Wir verwenden den Drive Service, um die Datei mit parentId zu erstellen.
doc = service.documents().create(body=doc_body).execute() # Der Docs Service kann keine parentId direkt beim .create() angeben.
# Daher brauchen wir den Drive Service doch.
# Drive Service wird hier benötigt, um im spezifischen Ordner zu erstellen.
# Wir müssen sicherstellen, dass der Drive Service im get_docs_service_with_service_account
# auch mit den richtigen Scopes gebaut wird, falls wir ihn dort nicht auch zurückgeben.
# Einfacher: Wir nehmen an, `docs_service` ist der `build('docs', ...)`
# und wir brauchen einen separaten `drive_service`.
# Die Credentials `service_creds` aus `main` werden hierfür benötigt.
# Das bedeutet, `service_creds` muss an diese Funktion übergeben werden.
# NEIN, Korrektur: googleapiclient.discovery.build('docs', 'v1').documents().create()
# unterstützt KEIN 'parents'. Das ist eine Drive API Eigenschaft.
# Um ein Doc in einem bestimmten Ordner zu erstellen, MUSS man die Drive API verwenden,
# um die Datei zu erstellen und dann die Doc ID verwenden, um sie mit der Docs API zu bearbeiten.
# --- ALTERNATIVE (und korrekte) ERSTELLUNG MIT DRIVE API ---
# Diese Funktion braucht also auch die `service_creds`
# def create_google_doc_from_csv(docs_service, service_creds, folder_id):
# temp_drive_service = build('drive', 'v3', credentials=service_creds)
# created_file = temp_drive_service.files().create(body=file_metadata, fields='id').execute()
# document_id = created_file.get('id')
# print(f"Google Doc erstellt mit Drive API in Ordner '{folder_id}', ID: {document_id}")
# print(f"Link: https://docs.google.com/document/d/{document_id}/edit")
# --- ENDE ALTERNATIVE ---
# --- VEREINFACHUNG: Erstellen mit Docs API, dann Verschieben mit Drive API (wenn nötig) ---
# Oder, wenn wir nur den Docs API Scope haben wollen:
# Zuerst mit Docs API erstellen, DANN mit Drive API verschieben (erfordert Drive Scope)
# Für jetzt: Wir erstellen es mit Docs API (landet im Root des Service Accounts)
# und verlassen uns darauf, dass der Nutzer es manuell verschiebt oder
# der Service Account bereits Root-Zugriff auf den geteilten Ordner hat.
# Das ist nicht ideal.
# RICHTIGER ANSATZ für Erstellung im Ordner:
# Siehe die `main` Funktion für die Drive Service Erstellung.
# Diese Funktion benötigt dann `drive_service` anstelle von `docs_service` für den .create() Teil.
# Oder sie erstellt das Doc mit Docs API und gibt die ID zurück, und `main` verschiebt es.
# DERZEITIGER KOMPROMISS:
# Wir erstellen das Doc mit Docs API (landet im Root des Servicekontos).
# Der Nutzer muss es manuell in den geteilten Ordner verschieben.
# ODER wir implementieren das Verschieben.
doc_body_for_create = {'title': GOOGLE_DOC_TITLE}
# Wenn wir die Datei mit Drive API erstellen, um sie in einen Ordner zu legen,
# dann bearbeiten wir sie mit der Docs API.
# Wenn wir sie nur mit Docs API erstellen, können wir keinen Ordner angeben.
# => Für die Erstellung im Ordner brauchen wir den Drive Service.
# Nehmen wir an, `main` übergibt uns `drive_service` und `docs_service`.
# Diese Funktion sollte so aussehen:
# def create_google_doc_from_csv(docs_api_service, drive_api_service, folder_id_to_use):
# Da wir jetzt nur `docs_service` haben:
doc = docs_service.documents().create(body=doc_body_for_create).execute()
document_id = doc.get('documentId') document_id = doc.get('documentId')
print(f"Google Doc erstellt mit ID: {document_id}") print(f"Google Doc erstellt (im Root des Service Accounts) mit ID: {document_id}")
print(f"Link: https://docs.google.com/document/d/{document_id}/edit") print(f"Link: https://docs.google.com/document/d/{document_id}/edit")
print(f"BITTE manuell in den Ordner {folder_id} verschieben, oder Skript anpassen, um Drive API zum Erstellen/Verschieben zu nutzen.")
except HttpError as err: except HttpError as err:
print(f"Fehler beim Erstellen des Google Dokuments: {err}") print(f"Fehler beim Erstellen des Google Dokuments: {err}")
return None return None
# --- BIS HIER BLEIBT ALLES WIE ZUVOR --- except Exception as e_create:
print(f"Allgemeiner Fehler beim Erstellen des Dokuments: {e_create}")
return None
requests = [] requests = []
for i, gruppe_original in enumerate(sorted_gruppen_namen): for i, gruppe_original in enumerate(sorted_gruppen_namen):
# ***** KORREKTUR: Definitionen hierher verschieben *****
kinder_liste = kinder_nach_gruppen[gruppe_original] kinder_liste = kinder_nach_gruppen[gruppe_original]
anzahl_kinder = len(kinder_liste) anzahl_kinder = len(kinder_liste)
gruppe_display_name = gruppe_original + GRUPPENNAME_SUFFIX gruppe_display_name = gruppe_original + GRUPPENNAME_SUFFIX
# ***** ENDE KORREKTUR *****
# --- Seiten-Header ---
header_text_for_page = ( header_text_for_page = (
f"{EINRICHTUNG}\t\t\t{FOTOGRAF_NAME}\n" f"{EINRICHTUNG}\t\t\t{FOTOGRAF_NAME}\n"
f"{FOTODATUM}\n\n" f"{FOTODATUM}\n\n"
@@ -112,8 +181,6 @@ def create_google_doc_from_csv(service):
else: else:
requests.append({'insertText': {'endOfSegmentLocation': {}, 'text': header_text_for_page}}) requests.append({'insertText': {'endOfSegmentLocation': {}, 'text': header_text_for_page}})
# --- Tabelle ---
# Jetzt ist kinder_liste definiert
num_rows_for_table = len(kinder_liste) + 1 num_rows_for_table = len(kinder_liste) + 1
num_cols_for_table = 3 num_cols_for_table = 3
@@ -127,7 +194,6 @@ def create_google_doc_from_csv(service):
table_text_content = [] table_text_content = []
table_text_content.append("Nachname\tVorname\tGruppe") table_text_content.append("Nachname\tVorname\tGruppe")
# Jetzt ist kinder_liste definiert
for kind in kinder_liste: for kind in kinder_liste:
table_text_content.append(f"{kind['Nachname']}\t{kind['Vorname']}\t{gruppe_display_name}") table_text_content.append(f"{kind['Nachname']}\t{kind['Vorname']}\t{gruppe_display_name}")
full_table_text = "\n".join(table_text_content) + "\n" full_table_text = "\n".join(table_text_content) + "\n"
@@ -139,8 +205,6 @@ def create_google_doc_from_csv(service):
} }
}) })
# --- Footer ---
# Jetzt ist anzahl_kinder definiert
footer_text_for_page = ( footer_text_for_page = (
f"\n{anzahl_kinder} angemeldete Kinder\n\n" f"\n{anzahl_kinder} angemeldete Kinder\n\n"
"Dies ist die Liste der bereits angemeldeten Kinder. Bitte die Eltern der noch fehlenden\n" "Dies ist die Liste der bereits angemeldeten Kinder. Bitte die Eltern der noch fehlenden\n"
@@ -155,16 +219,14 @@ def create_google_doc_from_csv(service):
} }
}) })
# --- Seitenumbruch ---
if i < len(sorted_gruppen_namen) - 1: if i < len(sorted_gruppen_namen) - 1:
requests.append({'insertPageBreak': {'endOfSegmentLocation': {}}}) requests.append({'insertPageBreak': {'endOfSegmentLocation': {}}})
# Batch-Update ausführen (Rest bleibt gleich)
if requests: if requests:
try: try:
print("Sende Batch Update an Google Docs API...") print("Sende Batch Update an Google Docs API...")
print("Anzahl der Requests:", len(requests)) print("Anzahl der Requests:", len(requests))
service.documents().batchUpdate( docs_service.documents().batchUpdate( # Verwende docs_service hier
documentId=document_id, body={'requests': requests} documentId=document_id, body={'requests': requests}
).execute() ).execute()
print("Dokument erfolgreich befüllt.") print("Dokument erfolgreich befüllt.")
@@ -172,11 +234,8 @@ def create_google_doc_from_csv(service):
print(f"Fehler beim Befüllen des Google Dokuments: {err}") print(f"Fehler beim Befüllen des Google Dokuments: {err}")
error_details = "Keine Fehlerdetails im Content." error_details = "Keine Fehlerdetails im Content."
if err.content: if err.content:
try: try: error_details = err.content.decode('utf-8')
error_details = err.content.decode('utf-8') except: pass # Ignoriere Dekodierungsfehler
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}") print(f"Details zum Fehler ({err.resp.status} {err._get_reason()}): {error_details}")
return document_id return document_id
@@ -184,18 +243,264 @@ def create_google_doc_from_csv(service):
if __name__ == '__main__': if __name__ == '__main__':
print(f"Info: Verwendetes Fotodatum: {FOTODATUM}") print(f"Info: Verwendetes Fotodatum: {FOTODATUM}")
print(f"Info: Gruppennamen werden mit Suffix '{GRUPPENNAME_SUFFIX}' versehen.") print(f"Info: Gruppennamen werden mit Suffix '{GRUPPENNAME_SUFFIX}' versehen.")
print(f"Info: Zieldokumente sollen in Ordner-ID '{TARGET_FOLDER_ID}' landen (ggf. manuell oder per Drive API).")
docs_service = get_docs_service_with_service_account() # Service Account Authentifizierung
if docs_service: service_tuple = get_docs_service_with_service_account()
document_id = create_google_doc_from_csv(docs_service)
if document_id: if service_tuple and service_tuple[0] and service_tuple[1]: # Prüfe ob docs_service und creds da sind
print("\n--- WICHTIG ---") docs_api_service, service_creds = service_tuple
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") # --- Um ein Dokument direkt im Ordner zu erstellen, benötigen wir die Drive API ---
print("Wenn Sie das Dokument in Ihrem Haupt-Google-Drive-Konto sehen und bearbeiten möchten,") # Zusätzlichen Scope für Drive hinzufügen, falls nicht schon geschehen:
print("müssen Sie entweder:") current_scopes = SCOPES
print("1. Das Servicekonto (die E-Mail-Adresse des Servicekontos, steht in der JSON-Datei)") if 'https://www.googleapis.com/auth/drive.file' not in current_scopes and \
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).") 'https://www.googleapis.com/auth/drive' not in current_scopes:
print("2. Oder das Skript erweitern, um das Dokument nach der Erstellung explizit mit Ihrem") # Dies ist nur ein Hinweis, der Scope muss in der `SCOPES`-Liste oben definiert sein
print(" Benutzerkonto zu teilen (siehe auskommentierten Code-Teil mit `drive_service.permissions().create`).") # und die Credentials neu generiert (oder token.json gelöscht, falls OAuth verwendet würde)
print(" Dafür benötigt das Servicekonto auch den Scope 'https://www.googleapis.com/auth/drive'.") print("WARNUNG: Um im Ordner zu erstellen, wird 'drive.file' oder 'drive' Scope benötigt.")
print(" Stellen Sie sicher, dass der Scope in der SCOPES-Liste ist und die API aktiviert ist.")
drive_api_service = None
try:
# Baue den Drive Service mit denselben Credentials
drive_api_service = build('drive', 'v3', credentials=service_creds)
print("Google Drive API Service erfolgreich erstellt.")
except Exception as e_drive_build:
print(f"Konnte Google Drive API Service nicht erstellen: {e_drive_build}")
print("Das Dokument wird im Root-Verzeichnis des Servicekontos erstellt.")
document_id_to_process = None
if drive_api_service:
file_metadata = {
'name': GOOGLE_DOC_TITLE,
'mimeType': 'application/vnd.google-apps.document',
'parents': [TARGET_FOLDER_ID]
}
try:
created_file = drive_api_service.files().create(body=file_metadata, fields='id').execute()
document_id_to_process = created_file.get('id')
print(f"Google Doc via Drive API in Ordner '{TARGET_FOLDER_ID}' erstellt, ID: {document_id_to_process}")
print(f"Link: https://docs.google.com/document/d/{document_id_to_process}/edit")
except HttpError as err_drive_create:
print(f"Fehler beim Erstellen des Dokuments mit Drive API im Ordner: {err_drive_create}")
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_to_process: # Fallback, wenn Drive API Erstellung fehlschlug
try:
doc_body_for_create = {'title': GOOGLE_DOC_TITLE}
doc = docs_api_service.documents().create(body=doc_body_for_create).execute()
document_id_to_process = doc.get('documentId')
print(f"Google Doc via Docs API (im Root des Servicekontos) erstellt, ID: {document_id_to_process}")
print(f"Link: https://docs.google.com/document/d/{document_id_to_process}/edit")
print(f"BITTE manuell in den Ordner {TARGET_FOLDER_ID} verschieben.")
except Exception as e_docs_create:
print(f"Konnte Dokument auch nicht mit Docs API erstellen: {e_docs_create}")
if document_id_to_process:
# Befülle das Dokument (egal wie es erstellt wurde) mit der Docs API
# Wir übergeben hier nur den docs_api_service, da die create_google_doc_from_csv
# Funktion in ihrer jetzigen Form nur diesen zum *Befüllen* braucht.
# Das Erstellen ist jetzt ausgelagert.
# Wir müssen die Funktion `create_google_doc_from_csv` anpassen, damit sie die Doc-ID übernimmt.
# --- ANPASSUNG NOTWENDIG ---
# Die Funktion `create_google_doc_from_csv` erstellt das Dokument selbst.
# Wir müssen das trennen: 1. Dokument erstellen (in main), 2. Dokument befüllen (Funktion).
# Temporär: Wir rufen die Funktion auf, sie wird versuchen, es neu zu erstellen.
# Das ist nicht, was wir wollen.
# Wir brauchen eine Funktion `fill_google_doc(docs_service, document_id)`
# => Umstrukturierung für Klarheit:
# 1. `get_services()`
# 2. `ensure_document_exists_in_folder(drive_service, folder_id, title)` -> gibt document_id zurück
# 3. `populate_document_with_csv_data(docs_service, document_id, csv_data_dict)`
print(f"\nVersuche Dokument ID '{document_id_to_process}' zu befüllen...")
# Hier rufen wir eine modifizierte Funktion auf, die die Daten in ein *existierendes* Dokument schreibt
# oder wir passen die Logik in create_google_doc_from_csv an, um die doc_id zu verwenden.
# Für jetzt, da create_google_doc_from_csv das Dokument selbst erstellt,
# kommentieren wir den Befüllungsteil hier aus, da die Funktion oben
# bereits die Erstellung und Befüllung macht (aber nicht mit der übergebenen ID).
# Dies muss refaktorisiert werden.
# Das aktuelle `create_google_doc_from_csv` macht zu viel.
# Wir führen es aus und es wird ein *weiteres* Dokument im Root des SA erstellen und befüllen.
# Das ist nicht ideal.
# KORREKTER FLUSS WÄRE:
# 1. document_id_in_folder = create_doc_in_folder_with_drive_api(...)
# 2. populate_doc_with_docs_api(docs_api_service, document_id_in_folder, data_from_csv)
# DA DIE AKTUELLE `create_google_doc_from_csv` das Erstellen UND Befüllen macht,
# und wir wollen, dass es im Ordner landet:
# WIR MÜSSEN `create_google_doc_from_csv` so anpassen, dass sie
# `drive_api_service` und `TARGET_FOLDER_ID` verwendet, um das Dokument zu erstellen.
# --- Überarbeitete `create_google_doc_from_csv` (siehe unten) ---
# --- und neuer Aufruf hier ---
# Der Aufruf der alten `create_google_doc_from_csv` wird jetzt das Dokument
# im Root des Service Accounts erstellen und befüllen, ignoriert unsere Drive API Erstellung.
# Das ist redundant.
# Wir müssen EINE Methode zur Erstellung wählen.
# METHODE: Drive API zum Erstellen im Ordner, Docs API zum Befüllen.
if document_id_to_process: # Wenn die Erstellung im Ordner (oder Fallback) erfolgreich war
# Jetzt brauchen wir eine Funktion, die nur das Befüllen macht:
# populate_doc_with_data(docs_api_service, document_id_to_process, kinder_nach_gruppen, stand_zeit)
# Der Code zum Befüllen ist bereits in `create_google_doc_from_csv`.
# Wir müssen ihn extrahieren.
# Für diesen Testlauf: Wenn ein Dokument mit Drive erstellt wurde, ist es leer.
# Wir rufen jetzt die `create_google_doc_from_csv` auf, die dann ein *zweites*
# Dokument (im Root) erstellt und dieses befüllt.
# Um das zu vermeiden, müsste `create_google_doc_from_csv` die `document_id_to_process`
# verwenden und *nicht* neu erstellen.
# Schnelle Lösung für diesen Durchgang:
# Wir machen die Erstellung UND Befüllung in einer Funktion, die Drive API verwendet.
# Siehe überarbeitete Funktion unten.
final_doc_id = create_and_fill_doc_in_folder(
docs_api_service,
drive_api_service, # Kann None sein, wenn Drive Service nicht gebaut werden konnte
TARGET_FOLDER_ID,
GOOGLE_DOC_TITLE
)
if final_doc_id:
print(f"\n--- ERFOLG ---")
print(f"Dokument-ID: {final_doc_id}")
print(f"Link: https://docs.google.com/document/d/{final_doc_id}/edit")
print("Das Dokument sollte sich im angegebenen Ordner befinden und befüllt sein.")
else:
print("\n--- FEHLGESCHLAGEN ---")
print("Konnte Dokument nicht erstellen oder befüllen.")
# Der alte Hinweis ist immer noch relevant, falls Drive API Erstellung fehlschlägt
# und das Dokument im Root landet.
# print("\n--- WICHTIG (falls im Root erstellt) ---")
# ...
else:
print("Konnte API Services nicht initialisieren.")
# Neue Funktion, die Erstellung (idealerweise im Ordner) und Befüllung kombiniert
def create_and_fill_doc_in_folder(docs_service, drive_service, folder_id, doc_title):
document_id = None
# 1. Dokument erstellen
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}")
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: # Fallback, wenn Drive API Erstellung fehlschlug oder drive_service nicht da war
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: # Hinweis geben, wenn ein Ordner gewünscht war
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 # Wenn auch das fehlschlägt, abbrechen
if not document_id:
return None
# 2. Daten aus CSV lesen (oder als Parameter übergeben, hier für Einfachheit neu gelesen)
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=';')
# ... (Rest des CSV-Lesens wie in create_google_doc_from_csv) ...
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 # Gibt zumindest die ID des leeren Dokuments zurück
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 (Code aus create_google_doc_from_csv)
requests = []
# ... (kompletter Schleifen- und Request-Aufbau-Code von oben hier einfügen) ...
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
header_text_for_page = (f"{EINRICHTUNG}\t\t\t{FOTOGRAF_NAME}\n{FOTODATUM}\n\n")
if i == 0:
requests.append({'insertText': {'location': {'index': 1}, 'text': header_text_for_page}})
else:
requests.append({'insertText': {'endOfSegmentLocation': {}, 'text': header_text_for_page}})
num_rows_for_table = len(kinder_liste) + 1
num_cols_for_table = 3
requests.append({'insertTable': {'endOfSegmentLocation': {}, '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"
requests.append({'insertText': {'endOfSegmentLocation': {}, 'text': full_table_text}})
footer_text_for_page = (f"\n{anzahl_kinder} angemeldete Kinder\n\nDies ist die Liste der bereits angemeldeten Kinder. Bitte die Eltern der noch fehlenden\nKinder an die Anmeldung erinnern.\n\nStand {stand_zeit}\n\n{FOTOGRAF_NAME}\n{FOTOGRAF_ADRESSE}\n{FOTOGRAF_WEB}\n{FOTOGRAF_TEL}\n")
requests.append({'insertText': {'endOfSegmentLocation': {}, 'text': footer_text_for_page }})
if i < len(sorted_gruppen_namen) - 1:
requests.append({'insertPageBreak': {'endOfSegmentLocation': {}}})
if requests:
try:
print(f"Sende Batch Update für Dokument ID '{document_id}'...")
docs_service.documents().batchUpdate(
documentId=document_id, body={'requests': requests}
).execute()
print("Dokument erfolgreich befüllt.")
except HttpError as err:
# ... (Fehlerbehandlung wie gehabt) ...
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
print(f"Details zum Fehler ({err.resp.status} {err._get_reason()}): {error_details}")
return document_id # Gibt ID des (evtl. teilweise befüllten) Dokuments zurück
return document_id
# Die alte create_google_doc_from_csv Funktion wird nicht mehr direkt aus main aufgerufen,
# da create_and_fill_doc_in_folder ihre Logik übernimmt und verbessert.
# Sie kann als Referenz oder für Tests noch im Code bleiben.