[32788f42] Update QR card generator: adjust Y-coordinates, add timezone support, and render checkboxes
This commit is contained in:
@@ -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.
|
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)
|
raw_data = get_calendly_events_raw(api_token, start_time, end_time, event_type_name)
|
||||||
formatted_data = []
|
formatted_data = []
|
||||||
|
|
||||||
for item in raw_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'))
|
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
|
# Format as HH:MM
|
||||||
time_str = start_dt.strftime('%H:%M')
|
time_str = start_dt.strftime('%H:%M')
|
||||||
|
|
||||||
name = item['invitee_name']
|
name = item['invitee_name']
|
||||||
|
|
||||||
# Extract specific answers from the Calendly form
|
# Extract specific answers from the Calendly form
|
||||||
# We look for the number of children and any additional notes
|
|
||||||
num_children = ""
|
num_children = ""
|
||||||
additional_notes = ""
|
additional_notes = ""
|
||||||
|
has_consent = False
|
||||||
questions_and_answers = item.get('questions_and_answers', [])
|
questions_and_answers = item.get('questions_and_answers', [])
|
||||||
|
|
||||||
for q_a in 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:
|
if "wie viele kinder" in q_text:
|
||||||
num_children = a_text
|
num_children = a_text
|
||||||
elif "nachricht" in q_text or "anmerkung" in q_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
|
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
|
# 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:
|
if num_children:
|
||||||
final_text += f", {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):
|
def overlay_text_on_pdf(base_pdf_path: str, output_pdf_path: str, texts: list):
|
||||||
"""
|
# Target:
|
||||||
Overlays text from the `texts` list onto a base PDF.
|
# Element 1: X: 72mm, Y: 22mm + 9mm = 31mm
|
||||||
Expects two text entries per page (top and bottom element).
|
# Element 2: X: 72mm, Y: 171mm + 9mm = 180mm
|
||||||
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)
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Convert mm to points (1 mm = 2.83465 points)
|
# 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.
|
# User coordinates are from top-left.
|
||||||
# ReportLab uses bottom-left as (0,0).
|
# ReportLab uses bottom-left as (0,0).
|
||||||
# Element 1 (Top): X = 72mm, Y = 22mm (from top) -> Y = page_height - 22mm
|
# Element 1 (Top): X = 72mm, Y = 31mm (from top) -> Y = page_height - 31mm
|
||||||
# Element 2 (Bottom): X = 72mm, Y = 171mm (from top) -> Y = page_height - 171mm
|
# Element 2 (Bottom): X = 72mm, Y = 180mm (from top) -> Y = page_height - 180mm
|
||||||
|
|
||||||
x_pos = 72 * mm_to_pt
|
x_pos = 72 * mm_to_pt
|
||||||
y_pos_1 = page_height - (22 * mm_to_pt)
|
y_pos_1 = page_height - (31 * mm_to_pt)
|
||||||
y_pos_2 = page_height - (171 * mm_to_pt)
|
y_pos_2 = page_height - (180 * mm_to_pt)
|
||||||
|
|
||||||
reader = PdfReader(base_pdf_path)
|
reader = PdfReader(base_pdf_path)
|
||||||
writer = PdfWriter()
|
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):
|
for page_idx, pair in enumerate(text_pairs):
|
||||||
if page_idx >= total_pages:
|
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
|
# Create a new blank page in memory to draw the text
|
||||||
packet = io.BytesIO()
|
packet = io.BytesIO()
|
||||||
can = canvas.Canvas(packet, pagesize=A4)
|
can = canvas.Canvas(packet, pagesize=A4)
|
||||||
|
|
||||||
# Draw the text.
|
# Draw the text.
|
||||||
|
# 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.setFont("Helvetica", 12)
|
||||||
|
can.drawString(current_x, y, text)
|
||||||
|
|
||||||
if len(pair) > 0:
|
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:
|
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()
|
can.save()
|
||||||
packet.seek(0)
|
packet.seek(0)
|
||||||
|
|||||||
Reference in New Issue
Block a user