506 lines
26 KiB
Python
506 lines
26 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')}" # Zeit hinzugefügt für Eindeutigkeit
|
|
TARGET_FOLDER_ID = "18DNQaH9zbcBzwhckJI-4Uah-WXTXg6bg" # <<-- IHRE ORDNER-ID
|
|
|
|
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']
|
|
# 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 ---
|
|
|
|
def get_docs_service_with_service_account():
|
|
"""Erstellt den API-Dienst mit einem Service Account und gibt Service und Credentials zurück."""
|
|
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, None # Gibt Tuple zurück
|
|
|
|
try:
|
|
# Build für Docs 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:
|
|
print(f"Ein Fehler beim Erstellen des/der API Service(s) mit Service Account ist aufgetreten: {err}")
|
|
return None, None
|
|
except Exception as e:
|
|
print(f"Ein unerwarteter Fehler beim Erstellen des/der API Service(s): {e}")
|
|
return None, None
|
|
|
|
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 im angegebenen Ordner."""
|
|
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
|
|
|
|
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")
|
|
|
|
# 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:
|
|
# Wichtig: Wir verwenden den Drive Service, um die Datei mit parentId zu erstellen.
|
|
# 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')
|
|
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"BITTE manuell in den Ordner {folder_id} verschieben, oder Skript anpassen, um Drive API zum Erstellen/Verschieben zu nutzen.")
|
|
|
|
except HttpError as err:
|
|
print(f"Fehler beim Erstellen des Google Dokuments: {err}")
|
|
return None
|
|
except Exception as e_create:
|
|
print(f"Allgemeiner Fehler beim Erstellen des Dokuments: {e_create}")
|
|
return None
|
|
|
|
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
|
|
|
|
header_text_for_page = (
|
|
f"{EINRICHTUNG}\t\t\t{FOTOGRAF_NAME}\n"
|
|
f"{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\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
|
|
}
|
|
})
|
|
|
|
if i < len(sorted_gruppen_namen) - 1:
|
|
requests.append({'insertPageBreak': {'endOfSegmentLocation': {}}})
|
|
|
|
if requests:
|
|
try:
|
|
print("Sende Batch Update an Google Docs API...")
|
|
print("Anzahl der Requests:", len(requests))
|
|
docs_service.documents().batchUpdate( # Verwende docs_service hier
|
|
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: pass # Ignoriere Dekodierungsfehler
|
|
print(f"Details zum Fehler ({err.resp.status} {err._get_reason()}): {error_details}")
|
|
return document_id
|
|
|
|
|
|
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 (ggf. manuell oder per Drive API).")
|
|
|
|
# Service Account Authentifizierung
|
|
service_tuple = get_docs_service_with_service_account()
|
|
|
|
if service_tuple and service_tuple[0] and service_tuple[1]: # Prüfe ob docs_service und creds da sind
|
|
docs_api_service, service_creds = service_tuple
|
|
|
|
# --- Um ein Dokument direkt im Ordner zu erstellen, benötigen wir die Drive API ---
|
|
# Zusätzlichen Scope für Drive hinzufügen, falls nicht schon geschehen:
|
|
current_scopes = SCOPES
|
|
if 'https://www.googleapis.com/auth/drive.file' not in current_scopes and \
|
|
'https://www.googleapis.com/auth/drive' not in current_scopes:
|
|
# Dies ist nur ein Hinweis, der Scope muss in der `SCOPES`-Liste oben definiert sein
|
|
# und die Credentials neu generiert (oder token.json gelöscht, falls OAuth verwendet würde)
|
|
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. |