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