From e50f423304b1d93b4b5200cf25a6e33efe9e371e Mon Sep 17 00:00:00 2001 From: Rob Date: Tue, 23 Jun 2026 11:49:54 +0200 Subject: [PATCH] =?UTF-8?q?input=20validierung=20f=C3=BCr=20Qualifikations?= =?UTF-8?q?feld.=20Wenn=20keine=20Daten=20->=20Platzhalter=20im=20template?= =?UTF-8?q?=20l=C3=B6schen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- coldrun.py | 14 +++++++++++++- src/validator.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/coldrun.py b/coldrun.py index 052e28a..0918c1e 100644 --- a/coldrun.py +++ b/coldrun.py @@ -22,7 +22,7 @@ from src.config import ( get_available_templates, ) from src.parser import parse_input_file, group_by_employee, get_unique_employees -from src.validator import validate_template +from src.validator import validate_input_file, validate_template from src.writer import generate_activity_reports @@ -70,6 +70,18 @@ def main(): total = tpl_result.info.get("total_fields", "?") print(f"[OK] {found}/{total} Platzhalter im Template gefunden.") + # ── Input validieren ────────────────────────────────────────────── + print() + print("[INFO] Validiere Input-Datei…") + inp_result = validate_input_file(input_path, config.input_schema, config.month_sheet_pattern) + if not inp_result.is_valid: + for err in inp_result.errors: + print(f"[FEHLER] {err}") + return 1 + if inp_result.warnings: + for warn in inp_result.warnings: + print(f"[WARN] {warn}") + # ── Input parsen ────────────────────────────────────────────────── print() print("[INFO] Parse Input-Datei…") diff --git a/src/validator.py b/src/validator.py index ca18170..d557867 100644 --- a/src/validator.py +++ b/src/validator.py @@ -81,6 +81,49 @@ def validate_input_file( info["sheets_with_data"] = sheets_with_data wb.close() + # ── Dateninhalts-Prüfung: leere Pflichtfelder ─────────────────── + required_fields = [f for f in schema if f.required] + if required_fields and sheets_with_data > 0: + # Mapping field_name → column index + field_col_map: dict[str, int] = {} + for f in required_fields: + field_col_map[f.field_name] = column_index_from_string(f.column) - 1 + max_col = max(field_col_map.values()) + 1 + + # {field_name: {name1, name2, ...}} für leere Pflichtwerte + empty_by_field: dict[str, set[str]] = {f.field_name: set() for f in required_fields} + + wb2 = load_workbook(filepath, data_only=True) + for sheet_name in wb2.sheetnames: + if not is_month_sheet(sheet_name, month_sheet_pattern): + continue + ws = wb2[sheet_name] + if ws.max_row < 2: + continue + for row in ws.iter_rows(min_row=2, max_row=ws.max_row, min_col=1, max_col=max_col, values_only=True): + name_val = str(row[field_col_map.get("Name", 0)] or "").strip() if len(row) > field_col_map.get("Name", 0) else "" + if not name_val: + continue + for f in required_fields: + col_idx = field_col_map[f.field_name] + if col_idx < len(row): + cell_val = str(row[col_idx] or "").strip() if row[col_idx] is not None else "" + if not cell_val: + empty_by_field[f.field_name].add(name_val) + wb2.close() + + for field_name, names in empty_by_field.items(): + if names: + sorted_names = sorted(names) + total = len(sorted_names) + preview = sorted_names[:5] + suffix = " …" if total > 5 else "" + warnings.append( + f"Feld '{field_name}' ist leer bei {total} Person(en): " + f"{', '.join(preview)}{suffix}" + ) + # ────────────────────────────────────────────────────────────────── + if sheets_with_data == 0: errors.append("Kein Sheet mit den erwarteten Spalten gefunden.")