[32788f42] Update QR card generator: adjust Y-coordinates, add timezone support, and render checkboxes

This commit is contained in:
2026-03-21 13:35:16 +00:00
parent e5add77a50
commit ec877ef65b

View File

@@ -79,21 +79,25 @@ def get_calendly_events(api_token: str, start_time: str, end_time: str, event_ty
"""
Fetches events from Calendly API for the current user within a time range.
"""
from zoneinfo import ZoneInfo
raw_data = get_calendly_events_raw(api_token, start_time, end_time, event_type_name)
formatted_data = []
for item in raw_data:
# Parse start time
# Parse start time from UTC
start_dt = datetime.datetime.fromisoformat(item['start_time'].replace('Z', '+00:00'))
# Convert to Europe/Berlin (CET/CEST)
start_dt = start_dt.astimezone(ZoneInfo("Europe/Berlin"))
# Format as HH:MM
time_str = start_dt.strftime('%H:%M')
name = item['invitee_name']
# Extract specific answers from the Calendly form
# We look for the number of children and any additional notes
num_children = ""
additional_notes = ""
has_consent = False
questions_and_answers = item.get('questions_and_answers', [])
for q_a in questions_and_answers:
@@ -103,12 +107,20 @@ def get_calendly_events(api_token: str, start_time: str, end_time: str, event_ty
if "wie viele kinder" in q_text:
num_children = a_text
elif "nachricht" in q_text or "anmerkung" in q_text:
# If there's a custom notes field in some events
additional_notes = a_text
elif "schöne bilder" in q_text and "website veröffentlichen" in q_text:
if "ja, gerne" in a_text.lower():
has_consent = True
# Construct the final string: "Name, X Kinder // HH:MM Uhr (Notes)"
# Construct the final string: "[☑] Name, X Kinder // HH:MM Uhr (Notes)"
# matching: Halime Türe, 1 Kind // 12:00 Uhr
final_text = f"{name}"
final_text = ""
if has_consent:
# We use a placeholder character or string that we will handle in overlay_text_on_pdf
# because standard Helvetica doesn't support Unicode checkbox.
final_text += ""
final_text += f"{name}"
if num_children:
final_text += f", {num_children}"
@@ -124,13 +136,9 @@ def get_calendly_events(api_token: str, start_time: str, end_time: str, event_ty
def overlay_text_on_pdf(base_pdf_path: str, output_pdf_path: str, texts: list):
"""
Overlays text from the `texts` list onto a base PDF.
Expects two text entries per page (top and bottom element).
Coordinates are in mm from bottom-left (ReportLab default).
Target:
Element 1: X: 72mm, Y: 22mm (from top-left in user spec, need to convert)
Element 2: X: 72mm, Y: 171mm (from top-left in user spec, need to convert)
# Target:
# Element 1: X: 72mm, Y: 22mm + 9mm = 31mm
# Element 2: X: 72mm, Y: 171mm + 9mm = 180mm
"""
# Convert mm to points (1 mm = 2.83465 points)
@@ -141,12 +149,12 @@ def overlay_text_on_pdf(base_pdf_path: str, output_pdf_path: str, texts: list):
# User coordinates are from top-left.
# ReportLab uses bottom-left as (0,0).
# Element 1 (Top): X = 72mm, Y = 22mm (from top) -> Y = page_height - 22mm
# Element 2 (Bottom): X = 72mm, Y = 171mm (from top) -> Y = page_height - 171mm
# Element 1 (Top): X = 72mm, Y = 31mm (from top) -> Y = page_height - 31mm
# Element 2 (Bottom): X = 72mm, Y = 180mm (from top) -> Y = page_height - 180mm
x_pos = 72 * mm_to_pt
y_pos_1 = page_height - (22 * mm_to_pt)
y_pos_2 = page_height - (171 * mm_to_pt)
y_pos_1 = page_height - (31 * mm_to_pt)
y_pos_2 = page_height - (180 * mm_to_pt)
reader = PdfReader(base_pdf_path)
writer = PdfWriter()
@@ -163,19 +171,38 @@ def overlay_text_on_pdf(base_pdf_path: str, output_pdf_path: str, texts: list):
for page_idx, pair in enumerate(text_pairs):
if page_idx >= total_pages:
break # Should be caught by the truncation above, but safety first
break # Safety first
# Create a new blank page in memory to draw the text
packet = io.BytesIO()
can = canvas.Canvas(packet, pagesize=A4)
# Draw the text.
can.setFont("Helvetica", 12)
# We handle the "" character manually since Helvetica might not support it.
def draw_text_with_checkbox(can, x, y, text):
current_x = x
if text.startswith(""):
# Draw a checkbox manually
size = 10
# Draw box (baseline adjustment to align with text)
can.rect(x, y - 1, size, size)
# Draw checkmark
can.setLineWidth(1.5)
can.line(x + 2, y + 3, x + 4.5, y + 0.5)
can.line(x + 4.5, y + 0.5, x + 8.5, y + 7)
can.setLineWidth(1)
# Move text X position to the right
current_x += size + 5
text = text[2:] # Remove the "" from string
can.setFont("Helvetica", 12)
can.drawString(current_x, y, text)
if len(pair) > 0:
can.drawString(x_pos, y_pos_1, pair[0])
draw_text_with_checkbox(can, x_pos, y_pos_1, pair[0])
if len(pair) > 1:
can.drawString(x_pos, y_pos_2, pair[1])
draw_text_with_checkbox(can, x_pos, y_pos_2, pair[1])
can.save()
packet.seek(0)