Fix Sichtbarkeit von Ist-Stand und Plan im PDF ohne JavaScript

This commit is contained in:
Rob committed 2026-03-27 14:41:04 +01:00
1 parent fc11c894a5
commit 6a06a5f2a9
1 file changed
+40
+40
View File
@@ -11,6 +11,7 @@ from pathlib import Path
from typing import Any, Dict, Optional from typing import Any, Dict, Optional
from pypdf import PdfReader, PdfWriter from pypdf import PdfReader, PdfWriter
from pypdf.generic import NameObject, NumberObject
from .config_loader import load_config from .config_loader import load_config
from .exceptions import PdfTemplateError from .exceptions import PdfTemplateError
@@ -73,6 +74,43 @@ def build_field_dict(
return fields return fields
def _update_widget_visibility(writer: PdfWriter, fields: Dict[str, str]) -> None:
"""Un-hide widget annotations for ist.N and plan.N fields that have a value.
In the PDF template these fields carry annotation flag /F=6 (Print + Hidden)
by default. The form's JavaScript (ZeileBerechnen) normally removes the
hidden bit at runtime when ``anwesend.N`` is selected. Because we write
values directly without executing JavaScript we must clear the hidden bit
ourselves for every row where a value is present.
"""
HIDDEN_FIELD_PREFIXES = ("ist.", "plan.")
HIDDEN_BIT = 2 # PDF annotation flag bit 2 = Hidden
for page in writer.pages:
annots = page.get("/Annots")
if not annots:
continue
for annot_ref in annots:
annot = annot_ref.get_object()
t = str(annot.get("/T", ""))
parent = annot.get("/Parent")
if parent:
par_t = str(parent.get_object().get("/T", ""))
full_name = f"{par_t}.{t}"
else:
full_name = t
if not any(full_name.startswith(p) for p in HIDDEN_FIELD_PREFIXES):
continue
has_value = bool(fields.get(full_name, ""))
current_f = int(annot.get("/F", 4))
# Remove hidden bit when value present, keep/set it when absent
new_f = (current_f & ~HIDDEN_BIT) if has_value else (current_f | HIDDEN_BIT)
if new_f != current_f:
annot[NameObject("/F")] = NumberObject(new_f)
def fill_pdf( def fill_pdf(
attendance: MonthlyAttendance, attendance: MonthlyAttendance,
template_path: str | Path, template_path: str | Path,
@@ -113,6 +151,8 @@ def fill_pdf(
for page in writer.pages: for page in writer.pages:
writer.update_page_form_field_values(page, fields, auto_regenerate=False) writer.update_page_form_field_values(page, fields, auto_regenerate=False)
_update_widget_visibility(writer, fields)
output_path.parent.mkdir(parents=True, exist_ok=True) output_path.parent.mkdir(parents=True, exist_ok=True)
with output_path.open("wb") as fh: with output_path.open("wb") as fh:
writer.write(fh) writer.write(fh)