diff --git a/.gitattributes b/.gitattributes index db2e5ec1b2..7048a9c0fc 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,17 +1,17 @@ -src/static/fontawesome/* linguist-vendored -src/static/lightbox/* linguist-vendored -src/static/typeahead/* linguist-vendored -src/static/moment/* linguist-vendored -src/static/datetimepicker/* linguist-vendored -src/static/colorpicker/* linguist-vendored -src/static/fileupload/* linguist-vendored -src/static/vuejs/* linguist-vendored -src/static/select2/* linguist-vendored -src/static/charts/* linguist-vendored -src/static/rrule/* linguist-vendored -src/static/iframeresizer/* linguist-vendored -src/pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/fabric.* linguist-vendored -src/pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/pdf.* linguist-vendored +src/pretix/static/fontawesome/* linguist-vendored +src/pretix/static/lightbox/* linguist-vendored +src/pretix/static/typeahead/* linguist-vendored +src/pretix/static/moment/* linguist-vendored +src/pretix/static/datetimepicker/* linguist-vendored +src/pretix/static/colorpicker/* linguist-vendored +src/pretix/static/fileupload/* linguist-vendored +src/pretix/static/vuejs/* linguist-vendored +src/pretix/static/select2/* linguist-vendored +src/pretix/static/charts/* linguist-vendored +src/pretix/static/rrule/* linguist-vendored +src/pretix/static/iframeresizer/* linguist-vendored +src/pretix/static/pdfjs/* linguist-vendored +src/pretix/static/fabric/* linguist-vendored # Denote all files that are truly binary and should not be modified. *.eot binary diff --git a/doc/development/api/general.rst b/doc/development/api/general.rst index bf40e7fea0..abf2a9b227 100644 --- a/doc/development/api/general.rst +++ b/doc/development/api/general.rst @@ -68,5 +68,5 @@ Dashboards Ticket designs """""""""""""" -.. automodule:: pretix.plugins.ticketoutputpdf.signals +.. automodule:: pretix.base.signals :members: layout_text_variables diff --git a/src/pretix/base/pdf.py b/src/pretix/base/pdf.py new file mode 100644 index 0000000000..07674a76a2 --- /dev/null +++ b/src/pretix/base/pdf.py @@ -0,0 +1,143 @@ +import copy +from collections import OrderedDict + +from django.utils.formats import date_format +from django.utils.translation import ugettext_lazy as _ +from pytz import timezone + +from pretix.base.signals import layout_text_variables +from pretix.base.templatetags.money import money_filter + +DEFAULT_VARIABLES = OrderedDict(( + ("secret", { + "label": _("Ticket code (barcode content)"), + "editor_sample": "tdmruoekvkpbv1o2mv8xccvqcikvr58u", + "evaluate": lambda orderposition, order, event: orderposition.secret + }), + ("order", { + "label": _("Order code"), + "editor_sample": "A1B2C", + "evaluate": lambda orderposition, order, event: orderposition.order.code + }), + ("item", { + "label": _("Product name"), + "editor_sample": _("Sample product"), + "evaluate": lambda orderposition, order, event: str(orderposition.item) + }), + ("variation", { + "label": _("Variation name"), + "editor_sample": _("Sample variation"), + "evaluate": lambda op, order, event: str(op.variation) if op.variation else '' + }), + ("item_description", { + "label": _("Product description"), + "editor_sample": _("Sample product description"), + "evaluate": lambda orderposition, order, event: str(orderposition.item.description) + }), + ("itemvar", { + "label": _("Product name and variation"), + "editor_sample": _("Sample product – sample variation"), + "evaluate": lambda orderposition, order, event: ( + '{} - {}'.format(orderposition.item, orderposition.variation) + if orderposition.variation else str(orderposition.item) + ) + }), + ("item_category", { + "label": _("Product category"), + "editor_sample": _("Ticket category"), + "evaluate": lambda orderposition, order, event: ( + str(orderposition.item.category.name) if orderposition.item.category else "" + ) + }), + ("price", { + "label": _("Price"), + "editor_sample": _("123.45 EUR"), + "evaluate": lambda op, order, event: money_filter(op.price, event.currency) + }), + ("attendee_name", { + "label": _("Attendee name"), + "editor_sample": _("John Doe"), + "evaluate": lambda op, order, ev: op.attendee_name or (op.addon_to.attendee_name if op.addon_to else '') + }), + ("event_name", { + "label": _("Event name"), + "editor_sample": _("Sample event name"), + "evaluate": lambda op, order, ev: str(ev.name) + }), + ("event_date", { + "label": _("Event date"), + "editor_sample": _("May 31st, 2017"), + "evaluate": lambda op, order, ev: ev.get_date_from_display(show_times=False) + }), + ("event_date_range", { + "label": _("Event date range"), + "editor_sample": _("May 31st – June 4th, 2017"), + "evaluate": lambda op, order, ev: ev.get_date_range_display() + }), + ("event_begin", { + "label": _("Event begin date and time"), + "editor_sample": _("2017-05-31 20:00"), + "evaluate": lambda op, order, ev: ev.get_date_from_display(show_times=True) + }), + ("event_begin_time", { + "label": _("Event begin time"), + "editor_sample": _("20:00"), + "evaluate": lambda op, order, ev: ev.get_time_from_display() + }), + ("event_admission", { + "label": _("Event admission date and time"), + "editor_sample": _("2017-05-31 19:00"), + "evaluate": lambda op, order, ev: date_format( + ev.date_admission.astimezone(timezone(ev.settings.timezone)), + "SHORT_DATETIME_FORMAT" + ) if ev.date_admission else "" + }), + ("event_admission_time", { + "label": _("Event admission time"), + "editor_sample": _("19:00"), + "evaluate": lambda op, order, ev: date_format( + ev.date_admission.astimezone(timezone(ev.settings.timezone)), + "TIME_FORMAT" + ) if ev.date_admission else "" + }), + ("event_location", { + "label": _("Event location"), + "editor_sample": _("Random City"), + "evaluate": lambda op, order, ev: str(ev.location).replace("\n", "
\n") + }), + ("invoice_name", { + "label": _("Invoice address: name"), + "editor_sample": _("John Doe"), + "evaluate": lambda op, order, ev: order.invoice_address.name if getattr(order, 'invoice_address') else '' + }), + ("invoice_company", { + "label": _("Invoice address: company"), + "editor_sample": _("Sample company"), + "evaluate": lambda op, order, ev: order.invoice_address.company if getattr(order, 'invoice_address') else '' + }), + ("addons", { + "label": _("List of Add-Ons"), + "editor_sample": _("Addon 1\nAddon 2"), + "evaluate": lambda op, order, ev: "
".join([ + '{} - {}'.format(p.item, p.variation) if p.variation else str(p.item) + for p in op.addons.select_related('item', 'variation') + ]) + }), + ("organizer", { + "label": _("Organizer name"), + "editor_sample": _("Event organizer company"), + "evaluate": lambda op, order, ev: str(order.event.organizer.name) + }), + ("organizer_info_text", { + "label": _("Organizer info text"), + "editor_sample": _("Event organizer info text"), + "evaluate": lambda op, order, ev: str(order.event.settings.organizer_info_text) + }), +)) + + +def get_variables(event): + v = copy.copy(DEFAULT_VARIABLES) + for recv, res in layout_text_variables.send(sender=event): + v.update(res) + return v diff --git a/src/pretix/base/signals.py b/src/pretix/base/signals.py index bfc51d898a..67aea57afd 100644 --- a/src/pretix/base/signals.py +++ b/src/pretix/base/signals.py @@ -338,3 +338,22 @@ The ``message`` argument will contain an ``EmailMultiAlternatives`` object. If the email is associated with a specific order, the ``order`` argument will be passed as well, otherwise it will be ``None``. """ + + +layout_text_variables = EventPluginSignal() +""" +This signal is sent out to collect variables that can be used to display text in ticket-related PDF layouts. +Receivers are expected to return a dictionary with globally unique identifiers as keys and more +dictionaries as values that contain keys like in the following example:: + + return { + "product": { + "label": _("Product name"), + "editor_sample": _("Sample product"), + "evaluate": lambda orderposition, order, event: str(orderposition.item) + } + } + +The evaluate member will be called with the order position, order and event as arguments. The event might +also be a subevent, if applicable. +""" diff --git a/src/pretix/plugins/ticketoutputpdf/templates/pretixplugins/ticketoutputpdf/index.html b/src/pretix/control/templates/pretixcontrol/pdf/index.html similarity index 97% rename from src/pretix/plugins/ticketoutputpdf/templates/pretixplugins/ticketoutputpdf/index.html rename to src/pretix/control/templates/pretixcontrol/pdf/index.html index 435aea0632..cb0a802554 100644 --- a/src/pretix/plugins/ticketoutputpdf/templates/pretixplugins/ticketoutputpdf/index.html +++ b/src/pretix/control/templates/pretixcontrol/pdf/index.html @@ -1,9 +1,22 @@ {% extends "pretixcontrol/event/base.html" %} {% load i18n %} {% load staticfiles %} +{% load compress %} {% block title %}{% trans "PDF Ticket Editor" %}{% endblock %} +{% block custom_header %} + {{ block.super }} + {% compress css %} + + {% endcompress %} + +{% endblock %} {% block content %} -

{% trans "PDF Ticket Editor" %}

+

+ {% trans "PDF Editor" %} + {% if title %} + {{ title }} + {% endif %} +