"""Template-based output workbook writer.""" from __future__ import annotations from collections import defaultdict from datetime import date from pathlib import Path from typing import Any from openpyxl import Workbook, load_workbook from .models import MatchedAssignment def _split_name_for_filename(name: str) -> tuple[str, str]: cleaned = str(name or "").strip() if "," in cleaned: last_name, first_name = [part.strip() for part in cleaned.split(",", 1)] return first_name or "Unknown", last_name or "Unknown" parts = cleaned.split() if len(parts) >= 2: return parts[0], parts[-1] if len(parts) == 1: return parts[0], "Unknown" return "Unknown", "Unknown" def _normalize_sheet_title(raw_title: str, fallback_index: int) -> str: cleaned = (raw_title or "").strip().replace("[", "(").replace("]", ")") if not cleaned: cleaned = f"Assignment_{fallback_index}" return cleaned[:31] def _set_target_value(worksheet: Any, target_cell: str, value: Any) -> None: if not target_cell: return worksheet[target_cell] = value def build_employee_workbooks( config: dict[str, Any], matched_assignments: list[MatchedAssignment], report_month: int, report_year: int, project_root: Path, ) -> dict[str, Workbook]: paths_cfg = config["paths"] files_cfg = config["files"] output_cfg = config["output"] targets = config.get("template_targets", {}) template_path = ( project_root / paths_cfg["template_dir"] / files_cfg["template_workbook"] ) assignments_by_employee: dict[str, list[MatchedAssignment]] = defaultdict(list) for assignment in matched_assignments: assignments_by_employee[assignment.allocation.employee_name].append(assignment) workbooks: dict[str, Workbook] = {} month_label = f"{report_month:02d}/{report_year}" today_label = date.today().strftime("%d.%m.%Y") for employee_name, assignments in assignments_by_employee.items(): workbook = load_workbook(template_path) 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: sheet = base_sheet else: sheet = workbook.copy_worksheet(base_sheet) sheet_name_pattern = output_cfg.get("sheet_name_pattern", "{index}_{funktion}") raw_sheet_name = sheet_name_pattern.format( index=index, funktion=assignment.masterdata.funktion, ) sheet.title = _normalize_sheet_title(raw_sheet_name, index) _set_target_value(sheet, targets.get("antragsnummer", ""), assignment.masterdata.antragsnummer) _set_target_value(sheet, targets.get("name_vorname", ""), assignment.allocation.employee_name) _set_target_value(sheet, targets.get("qualifikation", ""), assignment.masterdata.qualifikation) _set_target_value(sheet, targets.get("funktion", ""), assignment.masterdata.funktion) _set_target_value(sheet, targets.get("taetigkeiten", ""), assignment.masterdata.taetigkeit) _set_target_value(sheet, targets.get("reporting_month_label", ""), month_label) _set_target_value(sheet, targets.get("foerderquote", ""), f"{assignment.foerderquote_percent:.2f} %") _set_target_value(sheet, targets.get("generated_on", ""), today_label) workbooks[employee_name] = workbook return workbooks def build_output_filename( filename_pattern: str, employee_name: str, report_year: int, report_month: int, ) -> str: first_name, last_name = _split_name_for_filename(employee_name) safe_first = first_name.replace(" ", "_") safe_last = last_name.replace(" ", "_") return filename_pattern.format( year=report_year, month=f"{report_month:02d}", first_name=safe_first, last_name=safe_last, ) def save_employee_workbooks( config: dict[str, Any], employee_workbooks: dict[str, Workbook], report_month: int, report_year: int, project_root: Path, ) -> list[Path]: paths_cfg = config["paths"] output_cfg = config["output"] filename_pattern = output_cfg["filename_pattern"] output_dir = project_root / paths_cfg["output_dir"] output_dir.mkdir(parents=True, exist_ok=True) saved_paths: list[Path] = [] used_names: set[str] = set() for employee_name, workbook in employee_workbooks.items(): filename = build_output_filename( filename_pattern=filename_pattern, employee_name=employee_name, report_year=report_year, report_month=report_month, ) if filename in used_names: raise ValueError(f"Output filename collision detected: {filename}") used_names.add(filename) output_path = output_dir / filename workbook.save(output_path) workbook.close() saved_paths.append(output_path) return saved_paths