from __future__ import annotations import json from pathlib import Path import click from src.taetigkeitsnachweis.errors import TaetigkeitsnachweisError from src.taetigkeitsnachweis.logging_utils import configure_logging from src.taetigkeitsnachweis.matcher import match_assignments from src.taetigkeitsnachweis.parser import parse_allocation_records, parse_masterdata_records from src.taetigkeitsnachweis.validator import validate_business_rules, validate_sources from src.taetigkeitsnachweis.writer import ( build_employee_workbooks, build_output_filename, save_employee_workbooks, ) def _load_config(project_root: Path) -> dict: config_path = project_root / "config.json" with config_path.open("r", encoding="utf-8") as config_file: return json.load(config_file) def _print_issues(issues: list, title: str) -> None: if not issues: return click.echo(title) for issue in issues: click.echo(f"- [{issue.severity}] {issue.code}: {issue.message}") def _print_preview(month: int, year: int, matched_assignments: list, planned_files: list[str]) -> None: click.echo("=== Vorschau der ermittelten Werte ===") click.echo(f"Berichtsmonat : {month:02d}/{year}") click.echo(f"Aktive Faelle : {len(matched_assignments)}") click.echo("--- Zu erzeugende Taetigkeitsnachweise ---") for item in matched_assignments: click.echo( "- " f"{item.allocation.employee_name} | " f"{item.masterdata.funktion} | " f"{item.foerderquote_percent:.2f}%" ) click.echo("--- Geplante Ausgabedateien ---") for file_name in planned_files: click.echo(f"- {file_name}") @click.command() @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: configure_logging() project_root = Path(__file__).resolve().parent try: config = _load_config(project_root) source_issues = validate_sources( config=config, report_month=month, report_year=year, project_root=project_root, ) _print_issues(source_issues, "=== Source validation ===") if any(issue.severity == "error" for issue in source_issues): raise click.ClickException("Source validation failed.") allocation_records = parse_allocation_records( config=config, report_month=month, report_year=year, project_root=project_root, ) masterdata_records = parse_masterdata_records( config=config, project_root=project_root, ) matched_assignments, match_issues = match_assignments( allocation_records=allocation_records, masterdata_records=masterdata_records, config=config, ) _print_issues(match_issues, "=== Matching issues ===") business_issues = validate_business_rules( config=config, report_month=month, report_year=year, allocation_records=allocation_records, matched_assignments=matched_assignments, project_root=project_root, ) _print_issues(business_issues, "=== Business validation ===") all_issues = [*match_issues, *business_issues] if any(issue.severity == "error" for issue in all_issues): raise click.ClickException("Validation failed after matching.") filename_pattern = config["output"]["filename_pattern"] unique_employees = sorted({item.allocation.employee_name for item in matched_assignments}) planned_files = [ build_output_filename( filename_pattern=filename_pattern, employee_name=employee_name, report_year=year, report_month=month, ) for employee_name in unique_employees ] _print_preview( month=month, year=year, matched_assignments=matched_assignments, planned_files=planned_files, ) if not yes: confirmed = click.confirm("Dateien jetzt schreiben?", default=False) if not confirmed: click.echo("Abbruch ohne Schreibzugriff.") return employee_workbooks = build_employee_workbooks( config=config, matched_assignments=matched_assignments, report_month=month, report_year=year, project_root=project_root, ) output_paths = save_employee_workbooks( config=config, employee_workbooks=employee_workbooks, report_month=month, report_year=year, project_root=project_root, ) click.echo("=== Generated files ===") for output_path in output_paths: click.echo(f"- {output_path}") except TaetigkeitsnachweisError as exc: raise click.ClickException(str(exc)) from exc if __name__ == "__main__": main()