Create CLI pipeline entrypoint with validation and preview
This commit is contained in:
1 parent
5436315952
commit
7e8e68a9d8
3 files changed
+128
-6
No files matched your search
@@ -77,10 +77,10 @@ Projekt vollstaendig umsetzen: aus PS_PW.xlsx und Stellenbeschreibungen.xlsx mon
|
|||||||
- [x] Bei mehreren Zuordnungen: mehrere Sheets in derselben Datei
|
- [x] Bei mehreren Zuordnungen: mehrere Sheets in derselben Datei
|
||||||
|
|
||||||
## Phase 7 - CLI und Benutzerfluss
|
## Phase 7 - CLI und Benutzerfluss
|
||||||
- [ ] T13: CLI in `generate.py` implementieren
|
- [x] T13: CLI in `generate.py` implementieren
|
||||||
- [ ] Parameter `--month` und `--year`
|
- [x] Parameter `--month` und `--year`
|
||||||
- [ ] Pipeline orchestrieren: parse -> match -> validate -> preview -> write
|
- [x] Pipeline orchestrieren: parse -> match -> validate -> preview -> write
|
||||||
- [ ] Kontrollierter Exit-Code bei Fehlern
|
- [x] Kontrollierter Exit-Code bei Fehlern
|
||||||
- [ ] T14: Vorschau + Bestaetigung vor Schreiben
|
- [ ] T14: Vorschau + Bestaetigung vor Schreiben
|
||||||
- [ ] Uebersicht zu Berichtsmonat, aktiven Faellen, Fehlern
|
- [ ] Uebersicht zu Berichtsmonat, aktiven Faellen, Fehlern
|
||||||
- [ ] Liste der geplanten Ausgabedateien
|
- [ ] Liste der geplanten Ausgabedateien
|
||||||
@@ -111,4 +111,4 @@ Projekt vollstaendig umsetzen: aus PS_PW.xlsx und Stellenbeschreibungen.xlsx mon
|
|||||||
8. T15 -> T16 -> T17
|
8. T15 -> T16 -> T17
|
||||||
|
|
||||||
## Aktueller Startpunkt
|
## Aktueller Startpunkt
|
||||||
- [ ] Naechste aktive Aufgabe: T13 (CLI in generate.py implementieren)
|
- [ ] Naechste aktive Aufgabe: T14 (Vorschau + Bestaetigung vor Schreiben)
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
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, 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) -> 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.command()
|
||||||
|
@click.option("--month", type=click.IntRange(1, 12), required=True)
|
||||||
|
@click.option("--year", type=click.IntRange(2000, 2100), required=True)
|
||||||
|
def main(month: int, year: int) -> 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.")
|
||||||
|
|
||||||
|
_print_preview(month=month, year=year, matched_assignments=matched_assignments)
|
||||||
|
|
||||||
|
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()
|
||||||
@@ -266,6 +266,7 @@ def validate_business_rules(
|
|||||||
report_year: int,
|
report_year: int,
|
||||||
allocation_records: list[AllocationRecord],
|
allocation_records: list[AllocationRecord],
|
||||||
matched_assignments: list[MatchedAssignment],
|
matched_assignments: list[MatchedAssignment],
|
||||||
|
project_root: Path,
|
||||||
) -> list[ValidationIssue]:
|
) -> list[ValidationIssue]:
|
||||||
issues: list[ValidationIssue] = []
|
issues: list[ValidationIssue] = []
|
||||||
|
|
||||||
@@ -301,7 +302,6 @@ def validate_business_rules(
|
|||||||
|
|
||||||
paths_cfg = config["paths"]
|
paths_cfg = config["paths"]
|
||||||
files_cfg = config["files"]
|
files_cfg = config["files"]
|
||||||
project_root = Path.cwd()
|
|
||||||
template_path = (
|
template_path = (
|
||||||
project_root
|
project_root
|
||||||
/ paths_cfg["template_dir"]
|
/ paths_cfg["template_dir"]
|
||||||
|
|||||||
Reference in new issue
Block a user