Refactor and add signal layout_text_variables

This commit is contained in:
Raphael Michel
2017-09-27 13:15:18 +02:00
parent 39061b659a
commit 1f889be07a
7 changed files with 177 additions and 103 deletions

View File

@@ -64,3 +64,9 @@ Dashboards
.. automodule:: pretix.control.signals
:members: event_dashboard_widgets, user_dashboard_widgets
Ticket designs
""""""""""""""
.. automodule:: pretix.plugins.ticketoutputpdf.signals
:members: layout_text_variables

View File

@@ -3,7 +3,7 @@ from django.template.loader import get_template
from django.urls import resolve
from pretix.base.signals import (
register_data_exporters, register_ticket_outputs,
EventPluginSignal, register_data_exporters, register_ticket_outputs,
)
from pretix.control.signals import html_head
from pretix.presale.style import ( # NOQA: legacy import
@@ -33,3 +33,22 @@ def html_head_presale(sender, request=None, **kwargs):
})
else:
return ""
layout_text_variables = EventPluginSignal()
"""
This signal is sent out to collect variables that can be used to display text in PDF ticket 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.
"""

View File

@@ -158,35 +158,11 @@ var editor = {
editor._update_toolbox_values();
},
text_samples: {
"secret": "tdmruoekvkpbv1o2mv8xccvqcikvr58u",
"order": "A1B2C",
"item": gettext("Sample product"),
"variation": gettext("Sample variation"),
"itemvar": gettext("Sample product sample variation"),
"item_description": gettext("Sample product description"),
"price": gettext("123.45 EUR"),
"attendee_name": gettext("John Doe"),
"invoice_name": gettext("John Doe"),
"invoice_company": gettext("Sample company"),
"event_name": gettext("Sample event name"),
"event_date": gettext("May 31st, 2017"),
"event_date_range": gettext("May 31st June 4th, 2017"),
"event_begin_time": gettext("20:00"),
"event_admission_time": gettext("19:00"),
"event_begin": gettext("2017-05-31 20:00"),
"event_admission": gettext("2017-05-31 19:00"),
"event_location": gettext("Random City"),
"organizer": gettext("Event organizer company"),
"organizer_info_text": gettext("Event organizer info text"),
"addons": gettext("Addon 1\nAddon 2"),
},
_get_text_sample: function (key) {
if (key.startsWith('meta:')) {
return key.substr(5);
}
return editor.text_samples[key];
return $('#toolbox-content option[value='+key+']').attr('data-sample');
},
_load_pdf: function (dump) {
@@ -406,7 +382,7 @@ var editor = {
},
_add_text: function () {
var text = new fabric.Textarea(editor.text_samples['item'], {
var text = new fabric.Textarea(editor._get_text_sample('item'), {
left: 100,
top: 100,
width: editor._mm2px(50),

View File

@@ -279,27 +279,9 @@
<div class="col-sm-12">
<label>{% trans "Text content" %}</label><br>
<select class="input-block-level form-control" id="toolbox-content">
<option value="secret">{% trans "Ticket code (barcode content)" %}</option>
<option value="order">{% trans "Order code" %}</option>
<option value="item">{% trans "Product name" %}</option>
<option value="variation">{% trans "Variation name" %}</option>
<option value="item_description">{% trans "Product description" %}</option>
<option value="itemvar">{% trans "Product name and variation" %}</option>
<option value="price">{% trans "Price" %}</option>
<option value="attendee_name">{% trans "Attendee name" %}</option>
<option value="event_name">{% trans "Event name" %}</option>
<option value="event_date">{% trans "Event date" %}</option>
<option value="event_date_range">{% trans "Event date range" %}</option>
<option value="event_begin">{% trans "Event begin date and time" %}</option>
<option value="event_begin_time">{% trans "Event begin time" %}</option>
<option value="event_admission">{% trans "Event admission date and time" %}</option>
<option value="event_admission_time">{% trans "Event admission time" %}</option>
<option value="event_location">{% trans "Event location" %}</option>
<option value="invoice_name">{% trans "Invoice address: name" %}</option>
<option value="invoice_company">{% trans "Invoice address: company" %}</option>
<option value="addons">{% trans "List of Add-Ons" %}</option>
<option value="organizer">{% trans "Organizer name" %}</option>
<option value="organizer_info_text">{% trans "Organizer info text" %}</option>
{% for varname, var in variables.items %}
<option data-sample="{{ var.editor_sample }}" value="{{ varname }}">{{ var.label }}</option>
{% endfor %}
{% for p in request.organizer.meta_properties.all %}
<option value="meta:{{ p.name }}">
{% trans "Event attribute:" %} {{ p.name }}

View File

@@ -1,6 +1,7 @@
import copy
import logging
import uuid
from collections import OrderedDict
from io import BytesIO
from django.contrib.staticfiles import finders
@@ -26,11 +27,141 @@ from reportlab.platypus import Paragraph
from pretix.base.models import Order, OrderPosition
from pretix.base.ticketoutput import BaseTicketOutput
from pretix.plugins.ticketoutputpdf.signals import get_fonts
from pretix.plugins.ticketoutputpdf.signals import (
get_fonts, layout_text_variables,
)
logger = logging.getLogger('pretix.plugins.ticketoutputpdf')
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 sample variation"),
"evaluate": lambda orderposition, order, event: (
'{} - {}'.format(orderposition.item, orderposition.variation)
if orderposition.variation else str(orderposition.item)
)
}),
("itemvar", {
"label": _("Product name and variation"),
"editor_sample": _("Sample product description"),
"evaluate": lambda orderposition, order, event: str(orderposition.item.description)
}),
("price", {
"label": _("Price"),
"editor_sample": _("123.45 EUR"),
"evaluate": lambda op, order, event: '{} {}'.format(event.currency, localize(op.price))
}),
("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", "<br/>\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": _("Invocie 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: "<br/>".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
class PdfTicketOutput(BaseTicketOutput):
identifier = 'pdf'
verbose_name = _('PDF output')
@@ -39,6 +170,7 @@ class PdfTicketOutput(BaseTicketOutput):
def __init__(self, event, override_layout=None, override_background=None):
self.override_layout = override_layout
self.override_background = override_background
self.variables = get_variables(event)
super().__init__(event)
def _register_fonts(self):
@@ -71,61 +203,12 @@ class PdfTicketOutput(BaseTicketOutput):
return o['text'].replace("\n", "<br/>\n")
elif o['content'].startswith('meta:'):
return ev.meta_data.get(o['content'][5:]) or ''
elif o['content'] == 'order':
return order.code
elif o['content'] == 'item':
return str(op.item)
elif o['content'] == 'item_description':
return str(op.item.description)
elif o['content'] == 'organizer':
return str(order.event.organizer.name)
elif o['content'] == 'organizer_info_text':
return str(order.event.settings.organizer_info_text)
elif o['content'] == 'secret':
return op.secret
elif o['content'] == 'variation':
return str(op.variation) if op.variation else ''
elif o['content'] == 'itemvar':
return '{} - {}'.format(op.item, op.variation) if op.variation else str(op.item)
elif o['content'] == 'price':
return '{} {}'.format(order.event.currency, localize(op.price))
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(ev.name)
elif o['content'] == 'event_location':
return str(ev.location).replace("\n", "<br/>\n")
elif o['content'] == 'event_date':
return ev.get_date_from_display(show_times=False)
elif o['content'] == 'event_date_range':
return ev.get_date_range_display()
elif o['content'] == 'event_begin':
return ev.get_date_from_display(show_times=True)
elif o['content'] == 'event_begin_time':
return ev.get_time_from_display()
elif o['content'] == 'event_admission':
if ev.date_admission:
tz = timezone(order.event.settings.timezone)
return date_format(ev.date_admission.astimezone(tz), "SHORT_DATETIME_FORMAT")
elif o['content'] == 'event_admission_time':
if ev.date_admission:
tz = timezone(order.event.settings.timezone)
return date_format(ev.date_admission.astimezone(tz), "TIME_FORMAT")
elif o['content'] == 'invoice_name':
elif o['content'] in self.variables:
try:
return order.invoice_address.name
self.variables[o['content']]['evaluate'](op, order, ev)
except:
return ""
elif o['content'] == 'invoice_company':
try:
return order.invoice_address.company
except:
return ""
elif o['content'] == 'addons':
return "<br/>".join([
'{} - {}'.format(p.item, p.variation) if p.variation else str(p.item)
for p in op.addons.select_related('item', 'variation')
])
logger.exception('Failed to process variable.')
return '(error)'
return ''
def _draw_textarea(self, canvas: Canvas, op: OrderPosition, order: Order, o: dict):

View File

@@ -24,7 +24,7 @@ from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.helpers.database import rolledback_transaction
from pretix.plugins.ticketoutputpdf.signals import get_fonts
from .ticketoutput import PdfTicketOutput
from .ticketoutput import PdfTicketOutput, get_variables
logger = logging.getLogger(__name__)
@@ -156,6 +156,7 @@ class EditorView(EventPermissionRequiredMixin, TemplateView):
if self.request.event.settings.get('ticketoutput_{}_background'.format(self.identifier))
else static('pretixpresale/pdf/ticket_default_a4.pdf')
)
ctx['variables'] = get_variables(self.request.event)
ctx['layout'] = json.dumps(
self.request.event.settings.get('ticketoutput_{}_layout'.format(self.identifier), as_type=list)
or prov._default_layout()

View File

@@ -183,3 +183,10 @@ pre.mail-preview {
padding-top: 7px;
}
}
.inline-multiple-choice {
.checkbox {
display: inline-block;
margin-top: 0;
margin-right: 10px;
}
}