129 lines
4.0 KiB
Python
129 lines
4.0 KiB
Python
from io import BytesIO
|
||
|
||
from reportlab.lib import colors
|
||
from reportlab.lib.pagesizes import A4, portrait
|
||
from reportlab.lib.styles import getSampleStyleSheet
|
||
from reportlab.platypus import Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle
|
||
|
||
from meal_manager.models import Event
|
||
|
||
|
||
def build_dinner_overview_pdf(event: Event) -> BytesIO:
|
||
"""Build a PDF with an overview of the event's attendance."""
|
||
# Create an in-memory PDF
|
||
buffer = BytesIO()
|
||
doc = SimpleDocTemplate(
|
||
buffer,
|
||
pagesize=portrait(A4),
|
||
topMargin=30,
|
||
bottomMargin=30,
|
||
leftMargin=40,
|
||
rightMargin=40,
|
||
)
|
||
styles = getSampleStyleSheet()
|
||
elements = []
|
||
|
||
# Title
|
||
title_style = styles["Title"]
|
||
title_style.fontSize = 16
|
||
title_style.spaceAfter = 20
|
||
elements.append(
|
||
Paragraph(
|
||
f"Anwesenheitsliste – {event.title} ({event.event_time.date().strftime('%d.%m.%y')})",
|
||
title_style,
|
||
)
|
||
)
|
||
elements.append(Spacer(1, 20))
|
||
|
||
# Team overview section
|
||
elements.append(Paragraph("Dienste", styles["Heading2"]))
|
||
elements.append(Spacer(1, 12))
|
||
|
||
team_data = [["Team", "Personen"]]
|
||
team_types = {
|
||
"Kochen": [r for r in event.team if r.work_type == "cooking"],
|
||
"Abwaschen": [r for r in event.team if r.work_type == "dishes"],
|
||
"Tische decken": [r for r in event.team if r.work_type == "tables"],
|
||
}
|
||
|
||
for team_name, registrations in team_types.items():
|
||
members = ", ".join(r.person_name for r in registrations)
|
||
team_data.append([team_name, members])
|
||
|
||
team_table = Table(team_data, repeatRows=1, colWidths=[100, "*"])
|
||
team_table.setStyle(
|
||
TableStyle(
|
||
[
|
||
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#E8E8E8")),
|
||
("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#A0A0A0")),
|
||
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
|
||
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
||
("FONTSIZE", (0, 0), (-1, -1), 10),
|
||
("BOTTOMPADDING", (0, 0), (-1, -1), 8),
|
||
("TOPPADDING", (0, 0), (-1, -1), 8),
|
||
]
|
||
)
|
||
)
|
||
|
||
elements.append(team_table)
|
||
elements.append(Spacer(1, 25))
|
||
|
||
sum_adults = 0
|
||
sum_children = 0
|
||
sum_small_children = 0
|
||
for r in event.registrations:
|
||
sum_adults += r.num_adult_meals
|
||
sum_children += r.num_children_meals
|
||
sum_small_children += r.num_small_children_meals
|
||
|
||
# Attendance section
|
||
elements.append(Paragraph("Teilnehmende", styles["Heading2"]))
|
||
elements.append(
|
||
Paragraph(
|
||
f"Gesamt: {sum_adults} Erwachsene, {sum_children} Kinder, {sum_small_children} Kleinkinder"
|
||
)
|
||
)
|
||
elements.append(Spacer(1, 12))
|
||
|
||
# Table header
|
||
data = [
|
||
["Haushalt", "Erwachsene", "Kinder >7", "Kinder <7", "Kommentar", "Anwesend?"]
|
||
]
|
||
|
||
# Table rows
|
||
for r in event.registrations:
|
||
data.append(
|
||
[
|
||
r.household.name,
|
||
r.num_adult_meals,
|
||
r.num_children_meals,
|
||
r.num_small_children_meals,
|
||
Paragraph(r.comment or ""),
|
||
"",
|
||
]
|
||
)
|
||
for _ in range(5):
|
||
data.append([""] * 6)
|
||
|
||
# Create table
|
||
table = Table(data, repeatRows=1, colWidths=[120, 70, 60, 60, "*", 65])
|
||
table.setStyle(
|
||
TableStyle(
|
||
[
|
||
("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#E8E8E8")),
|
||
("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#A0A0A0")),
|
||
("ALIGN", (1, 1), (-2, -1), "CENTER"),
|
||
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
|
||
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
||
("FONTSIZE", (0, 0), (-1, -1), 10),
|
||
("BOTTOMPADDING", (0, 0), (-1, -1), 3),
|
||
("TOPPADDING", (0, 0), (-1, -1), 3),
|
||
]
|
||
)
|
||
)
|
||
|
||
elements.append(table)
|
||
doc.build(elements)
|
||
buffer.seek(0)
|
||
return buffer
|