forked from CGM_Public/pretix_original
Refactor and add signal layout_text_variables
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
"""
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -183,3 +183,10 @@ pre.mail-preview {
|
||||
padding-top: 7px;
|
||||
}
|
||||
}
|
||||
.inline-multiple-choice {
|
||||
.checkbox {
|
||||
display: inline-block;
|
||||
margin-top: 0;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user