diff --git a/src/build_template.py b/src/build_template.py index a921480..c7531a4 100644 --- a/src/build_template.py +++ b/src/build_template.py @@ -284,33 +284,71 @@ def _populate_checks(ws): def build_template(): - TEMPLATE_PATH.parent.mkdir(parents=True, exist_ok=True) - wb = Workbook() + """Builds the complete Excel template with all sheets and formulas.""" + try: + # Create output directory + try: + TEMPLATE_PATH.parent.mkdir(parents=True, exist_ok=True) + 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 - readme_ws = wb.active - readme_ws.title = "README" - _populate_readme(readme_ws) + # Create workbook + try: + wb = Workbook() + except Exception as e: + print(f"❌ Fehler beim Erstellen des Workbooks: {e}") + raise - rules_ws = wb.create_sheet("Regeln") - _populate_rules(rules_ws) + try: + readme_ws = wb.active + readme_ws.title = "README" + _populate_readme(readme_ws) - holiday_ws = wb.create_sheet("Feiertage") - _populate_holidays(holiday_ws) + rules_ws = wb.create_sheet("Regeln") + _populate_rules(rules_ws) - plan_ws = wb.create_sheet("Plan") - _populate_plan(plan_ws) + holiday_ws = wb.create_sheet("Feiertage") + _populate_holidays(holiday_ws) - auswertung_ws = wb.create_sheet("Auswertung") - _populate_auswertung(auswertung_ws) + plan_ws = wb.create_sheet("Plan") + _populate_plan(plan_ws) - checks_ws = wb.create_sheet("Checks") - _populate_checks(checks_ws) + auswertung_ws = wb.create_sheet("Auswertung") + _populate_auswertung(auswertung_ws) - wb.save(TEMPLATE_PATH) - return TEMPLATE_PATH + checks_ws = wb.create_sheet("Checks") + _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) + 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 + + except Exception as e: + print(f"❌ Unerwarteter Fehler beim Erstellen der Vorlage: {e}") + raise if __name__ == "__main__": - path = build_template() - print(f"✅ Vorlage (Variante 2 – streng) erstellt: {path}") + try: + path = build_template() + print(f"✅ Vorlage (Variante 2 – streng) erstellt: {path}") + except Exception: + # Error already printed in build_template + import sys + sys.exit(1) diff --git a/src/calculate.py b/src/calculate.py index f2464e7..b4db94e 100644 --- a/src/calculate.py +++ b/src/calculate.py @@ -20,25 +20,39 @@ ABZUG = 2.0 # Abzug nach Erreichen der Schwelle def load_holidays(wb): """Lädt Feiertage aus dem Feiertage-Blatt.""" if "Feiertage" not in wb.sheetnames: + print("⚠️ Warnung: Blatt 'Feiertage' nicht gefunden. Keine Feiertage geladen") return set() - + holidays = set() - ws = wb["Feiertage"] - - for row in ws.iter_rows(min_row=2, values_only=True): - if row[0] and row[2] == "NRW": # Datum und BL prüfen - date_raw = row[0] - if isinstance(date_raw, str): - try: - parsed_date = datetime.strptime(date_raw, '%d.%m.%Y').date() - holidays.add(parsed_date) - except: - pass - elif isinstance(date_raw, datetime): - holidays.add(date_raw.date()) - elif isinstance(date_raw, date): - holidays.add(date_raw) - + + try: + ws = wb["Feiertage"] + + for row_num, row in enumerate(ws.iter_rows(min_row=2, values_only=True), start=2): + try: + if row[0] and len(row) > 2 and row[2] == "NRW": # Datum und BL prüfen + date_raw = row[0] + if isinstance(date_raw, str): + try: + parsed_date = datetime.strptime(date_raw, '%d.%m.%Y').date() + holidays.add(parsed_date) + except ValueError as e: + print(f"⚠️ Warnung: Ungültiges Datumsformat in Zeile {row_num}: '{date_raw}' - {e}") + continue + elif isinstance(date_raw, datetime): + holidays.add(date_raw.date()) + elif isinstance(date_raw, date): + 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 @@ -154,89 +168,131 @@ def calculate_verguetung(plan_data, holidays): def process_file(filepath): """Verarbeitet die Excel-Datei und schreibt Auswertung.""" - - wb = load_workbook(filepath) - - # Lade Feiertage - holidays = load_holidays(wb) - print(f"📅 {len(holidays)} Feiertage geladen") - - # Lade Plan-Daten - if "Plan" not in wb.sheetnames: - print("❌ Blatt 'Plan' nicht gefunden!") + + # Load workbook + try: + wb = load_workbook(filepath) + except FileNotFoundError: + print(f"❌ Fehler: Datei '{filepath}' nicht gefunden") return - - plan_ws = wb["Plan"] - plan_data = [] - - for row in plan_ws.iter_rows(min_row=2, values_only=True): - if row[0]: # Wenn Datum vorhanden - datum_raw = row[0] - mitarbeiter = row[1] if len(row) > 1 else None - - # Parse Datum (kann String oder date sein) - if isinstance(datum_raw, str): - try: - datum = datetime.strptime(datum_raw, '%d.%m.%Y').date() - except: - continue - elif isinstance(datum_raw, datetime): - datum = datum_raw.date() - elif isinstance(datum_raw, date): - datum = datum_raw - else: + 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 + holidays = load_holidays(wb) + print(f"📅 {len(holidays)} Feiertage geladen") + + # Lade Plan-Daten + if "Plan" not in wb.sheetnames: + print("❌ Blatt 'Plan' nicht gefunden!") + return + + plan_ws = wb["Plan"] + plan_data = [] + + 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 + datum_raw = row[0] + mitarbeiter = row[1] if len(row) > 1 else None + + # Parse Datum (kann String oder date sein) + if isinstance(datum_raw, str): + try: + datum = datetime.strptime(datum_raw, '%d.%m.%Y').date() + except ValueError as e: + print(f"⚠️ Warnung: Ungültiges Datumsformat in Zeile {row_num}: '{datum_raw}' - übersprungen") + continue + elif isinstance(datum_raw, datetime): + datum = datum_raw.date() + elif isinstance(datum_raw, date): + datum = datum_raw + else: + print(f"⚠️ Warnung: Unbekannter Datumstyp in Zeile {row_num}: {type(datum_raw)} - übersprungen") + continue + + if mitarbeiter: + plan_data.append((datum, mitarbeiter)) + except Exception as e: + print(f"⚠️ Warnung: Fehler beim Verarbeiten von Plan-Zeile {row_num}: {e}") continue - - if mitarbeiter: - plan_data.append((datum, mitarbeiter)) - - print(f"📋 {len(plan_data)} Einträge im Plan") - - # Berechne Vergütung - results = calculate_verguetung(plan_data, holidays) - - # Schreibe Auswertung - if "Auswertung" not in wb.sheetnames: - print("❌ Blatt 'Auswertung' nicht gefunden!") + + 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 + try: + results = calculate_verguetung(plan_data, holidays) + except Exception as e: + print(f"❌ Fehler bei der Vergütungsberechnung: {e}") + return + + # Schreibe Auswertung + if "Auswertung" not in wb.sheetnames: + print("❌ Blatt 'Auswertung' nicht gefunden!") + return + + try: + auswertung_ws = wb["Auswertung"] + + # Lösche alte Daten (ab Zeile 2) + auswertung_ws.delete_rows(2, auswertung_ws.max_row) + + # Schreibe neue Daten + for idx, result in enumerate(results, start=2): + auswertung_ws[f"A{idx}"] = result['mitarbeiter'] + auswertung_ws[f"B{idx}"] = round(result['wt_einheiten'], 2) + auswertung_ws[f"C{idx}"] = round(result['we_freitag'], 2) + auswertung_ws[f"D{idx}"] = round(result['we_andere'], 2) + auswertung_ws[f"E{idx}"] = round(result['we_gesamt'], 2) + auswertung_ws[f"F{idx}"] = result['schwelle_erreicht'] + auswertung_ws[f"G{idx}"] = round(result['abzug_freitag'], 2) + auswertung_ws[f"H{idx}"] = round(result['abzug_andere'], 2) + auswertung_ws[f"I{idx}"] = round(result['we_bezahlt'], 2) + auswertung_ws[f"J{idx}"] = round(result['auszahlung_wt'], 2) + auswertung_ws[f"K{idx}"] = round(result['auszahlung_we'], 2) + auswertung_ws[f"L{idx}"] = round(result['auszahlung_gesamt'], 2) + + # Formatierung für Schwelle + if result['schwelle_erreicht'] == 'JA': + auswertung_ws[f"F{idx}"].fill = PatternFill(start_color="C6EFCE", end_color="C6EFCE", fill_type="solid") + else: + 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) + 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" Datei: {filepath}") + + # Zeige Zusammenfassung + print(f"\n{'='*70}") + print(f"{'Mitarbeiter':<20} {'WT':<8} {'WE':<8} {'Schwelle':<10} {'Gesamt':>10}") + print(f"{'='*70}") + for r in results: + 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}") + + except Exception as e: + print(f"❌ Unerwarteter Fehler beim Verarbeiten der Datei: {e}") return - - auswertung_ws = wb["Auswertung"] - - # Lösche alte Daten (ab Zeile 2) - auswertung_ws.delete_rows(2, auswertung_ws.max_row) - - # Schreibe neue Daten - for idx, result in enumerate(results, start=2): - auswertung_ws[f"A{idx}"] = result['mitarbeiter'] - auswertung_ws[f"B{idx}"] = round(result['wt_einheiten'], 2) - auswertung_ws[f"C{idx}"] = round(result['we_freitag'], 2) - auswertung_ws[f"D{idx}"] = round(result['we_andere'], 2) - auswertung_ws[f"E{idx}"] = round(result['we_gesamt'], 2) - auswertung_ws[f"F{idx}"] = result['schwelle_erreicht'] - auswertung_ws[f"G{idx}"] = round(result['abzug_freitag'], 2) - auswertung_ws[f"H{idx}"] = round(result['abzug_andere'], 2) - auswertung_ws[f"I{idx}"] = round(result['we_bezahlt'], 2) - auswertung_ws[f"J{idx}"] = round(result['auszahlung_wt'], 2) - auswertung_ws[f"K{idx}"] = round(result['auszahlung_we'], 2) - auswertung_ws[f"L{idx}"] = round(result['auszahlung_gesamt'], 2) - - # Formatierung für Schwelle - if result['schwelle_erreicht'] == 'JA': - auswertung_ws[f"F{idx}"].fill = PatternFill(start_color="C6EFCE", end_color="C6EFCE", fill_type="solid") - else: - auswertung_ws[f"F{idx}"].fill = PatternFill(start_color="FFC7CE", end_color="FFC7CE", fill_type="solid") - - wb.save(filepath) - print(f"\n✅ Auswertung geschrieben: {len(results)} Mitarbeiter") - print(f" Datei: {filepath}") - - # Zeige Zusammenfassung - print(f"\n{'='*70}") - print(f"{'Mitarbeiter':<20} {'WT':<8} {'WE':<8} {'Schwelle':<10} {'Gesamt':>10}") - print(f"{'='*70}") - for r in results: - 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}") if __name__ == "__main__": diff --git a/src/fill_plan_dates.py b/src/fill_plan_dates.py index 8636113..08d5984 100644 --- a/src/fill_plan_dates.py +++ b/src/fill_plan_dates.py @@ -15,46 +15,88 @@ def fill_plan_with_dates(template_path, output_path, year, month): Lädt die Vorlage und füllt Spalte A (Datum) im Plan-Blatt mit allen Tagen des angegebenen Monats. """ - wb = load_workbook(template_path) - - # Regeln-Blatt: Monat_Auswahl setzen - if "Regeln" in wb.sheetnames: - regeln_ws = wb["Regeln"] - # Zeile 7, Spalte B = Monat_Auswahl - regeln_ws["B7"] = date(year, month, 1) - - # Plan-Blatt füllen - if "Plan" not in wb.sheetnames: - print("❌ Blatt 'Plan' nicht gefunden!") + # 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 + if "Regeln" in wb.sheetnames: + regeln_ws = wb["Regeln"] + # Zeile 7, Spalte B = Monat_Auswahl + regeln_ws["B7"] = date(year, month, 1) + + # Plan-Blatt füllen + if "Plan" not in wb.sheetnames: + print("❌ Blatt 'Plan' nicht gefunden!") + return + + plan_ws = wb["Plan"] + + # Startdatum + try: + 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 + try: + if month == 12: + end_date = date(year + 1, 1, 1) - timedelta(days=1) + else: + 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 + current_date = start_date + row = 2 # Zeile 2 = erste Datenzeile nach Header + + while current_date <= end_date: + cell = plan_ws[f"A{row}"] + cell.value = current_date + cell.number_format = 'DD.MM.YYYY' # Deutsches Datumsformat + # Spalten B (Mitarbeiter) und C (Anteil) bleiben leer zum Ausfüllen + current_date += timedelta(days=1) + row += 1 + + # Save output file + try: + 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" Ausgabe: {output_path}") + 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 - - plan_ws = wb["Plan"] - - # Startdatum - start_date = date(year, month, 1) - - # Letzter Tag des Monats - if month == 12: - end_date = date(year + 1, 1, 1) - timedelta(days=1) - else: - end_date = date(year, month + 1, 1) - timedelta(days=1) - - # Alle Tage durchgehen - current_date = start_date - row = 2 # Zeile 2 = erste Datenzeile nach Header - - while current_date <= end_date: - cell = plan_ws[f"A{row}"] - cell.value = current_date - cell.number_format = 'DD.MM.YYYY' # Deutsches Datumsformat - # Spalten B (Mitarbeiter) und C (Anteil) bleiben leer zum Ausfüllen - current_date += timedelta(days=1) - row += 1 - - wb.save(output_path) - print(f"✅ Plan-Blatt vorbefüllt für {month:02d}/{year}") - print(f" Ausgabe: {output_path}") - print(f" Trage jetzt nur noch in Spalte B (Mitarbeiter) und C (Anteil) die Namen ein!") if __name__ == "__main__": diff --git a/src/main.py b/src/main.py index 0d23dde..80be83f 100644 --- a/src/main.py +++ b/src/main.py @@ -11,52 +11,71 @@ from datetime import datetime def create_example_excel(): """Erstellt eine Beispiel-Excel-Datei mit formatierten Daten.""" - - # Neues Workbook erstellen - wb = Workbook() - ws = wb.active - ws.title = "Beispiel" - - # Überschriften hinzufügen - headers = ["Name", "Alter", "Stadt", "Beruf"] - ws.append(headers) - - # Überschriften formatieren - header_fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid") - header_font = Font(bold=True, color="FFFFFF", size=12) - - for cell in ws[1]: - cell.fill = header_fill - cell.font = header_font - cell.alignment = Alignment(horizontal="center", vertical="center") - - # Beispieldaten hinzufügen - data = [ - ["Max Mustermann", 30, "Berlin", "Entwickler"], - ["Erika Musterfrau", 28, "München", "Designerin"], - ["Hans Schmidt", 35, "Hamburg", "Manager"], - ["Anna Weber", 27, "Köln", "Analyst"], - ] - - for row in data: - ws.append(row) - - # Spaltenbreiten anpassen - ws.column_dimensions['A'].width = 20 - ws.column_dimensions['B'].width = 10 - ws.column_dimensions['C'].width = 15 - ws.column_dimensions['D'].width = 15 - - # Ausgabeverzeichnis erstellen - output_dir = Path("output") - output_dir.mkdir(exist_ok=True) - - # Datei speichern - output_file = output_dir / f"example_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx" - wb.save(output_file) - - print(f"Excel-Datei erfolgreich erstellt: {output_file}") - return output_file + + try: + # Neues Workbook erstellen + wb = Workbook() + ws = wb.active + ws.title = "Beispiel" + + # Überschriften hinzufügen + headers = ["Name", "Alter", "Stadt", "Beruf"] + ws.append(headers) + + # Überschriften formatieren + header_fill = PatternFill(start_color="4472C4", end_color="4472C4", fill_type="solid") + header_font = Font(bold=True, color="FFFFFF", size=12) + + for cell in ws[1]: + cell.fill = header_fill + cell.font = header_font + cell.alignment = Alignment(horizontal="center", vertical="center") + + # Beispieldaten hinzufügen + data = [ + ["Max Mustermann", 30, "Berlin", "Entwickler"], + ["Erika Musterfrau", 28, "München", "Designerin"], + ["Hans Schmidt", 35, "Hamburg", "Manager"], + ["Anna Weber", 27, "Köln", "Analyst"], + ] + + for row in data: + ws.append(row) + + # Spaltenbreiten anpassen + ws.column_dimensions['A'].width = 20 + ws.column_dimensions['B'].width = 10 + ws.column_dimensions['C'].width = 15 + ws.column_dimensions['D'].width = 15 + + # Ausgabeverzeichnis erstellen + output_dir = Path("output") + try: + 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 + output_file = output_dir / f"example_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx" + try: + 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}") + return output_file + + except Exception as e: + print(f"❌ Unerwarteter Fehler beim Erstellen der Excel-Datei: {e}") + raise if __name__ == "__main__": diff --git a/src/read_excel.py b/src/read_excel.py index c5e09ef..5e19a1d 100644 --- a/src/read_excel.py +++ b/src/read_excel.py @@ -9,53 +9,80 @@ from pathlib import Path def read_excel_to_dict(filepath): """Liest eine Excel-Datei und gibt die Daten als Dictionary zurück.""" - - wb = load_workbook(filepath, data_only=True) + + try: + 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 = {} - - for sheet_name in wb.sheetnames: - ws = wb[sheet_name] - - # Daten aus dem Sheet lesen - data = [] - for row in ws.iter_rows(values_only=True): - # Nur Zeilen mit Inhalt - if any(cell is not None for cell in row): - data.append(list(row)) - - result[sheet_name] = data - + + try: + for sheet_name in wb.sheetnames: + ws = wb[sheet_name] + + # Daten aus dem Sheet lesen + data = [] + for row in ws.iter_rows(values_only=True): + # Nur Zeilen mit Inhalt + if any(cell is not None for cell in row): + data.append(list(row)) + + result[sheet_name] = data + except Exception as e: + print(f"❌ Fehler beim Lesen der Daten aus der Excel-Datei: {e}") + raise + return result def print_excel_content(filepath): """Gibt den Inhalt einer Excel-Datei formatiert aus.""" - + print(f"\n{'='*60}") print(f"Excel-Datei: {filepath}") print(f"{'='*60}\n") - - data = read_excel_to_dict(filepath) - - for sheet_name, rows in data.items(): - print(f"\n📊 Sheet: {sheet_name}") - print(f"{'-'*60}") - - if not rows: - print(" (leer)") - continue - - # Tabelle ausgeben - for i, row in enumerate(rows, 1): - row_str = " | ".join(str(cell) if cell is not None else "" for cell in row) - print(f" {i:3d}: {row_str}") - - print(f"\n{'='*60}\n") - - # Als JSON ausgeben - print("📄 JSON-Format:") - print(json.dumps(data, indent=2, ensure_ascii=False)) - + + try: + 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(): + print(f"\n📊 Sheet: {sheet_name}") + print(f"{'-'*60}") + + if not rows: + print(" (leer)") + continue + + # Tabelle ausgeben + for i, row in enumerate(rows, 1): + row_str = " | ".join(str(cell) if cell is not None else "" for cell in row) + print(f" {i:3d}: {row_str}") + + print(f"\n{'='*60}\n") + + # Als JSON ausgeben + print("📄 JSON-Format:") + try: + 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 diff --git a/webapp/storage.js b/webapp/storage.js index 631d0e3..3df3678 100644 --- a/webapp/storage.js +++ b/webapp/storage.js @@ -13,8 +13,21 @@ class DataStorage { * @returns {Array} Array of employee names */ getEmployees() { - const data = localStorage.getItem(this.STORAGE_KEY_EMPLOYEES); - return data ? JSON.parse(data) : []; + try { + const data = localStorage.getItem(this.STORAGE_KEY_EMPLOYEES); + 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 */ saveEmployees(employees) { - localStorage.setItem(this.STORAGE_KEY_EMPLOYEES, JSON.stringify(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)); + } 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]}} */ getAllDuties() { - const data = localStorage.getItem(this.STORAGE_KEY_DUTIES); - return data ? JSON.parse(data) : {}; + try { + const data = localStorage.getItem(this.STORAGE_KEY_DUTIES); + 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 */ saveAllDuties(duties) { - localStorage.setItem(this.STORAGE_KEY_DUTIES, JSON.stringify(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)); + } catch (e) { + console.error('Fehler beim Speichern der Dienst-Daten:', e); + throw e; + } } /** @@ -83,18 +127,35 @@ class DataStorage { * @returns {Array} Array of duty objects */ getDutiesForMonth(employeeName, year, month) { - const allDuties = this.getAllDuties(); - const monthKey = `${year}-${String(month).padStart(2, '0')}`; + try { + const allDuties = this.getAllDuties(); + const monthKey = `${year}-${String(month).padStart(2, '0')}`; - if (!allDuties[employeeName] || !allDuties[employeeName][monthKey]) { + if (!allDuties[employeeName] || !allDuties[employeeName][monthKey]) { + return []; + } + + // Convert date strings back to Date objects + 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, + 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 []; } - - // Convert date strings back to Date objects - return allDuties[employeeName][monthKey].map(duty => ({ - ...duty, - date: new Date(duty.date) - })); } /** @@ -105,20 +166,36 @@ class DataStorage { * @param {Array} duties - Array of duty objects */ saveDutiesForMonth(employeeName, year, month, duties) { - const allDuties = this.getAllDuties(); - const monthKey = `${year}-${String(month).padStart(2, '0')}`; + try { + if (!Array.isArray(duties)) { + console.error('Fehler: duties muss ein Array sein'); + throw new TypeError('duties muss ein Array sein'); + } - if (!allDuties[employeeName]) { - allDuties[employeeName] = {}; + const allDuties = this.getAllDuties(); + const monthKey = `${year}-${String(month).padStart(2, '0')}`; + + if (!allDuties[employeeName]) { + allDuties[employeeName] = {}; + } + + // Convert Date objects to strings for storage + 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, + date: duty.date.toISOString() + }; + }); + + this.saveAllDuties(allDuties); + } catch (e) { + console.error('Fehler beim Speichern der Dienste für Monat:', e); + throw e; } - - // Convert Date objects to strings for storage - allDuties[employeeName][monthKey] = duties.map(duty => ({ - ...duty, - date: duty.date.toISOString() - })); - - this.saveAllDuties(allDuties); } /** @@ -196,10 +273,15 @@ class DataStorage { * @returns {string} JSON string */ exportData() { - return JSON.stringify({ - employees: this.getEmployees(), - duties: this.getAllDuties() - }, null, 2); + try { + return JSON.stringify({ + employees: this.getEmployees(), + duties: this.getAllDuties() + }, null, 2); + } catch (e) { + console.error('Fehler beim Exportieren der Daten:', e); + throw new Error('Fehler beim Exportieren der Daten: ' + e.message); + } } /**