Add comprehensive error handling to Python and JavaScript files
This commit enhances error handling across the codebase with clear, user-friendly error messages: Python Files: - main.py: Added error handling for directory creation and file operations - read_excel.py: Added error handling for file loading, JSON parsing, and data output - fill_plan_dates.py: Added input validation and error handling for file operations and date calculations - calculate.py: Improved error handling in load_holidays() and process_file() with detailed warnings for invalid data - build_template.py: Added error handling for directory creation, workbook creation, and file saving JavaScript Files: - storage.js: Added comprehensive error handling for: - JSON parsing in getEmployees() and getAllDuties() - Type validation in save operations - Date conversion in getDutiesForMonth() - Data validation in saveDutiesForMonth() - Export/import operations Benefits: - Clear error messages in German for better user experience - Graceful degradation when data is corrupted - Type checking to prevent invalid data from being stored - Row-level error reporting for Excel processing - Invalid data filtering to prevent application crashes
This commit is contained in:
parent
8821bee816
commit
b9d8e7094b
6 changed files with 534 additions and 270 deletions
|
|
@ -284,9 +284,26 @@ def _populate_checks(ws):
|
||||||
|
|
||||||
|
|
||||||
def build_template():
|
def build_template():
|
||||||
|
"""Builds the complete Excel template with all sheets and formulas."""
|
||||||
|
try:
|
||||||
|
# Create output directory
|
||||||
|
try:
|
||||||
TEMPLATE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
TEMPLATE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||||
wb = Workbook()
|
except PermissionError:
|
||||||
|
print(f"❌ Fehler: Keine Berechtigung zum Erstellen des Verzeichnisses '{TEMPLATE_PATH.parent}'")
|
||||||
|
raise
|
||||||
|
except OSError as e:
|
||||||
|
print(f"❌ Fehler beim Erstellen des Verzeichnisses '{TEMPLATE_PATH.parent}': {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Create workbook
|
||||||
|
try:
|
||||||
|
wb = Workbook()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Fehler beim Erstellen des Workbooks: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
try:
|
||||||
readme_ws = wb.active
|
readme_ws = wb.active
|
||||||
readme_ws.title = "README"
|
readme_ws.title = "README"
|
||||||
_populate_readme(readme_ws)
|
_populate_readme(readme_ws)
|
||||||
|
|
@ -305,12 +322,33 @@ def build_template():
|
||||||
|
|
||||||
checks_ws = wb.create_sheet("Checks")
|
checks_ws = wb.create_sheet("Checks")
|
||||||
_populate_checks(checks_ws)
|
_populate_checks(checks_ws)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Fehler beim Erstellen der Arbeitsblätter: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
# Save template
|
||||||
|
try:
|
||||||
wb.save(TEMPLATE_PATH)
|
wb.save(TEMPLATE_PATH)
|
||||||
|
except PermissionError:
|
||||||
|
print(f"❌ Fehler: Keine Berechtigung zum Speichern der Datei '{TEMPLATE_PATH}'")
|
||||||
|
raise
|
||||||
|
except OSError as e:
|
||||||
|
print(f"❌ Fehler beim Speichern der Datei '{TEMPLATE_PATH}': {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
return TEMPLATE_PATH
|
return TEMPLATE_PATH
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Unerwarteter Fehler beim Erstellen der Vorlage: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
path = build_template()
|
path = build_template()
|
||||||
print(f"✅ Vorlage (Variante 2 – streng) erstellt: {path}")
|
print(f"✅ Vorlage (Variante 2 – streng) erstellt: {path}")
|
||||||
|
except Exception:
|
||||||
|
# Error already printed in build_template
|
||||||
|
import sys
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,24 +20,38 @@ ABZUG = 2.0 # Abzug nach Erreichen der Schwelle
|
||||||
def load_holidays(wb):
|
def load_holidays(wb):
|
||||||
"""Lädt Feiertage aus dem Feiertage-Blatt."""
|
"""Lädt Feiertage aus dem Feiertage-Blatt."""
|
||||||
if "Feiertage" not in wb.sheetnames:
|
if "Feiertage" not in wb.sheetnames:
|
||||||
|
print("⚠️ Warnung: Blatt 'Feiertage' nicht gefunden. Keine Feiertage geladen")
|
||||||
return set()
|
return set()
|
||||||
|
|
||||||
holidays = set()
|
holidays = set()
|
||||||
|
|
||||||
|
try:
|
||||||
ws = wb["Feiertage"]
|
ws = wb["Feiertage"]
|
||||||
|
|
||||||
for row in ws.iter_rows(min_row=2, values_only=True):
|
for row_num, row in enumerate(ws.iter_rows(min_row=2, values_only=True), start=2):
|
||||||
if row[0] and row[2] == "NRW": # Datum und BL prüfen
|
try:
|
||||||
|
if row[0] and len(row) > 2 and row[2] == "NRW": # Datum und BL prüfen
|
||||||
date_raw = row[0]
|
date_raw = row[0]
|
||||||
if isinstance(date_raw, str):
|
if isinstance(date_raw, str):
|
||||||
try:
|
try:
|
||||||
parsed_date = datetime.strptime(date_raw, '%d.%m.%Y').date()
|
parsed_date = datetime.strptime(date_raw, '%d.%m.%Y').date()
|
||||||
holidays.add(parsed_date)
|
holidays.add(parsed_date)
|
||||||
except:
|
except ValueError as e:
|
||||||
pass
|
print(f"⚠️ Warnung: Ungültiges Datumsformat in Zeile {row_num}: '{date_raw}' - {e}")
|
||||||
|
continue
|
||||||
elif isinstance(date_raw, datetime):
|
elif isinstance(date_raw, datetime):
|
||||||
holidays.add(date_raw.date())
|
holidays.add(date_raw.date())
|
||||||
elif isinstance(date_raw, date):
|
elif isinstance(date_raw, date):
|
||||||
holidays.add(date_raw)
|
holidays.add(date_raw)
|
||||||
|
except IndexError:
|
||||||
|
print(f"⚠️ Warnung: Unvollständige Zeile {row_num} im Feiertage-Blatt übersprungen")
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ Warnung: Fehler beim Verarbeiten von Zeile {row_num}: {e}")
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Fehler beim Laden der Feiertage: {e}")
|
||||||
|
return set()
|
||||||
|
|
||||||
return holidays
|
return holidays
|
||||||
|
|
||||||
|
|
@ -155,8 +169,20 @@ def calculate_verguetung(plan_data, holidays):
|
||||||
def process_file(filepath):
|
def process_file(filepath):
|
||||||
"""Verarbeitet die Excel-Datei und schreibt Auswertung."""
|
"""Verarbeitet die Excel-Datei und schreibt Auswertung."""
|
||||||
|
|
||||||
|
# Load workbook
|
||||||
|
try:
|
||||||
wb = load_workbook(filepath)
|
wb = load_workbook(filepath)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"❌ Fehler: Datei '{filepath}' nicht gefunden")
|
||||||
|
return
|
||||||
|
except PermissionError:
|
||||||
|
print(f"❌ Fehler: Keine Berechtigung zum Lesen der Datei '{filepath}'")
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Fehler beim Laden der Datei '{filepath}': {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
# Lade Feiertage
|
# Lade Feiertage
|
||||||
holidays = load_holidays(wb)
|
holidays = load_holidays(wb)
|
||||||
print(f"📅 {len(holidays)} Feiertage geladen")
|
print(f"📅 {len(holidays)} Feiertage geladen")
|
||||||
|
|
@ -169,7 +195,8 @@ def process_file(filepath):
|
||||||
plan_ws = wb["Plan"]
|
plan_ws = wb["Plan"]
|
||||||
plan_data = []
|
plan_data = []
|
||||||
|
|
||||||
for row in plan_ws.iter_rows(min_row=2, values_only=True):
|
for row_num, row in enumerate(plan_ws.iter_rows(min_row=2, values_only=True), start=2):
|
||||||
|
try:
|
||||||
if row[0]: # Wenn Datum vorhanden
|
if row[0]: # Wenn Datum vorhanden
|
||||||
datum_raw = row[0]
|
datum_raw = row[0]
|
||||||
mitarbeiter = row[1] if len(row) > 1 else None
|
mitarbeiter = row[1] if len(row) > 1 else None
|
||||||
|
|
@ -178,28 +205,41 @@ def process_file(filepath):
|
||||||
if isinstance(datum_raw, str):
|
if isinstance(datum_raw, str):
|
||||||
try:
|
try:
|
||||||
datum = datetime.strptime(datum_raw, '%d.%m.%Y').date()
|
datum = datetime.strptime(datum_raw, '%d.%m.%Y').date()
|
||||||
except:
|
except ValueError as e:
|
||||||
|
print(f"⚠️ Warnung: Ungültiges Datumsformat in Zeile {row_num}: '{datum_raw}' - übersprungen")
|
||||||
continue
|
continue
|
||||||
elif isinstance(datum_raw, datetime):
|
elif isinstance(datum_raw, datetime):
|
||||||
datum = datum_raw.date()
|
datum = datum_raw.date()
|
||||||
elif isinstance(datum_raw, date):
|
elif isinstance(datum_raw, date):
|
||||||
datum = datum_raw
|
datum = datum_raw
|
||||||
else:
|
else:
|
||||||
|
print(f"⚠️ Warnung: Unbekannter Datumstyp in Zeile {row_num}: {type(datum_raw)} - übersprungen")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if mitarbeiter:
|
if mitarbeiter:
|
||||||
plan_data.append((datum, mitarbeiter))
|
plan_data.append((datum, mitarbeiter))
|
||||||
|
except Exception as e:
|
||||||
|
print(f"⚠️ Warnung: Fehler beim Verarbeiten von Plan-Zeile {row_num}: {e}")
|
||||||
|
continue
|
||||||
|
|
||||||
print(f"📋 {len(plan_data)} Einträge im Plan")
|
print(f"📋 {len(plan_data)} Einträge im Plan")
|
||||||
|
|
||||||
|
if not plan_data:
|
||||||
|
print("⚠️ Warnung: Keine gültigen Plan-Einträge gefunden")
|
||||||
|
|
||||||
# Berechne Vergütung
|
# Berechne Vergütung
|
||||||
|
try:
|
||||||
results = calculate_verguetung(plan_data, holidays)
|
results = calculate_verguetung(plan_data, holidays)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Fehler bei der Vergütungsberechnung: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
# Schreibe Auswertung
|
# Schreibe Auswertung
|
||||||
if "Auswertung" not in wb.sheetnames:
|
if "Auswertung" not in wb.sheetnames:
|
||||||
print("❌ Blatt 'Auswertung' nicht gefunden!")
|
print("❌ Blatt 'Auswertung' nicht gefunden!")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
auswertung_ws = wb["Auswertung"]
|
auswertung_ws = wb["Auswertung"]
|
||||||
|
|
||||||
# Lösche alte Daten (ab Zeile 2)
|
# Lösche alte Daten (ab Zeile 2)
|
||||||
|
|
@ -225,8 +265,20 @@ def process_file(filepath):
|
||||||
auswertung_ws[f"F{idx}"].fill = PatternFill(start_color="C6EFCE", end_color="C6EFCE", fill_type="solid")
|
auswertung_ws[f"F{idx}"].fill = PatternFill(start_color="C6EFCE", end_color="C6EFCE", fill_type="solid")
|
||||||
else:
|
else:
|
||||||
auswertung_ws[f"F{idx}"].fill = PatternFill(start_color="FFC7CE", end_color="FFC7CE", fill_type="solid")
|
auswertung_ws[f"F{idx}"].fill = PatternFill(start_color="FFC7CE", end_color="FFC7CE", fill_type="solid")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Fehler beim Schreiben der Auswertung: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Save file
|
||||||
|
try:
|
||||||
wb.save(filepath)
|
wb.save(filepath)
|
||||||
|
except PermissionError:
|
||||||
|
print(f"❌ Fehler: Keine Berechtigung zum Speichern der Datei '{filepath}'")
|
||||||
|
return
|
||||||
|
except OSError as e:
|
||||||
|
print(f"❌ Fehler beim Speichern der Datei '{filepath}': {e}")
|
||||||
|
return
|
||||||
|
|
||||||
print(f"\n✅ Auswertung geschrieben: {len(results)} Mitarbeiter")
|
print(f"\n✅ Auswertung geschrieben: {len(results)} Mitarbeiter")
|
||||||
print(f" Datei: {filepath}")
|
print(f" Datei: {filepath}")
|
||||||
|
|
||||||
|
|
@ -238,6 +290,10 @@ def process_file(filepath):
|
||||||
print(f"{r['mitarbeiter']:<20} {r['wt_einheiten']:>6.1f} {r['we_gesamt']:>6.1f} {r['schwelle_erreicht']:<10} {r['auszahlung_gesamt']:>9.2f} €")
|
print(f"{r['mitarbeiter']:<20} {r['wt_einheiten']:>6.1f} {r['we_gesamt']:>6.1f} {r['schwelle_erreicht']:<10} {r['auszahlung_gesamt']:>9.2f} €")
|
||||||
print(f"{'='*70}")
|
print(f"{'='*70}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Unerwarteter Fehler beim Verarbeiten der Datei: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if len(sys.argv) >= 2:
|
if len(sys.argv) >= 2:
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,29 @@ def fill_plan_with_dates(template_path, output_path, year, month):
|
||||||
Lädt die Vorlage und füllt Spalte A (Datum) im Plan-Blatt
|
Lädt die Vorlage und füllt Spalte A (Datum) im Plan-Blatt
|
||||||
mit allen Tagen des angegebenen Monats.
|
mit allen Tagen des angegebenen Monats.
|
||||||
"""
|
"""
|
||||||
wb = load_workbook(template_path)
|
# Validate input parameters
|
||||||
|
if not (1 <= month <= 12):
|
||||||
|
print(f"❌ Fehler: Ungültiger Monat '{month}'. Monat muss zwischen 1 und 12 liegen")
|
||||||
|
return
|
||||||
|
|
||||||
|
if year < 1900 or year > 2100:
|
||||||
|
print(f"❌ Fehler: Ungültiges Jahr '{year}'. Jahr muss zwischen 1900 und 2100 liegen")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Load template workbook
|
||||||
|
try:
|
||||||
|
wb = load_workbook(template_path)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"❌ Fehler: Vorlagendatei '{template_path}' nicht gefunden")
|
||||||
|
return
|
||||||
|
except PermissionError:
|
||||||
|
print(f"❌ Fehler: Keine Berechtigung zum Lesen der Datei '{template_path}'")
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Fehler beim Laden der Vorlagendatei '{template_path}': {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
# Regeln-Blatt: Monat_Auswahl setzen
|
# Regeln-Blatt: Monat_Auswahl setzen
|
||||||
if "Regeln" in wb.sheetnames:
|
if "Regeln" in wb.sheetnames:
|
||||||
regeln_ws = wb["Regeln"]
|
regeln_ws = wb["Regeln"]
|
||||||
|
|
@ -31,13 +52,21 @@ def fill_plan_with_dates(template_path, output_path, year, month):
|
||||||
plan_ws = wb["Plan"]
|
plan_ws = wb["Plan"]
|
||||||
|
|
||||||
# Startdatum
|
# Startdatum
|
||||||
|
try:
|
||||||
start_date = date(year, month, 1)
|
start_date = date(year, month, 1)
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"❌ Fehler: Ungültiges Datum für Jahr {year}, Monat {month}: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
# Letzter Tag des Monats
|
# Letzter Tag des Monats
|
||||||
|
try:
|
||||||
if month == 12:
|
if month == 12:
|
||||||
end_date = date(year + 1, 1, 1) - timedelta(days=1)
|
end_date = date(year + 1, 1, 1) - timedelta(days=1)
|
||||||
else:
|
else:
|
||||||
end_date = date(year, month + 1, 1) - timedelta(days=1)
|
end_date = date(year, month + 1, 1) - timedelta(days=1)
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"❌ Fehler beim Berechnen des Enddatums: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
# Alle Tage durchgehen
|
# Alle Tage durchgehen
|
||||||
current_date = start_date
|
current_date = start_date
|
||||||
|
|
@ -51,11 +80,24 @@ def fill_plan_with_dates(template_path, output_path, year, month):
|
||||||
current_date += timedelta(days=1)
|
current_date += timedelta(days=1)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
|
# Save output file
|
||||||
|
try:
|
||||||
wb.save(output_path)
|
wb.save(output_path)
|
||||||
|
except PermissionError:
|
||||||
|
print(f"❌ Fehler: Keine Berechtigung zum Speichern der Datei '{output_path}'")
|
||||||
|
return
|
||||||
|
except OSError as e:
|
||||||
|
print(f"❌ Fehler beim Speichern der Datei '{output_path}': {e}")
|
||||||
|
return
|
||||||
|
|
||||||
print(f"✅ Plan-Blatt vorbefüllt für {month:02d}/{year}")
|
print(f"✅ Plan-Blatt vorbefüllt für {month:02d}/{year}")
|
||||||
print(f" Ausgabe: {output_path}")
|
print(f" Ausgabe: {output_path}")
|
||||||
print(f" Trage jetzt nur noch in Spalte B (Mitarbeiter) und C (Anteil) die Namen ein!")
|
print(f" Trage jetzt nur noch in Spalte B (Mitarbeiter) und C (Anteil) die Namen ein!")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Unerwarteter Fehler beim Füllen des Plan-Blatts: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
template = Path("templates/Dienstplan_Vorlage_V2_NRW.xlsx")
|
template = Path("templates/Dienstplan_Vorlage_V2_NRW.xlsx")
|
||||||
|
|
|
||||||
19
src/main.py
19
src/main.py
|
|
@ -12,6 +12,7 @@ from datetime import datetime
|
||||||
def create_example_excel():
|
def create_example_excel():
|
||||||
"""Erstellt eine Beispiel-Excel-Datei mit formatierten Daten."""
|
"""Erstellt eine Beispiel-Excel-Datei mit formatierten Daten."""
|
||||||
|
|
||||||
|
try:
|
||||||
# Neues Workbook erstellen
|
# Neues Workbook erstellen
|
||||||
wb = Workbook()
|
wb = Workbook()
|
||||||
ws = wb.active
|
ws = wb.active
|
||||||
|
|
@ -49,15 +50,33 @@ def create_example_excel():
|
||||||
|
|
||||||
# Ausgabeverzeichnis erstellen
|
# Ausgabeverzeichnis erstellen
|
||||||
output_dir = Path("output")
|
output_dir = Path("output")
|
||||||
|
try:
|
||||||
output_dir.mkdir(exist_ok=True)
|
output_dir.mkdir(exist_ok=True)
|
||||||
|
except PermissionError:
|
||||||
|
print(f"❌ Fehler: Keine Berechtigung zum Erstellen des Verzeichnisses '{output_dir}'")
|
||||||
|
raise
|
||||||
|
except OSError as e:
|
||||||
|
print(f"❌ Fehler beim Erstellen des Verzeichnisses '{output_dir}': {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
# Datei speichern
|
# Datei speichern
|
||||||
output_file = output_dir / f"example_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
|
output_file = output_dir / f"example_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
|
||||||
|
try:
|
||||||
wb.save(output_file)
|
wb.save(output_file)
|
||||||
|
except PermissionError:
|
||||||
|
print(f"❌ Fehler: Keine Berechtigung zum Speichern der Datei '{output_file}'")
|
||||||
|
raise
|
||||||
|
except OSError as e:
|
||||||
|
print(f"❌ Fehler beim Speichern der Datei '{output_file}': {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
print(f"Excel-Datei erfolgreich erstellt: {output_file}")
|
print(f"Excel-Datei erfolgreich erstellt: {output_file}")
|
||||||
return output_file
|
return output_file
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Unerwarteter Fehler beim Erstellen der Excel-Datei: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
create_example_excel()
|
create_example_excel()
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,21 @@ from pathlib import Path
|
||||||
def read_excel_to_dict(filepath):
|
def read_excel_to_dict(filepath):
|
||||||
"""Liest eine Excel-Datei und gibt die Daten als Dictionary zurück."""
|
"""Liest eine Excel-Datei und gibt die Daten als Dictionary zurück."""
|
||||||
|
|
||||||
|
try:
|
||||||
wb = load_workbook(filepath, data_only=True)
|
wb = load_workbook(filepath, data_only=True)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"❌ Fehler: Datei '{filepath}' nicht gefunden")
|
||||||
|
raise
|
||||||
|
except PermissionError:
|
||||||
|
print(f"❌ Fehler: Keine Berechtigung zum Lesen der Datei '{filepath}'")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Fehler beim Laden der Excel-Datei '{filepath}': {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
result = {}
|
result = {}
|
||||||
|
|
||||||
|
try:
|
||||||
for sheet_name in wb.sheetnames:
|
for sheet_name in wb.sheetnames:
|
||||||
ws = wb[sheet_name]
|
ws = wb[sheet_name]
|
||||||
|
|
||||||
|
|
@ -24,6 +36,9 @@ def read_excel_to_dict(filepath):
|
||||||
data.append(list(row))
|
data.append(list(row))
|
||||||
|
|
||||||
result[sheet_name] = data
|
result[sheet_name] = data
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Fehler beim Lesen der Daten aus der Excel-Datei: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
@ -35,8 +50,13 @@ def print_excel_content(filepath):
|
||||||
print(f"Excel-Datei: {filepath}")
|
print(f"Excel-Datei: {filepath}")
|
||||||
print(f"{'='*60}\n")
|
print(f"{'='*60}\n")
|
||||||
|
|
||||||
|
try:
|
||||||
data = read_excel_to_dict(filepath)
|
data = read_excel_to_dict(filepath)
|
||||||
|
except Exception:
|
||||||
|
# Error already printed in read_excel_to_dict
|
||||||
|
raise
|
||||||
|
|
||||||
|
try:
|
||||||
for sheet_name, rows in data.items():
|
for sheet_name, rows in data.items():
|
||||||
print(f"\n📊 Sheet: {sheet_name}")
|
print(f"\n📊 Sheet: {sheet_name}")
|
||||||
print(f"{'-'*60}")
|
print(f"{'-'*60}")
|
||||||
|
|
@ -54,7 +74,14 @@ def print_excel_content(filepath):
|
||||||
|
|
||||||
# Als JSON ausgeben
|
# Als JSON ausgeben
|
||||||
print("📄 JSON-Format:")
|
print("📄 JSON-Format:")
|
||||||
|
try:
|
||||||
print(json.dumps(data, indent=2, ensure_ascii=False))
|
print(json.dumps(data, indent=2, ensure_ascii=False))
|
||||||
|
except (TypeError, ValueError) as e:
|
||||||
|
print(f"❌ Fehler beim Konvertieren zu JSON: {e}")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Fehler beim Ausgeben der Excel-Daten: {e}")
|
||||||
|
raise
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,21 @@ class DataStorage {
|
||||||
* @returns {Array} Array of employee names
|
* @returns {Array} Array of employee names
|
||||||
*/
|
*/
|
||||||
getEmployees() {
|
getEmployees() {
|
||||||
|
try {
|
||||||
const data = localStorage.getItem(this.STORAGE_KEY_EMPLOYEES);
|
const data = localStorage.getItem(this.STORAGE_KEY_EMPLOYEES);
|
||||||
return data ? JSON.parse(data) : [];
|
if (!data) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const parsed = JSON.parse(data);
|
||||||
|
if (!Array.isArray(parsed)) {
|
||||||
|
console.error('Fehler: Mitarbeiter-Daten sind kein Array. Zurücksetzen auf leeres Array');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Fehler beim Laden der Mitarbeiter-Daten:', e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -22,7 +35,16 @@ class DataStorage {
|
||||||
* @param {Array} employees - Array of employee names
|
* @param {Array} employees - Array of employee names
|
||||||
*/
|
*/
|
||||||
saveEmployees(employees) {
|
saveEmployees(employees) {
|
||||||
|
try {
|
||||||
|
if (!Array.isArray(employees)) {
|
||||||
|
console.error('Fehler: employees muss ein Array sein');
|
||||||
|
throw new TypeError('employees muss ein Array sein');
|
||||||
|
}
|
||||||
localStorage.setItem(this.STORAGE_KEY_EMPLOYEES, JSON.stringify(employees));
|
localStorage.setItem(this.STORAGE_KEY_EMPLOYEES, JSON.stringify(employees));
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Fehler beim Speichern der Mitarbeiter-Daten:', e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -63,8 +85,21 @@ class DataStorage {
|
||||||
* @returns {Object} Object with structure: {employeeName: {year-month: [duties]}}
|
* @returns {Object} Object with structure: {employeeName: {year-month: [duties]}}
|
||||||
*/
|
*/
|
||||||
getAllDuties() {
|
getAllDuties() {
|
||||||
|
try {
|
||||||
const data = localStorage.getItem(this.STORAGE_KEY_DUTIES);
|
const data = localStorage.getItem(this.STORAGE_KEY_DUTIES);
|
||||||
return data ? JSON.parse(data) : {};
|
if (!data) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const parsed = JSON.parse(data);
|
||||||
|
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
||||||
|
console.error('Fehler: Dienst-Daten sind kein gültiges Objekt. Zurücksetzen auf leeres Objekt');
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return parsed;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Fehler beim Laden der Dienst-Daten:', e);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -72,7 +107,16 @@ class DataStorage {
|
||||||
* @param {Object} duties
|
* @param {Object} duties
|
||||||
*/
|
*/
|
||||||
saveAllDuties(duties) {
|
saveAllDuties(duties) {
|
||||||
|
try {
|
||||||
|
if (typeof duties !== 'object' || duties === null || Array.isArray(duties)) {
|
||||||
|
console.error('Fehler: duties muss ein gültiges Objekt sein');
|
||||||
|
throw new TypeError('duties muss ein gültiges Objekt sein');
|
||||||
|
}
|
||||||
localStorage.setItem(this.STORAGE_KEY_DUTIES, JSON.stringify(duties));
|
localStorage.setItem(this.STORAGE_KEY_DUTIES, JSON.stringify(duties));
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Fehler beim Speichern der Dienst-Daten:', e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -83,6 +127,7 @@ class DataStorage {
|
||||||
* @returns {Array} Array of duty objects
|
* @returns {Array} Array of duty objects
|
||||||
*/
|
*/
|
||||||
getDutiesForMonth(employeeName, year, month) {
|
getDutiesForMonth(employeeName, year, month) {
|
||||||
|
try {
|
||||||
const allDuties = this.getAllDuties();
|
const allDuties = this.getAllDuties();
|
||||||
const monthKey = `${year}-${String(month).padStart(2, '0')}`;
|
const monthKey = `${year}-${String(month).padStart(2, '0')}`;
|
||||||
|
|
||||||
|
|
@ -91,10 +136,26 @@ class DataStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert date strings back to Date objects
|
// Convert date strings back to Date objects
|
||||||
return allDuties[employeeName][monthKey].map(duty => ({
|
return allDuties[employeeName][monthKey].map(duty => {
|
||||||
|
try {
|
||||||
|
const dateObj = new Date(duty.date);
|
||||||
|
if (isNaN(dateObj.getTime())) {
|
||||||
|
console.error(`Fehler: Ungültiges Datum für Dienst: ${duty.date}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
...duty,
|
...duty,
|
||||||
date: new Date(duty.date)
|
date: dateObj
|
||||||
}));
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Fehler beim Konvertieren des Datums:', e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).filter(duty => duty !== null); // Filter out invalid entries
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Fehler beim Laden der Dienste für Monat:', e);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -105,6 +166,12 @@ class DataStorage {
|
||||||
* @param {Array} duties - Array of duty objects
|
* @param {Array} duties - Array of duty objects
|
||||||
*/
|
*/
|
||||||
saveDutiesForMonth(employeeName, year, month, duties) {
|
saveDutiesForMonth(employeeName, year, month, duties) {
|
||||||
|
try {
|
||||||
|
if (!Array.isArray(duties)) {
|
||||||
|
console.error('Fehler: duties muss ein Array sein');
|
||||||
|
throw new TypeError('duties muss ein Array sein');
|
||||||
|
}
|
||||||
|
|
||||||
const allDuties = this.getAllDuties();
|
const allDuties = this.getAllDuties();
|
||||||
const monthKey = `${year}-${String(month).padStart(2, '0')}`;
|
const monthKey = `${year}-${String(month).padStart(2, '0')}`;
|
||||||
|
|
||||||
|
|
@ -113,12 +180,22 @@ class DataStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert Date objects to strings for storage
|
// Convert Date objects to strings for storage
|
||||||
allDuties[employeeName][monthKey] = duties.map(duty => ({
|
allDuties[employeeName][monthKey] = duties.map(duty => {
|
||||||
|
if (!duty.date || !(duty.date instanceof Date)) {
|
||||||
|
console.error('Fehler: Dienst hat kein gültiges Datum:', duty);
|
||||||
|
throw new TypeError('Dienst muss ein gültiges Date-Objekt haben');
|
||||||
|
}
|
||||||
|
return {
|
||||||
...duty,
|
...duty,
|
||||||
date: duty.date.toISOString()
|
date: duty.date.toISOString()
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
|
|
||||||
this.saveAllDuties(allDuties);
|
this.saveAllDuties(allDuties);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Fehler beim Speichern der Dienste für Monat:', e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -196,10 +273,15 @@ class DataStorage {
|
||||||
* @returns {string} JSON string
|
* @returns {string} JSON string
|
||||||
*/
|
*/
|
||||||
exportData() {
|
exportData() {
|
||||||
|
try {
|
||||||
return JSON.stringify({
|
return JSON.stringify({
|
||||||
employees: this.getEmployees(),
|
employees: this.getEmployees(),
|
||||||
duties: this.getAllDuties()
|
duties: this.getAllDuties()
|
||||||
}, null, 2);
|
}, null, 2);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Fehler beim Exportieren der Daten:', e);
|
||||||
|
throw new Error('Fehler beim Exportieren der Daten: ' + e.message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
Reference in a new issue