Files
Brancheneinstufung2/list_generator.py
2025-05-26 18:58:27 +00:00

207 lines
9.8 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): # Umbenannt für Konsistenz
"""Erstellt ein Dokument (idealerweise im Ordner) und befüllt es mit CSV-Daten."""
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}")
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
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
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{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:
if not docs_service:
print("FEHLER: Docs API Service nicht verfügbar, kann Dokument nicht befüllen.")
return document_id # Gibt ID des (wahrscheinlich leeren) Dokuments zurück
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:
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
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()
if docs_api_service: # Mindestens Docs Service muss vorhanden sein
final_doc_id = create_and_fill_doc( # Name der Funktion hier korrigiert
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: # Hinweis, falls nicht im Ordner erstellt
print("Das Dokument wurde im Root-Verzeichnis des Servicekontos erstellt.")
else:
print("\n--- FEHLGESCHLAGEN ---")
print("Konnte Dokument nicht erstellen oder befüllen.")
else:
print("Konnte Google Docs API Service nicht initialisieren. Skript wird beendet.")