mirror of
https://github.com/pretix/pretix.git
synced 2026-05-05 15:14:04 +00:00
208 lines
9.9 KiB
Python
208 lines
9.9 KiB
Python
import copy
|
||
import logging
|
||
from collections import OrderedDict
|
||
from io import BytesIO
|
||
|
||
from django import forms
|
||
from django.contrib.staticfiles import finders
|
||
from django.core.files import File
|
||
from django.core.files.storage import default_storage
|
||
from django.utils.translation import ugettext_lazy as _
|
||
|
||
from pretix.base.models import Order
|
||
from pretix.base.ticketoutput import BaseTicketOutput
|
||
from pretix.control.forms import ExtFileField
|
||
|
||
logger = logging.getLogger('pretix.plugins.ticketoutputpdf')
|
||
|
||
|
||
class PdfTicketOutput(BaseTicketOutput):
|
||
identifier = 'pdf'
|
||
verbose_name = _('PDF output')
|
||
download_button_text = _('PDF')
|
||
|
||
def _draw_page(self, p, op, order):
|
||
from reportlab.graphics.shapes import Drawing
|
||
from reportlab.lib import units
|
||
from reportlab.graphics.barcode.qr import QrCodeWidget
|
||
from reportlab.graphics import renderPDF
|
||
|
||
event_s = self.settings.get('event_s', default=22, as_type=float)
|
||
if event_s:
|
||
p.setFont("Helvetica", event_s)
|
||
event_x = self.settings.get('event_x', default=15, as_type=float)
|
||
event_y = self.settings.get('event_y', default=235, as_type=float)
|
||
p.drawString(event_x * units.mm, event_y * units.mm, str(self.event.name))
|
||
|
||
order_s = self.settings.get('order_s', default=17, as_type=float)
|
||
if order_s:
|
||
p.setFont("Helvetica", order_s)
|
||
order_x = self.settings.get('order_x', default=15, as_type=float)
|
||
order_y = self.settings.get('order_y', default=220, as_type=float)
|
||
p.drawString(order_x * units.mm, order_y * units.mm, _('Order code: {code}').format(code=order.code))
|
||
|
||
name_s = self.settings.get('name_s', default=17, as_type=float)
|
||
if name_s:
|
||
p.setFont("Helvetica", name_s)
|
||
name_x = self.settings.get('name_x', default=15, as_type=float)
|
||
name_y = self.settings.get('name_y', default=210, as_type=float)
|
||
item = str(op.item.name)
|
||
if op.variation:
|
||
item += " – " + str(op.variation)
|
||
p.drawString(name_x * units.mm, name_y * units.mm, item)
|
||
|
||
price_s = self.settings.get('price_s', default=17, as_type=float)
|
||
if price_s:
|
||
p.setFont("Helvetica", price_s)
|
||
price_x = self.settings.get('price_x', default=15, as_type=float)
|
||
price_y = self.settings.get('price_y', default=200, as_type=float)
|
||
p.drawString(price_x * units.mm, price_y * units.mm, "%s %s" % (str(op.price), self.event.currency))
|
||
|
||
qr_s = self.settings.get('qr_s', default=80, as_type=float)
|
||
if qr_s:
|
||
reqs = qr_s * units.mm
|
||
qrw = QrCodeWidget(op.secret, barLevel='H')
|
||
b = qrw.getBounds()
|
||
w = b[2] - b[0]
|
||
h = b[3] - b[1]
|
||
d = Drawing(reqs, reqs, transform=[reqs / w, 0, 0, reqs / h, 0, 0])
|
||
d.add(qrw)
|
||
qr_x = self.settings.get('qr_x', default=10, as_type=float)
|
||
qr_y = self.settings.get('qr_y', default=120, as_type=float)
|
||
renderPDF.draw(d, p, qr_x * units.mm, qr_y * units.mm)
|
||
|
||
code_s = self.settings.get('code_s', default=11, as_type=float)
|
||
if code_s:
|
||
p.setFont("Helvetica", code_s)
|
||
code_x = self.settings.get('code_x', default=15, as_type=float)
|
||
code_y = self.settings.get('code_y', default=120, as_type=float)
|
||
p.drawString(code_x * units.mm, code_y * units.mm, op.secret)
|
||
|
||
attendee_s = self.settings.get('attendee_s', default=0, as_type=float)
|
||
if attendee_s and op.attendee_name:
|
||
p.setFont("Helvetica", attendee_s)
|
||
attendee_x = self.settings.get('attendee_x', default=15, as_type=float)
|
||
attendee_y = self.settings.get('attendee_y', default=90, as_type=float)
|
||
p.drawString(attendee_x * units.mm, attendee_y * units.mm, op.attendee_name)
|
||
|
||
p.showPage()
|
||
|
||
def generate_order(self, order: Order):
|
||
buffer = BytesIO()
|
||
p = self._create_canvas(buffer)
|
||
for op in order.positions.all():
|
||
if op.addon_to_id and not self.event.settings.ticket_download_addons:
|
||
continue
|
||
self._draw_page(p, op, order)
|
||
p.save()
|
||
outbuffer = self._render_with_background(buffer)
|
||
return 'order%s%s.pdf' % (self.event.slug, order.code), 'application/pdf', outbuffer.read()
|
||
|
||
def generate(self, op):
|
||
buffer = BytesIO()
|
||
p = self._create_canvas(buffer)
|
||
order = op.order
|
||
self._draw_page(p, op, order)
|
||
p.save()
|
||
outbuffer = self._render_with_background(buffer)
|
||
return 'order%s%s.pdf' % (self.event.slug, order.code), 'application/pdf', outbuffer.read()
|
||
|
||
def _create_canvas(self, buffer):
|
||
from reportlab.pdfgen import canvas
|
||
from reportlab.lib import pagesizes
|
||
|
||
pagesize = self.settings.get('pagesize', default='A4')
|
||
if hasattr(pagesizes, pagesize):
|
||
pagesize = getattr(pagesizes, pagesize)
|
||
else:
|
||
pagesize = pagesizes.A4
|
||
orientation = self.settings.get('orientation', default='portrait')
|
||
if hasattr(pagesizes, orientation):
|
||
pagesize = getattr(pagesizes, orientation)(pagesize)
|
||
|
||
return canvas.Canvas(buffer, pagesize=pagesize)
|
||
|
||
def _render_with_background(self, buffer):
|
||
from PyPDF2 import PdfFileWriter, PdfFileReader
|
||
buffer.seek(0)
|
||
new_pdf = PdfFileReader(buffer)
|
||
output = PdfFileWriter()
|
||
bg_file = self.settings.get('background', as_type=File)
|
||
if isinstance(bg_file, File):
|
||
bgf = default_storage.open(bg_file.name, "rb")
|
||
else:
|
||
bgf = open(finders.find('pretixpresale/pdf/ticket_default_a4.pdf'), "rb")
|
||
bg_pdf = PdfFileReader(bgf)
|
||
for page in new_pdf.pages:
|
||
bg_page = copy.copy(bg_pdf.getPage(0))
|
||
bg_page.mergePage(page)
|
||
output.addPage(bg_page)
|
||
|
||
outbuffer = BytesIO()
|
||
output.write(outbuffer)
|
||
outbuffer.seek(0)
|
||
return outbuffer
|
||
|
||
@property
|
||
def settings_form_fields(self) -> dict:
|
||
return OrderedDict(
|
||
list(super().settings_form_fields.items()) + [
|
||
('paper_size',
|
||
forms.ChoiceField(
|
||
label=_('Paper size'),
|
||
choices=(
|
||
('A4', 'A4'),
|
||
('A5', 'A5'),
|
||
('B4', 'B4'),
|
||
('B5', 'B5'),
|
||
('letter', 'Letter'),
|
||
('legal', 'Legal'),
|
||
),
|
||
required=False
|
||
)),
|
||
('orientation',
|
||
forms.ChoiceField(
|
||
label=_('Paper orientation'),
|
||
choices=(
|
||
('portrait', _('Portrait')),
|
||
('landscape', _('Landscape')),
|
||
),
|
||
required=False
|
||
)),
|
||
('background',
|
||
ExtFileField(
|
||
label=_('Background PDF'),
|
||
ext_whitelist=(".pdf", ),
|
||
required=False
|
||
)),
|
||
('qr_x', forms.FloatField(label=_('QR-Code x position (mm)'), required=False)),
|
||
('qr_y', forms.FloatField(label=_('QR-Code y position (mm)'), required=False)),
|
||
('qr_s', forms.FloatField(label=_('QR-Code size (mm)'), required=False)),
|
||
('code_x', forms.FloatField(label=_('Ticket code x position (mm)'), required=False)),
|
||
('code_y', forms.FloatField(label=_('Ticket code y position (mm)'), required=False)),
|
||
('code_s', forms.FloatField(label=_('Ticket code size (mm)'), required=False,
|
||
help_text=_('Visible by default, set this to 0 to hide the element.'))),
|
||
('order_x', forms.FloatField(label=_('Order x position (mm)'), required=False)),
|
||
('order_y', forms.FloatField(label=_('Order y position (mm)'), required=False)),
|
||
('order_s', forms.FloatField(label=_('Order size (mm)'), required=False,
|
||
help_text=_('Visible by default, set this to 0 to hide the element.'))),
|
||
('name_x', forms.FloatField(label=_('Product name x position (mm)'), required=False)),
|
||
('name_y', forms.FloatField(label=_('Product name y position (mm)'), required=False)),
|
||
('name_s', forms.FloatField(label=_('Product name size (mm)'), required=False,
|
||
help_text=_('Visible by default, set this to 0 to hide the element.'))),
|
||
('price_x', forms.FloatField(label=_('Price x position (mm)'), required=False)),
|
||
('price_y', forms.FloatField(label=_('Price y position (mm)'), required=False)),
|
||
('price_s', forms.FloatField(label=_('Price size (mm)'), required=False,
|
||
help_text=_('Visible by default, set this to 0 to hide the element.'))),
|
||
('event_x', forms.FloatField(label=_('Event name x position (mm)'), required=False)),
|
||
('event_y', forms.FloatField(label=_('Event name y position (mm)'), required=False)),
|
||
('event_s', forms.FloatField(label=_('Event name size (mm)'), required=False,
|
||
help_text=_('Visible by default, set this to 0 to hide the element.'))),
|
||
('attendee_x', forms.FloatField(label=_('Attendee name x position (mm)'), required=False)),
|
||
('attendee_y', forms.FloatField(label=_('Attendee name y position (mm)'), required=False)),
|
||
('attendee_s', forms.FloatField(label=_('Attendee name size (mm)'), required=False,
|
||
help_text=_('Invisible by default, set this to a number greater than 0 '
|
||
'to show.')))
|
||
]
|
||
)
|