feat(list-generator): implement dynamic labels and fix logo rendering [32788f42]
This commit is contained in:
12
list-generator/.gitignore
vendored
Normal file
12
list-generator/.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
*.egg-info/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
.pytest_cache/
|
||||||
@@ -15,6 +15,16 @@ def get_logo_base64():
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def generate_school_pdf(institution: str, date_info: str, list_type: str, students_csv_path: str, families_csv_path: str = None, output_dir: str = "/tmp") -> str:
|
def generate_school_pdf(institution: str, date_info: str, list_type: str, students_csv_path: str, families_csv_path: str = None, output_dir: str = "/tmp") -> str:
|
||||||
|
# Determine labels based on list_type
|
||||||
|
if list_type.lower() == 'k':
|
||||||
|
group_label = "Gruppe"
|
||||||
|
person_label = "Kinder"
|
||||||
|
person_label_plural = "Kinder"
|
||||||
|
else: # Default to 'school'
|
||||||
|
group_label = "Klasse"
|
||||||
|
person_label = "Schüler"
|
||||||
|
person_label_plural = "Schüler"
|
||||||
|
|
||||||
df = None
|
df = None
|
||||||
for sep in [";", ","]:
|
for sep in [";", ","]:
|
||||||
try:
|
try:
|
||||||
@@ -26,8 +36,10 @@ def generate_school_pdf(institution: str, date_info: str, list_type: str, studen
|
|||||||
continue
|
continue
|
||||||
if df is None:
|
if df is None:
|
||||||
df = pd.read_csv(students_csv_path, sep=";", encoding="latin1")
|
df = pd.read_csv(students_csv_path, sep=";", encoding="latin1")
|
||||||
|
|
||||||
df.columns = df.columns.str.strip().str.replace("\"", "")
|
df.columns = df.columns.str.strip().str.replace("\"", "")
|
||||||
print(f"Detected columns: {list(df.columns)}")
|
print(f"Detected columns: {list(df.columns)}")
|
||||||
|
|
||||||
col_mapping = {}
|
col_mapping = {}
|
||||||
for col in df.columns:
|
for col in df.columns:
|
||||||
lower_col = col.lower().strip()
|
lower_col = col.lower().strip()
|
||||||
@@ -36,36 +48,52 @@ def generate_school_pdf(institution: str, date_info: str, list_type: str, studen
|
|||||||
elif lower_col in ["nachname kind", "nachname", "last name"]:
|
elif lower_col in ["nachname kind", "nachname", "last name"]:
|
||||||
col_mapping[col] = "Nachname"
|
col_mapping[col] = "Nachname"
|
||||||
elif lower_col in ["gruppe", "klasse", "group", "class"]:
|
elif lower_col in ["gruppe", "klasse", "group", "class"]:
|
||||||
col_mapping[col] = "Klasse"
|
col_mapping[col] = group_label # Use dynamic label
|
||||||
|
|
||||||
df = df.rename(columns=col_mapping)
|
df = df.rename(columns=col_mapping)
|
||||||
df = df.fillna("")
|
df = df.fillna("")
|
||||||
for col in ["Vorname", "Nachname", "Klasse"]:
|
|
||||||
|
for col in ["Vorname", "Nachname", group_label]:
|
||||||
if col not in df.columns:
|
if col not in df.columns:
|
||||||
df[col] = "Alle" if col == "Klasse" else ""
|
df[col] = "Alle" if col == group_label else ""
|
||||||
df = df.sort_values(by=["Klasse", "Nachname", "Vorname"])
|
|
||||||
grouped = df.groupby("Klasse")
|
df = df.sort_values(by=[group_label, "Nachname", "Vorname"])
|
||||||
|
grouped = df.groupby(group_label)
|
||||||
|
|
||||||
class_data = []
|
class_data = []
|
||||||
for class_name, group in grouped:
|
for class_name, group in grouped:
|
||||||
class_data.append({"name": class_name, "students": group.to_dict("records")})
|
class_data.append({"name": class_name, "students": group.to_dict("records")})
|
||||||
|
|
||||||
class_counts = [{"name": c, "count": len(g)} for c, g in grouped]
|
class_counts = [{"name": c, "count": len(g)} for c, g in grouped]
|
||||||
total_students = len(df)
|
total_students = len(df)
|
||||||
|
|
||||||
template_dir = os.path.join(os.path.dirname(__file__), "..", "templates")
|
template_dir = os.path.join(os.path.dirname(__file__), "..", "templates")
|
||||||
env = Environment(loader=FileSystemLoader(template_dir))
|
env = Environment(loader=FileSystemLoader(template_dir))
|
||||||
template = env.get_template("school_list.html")
|
template = env.get_template("school_list.html")
|
||||||
|
|
||||||
current_time = datetime.datetime.now().strftime("%d.%m.%Y %H:%M Uhr")
|
current_time = datetime.datetime.now().strftime("%d.%m.%Y %H:%M Uhr")
|
||||||
logo_base64 = get_logo_base64()
|
logo_base64 = get_logo_base64()
|
||||||
html_out = template.render(
|
|
||||||
institution=institution,
|
render_context = {
|
||||||
date_info=date_info,
|
"institution": institution,
|
||||||
class_counts=class_counts,
|
"date_info": date_info,
|
||||||
total_students=total_students,
|
"class_counts": class_counts,
|
||||||
class_data=class_data,
|
"total_students": total_students,
|
||||||
current_time=current_time,
|
"class_data": class_data,
|
||||||
logo_base64=logo_base64
|
"current_time": current_time,
|
||||||
)
|
"logo_base64": logo_base64,
|
||||||
|
"group_label": group_label,
|
||||||
|
"person_label": person_label,
|
||||||
|
"person_label_plural": person_label_plural,
|
||||||
|
"group_column_name": group_label # Pass the actual column name for the table header
|
||||||
|
}
|
||||||
|
|
||||||
|
html_out = template.render(render_context)
|
||||||
|
|
||||||
clean_inst = institution.replace(" ", "_").replace("/", "-")
|
clean_inst = institution.replace(" ", "_").replace("/", "-")
|
||||||
time_str = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M")
|
time_str = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M")
|
||||||
output_filename = f"Listen_{clean_inst}_{list_type}_{time_str}.pdf"
|
output_filename = f"Listen_{clean_inst}_{list_type}_{time_str}.pdf"
|
||||||
output_path = os.path.join(output_dir, output_filename)
|
output_path = os.path.join(output_dir, output_filename)
|
||||||
|
|
||||||
HTML(string=html_out).write_pdf(output_path)
|
HTML(string=html_out).write_pdf(output_path)
|
||||||
return output_path
|
return output_path
|
||||||
|
|||||||
@@ -25,13 +25,15 @@
|
|||||||
<div class="institution-name">{{ institution }}</div>
|
<div class="institution-name">{{ institution }}</div>
|
||||||
<div class="date-info">{{ date_info }}</div>
|
<div class="date-info">{{ date_info }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if logo_base64 %}
|
||||||
<div>
|
<div>
|
||||||
<img src="data:image/png;base64,{{ logo_base64 }}" alt="Logo" style="max-height: 60px;">
|
<img src="data:image/png;base64,{{ logo_base64 }}" alt="Logo" style="max-height: 60px;">
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="summary"><h2>Übersicht der Anmeldungen:</h2><table class="summary-table">
|
<div class="summary"><h2>Übersicht der Anmeldungen:</h2><table class="summary-table">
|
||||||
{% for count in class_counts %}
|
{% for count in class_counts %}
|
||||||
<tr><td style="width: 50%;">Klasse {{ count.name }}</td><td>{{ count.count }} Anmeldungen</td></tr>
|
<tr><td style="width: 50%;">{{ group_label }} {{ count.name }}</td><td>{{ count.count }} Anmeldungen</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table><div class="summary-total">Gesamt: {{ total_students }} Anmeldungen</div></div>
|
</table><div class="summary-total">Gesamt: {{ total_students }} Anmeldungen</div></div>
|
||||||
{% for class_info in class_data %}
|
{% for class_info in class_data %}
|
||||||
@@ -41,17 +43,19 @@
|
|||||||
<div class="institution-name">{{ institution }}</div>
|
<div class="institution-name">{{ institution }}</div>
|
||||||
<div class="date-info">{{ date_info }}</div>
|
<div class="date-info">{{ date_info }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if logo_base64 %}
|
||||||
<div>
|
<div>
|
||||||
<img src="data:image/png;base64,{{ logo_base64 }}" alt="Logo" style="max-height: 60px;">
|
<img src="data:image/png;base64,{{ logo_base64 }}" alt="Logo" style="max-height: 60px;">
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<table class="student-table"><thead><tr><th style="width: 40%">Nachname</th><th style="width: 40%">Vorname</th><th style="width: 20%">Klasse</th></tr></thead><tbody>
|
<table class="student-table"><thead><tr><th style="width: 40%">Nachname</th><th style="width: 40%">Vorname</th><th style="width: 20%">{{ group_label }}</th></tr></thead><tbody>
|
||||||
{% for student in class_info.students %}
|
{% for student in class_info.students %}
|
||||||
<tr><td>{{ student.Nachname }}</td><td>{{ student.Vorname }}</td><td>{{ student.Klasse }}</td></tr>
|
<tr><td>{{ student.Nachname }}</td><td>{{ student.Vorname }}</td><td>{{ student[group_column_name] }}</td></tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody></table>
|
</tbody></table>
|
||||||
<div class="class-summary">{{ class_info.students|length }} angemeldete Kinder</div>
|
<div class="class-summary">{{ class_info.students|length }} angemeldete {{ person_label_plural }}</div>
|
||||||
<div class="class-note">Dies ist die Liste der bereits angemeldeten Schüler. Bitte die noch fehlenden<br>Schüler an die Anmeldung erinnern.</div>
|
<div class="class-note">Dies ist die Liste der bereits angemeldeten {{ person_label_plural }}. Bitte die noch fehlenden<br>{{ person_label_plural }} an die Anmeldung erinnern.</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="footer"><div class="footer-left">Stand {{ current_time }}</div><div class="footer-right">Kinderfotos Erding<br>Gartenstr. 10 85445 Oberding<br>www.kinderfotos-erding.de<br>08122-8470867</div></div>
|
<div class="footer"><div class="footer-left">Stand {{ current_time }}</div><div class="footer-right">Kinderfotos Erding<br>Gartenstr. 10 85445 Oberding<br>www.kinderfotos-erding.de<br>08122-8470867</div></div>
|
||||||
|
|||||||
Reference in New Issue
Block a user