Configure template target cells and add skip-errors mode

This commit is contained in:
Rob committed 2026-04-21 16:12:49 +02:00
1 parent 418d8336f5
commit 5f3a820641
5 files changed
+31 -17

No files matched your search

+7 -2
View File
@@ -89,9 +89,14 @@ Projekt vollstaendig umsetzen: aus PS_PW.xlsx und Stellenbeschreibungen.xlsx mon
## Phase 8 - Tests und Abnahme
- [ ] T15: Smoke-Test fuer End-to-End-Lauf
- [x] Beispielmonat ausfuehren
- [x] Pipeline laeuft bis Dateiausgabe durch (0 Dateien, da 0 gematchte Faelle)
- [ ] Dateien in `output/` entstehen erwartungsgemaess
- [ ] Blocker: Masterdata-Matches fehlen fuer mehrere aktive Namen.
- [ ] Blocker: Template-Regel verletzt (aktuell 5 Sheets statt 1) und template_targets sind noch nicht konfiguriert.
- [ ] DATENBLOCKER: `Stellenbeschreibungen.xlsx` enthaelt nur Meyer,Johannes (25%/75%).
Alle anderen aktiven Mitarbeiter aus PS_PW.xlsx fehlen als Stammdaten.
Meyer's Foerderquote (85%/15%) stimmt nicht mit eingetragenem Stellenanteil (25%/75%) ueberein.
-> Stellenbeschreibungen.xlsx mit allen aktiven Mitarbeitern und korrekten Anteilen befuellen.
- [x] Template-Zielzellen konfiguriert (A3, A17, Q17, A21, Q21, A25, A31, I95)
- [x] Template-Sheet-Pfad konfiguriert (<MM_YYYY>_<Stellenbeschreibung>)
- [ ] T16: Fachtests definieren und ausfuehren
- [ ] Mehrfachzuordnung eines Mitarbeiters
- [ ] Fehlender Match
+9 -9
View File
@@ -12,7 +12,7 @@
"sheets": {
"allocation": "Tabelle1",
"masterdata": "Tabelle1",
"template_source": "Tabelle1"
"template_source": "<MM_YYYY>_<Stellenbeschreibung>"
},
"allocation": {
"header_month_marker_row": 2,
@@ -66,14 +66,14 @@
"sheet_name_pattern": "{index}_{funktion}"
},
"template_targets": {
"antragsnummer": "",
"name_vorname": "",
"qualifikation": "",
"funktion": "",
"taetigkeiten": "",
"reporting_month_label": "",
"foerderquote": "",
"generated_on": ""
"antragsnummer": "A3",
"name_vorname": "A17",
"qualifikation": "A21",
"funktion": "A25",
"taetigkeiten": "A31",
"reporting_month_label": "Q21",
"foerderquote": "Q17",
"generated_on": "I95"
},
"runtime": {
"abort_on_validation_errors": true,
+6 -2
View File
@@ -53,7 +53,8 @@ def _print_preview(month: int, year: int, matched_assignments: list, planned_fil
@click.option("--month", type=click.IntRange(1, 12), required=True)
@click.option("--year", type=click.IntRange(2000, 2100), required=True)
@click.option("--yes", is_flag=True, default=False, help="Skip interactive confirmation.")
def main(month: int, year: int, yes: bool) -> None:
@click.option("--skip-errors", is_flag=True, default=False, help="Generate files for matched records, skip unresolved ones.")
def main(month: int, year: int, yes: bool, skip_errors: bool) -> None:
configure_logging()
project_root = Path(__file__).resolve().parent
@@ -99,8 +100,11 @@ def main(month: int, year: int, yes: bool) -> None:
_print_issues(business_issues, "=== Business validation ===")
all_issues = [*match_issues, *business_issues]
if any(issue.severity == "error" for issue in all_issues):
has_errors = any(issue.severity == "error" for issue in all_issues)
if has_errors and not skip_errors:
raise click.ClickException("Validation failed after matching.")
if has_errors and skip_errors:
click.echo("Warnhinweis: Fehler vorhanden. Weiterfahrt mit --skip-errors (nur gematchte Faelle werden erzeugt).")
filename_pattern = config["output"]["filename_pattern"]
unique_employees = sorted({item.allocation.employee_name for item in matched_assignments})
+4 -3
View File
@@ -319,12 +319,13 @@ def validate_business_rules(
if template_path.exists():
template_wb = load_workbook(template_path, data_only=True)
if len(template_wb.sheetnames) != 1:
configured_sheet = config["sheets"].get("template_source", "")
if configured_sheet not in template_wb.sheetnames:
issues.append(
ValidationIssue(
code="TEMPLATE_SHEET_COUNT",
code="TEMPLATE_SHEET_MISSING",
message=(
f"Template workbook must contain exactly one sheet, found {len(template_wb.sheetnames)}."
f"Configured template sheet '{configured_sheet}' not found in template workbook."
),
severity="error",
)
+5 -1
View File
@@ -67,7 +67,11 @@ def build_employee_workbooks(
for employee_name, assignments in assignments_by_employee.items():
workbook = load_workbook(template_path)
base_sheet = workbook.worksheets[0]
template_sheet_name = config["sheets"].get("template_source", "")
if template_sheet_name and template_sheet_name in workbook.sheetnames:
base_sheet = workbook[template_sheet_name]
else:
base_sheet = workbook.worksheets[0]
for index, assignment in enumerate(assignments, start=1):
if index == 1: