deepseek den plan umsetzen lassen

This commit is contained in:
trnq1ll0 committed 2026-06-09 08:33:47 +02:00
1 parent 6c60a72e0f
commit 044e4df783
16 files changed
+971 -55

No files matched your search

+158
View File
@@ -0,0 +1,158 @@
"""Template-basierte Activity-Report-Generierung."""
from datetime import date
from pathlib import Path
from openpyxl import load_workbook
from openpyxl.cell.cell import MergedCell
from openpyxl.utils import column_index_from_string
from .models import EmployeeRecord, OutputMapping
def _split_name_for_filename(name: str) -> tuple[str, str]:
"""Teilt 'Nachname, Vorname' oder 'Vorname Nachname' in (Vorname, Nachname)."""
cleaned = str(name or "").strip()
if "," in cleaned:
last_name, first_name = [p.strip() for p 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 _format_value(value, fmt: str | None) -> str:
"""Formatiert einen Wert gemäß Format-String."""
if value is None:
return ""
if fmt is None:
return str(value)
# Numerische Formatierung (z.B. "%.2f")
if "%" in fmt:
try:
return fmt % float(value)
except (ValueError, TypeError):
return str(value)
return str(value)
def _set_cell_value(ws, target_cell: str, value) -> None:
"""Setzt einen Wert in einer Zelle des Worksheets.
Behandelt MergedCells, indem in die Top-Left-Zelle des Merge-Bereichs geschrieben wird."""
try:
cell = ws[target_cell]
# Wenn es eine MergedCell ist, finde die Top-Left-Zelle des Merge-Bereichs
if isinstance(cell, MergedCell):
for merged_range in ws.merged_cells.ranges:
if cell.coordinate in merged_range:
top_left = merged_range.min_row, merged_range.min_col
ws.cell(row=top_left[0], column=top_left[1]).value = value
return
else:
cell.value = value
except (ValueError, KeyError):
pass # Zelle existiert nicht
def _format_month_for_template(monat_str: str) -> str:
"""Konvertiert 'MM.JJ' zu 'MM.JJJJ' (z.B. '01.2025' → '01.2025', '01.25' → '01.2025')."""
monat_str = monat_str.strip()
parts = monat_str.split(".")
if len(parts) == 2:
month = parts[0]
year = parts[1]
if len(year) == 2:
year = "20" + year
return f"{month}.{year}"
return monat_str
def generate_activity_reports(
employee_records: dict[str, list[EmployeeRecord]],
template_path: Path,
mapping: list[OutputMapping],
output_dir: Path,
filename_pattern: str,
) -> list[Path]:
"""
Generiert für jeden Mitarbeiter eine Excel-Datei.
Jeder Monat wird als eigenes Sheet im Template-Stil erstellt.
"""
output_dir.mkdir(parents=True, exist_ok=True)
generated_files: list[Path] = []
# Build source_field → mapping lookup
field_map: dict[str, OutputMapping] = {m.source_field: m for m in mapping}
for employee_name, records in employee_records.items():
if not records:
continue
first_name, last_name = _split_name_for_filename(employee_name)
safe_first = first_name.replace(" ", "_").replace("/", "_")
safe_last = last_name.replace(" ", "_").replace("/", "_")
filename = filename_pattern.format(
first_name=safe_first,
last_name=safe_last,
)
output_path = output_dir / filename
# Lade Template
wb = load_workbook(template_path)
template_sheet = wb.worksheets[0]
# Sortiere Records nach Monat
sorted_records = sorted(records, key=lambda r: r.month_index)
for idx, record in enumerate(sorted_records):
if idx == 0:
sheet = template_sheet
else:
sheet = wb.copy_worksheet(template_sheet)
# Sheet-Name: Monatsname
month_names = [
"", "Januar", "Februar", "März", "April", "Mai", "Juni",
"Juli", "August", "September", "Oktober", "November", "Dezember"
]
mi = record.month_index
sheet_name = f"{mi:02d}_{month_names[mi]}" if 1 <= mi <= 12 else f"Monat_{idx + 1}"
sheet.title = sheet_name[:31]
# Befülle Zielfelder
for source_field, m in field_map.items():
if source_field == "Monat (MM.JJ)":
value = _format_month_for_template(record.monat)
elif source_field == "Stellenanteil in %":
value = record.stellenanteil
elif hasattr(record, source_field.lower().replace(" ", "_")):
value = getattr(record, source_field.lower().replace(" ", "_"))
elif source_field == "Name":
value = employee_name
elif source_field == "Antragsnummer":
value = record.antragsnummer
elif source_field == "Qualifikation":
value = record.qualifikation
elif source_field == "Funktion":
value = record.funktion
elif source_field == "Tätigkeit":
value = record.taetigkeit
else:
continue
formatted = _format_value(value, m.format)
_set_cell_value(sheet, m.target_cell, formatted)
# Setze aktuelles Datum für das Erstelldatum
today = date.today().strftime("%d.%m.%Y")
_set_cell_value(sheet, "K94", today)
wb.save(output_path)
wb.close()
generated_files.append(output_path)
return generated_files