diff --git a/src/pretix/base/ticketoutput.py b/src/pretix/base/ticketoutput.py
index daa0a4e156..2934e64f1e 100644
--- a/src/pretix/base/ticketoutput.py
+++ b/src/pretix/base/ticketoutput.py
@@ -45,6 +45,13 @@ class BaseTicketOutput:
This method should generate the download file and return a tuple consisting of a
filename, a file type and file content. The extension will be taken from the filename
which is otherwise ignored.
+
+ .. note:: If the event uses the event series feature (internally called subevents)
+ and your generated ticket contains information like the event name or date,
+ you probably want to display the properties of the subevent. A common pattern
+ to do this would be a declaration ``ev = position.subevent or position.order.event``
+ and then access properties that are present on both classes like ``ev.name`` or
+ ``ev.date_from``.
"""
raise NotImplementedError()
diff --git a/src/pretix/plugins/ticketoutputpdf/ticketoutput.py b/src/pretix/plugins/ticketoutputpdf/ticketoutput.py
index f11e384f64..49fc0818c6 100644
--- a/src/pretix/plugins/ticketoutputpdf/ticketoutput.py
+++ b/src/pretix/plugins/ticketoutputpdf/ticketoutput.py
@@ -63,6 +63,7 @@ class PdfTicketOutput(BaseTicketOutput):
renderPDF.draw(d, canvas, qr_x, qr_y)
def _get_text_content(self, op: OrderPosition, order: Order, o: dict):
+ ev = op.subevent or order.event
if o['content'] == 'other':
return o['text'].replace("\n", "
\n")
elif o['content'] == 'order':
@@ -80,25 +81,25 @@ class PdfTicketOutput(BaseTicketOutput):
elif o['content'] == 'attendee_name':
return op.attendee_name or (op.addon_to.attendee_name if op.addon_to else '')
elif o['content'] == 'event_name':
- return str(order.event)
+ return str(ev.name)
elif o['content'] == 'event_location':
- return str(order.event.location).replace("\n", "
\n")
+ return str(ev.location).replace("\n", "
\n")
elif o['content'] == 'event_date':
- return order.event.get_date_from_display(show_times=False)
+ return ev.get_date_from_display(show_times=False)
elif o['content'] == 'event_date_range':
- return order.event.get_date_range_display()
+ return ev.get_date_range_display()
elif o['content'] == 'event_begin':
- return order.event.get_date_from_display(show_times=True)
+ return ev.get_date_from_display(show_times=True)
elif o['content'] == 'event_begin_time':
- return order.event.get_time_from_display()
+ return ev.get_time_from_display()
elif o['content'] == 'event_admission':
- if order.event.date_admission:
+ if ev.date_admission:
tz = timezone(order.event.settings.timezone)
- return date_format(order.event.date_admission.astimezone(tz), "SHORT_DATETIME_FORMAT")
+ return date_format(ev.date_admission.astimezone(tz), "SHORT_DATETIME_FORMAT")
elif o['content'] == 'event_admission_time':
- if order.event.date_admission:
+ if ev.date_admission:
tz = timezone(order.event.settings.timezone)
- return date_format(order.event.date_admission.astimezone(tz), "TIME_FORMAT")
+ return date_format(ev.date_admission.astimezone(tz), "TIME_FORMAT")
elif o['content'] == 'addons':
return "
".join([
'{} - {}'.format(p.item, p.variation) if p.variation else str(p.item)