Compare commits

..

1 Commits

Author SHA1 Message Date
Raphael Michel
db67959abf Add a custom manager 2017-05-19 10:31:02 +02:00
64 changed files with 796 additions and 917 deletions

View File

@@ -51,7 +51,7 @@ If there is a problem, a status code in the ``5xx`` range will be returned.
Performance monitoring
----------------------
If you want to generate detailed performance statistics of your pretix installation, there is an
If you to generate detailled performance statistics of your pretix installation, there is an
endpoint at ``https://pretix.mydomain.com/metrics`` (no slash at the end) which returns a
number of values in the text format understood by monitoring tools like Prometheus_. This data
is only collected and exposed if you enable it in the :ref:`metrics-settings` section of your

View File

@@ -25,7 +25,7 @@ Frontend
--------
.. automodule:: pretix.presale.signals
:members: html_head, html_footer, footer_links, front_page_top, front_page_bottom, contact_form_fields, checkout_confirm_messages
:members: html_head, html_footer, footer_links, front_page_top, front_page_bottom, checkout_confirm_messages
.. automodule:: pretix.presale.signals

View File

@@ -40,7 +40,7 @@ automatically). If you are working on Ubuntu or Debian, we strongly recommend up
your pip and setuptools installation inside the virtual environment, otherwise some of
the dependencies might fail::
pip3 install -U pip setuptools
pip3 install -U pip setuptools==28.6.1
Working with the code
---------------------
@@ -81,7 +81,7 @@ and head to http://localhost:8000/
As we did not implement an overall front page yet, you need to go directly to
http://localhost:8000/control/ for the admin view or, if you imported the test
data as suggested above, to the event page at http://localhost:8000/bigevents/2018/
data as suggested above, to the event page at http://localhost:8000/bigevents/2017/
.. note:: If you want the development server to listen on a different interface or
port (for example because you develop on `pretixdroid`_), you can check

View File

@@ -15,8 +15,7 @@ ways that pretix itself is:
* PDF ticket output
The following plugins are not shipped with pretix but are maintained by the
same team. We update them regularly to make them compatible with the latest
pretix releases:
same team:
* `SEPA direct debit`_
* `Pages`_
@@ -24,17 +23,8 @@ pretix releases:
* `Cartshare`_
* `Fontpack Free fonts`_
The following closed-source plugins are available to customers of the hosted pretix.eu platform.
Please get in touch with the pretix team if you want to have them for your self-hosted
pretix installation:
* Campaign tracking
* Integration with Google Analytics and Facebook Pixel
* Integration with Slack
* Integration with MailChimp
The following plugins are from independent third-party authors, so we can make
no statements about their stability or compatibility:
no statements about their stability:
* `esPass ticket output`_
* `IcePay integration`_

View File

@@ -36,11 +36,11 @@ t = Team.objects.get_or_create(
can_change_organizer_settings=True, can_change_event_settings=True, can_change_items=True,
can_view_orders=True, can_change_orders=True, can_view_vouchers=True, can_change_vouchers=True
)
t[0].members.add(user)
cat_tickets = ItemCategory.objects.create(
t.members.add(user)
cat_tickets = ItemCategory.all.create(
event=event, name='Tickets'
)
cat_merch = ItemCategory.objects.create(
cat_merch = ItemCategory.all.create(
event=event, name='Merchandise'
)
question = Question.objects.create(

View File

@@ -1 +1 @@
__version__ = "1.4.0"
__version__ = "1.4.0-dev0"

View File

@@ -1,27 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2017-05-21 09:42
from __future__ import unicode_literals
from django.core.cache import cache
from django.db import migrations
def rename_placeholder(app, schema_editor):
EventSettingsStore = app.get_model('pretixbase', 'Event_SettingsStore')
for setting in EventSettingsStore.objects.all():
if setting.key == 'mail_text_order_placed':
new_value = setting.value.replace('{paymentinfo}', '{payment_info}')
setting.value = new_value
cache.delete('hierarkey_{}_{}'.format('event', setting.object_id))
setting.save()
class Migration(migrations.Migration):
dependencies = [
('pretixbase', '0060_auto_20170510_1027'),
]
operations = [
migrations.RunPython(rename_placeholder, migrations.RunPython.noop)
]

View File

@@ -2,6 +2,7 @@ import json
import uuid
from django.contrib.contenttypes.models import ContentType
from django.core import checks
from django.db import models
from django.db.models.signals import post_delete
from django.dispatch import receiver
@@ -34,7 +35,6 @@ def cached_file_delete(sender, instance, **kwargs):
class LoggingMixin:
def log_action(self, action, data=None, user=None):
"""
Create a LogEntry object that is related to this object.
@@ -59,7 +59,6 @@ class LoggingMixin:
class LoggedModel(models.Model, LoggingMixin):
class Meta:
abstract = True
@@ -74,3 +73,38 @@ class LoggedModel(models.Model, LoggingMixin):
return LogEntry.objects.filter(
content_type=ContentType.objects.get_for_model(type(self)), object_id=self.pk
).select_related('user', 'event')
class EventBoundModelMixin:
event_lookup = 'event'
@classmethod
def for_event(cls, event):
return cls.all.filter(**{
cls.event_lookup: event
})
@classmethod
def check(cls, **kwargs):
try:
errors = super(cls).check(**kwargs)
except AttributeError:
errors = []
if hasattr(cls, 'objects'):
errors.append(
checks.Error(
'Default model manager "objects" defined.',
hint='Replace the objects manager by a manager called "all".',
obj=cls,
id='pretixbase.E001',
)
)
if not hasattr(cls, 'all'):
errors.append(
checks.Error(
'Model manager "all" not defined.',
obj=cls,
id='pretixbase.E002',
)
)
return errors

View File

@@ -234,14 +234,14 @@ class Event(LoggedModel):
), tz)
def copy_data_from(self, other):
from . import ItemAddOn, ItemCategory, Item, Question, Quota
from . import ItemAddOn, Item, Question, Quota
from ..signals import event_copy_data
self.plugins = other.plugins
self.save()
category_map = {}
for c in ItemCategory.objects.filter(event=other):
for c in other.categories.all():
category_map[c.pk] = c
c.pk = None
c.event = self

View File

@@ -14,12 +14,12 @@ from django.utils.translation import ugettext_lazy as _
from i18nfield.fields import I18nCharField, I18nTextField
from pretix.base.decimal import round_decimal
from pretix.base.models.base import LoggedModel
from pretix.base.models.base import EventBoundModelMixin, LoggedModel
from .event import Event
class ItemCategory(LoggedModel):
class ItemCategory(EventBoundModelMixin, LoggedModel):
"""
Items can be sorted into these categories.
@@ -53,6 +53,8 @@ class ItemCategory(LoggedModel):
'source for add-ons.')
)
all = models.Manager()
class Meta:
verbose_name = _("Product category")
verbose_name_plural = _("Product categories")

View File

@@ -1,5 +1,4 @@
import copy
import json
import os
import string
from datetime import datetime
@@ -184,10 +183,6 @@ class Order(LoggedModel):
def __str__(self):
return self.full_code
@cached_property
def meta_info_data(self):
return json.loads(self.meta_info)
@property
def full_code(self):
"""

View File

@@ -414,7 +414,7 @@ def _perform_order(event: str, payment_provider: str, position_ids: List[str],
'order': order.code,
'secret': order.secret
}),
'payment_info': str(pprov.order_pending_mail_render(order)),
'paymentinfo': str(pprov.order_pending_mail_render(order)),
'invoice_name': invoice_name,
'invoice_company': invoice_company,
},
@@ -512,7 +512,7 @@ class OrderChangeManager:
if (not variation and item.has_variations) or (variation and variation.item_id != item.pk):
raise OrderError(self.error_messages['product_without_variation'])
price = item.default_price if variation is None else variation.price
if price is None:
if not price:
raise OrderError(self.error_messages['product_invalid'])
self._totaldiff = price - position.price
self._quotadiff.update(variation.quotas.all() if variation else item.quotas.all())

View File

@@ -240,7 +240,7 @@ Your {event} team"""))
we successfully received your order for {event} with a total value
of {total} {currency}. Please complete your payment before {date}.
{payment_info}
{paymentinfo}
You can change your order details and view the status of your order at
{url}

View File

@@ -33,7 +33,7 @@ def contextprocessor(request):
_js_payment_weekdays_disabled = '[]'
_nav_event = []
if getattr(request, 'event', None) and hasattr(request, 'organizer'):
if hasattr(request, 'event'):
for receiver, response in nav_event.send(request.event, request=request):
_nav_event += response
if request.event.settings.get('payment_term_weekdays'):

View File

@@ -259,12 +259,10 @@ class EventSettingsForm(SettingsForm):
)
attendee_emails_asked = forms.BooleanField(
label=_("Ask for email addresses per ticket"),
help_text=_("Normally, pretix asks for one email address per order and the order confirmation will be sent "
"only to that email address. If you enable this option, the system will additionally ask for "
help_text=_("Normally, pretix asks for one email address per order and the order confirmation will be send "
"to that email address. If you enable this option, the system will additionally ask for "
"individual email addresses for every admission ticket. This might be useful if you want to "
"obtain individual addresses for every attendee even in case of group orders. However, "
"pretix will send the order confirmation only to the one primary email address, not to the "
"per-attendee addresses."),
"obtain individual addresses for every attendee even in case of group orders."),
required=False
)
attendee_emails_required = forms.BooleanField(
@@ -492,9 +490,9 @@ class MailSettingsForm(SettingsForm):
label=_("Text"),
required=False,
widget=I18nTextarea,
help_text=_("Available placeholders: {event}, {total}, {currency}, {date}, {payment_info}, {url}, "
help_text=_("Available placeholders: {event}, {total}, {currency}, {date}, {paymentinfo}, {url}, "
"{invoice_name}, {invoice_company}"),
validators=[PlaceholderValidator(['{event}', '{total}', '{currency}', '{date}', '{payment_info}',
validators=[PlaceholderValidator(['{event}', '{total}', '{currency}', '{date}', '{paymentinfo}',
'{url}', '{invoice_name}', '{invoice_company}'])]
)
mail_text_order_paid = I18nFormField(

View File

@@ -1,6 +1,5 @@
{% extends "pretixcontrol/base.html" %}
{% load i18n %}
{% load staticfiles %}
{% block title %}{{ request.event.name }}{% endblock %}
{% block nav %}
@@ -113,9 +112,7 @@
<li>
<a href="{{ nav.url }}" {% if nav.active %}class="active"{% endif %}
{% if nav.children %}class="has-children"{% endif %}>
{% if nav.icon and "." in nav.icon %}
<img src="{% static nav.icon %}" class="fa-img">
{% elif nav.icon %}
{% if nav.icon %}
<i class="fa fa-{{ nav.icon }} fa-fw"></i>
{% endif %}
{{ nav.label }}

View File

@@ -1,4 +1,4 @@
from django.db.models import F, Prefetch, Q
from django.db.models import Prefetch, Q
from django.db.models.functions import Coalesce
from django.views.generic import ListView
@@ -68,15 +68,12 @@ class CheckInView(EventPermissionRequiredMixin, ListView):
'-code': '-order__code',
'email': 'order__email',
'-email': '-order__email',
# Set nulls_first to be consistent over databases
'status': F('checkins__id').asc(nulls_first=True),
'-status': F('checkins__id').desc(nulls_last=True),
'timestamp': F('checkins__datetime').asc(nulls_first=True),
'-timestamp': F('checkins__datetime').desc(nulls_last=True),
'status': 'checkins__id',
'-status': '-checkins__id',
'timestamp': 'checkins__datetime',
'-timestamp': '-checkins__datetime',
'item': 'item__name',
'-item': '-item__name',
'name': (F('display_name').asc(nulls_first=True),
{'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
'-name': (F('display_name').desc(nulls_last=True),
{'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
'name': ('display_name', {'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
'-name': ('-display_name', {'display_name': Coalesce('attendee_name', 'addon_to__attendee_name')}),
}

View File

@@ -316,7 +316,8 @@ class InvoicePreview(EventPermissionRequiredMixin, View):
def get(self, request, *args, **kwargs):
pdf = build_preview_invoice_pdf(request.event)
resp = HttpResponse(pdf, content_type='application/pdf')
resp['Content-Disposition'] = 'attachment; filename="invoice-preview.pdf"'
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="invoice-preview.pdf"'
return resp
@@ -436,7 +437,7 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
def items(self):
return {
'mail_text_order_placed': ['total', 'currency', 'date', 'invoice_company',
'event', 'payment_info', 'url', 'invoice_name'],
'event', 'paymentinfo', 'url', 'invoice_name'],
'mail_text_order_paid': ['event', 'url', 'invoice_name', 'invoice_company', 'payment_info'],
'mail_text_order_free': ['event', 'url', 'invoice_name', 'invoice_company'],
'mail_text_resend_link': ['event', 'url', 'invoice_name', 'invoice_company'],
@@ -467,7 +468,7 @@ class MailSettingsPreview(EventPermissionRequiredMixin, View):
'code': '68CYU2H6ZTP3WLK5',
'invoice_name': _('John Doe'),
'invoice_company': _('Sample Corporation'),
'payment_info': _('Please transfer money to this bank account: 9999-9999-9999-9999')
'paymentinfo': _('Please transfer money to this bank account: 9999-9999-9999-9999')
}
def generate_order_url(self, code, secret):
@@ -527,7 +528,11 @@ class TicketSettingsPreview(EventPermissionRequiredMixin, View):
fname, mimet, data = tickets.preview(self.request.event.pk, self.output.identifier)
resp = HttpResponse(data, content_type=mimet)
ftype = fname.split(".")[-1]
resp['Content-Disposition'] = 'attachment; filename="ticket-preview.{}"'.format(ftype)
if mimet == "application/pdf":
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="ticket-preview.{}"'.format(ftype)
else:
resp['Content-Disposition'] = 'attachment; filename="ticket-preview.{}"'.format(ftype)
return resp
def get_error_url(self) -> str:

View File

@@ -674,7 +674,7 @@ class ExportDoView(EventPermissionRequiredMixin, ExportMixin, AsyncAction, View)
if not self.exporter.form.is_valid():
messages.error(self.request, _('There was a problem processing your input. See below for error details.'))
return self.get(request, *args, **kwargs)
return self.get(*args, **kwargs)
cf = CachedFile()
cf.date = now()

View File

@@ -0,0 +1,6 @@
from debug_toolbar.middleware import DebugToolbarMiddleware
from django.utils.deprecation import MiddlewareMixin
class DebugMiddlewareCompatibilityShim(MiddlewareMixin, DebugToolbarMiddleware):
pass

File diff suppressed because it is too large Load Diff

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-01 10:54+0000\n"
"PO-Revision-Date: 2017-06-01 12:56+0200\n"
"POT-Creation-Date: 2017-05-18 09:17+0000\n"
"PO-Revision-Date: 2017-05-11 12:13+0200\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: \n"
"Language: de\n"
@@ -79,71 +79,59 @@ msgid "May 31st, 2017"
msgstr "31. Mai 2017"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:164
msgid "May 31st June 4th, 2017"
msgstr "31. Mai 4. Juni 2017"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:165
msgid "20:00"
msgstr "20:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:166
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:165
msgid "19:00"
msgstr "19:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:167
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:166
msgid "2017-05-31 20:00"
msgstr "31.05.2016 20:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:168
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:167
msgid "2017-05-31 19:00"
msgstr "31.05.2016 19:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:169
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:168
msgid "Random City"
msgstr "Musterstadt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:170
msgid ""
"Addon 1\n"
"Addon 2"
msgstr ""
"Workshop 1\n"
"Workshop 2"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:215
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:213
msgid "The PDF background file could not be loaded for the following reason:"
msgstr "Die Hintergrund-PDF-Datei konnte nicht geladen werden:"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:364
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:362
msgid "Group of objects"
msgstr "Gruppe von Objekten"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:370
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:368
msgid "Text object"
msgstr "Text-Objekt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:372
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:370
msgid "Barcode area"
msgstr "QR-Code-Bereich"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:374
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:372
msgid "Object"
msgstr "Objekt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:378
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:376
msgid "Ticket design"
msgstr "Ticket-Design"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:614
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:612
msgid "Saving failed."
msgstr "Speichern fehlgeschlagen."
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:646
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:644
msgid "Do you really want to leave the editor without saving your changes?"
msgstr ""
"Möchten Sie den Editor wirklich schließen ohne Ihre Änderungen zu speichern?"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:659
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:657
msgid "Error while uploading your PDF file, please try again."
msgstr ""
"Es gab ein Problem beim Hochladen der PDF-Datei, bitte erneut versuchen."

File diff suppressed because it is too large Load Diff

View File

@@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-06-01 10:54+0000\n"
"PO-Revision-Date: 2017-06-01 12:56+0200\n"
"POT-Creation-Date: 2017-05-18 09:17+0000\n"
"PO-Revision-Date: 2017-05-11 12:13+0200\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: \n"
"Language: de\n"
@@ -79,71 +79,59 @@ msgid "May 31st, 2017"
msgstr "31. Mai 2017"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:164
msgid "May 31st June 4th, 2017"
msgstr "31. Mai 4. Juni 2017"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:165
msgid "20:00"
msgstr "20:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:166
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:165
msgid "19:00"
msgstr "19:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:167
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:166
msgid "2017-05-31 20:00"
msgstr "31.05.2016 20:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:168
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:167
msgid "2017-05-31 19:00"
msgstr "31.05.2016 19:00"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:169
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:168
msgid "Random City"
msgstr "Musterstadt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:170
msgid ""
"Addon 1\n"
"Addon 2"
msgstr ""
"Workshop 1\n"
"Workshop 2"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:215
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:213
msgid "The PDF background file could not be loaded for the following reason:"
msgstr "Die Hintergrund-PDF-Datei konnte nicht geladen werden:"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:364
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:362
msgid "Group of objects"
msgstr "Gruppe von Objekten"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:370
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:368
msgid "Text object"
msgstr "Text-Objekt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:372
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:370
msgid "Barcode area"
msgstr "QR-Code-Bereich"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:374
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:372
msgid "Object"
msgstr "Objekt"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:378
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:376
msgid "Ticket design"
msgstr "Ticket-Design"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:614
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:612
msgid "Saving failed."
msgstr "Speichern fehlgeschlagen."
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:646
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:644
msgid "Do you really want to leave the editor without saving your changes?"
msgstr ""
"Möchtest du den Editor wirklich schließen ohne Ihre Änderungen zu speichern?"
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:659
#: pretix/plugins/ticketoutputpdf/static/pretixplugins/ticketoutputpdf/editor.js:657
msgid "Error while uploading your PDF file, please try again."
msgstr ""
"Es gab ein Problem beim Hochladen der PDF-Datei, bitte erneut versuchen."

View File

@@ -13,7 +13,6 @@ def parse(data, hint):
raise HintMismatchError('Invalid hint')
if len(data[0]) != hint['cols']:
raise HintMismatchError('Wrong column count')
good_hint = False
for row in data:
resrow = {}
if None in row or len(row) != hint['cols']:
@@ -32,10 +31,8 @@ def parse(data, hint):
or len(resrow['reference']) == 0 or resrow['date'] == '':
# This is probably a headline or something other special.
continue
if resrow['reference'] or resrow['payer']:
good_hint = True
result.append(resrow)
return result, good_hint
return result
def get_rows_from_file(file):

View File

@@ -20,7 +20,7 @@ def parse(file):
result.append({
'reference': "\n".join([
t.data.get(f) for f in ('transaction_details', 'customer_reference', 'bank_reference',
'extra_details', 'non_swift_text') if t.data.get(f, '')]),
'extra_details') if t.data.get(f, '')]),
'amount': str(round_decimal(t.data['amount'].amount)),
'date': t.data['date'].isoformat()
})

View File

@@ -84,7 +84,7 @@ def _get_unknown_transactions(event: Event, job: BankImportJob, data: list):
amount = Decimal("0.00")
trans = BankTransaction(event=event, import_job=job,
payer=row.get('payer', ''),
payer=row['payer'],
reference=row['reference'],
amount=amount,
date=row['date'])

View File

@@ -14,15 +14,9 @@
<dd>{{ payment_info.reference }}</dd>
</dl>
{% else %}
{% if order.status == "p" %}
<p>{% blocktrans trimmed %}
This order has been marked as paid via bank transfer manually.
{% endblocktrans %}</p>
{% else %}
<p>{% blocktrans trimmed %}
This order has been planned to be paid via bank transfer, but no payment has been received yet.
{% endblocktrans %}</p>
{% endif %}
<p>{% blocktrans trimmed %}
This order has been planned to be paid via bank transfer, but no payment has been received yet.
{% endblocktrans %}</p>
<dl class="dl-horizontal">
<dt>{% trans "Reference code" %}</dt>
<dd>{{ order.full_code }}</dd>

View File

@@ -275,14 +275,12 @@ class ImportView(EventPermissionRequiredMixin, ListView):
if self.request.event.settings.get('banktransfer_csvhint') is not None:
hint = self.request.event.settings.get('banktransfer_csvhint', as_type=dict)
try:
parsed, good = csvimport.parse(data, hint)
parsed = csvimport.parse(data, hint)
except csvimport.HintMismatchError: # TODO: narrow down
logger.exception('Import using stored hint failed')
else:
if good:
return self.start_processing(parsed)
return self.start_processing(parsed)
return self.assign_view(data)
@@ -310,7 +308,7 @@ class ImportView(EventPermissionRequiredMixin, ListView):
logger.error('Import using stored hint failed: ' + str(e))
pass
else:
parsed, __ = csvimport.parse(data, hint)
parsed = csvimport.parse(data, hint)
return self.start_processing(parsed)
def process_csv(self):

View File

@@ -110,7 +110,7 @@ class CSVCheckinList(BaseCheckinList):
if form_data['secrets']:
row.append(op.secret)
if self.event.settings.attendee_emails_asked:
row.append(op.attendee_email or (op.addon_to.attendee_email if op.addon_to else ''))
row.append(op.attendee_email or (op.addon_to.attendee_name if op.addon_to else ''))
acache = {}
for a in op.answers.all():
acache[a.question_id] = str(a)

View File

@@ -161,13 +161,11 @@ var editor = {
"attendee_name": gettext("John Doe"),
"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"),
"addons": gettext("Addon 1\nAddon 2"),
"event_location": gettext("Random City")
},
_load_pdf: function (dump) {

View File

@@ -267,13 +267,11 @@
<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="addons">{% trans "List of Add-Ons" %}</option>
<option value="other">{% trans "Other…" %}</option>
</select>
<textarea type="text" value="" class="input-block-level form-control"

View File

@@ -85,8 +85,6 @@ class PdfTicketOutput(BaseTicketOutput):
return str(order.event.location).replace("\n", "<br/>\n")
elif o['content'] == 'event_date':
return order.event.get_date_from_display(show_times=False)
elif o['content'] == 'event_date_range':
return order.event.get_date_range_display()
elif o['content'] == 'event_begin':
return order.event.get_date_from_display(show_times=True)
elif o['content'] == 'event_begin_time':
@@ -99,11 +97,6 @@ class PdfTicketOutput(BaseTicketOutput):
if order.event.date_admission:
tz = timezone(order.event.settings.timezone)
return date_format(order.event.date_admission.astimezone(tz), "TIME_FORMAT")
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')
])
return ''
def _draw_textarea(self, canvas: Canvas, op: OrderPosition, order: Order, o: dict):
@@ -233,9 +226,9 @@ class PdfTicketOutput(BaseTicketOutput):
"fontfamily": "Open Sans", "bold": False, "italic": False, "width": "110.00", "content": "attendee_name",
"text": "John Doe", "align": "left"},
{"type": "textarea", "left": "17.50", "bottom": "242.10", "fontsize": "13.0", "color": [0, 0, 0, 1],
"fontfamily": "Open Sans", "bold": False, "italic": False, "width": "110.00",
"content": "event_date_range", "text": "May 31st, 2017", "align": "left"},
{"type": "textarea", "left": "17.50", "bottom": "204.80", "fontsize": "13.0", "color": [0, 0, 0, 1],
"fontfamily": "Open Sans", "bold": False, "italic": False, "width": "110.00", "content": "event_date",
"text": "May 31st, 2017", "align": "left"},
{"type": "textarea", "left": "17.50", "bottom": "234.30", "fontsize": "13.0", "color": [0, 0, 0, 1],
"fontfamily": "Open Sans", "bold": False, "italic": False, "width": "110.00", "content": "event_location",
"text": "Random City", "align": "left"},
{"type": "textarea", "left": "17.50", "bottom": "194.50", "fontsize": "13.0", "color": [0, 0, 0, 1],

View File

@@ -86,7 +86,6 @@ class EditorView(EventPermissionRequiredMixin, ChartContainingView, TemplateView
if "preview" in request.POST:
with rolledback_transaction(), language(request.event.settings.locale):
item = request.event.items.create(name=_("Sample product"), default_price=42.23)
item2 = request.event.items.create(name=_("Sample workshop"), default_price=23.40)
from pretix.base.models import Order
order = request.event.orders.create(status=Order.STATUS_PENDING, datetime=now(),
@@ -94,8 +93,6 @@ class EditorView(EventPermissionRequiredMixin, ChartContainingView, TemplateView
expires=now(), code="PREVIEW1234", total=119)
p = order.positions.create(item=item, attendee_name=_("John Doe"), price=item.default_price)
order.positions.create(item=item2, attendee_name=_("John Doe"), price=item.default_price, addon_to=p)
order.positions.create(item=item2, attendee_name=_("John Doe"), price=item.default_price, addon_to=p)
prov = PdfTicketOutput(request.event,
override_layout=(json.loads(request.POST.get("data"))
@@ -105,7 +102,8 @@ class EditorView(EventPermissionRequiredMixin, ChartContainingView, TemplateView
resp = HttpResponse(data, content_type=mimet)
ftype = fname.split(".")[-1]
resp['Content-Disposition'] = 'attachment; filename="ticket-preview.{}"'.format(ftype)
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="ticket-preview.{}"'.format(ftype)
return resp
elif "data" in request.POST:
if cf:

View File

@@ -19,8 +19,7 @@ from pretix.presale.forms.checkout import (
AddOnsForm, ContactForm, InvoiceAddressForm,
)
from pretix.presale.signals import (
checkout_confirm_messages, checkout_flow_steps, contact_form_fields,
order_meta_from_request,
checkout_confirm_messages, checkout_flow_steps, order_meta_from_request,
)
from pretix.presale.views import CartMixin, get_cart, get_cart_total
from pretix.presale.views.async import AsyncAction
@@ -256,13 +255,10 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
@cached_property
def contact_form(self):
initial = {
'email': self.request.session.get('email', '')
}
initial.update(self.request.session.get('contact_form_data', {}))
return ContactForm(data=self.request.POST if self.request.method == "POST" else None,
event=self.request.event,
initial=initial)
initial={
'email': self.request.session.get('email', '')
})
@cached_property
def invoice_address(self):
@@ -294,7 +290,6 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
if request.event.settings.invoice_address_asked:
addr = self.invoice_form.save()
request.session['invoice_address'] = addr.pk
request.session['contact_form_data'] = self.contact_form.cleaned_data
return redirect(self.get_next_url(request))
@@ -440,18 +435,6 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
ctx['payment_provider'] = self.payment_provider
ctx['addr'] = self.invoice_address
ctx['confirm_messages'] = self.confirm_messages
ctx['contact_info'] = []
responses = contact_form_fields.send(self.event)
for r, response in sorted(responses, key=lambda r: str(r[0])):
for key, value in response.items():
v = self.request.session.get('contact_form_data', {}).get(key)
if v is True:
v = _('Yes')
elif v is False:
v = _('No')
ctx['contact_info'].append((value.label, v))
return ctx
@cached_property
@@ -502,12 +485,9 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
})
return redirect(self.get_error_url())
meta_info = {
'contact_form_data': self.request.session.get('contact_form_data', {})
}
meta_info = {}
for receiver, response in order_meta_from_request.send(sender=request.event, request=request):
meta_info.update(response)
return self.do(self.request.event.id, self.payment_provider.identifier,
[p.id for p in self.positions], request.session.get('email'),
translation.get_language(), self.invoice_address.pk, meta_info)

View File

@@ -1,18 +1,19 @@
from decimal import Decimal
from itertools import chain
from django import forms
from django.core.exceptions import ValidationError
from django.db.models import Count, Prefetch, Q
from django.forms.widgets import RadioChoiceInput, RadioFieldRenderer
from django.utils.encoding import force_text
from django.utils.formats import number_format
from django.utils.html import format_html
from django.utils.safestring import mark_safe
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from pretix.base.models import ItemVariation, Question
from pretix.base.models.orders import InvoiceAddress
from pretix.base.templatetags.rich_text import rich_text
from pretix.presale.signals import contact_form_fields
class ContactForm(forms.Form):
@@ -22,16 +23,6 @@ class ContactForm(forms.Form):
'modifications to your order or download your ticket later.'),
widget=forms.EmailInput(attrs={'data-typocheck-target': '1'}))
def __init__(self, *args, **kwargs):
self.event = kwargs.pop('event')
super().__init__(*args, **kwargs)
responses = contact_form_fields.send(self.event)
for r, response in sorted(responses, key=lambda r: str(r[0])):
for key, value in response.items():
# We need to be this explicit, since OrderedDict.update does not retain ordering
self.fields[key] = value
class InvoiceAddressForm(forms.ModelForm):
@@ -164,35 +155,51 @@ class QuestionsForm(forms.Form):
self.fields['question_%s' % q.id] = field
class AddOnRadioSelect(forms.RadioSelect):
option_template_name = 'pretixpresale/forms/addon_choice_option.html'
# The following will get totally different once Django 1.11 is integrated
class AddOnVariationSelectInput(RadioChoiceInput):
def optgroups(self, name, value, attrs=None):
attrs = attrs or {}
groups = []
has_selected = False
for index, (option_value, option_label, option_desc) in enumerate(chain(self.choices)):
if option_value is None:
option_value = ''
if isinstance(option_label, (list, tuple)):
raise TypeError('Choice groups are not supported here')
group_name = None
subgroup = []
groups.append((group_name, subgroup, index))
def __init__(self, name, value, attrs, choice, index):
super().__init__(name, value, attrs, choice, index)
self.description = force_text(choice[2])
selected = (
force_text(option_value) in value and
(has_selected is False or self.allow_multiple_selected)
def render(self, name=None, value=None, attrs=None):
if self.id_for_label:
label_for = format_html(' for="{}"', self.id_for_label)
else:
label_for = ''
attrs = dict(self.attrs, **attrs) if attrs else self.attrs
if self.description:
return format_html(
'<label{}>{} {}</label> <span class="fa fa-info-circle toggle-variation-description"></span>'
'<div class="variation-description addon-variation-description">{}</div>',
label_for, self.tag(attrs), self.choice_label,
rich_text(str(self.description))
)
else:
return format_html(
'<label{}>{} {}</label>',
label_for, self.tag(attrs), self.choice_label,
)
if selected is True and has_selected is False:
has_selected = True
attrs['description'] = option_desc
subgroup.append(self.create_option(
name, option_value, option_label, selected, index,
subindex=None, attrs=attrs,
))
return groups
class AddOnVariationSelectRenderer(RadioFieldRenderer):
choice_input_class = AddOnVariationSelectInput
def render(self):
id_ = self.attrs.get('id')
output = []
for i, choice in enumerate(self.choices):
w = self.choice_input_class(self.name, self.value, self.attrs.copy(), choice, i)
output.append(format_html(self.inner_html, choice_value=force_text(w), sub_widgets=''))
return format_html(
self.outer_html,
id_attr=format_html(' id="{}"', id_) if id_ else '',
content=mark_safe('\n'.join(output)),
)
class AddOnVariationSelect(forms.RadioSelect):
renderer = AddOnVariationSelectRenderer
class AddOnVariationField(forms.ChoiceField):
@@ -300,7 +307,7 @@ class AddOnsForm(forms.Form):
choices=choices,
label=i.name,
required=False,
widget=AddOnRadioSelect,
widget=AddOnVariationSelect,
help_text=rich_text(str(i.description)),
initial=current_addons.get(i.pk),
)

View File

@@ -69,18 +69,6 @@ You will recieve the request triggering the order creation as the ``request`` ke
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
"""
contact_form_fields = EventPluginSignal(
providing_args=[]
)
"""
This signals allows you to add form fields to the contact form that is presented during checkout
and by default only asks for the email address. You are supposed to return a dictionary of
form fields with globally unique keys. The validated form results will be saved into the
``contact_form_data`` entry of the order metadata dictionary.
As with all plugin signals, the ``sender`` keyword argument will contain the event.
"""
order_info = EventPluginSignal(
providing_args=["order"]
)

View File

@@ -8,7 +8,7 @@
<head>
<title>{% block thetitle %}{% endblock %}</title>
{% compress css %}
<link rel="stylesheet" type="text/x-scss" href="{% static "lightbox/css/lightbox.scss" %}" />
<link rel="stylesheet" type="text/css" href="{% static "lightbox/css/lightbox.css" %}" />
{% endcompress %}
{% if css_file %}
<link rel="stylesheet" type="text/css" href="{{ css_file }}"/>

View File

@@ -111,12 +111,6 @@
<dt>{% trans "E-mail address" %}</dt>
<dd>{{ request.session.email }}</dd>
</dl>
{% for l, v in contact_info %}
<dl class="dl-horizontal">
<dt>{{ l }}</dt>
<dd>{{ v }}</dd>
</dl>
{% endfor %}
</div>
</div>
</div>

View File

@@ -1,3 +0,0 @@
{% load rich_text %}
<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{% include "django/forms/widgets/input.html" %} {{ widget.label }}</label> {% if widget.attrs.description %}<span class="fa fa-info-circle toggle-variation-description"></span>
<div class="variation-description addon-variation-description">{{ widget.attrs.description|rich_text }}</div>{% endif %}

View File

@@ -581,9 +581,15 @@ class OrderDownload(EventViewMixin, OrderDetailMixin, View):
return render(self.request, "pretixbase/cachedfiles/pending.html", {})
else:
resp = FileResponse(ct.file.file, content_type=ct.type)
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.output.identifier, ct.extension
)
if ct.type == "application/pdf":
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.output.identifier, ct.extension
)
else:
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.output.identifier, ct.extension
)
return resp
def _download_position(self):
@@ -614,10 +620,17 @@ class OrderDownload(EventViewMixin, OrderDetailMixin, View):
return render(self.request, "pretixbase/cachedfiles/pending.html", {})
else:
resp = FileResponse(ct.file.file, content_type=ct.type)
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.order_position.positionid,
self.output.identifier, ct.extension
)
if ct.type == "application/pdf":
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="{}-{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.order_position.positionid,
self.output.identifier, ct.extension
)
else:
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}-{}{}"'.format(
self.request.event.slug.upper(), self.order.code, self.order_position.positionid,
self.output.identifier, ct.extension
)
return resp
@@ -647,5 +660,6 @@ class InvoiceDownload(EventViewMixin, OrderDetailMixin, View):
return redirect(self.get_order_url())
resp = FileResponse(invoice.file.file, content_type='application/pdf')
resp['Content-Disposition'] = 'attachment; filename="{}.pdf"'.format(invoice.number)
resp['Content-Security-Policy'] = "style-src 'unsafe-inline'; script-src 'unsafe-inline'; object-src 'self'"
resp['Content-Disposition'] = 'inline; filename="{}.pdf"'.format(invoice.number)
return resp

View File

@@ -83,7 +83,7 @@ PRETIX_PASSWORD_RESET = config.getboolean('pretix', 'password_reset', fallback=T
SITE_URL = config.get('pretix', 'url', fallback='http://localhost')
PRETIX_PLUGINS_DEFAULT = config.get('pretix', 'plugins_default',
fallback='pretix.plugins.sendmail,pretix.plugins.statistics,pretix.plugins.checkinlists')
fallback='pretix.plugins.sendmail,pretix.plugins.statistics')
DEFAULT_CURRENCY = config.get('pretix', 'currency', fallback='EUR')
CURRENCIES = list(currencies)
@@ -258,7 +258,7 @@ try:
import debug_toolbar # noqa
if DEBUG:
INSTALLED_APPS.append('debug_toolbar.apps.DebugToolbarConfig')
MIDDLEWARE.insert(0, 'debug_toolbar.middleware.DebugToolbarMiddleware')
MIDDLEWARE.insert(0, 'pretix.helpers.debug.DebugMiddlewareCompatibilityShim')
except ImportError:
pass
@@ -376,9 +376,7 @@ COMPRESS_PRECOMPILERS = (
COMPRESS_ENABLED = COMPRESS_OFFLINE = not debug_fallback
COMPRESS_CSS_FILTERS = (
# CssAbsoluteFilter is incredibly slow, especially when dealing with our _flags.scss
# However, we don't need it if we consequently use the static() function in Sass
# 'compressor.filters.css_default.CssAbsoluteFilter',
'compressor.filters.css_default.CssAbsoluteFilter',
'compressor.filters.cssmin.CSSCompressorFilter',
)

View File

@@ -1,6 +1,6 @@
/* Preload images */
body:after {
content: url(static('lightbox/images/close.png')) url(static('lightbox/images/loading.gif')) url(static('lightbox/images/prev.png')) url(static('lightbox/images/next.png'));
content: url(../images/close.png) url(../images/loading.gif) url(../images/prev.png) url(../images/next.png);
display: none;
}
@@ -79,7 +79,7 @@ body:after {
width: 32px;
height: 32px;
margin: 0 auto;
background: url(static('lightbox/images/loading.gif')) no-repeat;
background: url(../images/loading.gif) no-repeat;
}
.lb-nav {
@@ -110,7 +110,7 @@ body:after {
width: 34%;
left: 0;
float: left;
background: url(static('lightbox/images/prev.png')) left 48% no-repeat;
background: url(../images/prev.png) left 48% no-repeat;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
opacity: 0;
-webkit-transition: opacity 0.6s;
@@ -128,7 +128,7 @@ body:after {
width: 64%;
right: 0;
float: right;
background: url(static('lightbox/images/next.png')) right 48% no-repeat;
background: url(../images/next.png) right 48% no-repeat;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
opacity: 0;
-webkit-transition: opacity 0.6s;
@@ -192,7 +192,7 @@ body:after {
float: right;
width: 30px;
height: 30px;
background: url(static('lightbox/images/close.png')) top right no-repeat;
background: url(../images/close.png) top right no-repeat;
text-align: right;
outline: none;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=70);

View File

@@ -29,11 +29,6 @@ nav.navbar {
display: inline;
}
#side-menu img.fa-img {
height: auto;
width: 1.28571em;
}
nav.navbar .danger, nav.navbar .danger:hover, nav.navbar .danger:active {
background: $brand-danger !important;
}

View File

@@ -12,7 +12,7 @@ function typocheck() {
$sources.each(function () {
$.each($(this).val().toLowerCase().replace('-', '').split(' '), function (i, w) {
if (w && w.length > 5) {
if (w) {
words.push(w);
}
});

View File

@@ -1,4 +1,4 @@
django-debug-toolbar==1.8
django-debug-toolbar==1.5
sqlparse==0.2.1 # pinned due to difficulties with django-debug-toolbar
# Testing requirements
pep8==1.5.7 # exact requirement by flake8 2.4.0

View File

@@ -1,19 +1,19 @@
# Functional requirements
Django>=1.11.*
Django>=1.10.7,<1.11
python-dateutil
pytz
django-bootstrap3==8.2.*
django-bootstrap3==8.0.*
django-formset-js-improved==0.5.0.1
django-compressor==2.1.1
django-compressor==2.1
django-hierarkey==1.0.*
reportlab==3.2.*
PyPDF2==1.26.*
easy-thumbnails==2.4.*
easy-thumbnails==2.*
django-libsass
libsass
django-otp==0.3.*
python-u2flib-server==4.*
django-formtools==2.0
django-formtools==1.0
celery==4.0.2
kombu==4.0.2
django-statici18n==1.3.*
@@ -28,14 +28,14 @@ django-markup
markdown
bleach==2.*
raven
django-i18nfield>=1.0.1
django-i18nfield
# Stripe
stripe==1.22.*
# PayPal
paypalrestsdk==1.12.*
pycparser==2.13 # https://github.com/eliben/pycparser/issues/147
# Banktransfer
chardet<3.1.0,>=3.0.2
chardet>=2.3,<3
mt-940==3.2
vobject==0.9.*
pycountry

View File

@@ -1,2 +1,2 @@
django-redis==4.8.*
django-redis==4.1.*
redis==2.10.5

View File

@@ -62,21 +62,21 @@ setup(
keywords='tickets web shop ecommerce',
install_requires=[
'Django==1.11.*',
'Django==1.10.*',
'python-dateutil==2.4.*',
'pytz',
'django-bootstrap3==8.2.*',
'django-bootstrap3==7.1.*',
'django-formset-js-improved==0.5.0.1',
'django-compressor==2.1',
'django-hierarkey==1.0.*',
'reportlab==3.2.*',
'easy-thumbnails==2.4.*',
'easy-thumbnails==2.*',
'PyPDF2==1.26.*',
'django-libsass',
'libsass',
'django-otp==0.3.*',
'python-u2flib-server==4.*',
'django-formtools==2.0',
'django-formtools==1.0',
'celery==4.0.2',
'kombu==4.0.2',
'django-statici18n==1.3.*',
@@ -93,18 +93,18 @@ setup(
'raven',
'paypalrestsdk==1.12.*',
'pycparser==2.13',
'django-redis==4.7.*',
'django-redis==4.1.*',
'redis==2.10.5',
'stripe==1.22.*',
'chardet<3.1.0,>=3.0.2',
'mt-940==4.7',
'django-i18nfield>=1.0.1',
'chardet>=2.3,<3',
'mt-940==3.2',
'django-i18nfield',
'vobject==0.9.*',
'pycountry'
],
extras_require={
'dev': [
'django-debug-toolbar==1.7',
'django-debug-toolbar==1.5',
'sqlparse==0.2.1',
'pep8==1.5.7',
'pyflakes==1.1.0',

View File

@@ -92,6 +92,7 @@ class I18nFieldTest(TestCase):
"""
This test case tests the I18n*Field classes
"""
@classmethod
def setUpTestData(cls):
o = Organizer.objects.create(name='Dummy', slug='dummy')
@@ -101,8 +102,8 @@ class I18nFieldTest(TestCase):
)
def test_save_load_cycle_plain_string(self):
obj = ItemCategory.objects.create(event=self.event, name="Hello")
obj = ItemCategory.objects.get(id=obj.id)
obj = ItemCategory.all.create(event=self.event, name="Hello")
obj = ItemCategory.all.get(id=obj.id)
self.assertIsInstance(obj.name, LazyI18nString)
translation.activate('en')
self.assertEqual(str(obj.name), "Hello")
@@ -110,14 +111,14 @@ class I18nFieldTest(TestCase):
self.assertEqual(str(obj.name), "Hello")
def test_save_load_cycle_i18n_string(self):
obj = ItemCategory.objects.create(event=self.event,
name=LazyI18nString(
{
'de': 'Hallo',
'en': 'Hello'
}
))
obj = ItemCategory.objects.get(id=obj.id)
obj = ItemCategory.all.create(event=self.event,
name=LazyI18nString(
{
'de': 'Hallo',
'en': 'Hello'
}
))
obj = ItemCategory.all.get(id=obj.id)
self.assertIsInstance(obj.name, LazyI18nString)
translation.activate('en')
self.assertEqual(str(obj.name), "Hello")

View File

@@ -687,8 +687,8 @@ class ItemCategoryTest(TestCase):
)
def test_sorting(self):
c1 = ItemCategory.objects.create(event=self.event)
c2 = ItemCategory.objects.create(event=self.event)
c1 = ItemCategory.all.create(event=self.event)
c2 = ItemCategory.all.create(event=self.event)
assert c1 < c2
c1.position = 2
c2.position = 1

View File

@@ -210,12 +210,12 @@ def checkin_list_env():
('code', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
('-email', ['A3Ticket', 'A2Ticket', 'A1Ticket', 'A1Mascot']),
('email', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
('-status', ['A3Ticket', 'A1Ticket', 'A1Mascot', 'A2Ticket']),
('status', ['A1Mascot', 'A2Ticket', 'A1Ticket', 'A3Ticket']),
('-timestamp', ['A1Ticket', 'A3Ticket', 'A1Mascot', 'A2Ticket']), # A1 checkin date > A3 checkin date
('timestamp', ['A1Mascot', 'A2Ticket', 'A3Ticket', 'A1Ticket']),
('-name', ['A3Ticket', 'A2Ticket', 'A1Ticket', 'A1Mascot']),
('name', ['A1Mascot', 'A1Ticket', 'A2Ticket', 'A3Ticket']), # mascot doesn't include attendee name
# ('-status', ['A3Ticket', 'A1Ticket', 'A1Mascot', 'A2Ticket']),
# ('status', ['A1Mascot', 'A2Ticket', 'A1Ticket', 'A3Ticket']),
# ('-timestamp', ['A1Ticket', 'A3Ticket', 'A1Mascot', 'A2Ticket']), # A1 checkin date > A3 checkin date
# ('timestamp', ['A1Mascot', 'A2Ticket', 'A3Ticket', 'A1Ticket']),
# ('-name', ['A3Ticket', 'A2Ticket', 'A1Ticket', 'A1Mascot']),
# ('name', ['A1Mascot', 'A1Ticket', 'A2Ticket', 'A3Ticket']), # mascot doesn't include attendee name
('-item', ['A1Ticket', 'A2Ticket', 'A3Ticket', 'A1Mascot']),
('item', ['A1Mascot', 'A1Ticket', 'A2Ticket', 'A3Ticket']),
])
@@ -259,7 +259,8 @@ def test_checkins_item_filter(client, checkin_list_env):
@pytest.mark.parametrize("query, expected", [
('status=&item=&user=&ordering=', ['A1Ticket', 'A1Mascot', 'A2Ticket', 'A3Ticket']),
('status=1&item=&user=&ordering=timestamp', ['A3Ticket', 'A1Ticket']),
('status=0&item=&user=&ordering=-name', ['A2Ticket', 'A1Mascot']),
# ('status=0&item=&user=&ordering=-name', ['A2Ticket', 'A1Mascot']),
# ('status=&item=Ticket&user=&ordering=checkins__datetime', ['A2Ticket', 'A3Ticket', 'A1Ticket']),
])
def test_checkins_list_mixed(client, checkin_list_env, query, expected):
client.login(email='dummy@dummy.dummy', password='dummy')
@@ -288,8 +289,8 @@ def checkin_list_with_addon_env():
team.limit_events.add(event)
# item
cat_adm = ItemCategory.objects.create(event=event, name="Admission")
cat_workshop = ItemCategory.objects.create(event=event, name="Admission", is_addon=True)
cat_adm = ItemCategory.all.create(event=event, name="Admission")
cat_workshop = ItemCategory.all.create(event=event, name="Admission", is_addon=True)
item_ticket = Item.objects.create(event=event, name="Ticket", default_price=23, admission=True, category=cat_adm)
item_workshop = Item.objects.create(event=event, name="Workshop", default_price=10, admission=False,
category=cat_workshop)

View File

@@ -68,7 +68,7 @@ class EventsTest(SoupTest):
assert len(doc.select(".alert-success")) > 0
# date_to should not be changed even though the timezone is changed
assert doc.select("[name=date_to]")[0]['value'] == "2013-12-30 17:00:00"
assert 'selected' in doc.find('option', {"value": "Asia/Tokyo"}).attrs
assert doc.find('option', {"value": "Asia/Tokyo"})['selected'] == "selected"
assert doc.select("[name=settings-max_items_per_order]")[0]['value'] == "12"
self.event1.refresh_from_db()

View File

@@ -37,7 +37,7 @@ class CategoriesTest(ItemFormTest):
self.assertIn("Entry tickets", doc.select("#page-wrapper table")[0].text)
def test_update(self):
c = ItemCategory.objects.create(event=self.event1, name="Entry tickets")
c = ItemCategory.all.create(event=self.event1, name="Entry tickets")
doc = self.get_doc('/control/event/%s/%s/categories/%s/' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
form_data['name_0'] = 'T-Shirts'
@@ -46,11 +46,11 @@ class CategoriesTest(ItemFormTest):
assert doc.select(".alert-success")
self.assertIn("T-Shirts", doc.select("#page-wrapper table")[0].text)
self.assertNotIn("Entry tickets", doc.select("#page-wrapper table")[0].text)
assert str(ItemCategory.objects.get(id=c.id).name) == 'T-Shirts'
assert str(ItemCategory.all.get(id=c.id).name) == 'T-Shirts'
def test_sort(self):
c1 = ItemCategory.objects.create(event=self.event1, name="Entry tickets", position=0)
ItemCategory.objects.create(event=self.event1, name="T-Shirts", position=1)
c1 = ItemCategory.all.create(event=self.event1, name="Entry tickets", position=0)
ItemCategory.all.create(event=self.event1, name="T-Shirts", position=1)
doc = self.get_doc('/control/event/%s/%s/categories/' % (self.orga1.slug, self.event1.slug))
self.assertIn("Entry tickets", doc.select("table > tbody > tr")[0].text)
self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text)
@@ -66,14 +66,14 @@ class CategoriesTest(ItemFormTest):
self.assertIn("T-Shirts", doc.select("table > tbody > tr")[1].text)
def test_delete(self):
c = ItemCategory.objects.create(event=self.event1, name="Entry tickets")
c = ItemCategory.all.create(event=self.event1, name="Entry tickets")
doc = self.get_doc('/control/event/%s/%s/categories/%s/delete' % (self.orga1.slug, self.event1.slug, c.id))
form_data = extract_form_fields(doc.select('.container-fluid form')[0])
doc = self.post_doc('/control/event/%s/%s/categories/%s/delete' % (self.orga1.slug, self.event1.slug, c.id),
form_data)
assert doc.select(".alert-success")
self.assertNotIn("Entry tickets", doc.select("#page-wrapper")[0].text)
assert not ItemCategory.objects.filter(id=c.id).exists()
assert not ItemCategory.all.filter(id=c.id).exists()
class QuestionsTest(ItemFormTest):
@@ -264,7 +264,7 @@ class ItemsTest(ItemFormTest):
require_voucher=True, allow_cancel=False)
self.var1 = ItemVariation.objects.create(item=self.item2, value="Silver")
self.var2 = ItemVariation.objects.create(item=self.item2, value="Gold")
self.addoncat = ItemCategory.objects.create(event=self.event1, name="Item category")
self.addoncat = ItemCategory.all.create(event=self.event1, name="Item category")
def test_move(self):
self.client.post('/control/event/%s/%s/items/%s/down' % (self.orga1.slug, self.event1.slug, self.item1.id),)

View File

@@ -141,7 +141,7 @@ class MailSettingPreviewTest(SoupTest):
assert res['msgs']['en'] == self.locale_event.name['en']
def test_mail_text_order_placed(self):
text = '{event}{total}{currency}{date}{payment_info}{url}{invoice_name}{invoice_company}'
text = '{event}{total}{currency}{date}{paymentinfo}{url}{invoice_name}{invoice_company}'
response = self.client.post(self.target.format(
self.orga1.slug, self.event1.slug), {
'item': 'mail_text_order_placed',

View File

@@ -26,7 +26,7 @@ def item(event):
@pytest.fixture
def item_category(event):
return ItemCategory.objects.create(event=event)
return ItemCategory.all.create(event=event)
@pytest.fixture

View File

@@ -15,7 +15,7 @@ class CsvImportTest(TestCase):
with open(os.path.join(DATA_DIR, filename), 'rb') as f:
data = csvimport.get_rows_from_file(f)
self.assertEqual(data, expected)
parsed, good = csvimport.parse(data, hint)
parsed = csvimport.parse(data, hint)
self.assertEqual(parsed, expected_parsed)
def test_sample_file_bbbank(self):
@@ -125,7 +125,7 @@ class CsvImportTest(TestCase):
def test_sample_file_postbank(self):
expected = [
['Buchungstag', 'Wertstellung', 'Umsatzart', 'Buchungsdetails', 'Auftraggeber', 'Empfänger',
'Betrag ()', 'Saldo ()'],
'Betrag (\x80)', 'Saldo (\x80)'],
['07.08.2016', '01.08.2016', 'Gutschrift', 'Verwendungszweck 2015ABCDE', 'Karla Kundin',
'Fiktive Veranstaltungsgesellschaft mbH', '\xA4 42,00', '\xA4 1.337,42'],
['29.07.2016', '29.07.2016', 'Gutschrift', 'Referenz NOTPROVIDED', 'Lars Lieferant',

View File

@@ -18,7 +18,7 @@ def env(client):
plugins='pretix.plugins.paypal',
live=True
)
category = ItemCategory.objects.create(event=event, name="Everything", position=0)
category = ItemCategory.all.create(event=event, name="Everything", position=0)
quota_tickets = Quota.objects.create(event=event, name='Tickets', size=5)
ticket = Item.objects.create(event=event, name='Early-bird ticket',
category=category, default_price=23, admission=True)

View File

@@ -27,7 +27,7 @@ def env(client):
plugins='pretix.plugins.stripe',
live=True
)
category = ItemCategory.objects.create(event=event, name="Everything", position=0)
category = ItemCategory.all.create(event=event, name="Everything", position=0)
quota_tickets = Quota.objects.create(event=event, name='Tickets', size=5)
ticket = Item.objects.create(event=event, name='Early-bird ticket',
category=category, default_price=23, admission=True)

View File

@@ -30,7 +30,7 @@ def item(event):
@pytest.fixture
def item_category(event):
"""Returns an item category instance"""
return ItemCategory.objects.create(event=event)
return ItemCategory.all.create(event=event)
@pytest.fixture

View File

@@ -24,7 +24,7 @@ class CartTestMixin:
date_from=datetime.datetime(2013, 12, 26, tzinfo=datetime.timezone.utc),
live=True
)
self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0)
self.category = ItemCategory.all.create(event=self.event, name="Everything", position=0)
self.quota_shirts = Quota.objects.create(event=self.event, name='Shirts', size=2)
self.shirt = Item.objects.create(event=self.event, name='T-Shirt', category=self.category, default_price=12)
self.quota_shirts.items.add(self.shirt)
@@ -1013,7 +1013,7 @@ class CartTest(CartTestMixin, TestCase):
class CartAddonTest(CartTestMixin, TestCase):
def setUp(self):
super().setUp()
self.workshopcat = ItemCategory.objects.create(name="Workshops", is_addon=True, event=self.event)
self.workshopcat = ItemCategory.all.create(name="Workshops", is_addon=True, event=self.event)
self.workshopquota = Quota.objects.create(event=self.event, name='Workshop 1', size=5)
self.workshop1 = Item.objects.create(event=self.event, name='Workshop 1',
category=self.workshopcat, default_price=12)

View File

@@ -24,7 +24,7 @@ class CheckoutTestCase(TestCase):
plugins='pretix.plugins.stripe,pretix.plugins.banktransfer',
live=True
)
self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0)
self.category = ItemCategory.all.create(event=self.event, name="Everything", position=0)
self.quota_tickets = Quota.objects.create(event=self.event, name='Tickets', size=5)
self.ticket = Item.objects.create(event=self.event, name='Early-bird ticket',
category=self.category, default_price=23, admission=True)
@@ -36,7 +36,7 @@ class CheckoutTestCase(TestCase):
self.session_key = self.client.cookies.get(settings.SESSION_COOKIE_NAME).value
self._set_session('email', 'admin@localhost')
self.workshopcat = ItemCategory.objects.create(name="Workshops", is_addon=True, event=self.event)
self.workshopcat = ItemCategory.all.create(name="Workshops", is_addon=True, event=self.event)
self.workshopquota = Quota.objects.create(event=self.event, name='Workshop 1', size=5)
self.workshop1 = Item.objects.create(event=self.event, name='Workshop 1',
category=self.workshopcat, default_price=12)

View File

@@ -116,7 +116,7 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
self.assertNotIn("Early-bird", html)
def test_simple_with_category(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
q.items.add(item)
@@ -125,13 +125,13 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
self.assertIn("Early-bird", doc.select("section:nth-of-type(1) div:nth-of-type(1)")[0].text)
def test_simple_without_quota(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
resp = self.client.get('/%s/%s/' % (self.orga.slug, self.event.slug))
self.assertNotIn("Early-bird", resp.rendered_content)
def test_no_variations_in_quota(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
ItemVariation.objects.create(item=item, value='Blue')
@@ -140,7 +140,7 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
self.assertNotIn("Early-bird", resp.rendered_content)
def test_one_variation_in_quota(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
var1 = ItemVariation.objects.create(item=item, value='Red')
@@ -150,7 +150,7 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
self._assert_variation_found()
def test_one_variation_in_unlimited_quota(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=None)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=0)
var1 = ItemVariation.objects.create(item=item, value='Red')
@@ -166,7 +166,7 @@ class ItemDisplayTest(EventTestMixin, SoupTest):
self.assertNotIn("Black", doc.select("section:nth-of-type(1)")[0].text)
def test_variation_prices_in_quota(self):
c = ItemCategory.objects.create(event=self.event, name="Entry tickets", position=0)
c = ItemCategory.all.create(event=self.event, name="Entry tickets", position=0)
q = Quota.objects.create(event=self.event, name='Quota', size=2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', category=c, default_price=12)
var1 = ItemVariation.objects.create(item=item, value='Red', default_price=14, position=1)

View File

@@ -25,7 +25,7 @@ class OrdersTest(TestCase):
self.event.settings.set('payment_banktransfer__enabled', True)
self.event.settings.set('ticketoutput_testdummy__enabled', True)
self.category = ItemCategory.objects.create(event=self.event, name="Everything", position=0)
self.category = ItemCategory.all.create(event=self.event, name="Everything", position=0)
self.quota_shirts = Quota.objects.create(event=self.event, name='Shirts', size=2)
self.shirt = Item.objects.create(event=self.event, name='T-Shirt', category=self.category, default_price=12)
self.quota_shirts.items.add(self.shirt)