forked from CGM_Public/pretix_original
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ecf81bdfe | ||
|
|
e395834811 | ||
|
|
86a32d7856 | ||
|
|
47e8549f19 | ||
|
|
47b84c06b0 | ||
|
|
204bc84e85 | ||
|
|
0487d5803b | ||
|
|
a94c89ba4f | ||
|
|
2045009e2e | ||
|
|
9269a485a6 | ||
|
|
166f50fcb0 | ||
|
|
a3358bae6b | ||
|
|
a3164a94b7 | ||
|
|
f56df892e3 | ||
|
|
093a0db182 |
@@ -20,9 +20,8 @@ internal_name string An optional nam
|
|||||||
rate decimal (string) Tax rate in percent
|
rate decimal (string) Tax rate in percent
|
||||||
price_includes_tax boolean If ``true`` (default), tax is assumed to be included in
|
price_includes_tax boolean If ``true`` (default), tax is assumed to be included in
|
||||||
the specified product price
|
the specified product price
|
||||||
eu_reverse_charge boolean **DEPRECATED**. If ``true``, EU reverse charge rules
|
eu_reverse_charge boolean If ``true``, EU reverse charge rules are applied. Will
|
||||||
are applied. Will be ignored if custom rules are set.
|
be ignored if custom rules are set.
|
||||||
Use custom rules instead.
|
|
||||||
home_country string Merchant country (required for reverse charge), can be
|
home_country string Merchant country (required for reverse charge), can be
|
||||||
``null`` or empty string
|
``null`` or empty string
|
||||||
keep_gross_if_rate_changes boolean If ``true``, changes of the tax rate based on custom
|
keep_gross_if_rate_changes boolean If ``true``, changes of the tax rate based on custom
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ without any special behavior.
|
|||||||
Connecting SSO providers (pretix as the SSO client)
|
Connecting SSO providers (pretix as the SSO client)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
To connect an external application as a SSO provider, go to "Customer accounts" → "SSO providers" → "Create a new SSO provider"
|
To connect an external application as a SSO client, go to "Customer accounts" → "SSO providers" → "Create a new SSO provider"
|
||||||
in your organizer account.
|
in your organizer account.
|
||||||
|
|
||||||
.. thumbnail:: ../../screens/organizer/customer_ssoprovider_add.png
|
.. thumbnail:: ../../screens/organizer/customer_ssoprovider_add.png
|
||||||
|
|||||||
+3
-3
@@ -36,7 +36,7 @@ dependencies = [
|
|||||||
"css-inline==0.14.*",
|
"css-inline==0.14.*",
|
||||||
"defusedcsv>=1.1.0",
|
"defusedcsv>=1.1.0",
|
||||||
"Django[argon2]==4.2.*,>=4.2.15",
|
"Django[argon2]==4.2.*,>=4.2.15",
|
||||||
"django-bootstrap3==24.3",
|
"django-bootstrap3==24.2",
|
||||||
"django-compressor==4.5.1",
|
"django-compressor==4.5.1",
|
||||||
"django-countries==7.6.*",
|
"django-countries==7.6.*",
|
||||||
"django-filter==24.3",
|
"django-filter==24.3",
|
||||||
@@ -81,7 +81,7 @@ dependencies = [
|
|||||||
"pycountry",
|
"pycountry",
|
||||||
"pycparser==2.22",
|
"pycparser==2.22",
|
||||||
"pycryptodome==3.20.*",
|
"pycryptodome==3.20.*",
|
||||||
"pypdf==5.0.*",
|
"pypdf==4.3.*",
|
||||||
"python-bidi==0.6.*", # Support for Arabic in reportlab
|
"python-bidi==0.6.*", # Support for Arabic in reportlab
|
||||||
"python-dateutil==2.9.*",
|
"python-dateutil==2.9.*",
|
||||||
"pytz",
|
"pytz",
|
||||||
@@ -91,7 +91,7 @@ dependencies = [
|
|||||||
"redis==5.0.*",
|
"redis==5.0.*",
|
||||||
"reportlab==4.2.*",
|
"reportlab==4.2.*",
|
||||||
"requests==2.31.*",
|
"requests==2.31.*",
|
||||||
"sentry-sdk==2.14.*",
|
"sentry-sdk==2.13.*",
|
||||||
"sepaxml==2.6.*",
|
"sepaxml==2.6.*",
|
||||||
"slimit",
|
"slimit",
|
||||||
"stripe==7.9.*",
|
"stripe==7.9.*",
|
||||||
|
|||||||
@@ -19,4 +19,4 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||||
# <https://www.gnu.org/licenses/>.
|
# <https://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
__version__ = "2024.10.0.dev0"
|
__version__ = "2024.9.0.dev0"
|
||||||
|
|||||||
@@ -75,6 +75,14 @@ FORMAT_MODULE_PATH = [
|
|||||||
'pretix.helpers.formats',
|
'pretix.helpers.formats',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
CORE_MODULES = {
|
||||||
|
"pretix.base",
|
||||||
|
"pretix.presale",
|
||||||
|
"pretix.control",
|
||||||
|
"pretix.plugins.checkinlists",
|
||||||
|
"pretix.plugins.reports",
|
||||||
|
}
|
||||||
|
|
||||||
ALL_LANGUAGES = [
|
ALL_LANGUAGES = [
|
||||||
('en', _('English')),
|
('en', _('English')),
|
||||||
('de', _('German')),
|
('de', _('German')),
|
||||||
|
|||||||
+1
-63
@@ -32,16 +32,13 @@
|
|||||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations under the License.
|
# License for the specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
import string
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import authenticate
|
from django.contrib.auth import authenticate
|
||||||
from django.contrib.auth.hashers import check_password, make_password
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
from django.utils.translation import gettext_lazy as _, ngettext
|
|
||||||
|
|
||||||
|
|
||||||
def get_auth_backends():
|
def get_auth_backends():
|
||||||
@@ -163,62 +160,3 @@ class NativeAuthBackend(BaseAuthBackend):
|
|||||||
u = authenticate(request=request, email=form_data['email'].lower(), password=form_data['password'])
|
u = authenticate(request=request, email=form_data['email'].lower(), password=form_data['password'])
|
||||||
if u and u.auth_backend == self.identifier:
|
if u and u.auth_backend == self.identifier:
|
||||||
return u
|
return u
|
||||||
|
|
||||||
|
|
||||||
class NumericAndAlphabeticPasswordValidator:
|
|
||||||
|
|
||||||
def validate(self, password, user=None):
|
|
||||||
has_numeric = any(c in string.digits for c in password)
|
|
||||||
has_alpha = any(c in string.ascii_letters for c in password)
|
|
||||||
if not has_numeric or not has_alpha:
|
|
||||||
raise ValidationError(
|
|
||||||
_(
|
|
||||||
"Your password must contain both numeric and alphabetic characters.",
|
|
||||||
),
|
|
||||||
code="password_numeric_and_alphabetic",
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_help_text(self):
|
|
||||||
return _(
|
|
||||||
"Your password must contain both numeric and alphabetic characters.",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class HistoryPasswordValidator:
|
|
||||||
|
|
||||||
def __init__(self, history_length=4):
|
|
||||||
self.history_length = history_length
|
|
||||||
|
|
||||||
def validate(self, password, user=None):
|
|
||||||
from pretix.base.models import User
|
|
||||||
|
|
||||||
if not user or not user.pk or not isinstance(user, User):
|
|
||||||
return
|
|
||||||
|
|
||||||
for hp in user.historic_passwords.order_by("-created")[:self.history_length]:
|
|
||||||
if check_password(password, hp.password):
|
|
||||||
raise ValidationError(
|
|
||||||
ngettext(
|
|
||||||
"Your password may not be the same as your previous password.",
|
|
||||||
"Your password may not be the same as one of your %(history_length)s previous passwords.",
|
|
||||||
self.history_length,
|
|
||||||
),
|
|
||||||
code="password_history",
|
|
||||||
params={"history_length": self.history_length},
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_help_text(self):
|
|
||||||
return ngettext(
|
|
||||||
"Your password may not be the same as your previous password.",
|
|
||||||
"Your password may not be the same as one of your %(history_length)s previous passwords.",
|
|
||||||
self.history_length,
|
|
||||||
) % {"history_length": self.history_length}
|
|
||||||
|
|
||||||
def password_changed(self, password, user=None):
|
|
||||||
if not user:
|
|
||||||
pass
|
|
||||||
|
|
||||||
user.historic_passwords.create(password=make_password(password))
|
|
||||||
user.historic_passwords.filter(
|
|
||||||
pk__in=user.historic_passwords.order_by("-created")[self.history_length:].values_list("pk", flat=True),
|
|
||||||
).delete()
|
|
||||||
|
|||||||
@@ -46,8 +46,6 @@ This module contains utilities for implementing OpenID Connect for customer auth
|
|||||||
as well as an OpenID Provider (OP).
|
as well as an OpenID Provider (OP).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pretix_token_endpoint_auth_methods = ['client_secret_basic', 'client_secret_post']
|
|
||||||
|
|
||||||
|
|
||||||
def _urljoin(base, path):
|
def _urljoin(base, path):
|
||||||
if not base.endswith("/"):
|
if not base.endswith("/"):
|
||||||
@@ -129,16 +127,6 @@ def oidc_validate_and_complete_config(config):
|
|||||||
fields=", ".join(provider_config.get("claims_supported", []))
|
fields=", ".join(provider_config.get("claims_supported", []))
|
||||||
))
|
))
|
||||||
|
|
||||||
if "token_endpoint_auth_methods_supported" in provider_config:
|
|
||||||
token_endpoint_auth_methods_supported = provider_config.get("token_endpoint_auth_methods_supported",
|
|
||||||
["client_secret_basic"])
|
|
||||||
if not any(x in pretix_token_endpoint_auth_methods for x in token_endpoint_auth_methods_supported):
|
|
||||||
raise ValidationError(
|
|
||||||
_(f'No supported Token Endpoint Auth Methods supported: {token_endpoint_auth_methods_supported}').format(
|
|
||||||
token_endpoint_auth_methods_supported=", ".join(token_endpoint_auth_methods_supported)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
config['provider_config'] = provider_config
|
config['provider_config'] = provider_config
|
||||||
return config
|
return config
|
||||||
|
|
||||||
@@ -159,18 +147,6 @@ def oidc_authorize_url(provider, state, redirect_uri):
|
|||||||
|
|
||||||
def oidc_validate_authorization(provider, code, redirect_uri):
|
def oidc_validate_authorization(provider, code, redirect_uri):
|
||||||
endpoint = provider.configuration['provider_config']['token_endpoint']
|
endpoint = provider.configuration['provider_config']['token_endpoint']
|
||||||
|
|
||||||
# Wall of shame and RFC ignorant IDPs
|
|
||||||
if endpoint == 'https://www.linkedin.com/oauth/v2/accessToken':
|
|
||||||
token_endpoint_auth_method = 'client_secret_post'
|
|
||||||
else:
|
|
||||||
token_endpoint_auth_methods = provider.configuration['provider_config'].get(
|
|
||||||
'token_endpoint_auth_methods_supported', ['client_secret_basic']
|
|
||||||
)
|
|
||||||
token_endpoint_auth_method = [
|
|
||||||
x for x in pretix_token_endpoint_auth_methods if x in token_endpoint_auth_methods
|
|
||||||
][0]
|
|
||||||
|
|
||||||
params = {
|
params = {
|
||||||
# https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3
|
# https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3
|
||||||
# https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
|
# https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint
|
||||||
@@ -178,11 +154,6 @@ def oidc_validate_authorization(provider, code, redirect_uri):
|
|||||||
'code': code,
|
'code': code,
|
||||||
'redirect_uri': redirect_uri,
|
'redirect_uri': redirect_uri,
|
||||||
}
|
}
|
||||||
|
|
||||||
if token_endpoint_auth_method == 'client_secret_post':
|
|
||||||
params['client_id'] = provider.configuration['client_id']
|
|
||||||
params['client_secret'] = provider.configuration['client_secret']
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
resp = requests.post(
|
resp = requests.post(
|
||||||
endpoint,
|
endpoint,
|
||||||
@@ -190,10 +161,7 @@ def oidc_validate_authorization(provider, code, redirect_uri):
|
|||||||
headers={
|
headers={
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
},
|
},
|
||||||
auth=(
|
auth=(provider.configuration['client_id'], provider.configuration['client_secret']),
|
||||||
provider.configuration['client_id'],
|
|
||||||
provider.configuration['client_secret']
|
|
||||||
) if token_endpoint_auth_method == 'client_secret_basic' else None,
|
|
||||||
)
|
)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
|
|||||||
@@ -0,0 +1,164 @@
|
|||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.utils.html import escape
|
||||||
|
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||||
|
|
||||||
|
from pretix.base.signals import PluginRegistry
|
||||||
|
|
||||||
|
|
||||||
|
def make_link(a_map, wrapper, is_active=True, event=None, plugin_name=None):
|
||||||
|
if a_map:
|
||||||
|
if is_active:
|
||||||
|
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
|
||||||
|
elif event and plugin_name:
|
||||||
|
a_map['val'] = (
|
||||||
|
'<i>{val}</i> <a href="{plugin_href}">'
|
||||||
|
'<span data-toggle="tooltip" title="{errmes}" class="fa fa-warning fa-fw"></span></a>'
|
||||||
|
).format_map({
|
||||||
|
**a_map,
|
||||||
|
"errmes": _("The relevant plugin is currently not active. To activate it, click here to go to the plugin settings."),
|
||||||
|
"plugin_href": reverse('control:event.settings.plugins', kwargs={
|
||||||
|
'organizer': event.organizer.slug,
|
||||||
|
'event': event.slug,
|
||||||
|
}) + '#plugin_' + plugin_name,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
a_map['val'] = '<i>{val}</i> <span data-toggle="tooltip" title="{errmes}" class="fa fa-warning fa-fw"></span>'.format_map({
|
||||||
|
**a_map,
|
||||||
|
"errmes": _("The relevant plugin is currently not active."),
|
||||||
|
})
|
||||||
|
return wrapper.format_map(a_map)
|
||||||
|
|
||||||
|
|
||||||
|
class LogEntryTypeRegistry(PluginRegistry):
|
||||||
|
def new_from_dict(self, data):
|
||||||
|
def reg(clz):
|
||||||
|
for action_type, plain in data.items():
|
||||||
|
self.register(clz(action_type=action_type, plain=plain))
|
||||||
|
return reg
|
||||||
|
|
||||||
|
|
||||||
|
log_entry_types = LogEntryTypeRegistry({'action_type': lambda o: getattr(o, 'action_type')})
|
||||||
|
|
||||||
|
|
||||||
|
class LogEntryType:
|
||||||
|
def __init__(self, action_type=None, plain=None):
|
||||||
|
assert self.__module__ != LogEntryType.__module__ # must not instantiate base classes, only derived ones
|
||||||
|
if action_type:
|
||||||
|
self.action_type = action_type
|
||||||
|
if plain:
|
||||||
|
self.plain = plain
|
||||||
|
|
||||||
|
def display(self, logentry):
|
||||||
|
if hasattr(self, 'plain'):
|
||||||
|
plain = str(self.plain)
|
||||||
|
if '{' in plain:
|
||||||
|
data = defaultdict(lambda: '?', logentry.parsed_data)
|
||||||
|
return plain.format_map(data)
|
||||||
|
else:
|
||||||
|
return plain
|
||||||
|
|
||||||
|
def get_object_link_info(self, logentry) -> dict:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_object_link(self, logentry):
|
||||||
|
a_map = self.get_object_link_info(logentry)
|
||||||
|
return make_link(a_map, self.object_link_wrapper)
|
||||||
|
|
||||||
|
object_link_wrapper = '{val}'
|
||||||
|
|
||||||
|
def shred_pii(self, logentry):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
|
class EventLogEntryType(LogEntryType):
|
||||||
|
def get_object_link_info(self, logentry) -> dict:
|
||||||
|
if hasattr(self, 'object_link_viewname') and hasattr(self, 'object_link_argname') and logentry.content_object:
|
||||||
|
return {
|
||||||
|
'href': reverse(self.object_link_viewname, kwargs={
|
||||||
|
'event': logentry.event.slug,
|
||||||
|
'organizer': logentry.event.organizer.slug,
|
||||||
|
self.object_link_argname: self.object_link_argvalue(logentry.content_object),
|
||||||
|
}),
|
||||||
|
'val': escape(self.object_link_display_name(logentry.content_object)),
|
||||||
|
}
|
||||||
|
|
||||||
|
def object_link_argvalue(self, content_object):
|
||||||
|
return content_object.id
|
||||||
|
|
||||||
|
def object_link_display_name(self, content_object):
|
||||||
|
return str(content_object)
|
||||||
|
|
||||||
|
|
||||||
|
class OrderLogEntryType(EventLogEntryType):
|
||||||
|
object_link_wrapper = _('Order {val}')
|
||||||
|
object_link_viewname = 'control:event.order'
|
||||||
|
object_link_argname = 'code'
|
||||||
|
|
||||||
|
def object_link_argvalue(self, order):
|
||||||
|
return order.code
|
||||||
|
|
||||||
|
def object_link_display_name(self, order):
|
||||||
|
return order.code
|
||||||
|
|
||||||
|
|
||||||
|
class VoucherLogEntryType(EventLogEntryType):
|
||||||
|
object_link_wrapper = _('Voucher {val}…')
|
||||||
|
object_link_viewname = 'control:event.voucher'
|
||||||
|
object_link_argname = 'voucher'
|
||||||
|
|
||||||
|
def object_link_display_name(self, order):
|
||||||
|
return order.code[:6]
|
||||||
|
|
||||||
|
|
||||||
|
class ItemLogEntryType(EventLogEntryType):
|
||||||
|
object_link_wrapper = _('Product {val}')
|
||||||
|
object_link_viewname = 'control:event.item'
|
||||||
|
object_link_argname = 'item'
|
||||||
|
|
||||||
|
|
||||||
|
class SubEventLogEntryType(EventLogEntryType):
|
||||||
|
object_link_wrapper = pgettext_lazy('subevent', 'Date {val}')
|
||||||
|
object_link_viewname = 'control:event.subevent'
|
||||||
|
object_link_argname = 'subevent'
|
||||||
|
|
||||||
|
|
||||||
|
class QuotaLogEntryType(EventLogEntryType):
|
||||||
|
object_link_wrapper = _('Quota {val}')
|
||||||
|
object_link_viewname = 'control:event.items.quotas.show'
|
||||||
|
object_link_argname = 'quota'
|
||||||
|
|
||||||
|
|
||||||
|
class DiscountLogEntryType(EventLogEntryType):
|
||||||
|
object_link_wrapper = _('Discount {val}')
|
||||||
|
object_link_viewname = 'control:event.items.discounts.edit'
|
||||||
|
object_link_argname = 'discount'
|
||||||
|
|
||||||
|
|
||||||
|
class ItemCategoryLogEntryType(EventLogEntryType):
|
||||||
|
object_link_wrapper = _('Category {val}')
|
||||||
|
object_link_viewname = 'control:event.items.categories.edit'
|
||||||
|
object_link_argname = 'category'
|
||||||
|
|
||||||
|
|
||||||
|
class QuestionLogEntryType(EventLogEntryType):
|
||||||
|
object_link_wrapper = _('Question {val}')
|
||||||
|
object_link_viewname = 'control:event.items.questions.show'
|
||||||
|
object_link_argname = 'question'
|
||||||
|
|
||||||
|
|
||||||
|
class TaxRuleLogEntryType(EventLogEntryType):
|
||||||
|
object_link_wrapper = _('Tax rule {val}')
|
||||||
|
object_link_viewname = 'control:event.settings.tax.edit'
|
||||||
|
object_link_argname = 'rule'
|
||||||
|
|
||||||
|
|
||||||
|
class NoOpShredderMixin:
|
||||||
|
def shred_pii(self, logentry):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ClearDataShredderMixin:
|
||||||
|
def shred_pii(self, logentry):
|
||||||
|
logentry.data = None
|
||||||
@@ -50,7 +50,6 @@ class Command(BaseCommand):
|
|||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument('--tasks', action='store', type=str, help='Only execute the tasks with this name '
|
parser.add_argument('--tasks', action='store', type=str, help='Only execute the tasks with this name '
|
||||||
'(dotted path, comma separation)')
|
'(dotted path, comma separation)')
|
||||||
parser.add_argument('--list-tasks', action='store_true', help='Only list all tasks')
|
|
||||||
parser.add_argument('--exclude', action='store', type=str, help='Exclude the tasks with this name '
|
parser.add_argument('--exclude', action='store', type=str, help='Exclude the tasks with this name '
|
||||||
'(dotted path, comma separation)')
|
'(dotted path, comma separation)')
|
||||||
|
|
||||||
@@ -62,9 +61,6 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
for receiver in periodic_task._live_receivers(self):
|
for receiver in periodic_task._live_receivers(self):
|
||||||
name = f'{receiver.__module__}.{receiver.__name__}'
|
name = f'{receiver.__module__}.{receiver.__name__}'
|
||||||
if options['list_tasks']:
|
|
||||||
print(name)
|
|
||||||
continue
|
|
||||||
if options.get('tasks'):
|
if options.get('tasks'):
|
||||||
if name not in options.get('tasks').split(','):
|
if name not in options.get('tasks').split(','):
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
# Generated by Django 4.2.15 on 2024-09-16 15:10
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
("pretixbase", "0269_order_api_meta"),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name="HistoricPassword",
|
|
||||||
fields=[
|
|
||||||
(
|
|
||||||
"id",
|
|
||||||
models.BigAutoField(
|
|
||||||
auto_created=True, primary_key=True, serialize=False
|
|
||||||
),
|
|
||||||
),
|
|
||||||
("created", models.DateTimeField(auto_now_add=True)),
|
|
||||||
("password", models.CharField(max_length=128)),
|
|
||||||
(
|
|
||||||
"user",
|
|
||||||
models.ForeignKey(
|
|
||||||
on_delete=django.db.models.deletion.CASCADE,
|
|
||||||
related_name="historic_passwords",
|
|
||||||
to=settings.AUTH_USER_MODEL,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -213,13 +213,7 @@ class DatetimeColumnMixin:
|
|||||||
except (ValueError, TypeError):
|
except (ValueError, TypeError):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
try:
|
raise ValidationError(_("Could not parse {value} as a date and time.").format(value=value))
|
||||||
d = datetime.datetime.fromisoformat(value)
|
|
||||||
if not d.tzinfo:
|
|
||||||
d = d.replace(tzinfo=self.timezone)
|
|
||||||
return d
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
raise ValidationError(_("Could not parse {value} as a date and time.").format(value=value))
|
|
||||||
|
|
||||||
|
|
||||||
class DecimalColumnMixin:
|
class DecimalColumnMixin:
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ from phonenumbers import SUPPORTED_REGIONS
|
|||||||
|
|
||||||
from pretix.base.forms.questions import guess_country
|
from pretix.base.forms.questions import guess_country
|
||||||
from pretix.base.modelimport import (
|
from pretix.base.modelimport import (
|
||||||
BooleanColumnMixin, DatetimeColumnMixin, DecimalColumnMixin, ImportColumn,
|
DatetimeColumnMixin, DecimalColumnMixin, ImportColumn, SubeventColumnMixin,
|
||||||
SubeventColumnMixin, i18n_flat,
|
i18n_flat,
|
||||||
)
|
)
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
Customer, ItemVariation, OrderPosition, Question, QuestionAnswer,
|
Customer, ItemVariation, OrderPosition, Question, QuestionAnswer,
|
||||||
@@ -604,22 +604,6 @@ class Comment(ImportColumn):
|
|||||||
order.comment = value or ''
|
order.comment = value or ''
|
||||||
|
|
||||||
|
|
||||||
class CheckinAttentionColumn(BooleanColumnMixin, ImportColumn):
|
|
||||||
identifier = 'checkin_attention'
|
|
||||||
verbose_name = gettext_lazy('Requires special attention')
|
|
||||||
|
|
||||||
def assign(self, value, order, position, invoice_address, **kwargs):
|
|
||||||
order.checkin_attention = value
|
|
||||||
|
|
||||||
|
|
||||||
class CheckinTextColumn(ImportColumn):
|
|
||||||
identifier = 'checkin_text'
|
|
||||||
verbose_name = gettext_lazy('Check-in text')
|
|
||||||
|
|
||||||
def assign(self, value, order, position, invoice_address, **kwargs):
|
|
||||||
order.checkin_text = value
|
|
||||||
|
|
||||||
|
|
||||||
class QuestionColumn(ImportColumn):
|
class QuestionColumn(ImportColumn):
|
||||||
def __init__(self, event, q):
|
def __init__(self, event, q):
|
||||||
self.q = q
|
self.q = q
|
||||||
@@ -758,8 +742,6 @@ def get_order_import_columns(event):
|
|||||||
ValidUntil(event),
|
ValidUntil(event),
|
||||||
Locale(event),
|
Locale(event),
|
||||||
Saleschannel(event),
|
Saleschannel(event),
|
||||||
CheckinAttentionColumn(event),
|
|
||||||
CheckinTextColumn(event),
|
|
||||||
Expires(event),
|
Expires(event),
|
||||||
Comment(event),
|
Comment(event),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -654,9 +654,3 @@ class WebAuthnDevice(Device):
|
|||||||
@property
|
@property
|
||||||
def webauthnpubkey(self):
|
def webauthnpubkey(self):
|
||||||
return websafe_decode(self.pub_key)
|
return websafe_decode(self.pub_key)
|
||||||
|
|
||||||
|
|
||||||
class HistoricPassword(models.Model):
|
|
||||||
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="historic_passwords")
|
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
|
||||||
password = models.CharField(verbose_name=_("Password"), max_length=128)
|
|
||||||
|
|||||||
@@ -313,9 +313,38 @@ class EventMixin:
|
|||||||
items=GroupConcat('pk', delimiter=',')
|
items=GroupConcat('pk', delimiter=',')
|
||||||
).values('items')
|
).values('items')
|
||||||
|
|
||||||
sq_active_variation = ItemVariation.objects.filter_available(channel=channel, voucher=voucher).filter(
|
q_variation = (
|
||||||
Q(quotas__pk=OuterRef('pk'))
|
Q(active=True)
|
||||||
).order_by().values_list('quotas__pk').annotate(
|
& Q(Q(available_from__isnull=True) | Q(available_from__lte=time_machine_now()))
|
||||||
|
& Q(Q(available_until__isnull=True) | Q(available_until__gte=time_machine_now()))
|
||||||
|
& Q(item__active=True)
|
||||||
|
& Q(Q(item__available_from__isnull=True) | Q(item__available_from__lte=time_machine_now()))
|
||||||
|
& Q(Q(item__available_until__isnull=True) | Q(item__available_until__gte=time_machine_now()))
|
||||||
|
& Q(Q(item__category__isnull=True) | Q(item__category__is_addon=False))
|
||||||
|
& Q(item__require_bundling=False)
|
||||||
|
& Q(quotas__pk=OuterRef('pk'))
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(channel, str):
|
||||||
|
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
|
||||||
|
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__identifier=channel))
|
||||||
|
else:
|
||||||
|
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
|
||||||
|
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels=channel))
|
||||||
|
|
||||||
|
if voucher:
|
||||||
|
if voucher.variation_id:
|
||||||
|
q_variation &= Q(pk=voucher.variation_id)
|
||||||
|
elif voucher.item_id:
|
||||||
|
q_variation &= Q(item_id=voucher.item_id)
|
||||||
|
elif voucher.quota_id:
|
||||||
|
q_variation &= Q(quotas__in=[voucher.quota_id])
|
||||||
|
|
||||||
|
if not voucher or not voucher.show_hidden_items:
|
||||||
|
q_variation &= Q(hide_without_voucher=False)
|
||||||
|
q_variation &= Q(item__hide_without_voucher=False)
|
||||||
|
|
||||||
|
sq_active_variation = ItemVariation.objects.filter(q_variation).order_by().values_list('quotas__pk').annotate(
|
||||||
items=GroupConcat('pk', delimiter=',')
|
items=GroupConcat('pk', delimiter=',')
|
||||||
).values('items')
|
).values('items')
|
||||||
quota_base_qs = Quota.objects.using(settings.DATABASE_REPLICA).filter(
|
quota_base_qs = Quota.objects.using(settings.DATABASE_REPLICA).filter(
|
||||||
@@ -713,8 +742,8 @@ class Event(EventMixin, LoggedModel):
|
|||||||
Returns the names of the plugins activated for this event as a list.
|
Returns the names of the plugins activated for this event as a list.
|
||||||
"""
|
"""
|
||||||
if self.plugins is None:
|
if self.plugins is None:
|
||||||
return []
|
return self.organizer.get_plugins()
|
||||||
return self.plugins.split(",")
|
return self.plugins.split(",") + self.organizer.get_plugins()
|
||||||
|
|
||||||
def get_cache(self):
|
def get_cache(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -303,48 +303,6 @@ def filter_available(qs, channel='web', voucher=None, allow_addons=False):
|
|||||||
return qs.filter(q)
|
return qs.filter(q)
|
||||||
|
|
||||||
|
|
||||||
def filter_variations_available(qs, channel='web', voucher=None, allow_addons=False):
|
|
||||||
# Channel can currently be a SalesChannel or a str, since we need that compatibility, but a SalesChannel
|
|
||||||
# makes the query SIGNIFICANTLY faster
|
|
||||||
from .organizer import SalesChannel
|
|
||||||
|
|
||||||
assert isinstance(channel, (SalesChannel, str))
|
|
||||||
q = (
|
|
||||||
Q(active=True)
|
|
||||||
& Q(Q(available_from__isnull=True) | Q(available_from__lte=time_machine_now()))
|
|
||||||
& Q(Q(available_until__isnull=True) | Q(available_until__gte=time_machine_now()))
|
|
||||||
& Q(item__active=True)
|
|
||||||
& Q(Q(item__available_from__isnull=True) | Q(item__available_from__lte=time_machine_now()))
|
|
||||||
& Q(Q(item__available_until__isnull=True) | Q(item__available_until__gte=time_machine_now()))
|
|
||||||
& Q(Q(item__category__isnull=True) | Q(item__category__is_addon=False))
|
|
||||||
& Q(item__require_bundling=False)
|
|
||||||
)
|
|
||||||
|
|
||||||
if isinstance(channel, str):
|
|
||||||
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
|
|
||||||
q &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__identifier=channel))
|
|
||||||
else:
|
|
||||||
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
|
|
||||||
q &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels=channel))
|
|
||||||
|
|
||||||
if not allow_addons:
|
|
||||||
q &= Q(Q(item__category__isnull=True) | Q(item__category__is_addon=False))
|
|
||||||
|
|
||||||
if voucher:
|
|
||||||
if voucher.variation_id:
|
|
||||||
q &= Q(pk=voucher.variation_id)
|
|
||||||
elif voucher.item_id:
|
|
||||||
q &= Q(item_id=voucher.item_id)
|
|
||||||
elif voucher.quota_id:
|
|
||||||
q &= Q(quotas__in=[voucher.quota_id])
|
|
||||||
|
|
||||||
if not voucher or not voucher.show_hidden_items:
|
|
||||||
q &= Q(hide_without_voucher=False)
|
|
||||||
q &= Q(item__hide_without_voucher=False)
|
|
||||||
|
|
||||||
return qs.filter(q)
|
|
||||||
|
|
||||||
|
|
||||||
class ItemQuerySet(models.QuerySet):
|
class ItemQuerySet(models.QuerySet):
|
||||||
def filter_available(self, channel='web', voucher=None, allow_addons=False):
|
def filter_available(self, channel='web', voucher=None, allow_addons=False):
|
||||||
return filter_available(self, channel, voucher, allow_addons)
|
return filter_available(self, channel, voucher, allow_addons)
|
||||||
@@ -359,20 +317,6 @@ class ItemQuerySetManager(ScopedManager(organizer='event__organizer').__class__)
|
|||||||
return filter_available(self.get_queryset(), channel, voucher, allow_addons)
|
return filter_available(self.get_queryset(), channel, voucher, allow_addons)
|
||||||
|
|
||||||
|
|
||||||
class ItemVariationQuerySet(models.QuerySet):
|
|
||||||
def filter_available(self, channel='web', voucher=None, allow_addons=False):
|
|
||||||
return filter_variations_available(self, channel, voucher, allow_addons)
|
|
||||||
|
|
||||||
|
|
||||||
class ItemVariationQuerySetManager(ScopedManager(organizer='item__event__organizer').__class__):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self._queryset_class = ItemVariationQuerySet
|
|
||||||
|
|
||||||
def filter_available(self, channel='web', voucher=None, allow_addons=False):
|
|
||||||
return filter_variations_available(self.get_queryset(), channel, voucher, allow_addons)
|
|
||||||
|
|
||||||
|
|
||||||
class Item(LoggedModel):
|
class Item(LoggedModel):
|
||||||
"""
|
"""
|
||||||
An item is a thing which can be sold. It belongs to an event and may or may not belong to a category.
|
An item is a thing which can be sold. It belongs to an event and may or may not belong to a category.
|
||||||
@@ -1255,7 +1199,7 @@ class ItemVariation(models.Model):
|
|||||||
help_text=_('This text will be shown by the check-in app if a ticket of this type is scanned.')
|
help_text=_('This text will be shown by the check-in app if a ticket of this type is scanned.')
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = ItemVariationQuerySetManager()
|
objects = ScopedManager(organizer='item__event__organizer')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Product variation")
|
verbose_name = _("Product variation")
|
||||||
|
|||||||
+25
-107
@@ -33,16 +33,17 @@
|
|||||||
# License for the specific language governing permissions and limitations under the License.
|
# License for the specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
|
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.html import escape
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
|
||||||
|
|
||||||
from pretix.base.signals import logentry_object_link
|
from pretix.base.logentrytypes import log_entry_types, make_link
|
||||||
|
from pretix.base.signals import is_app_active, logentry_object_link
|
||||||
|
|
||||||
|
|
||||||
class VisibleOnlyManager(models.Manager):
|
class VisibleOnlyManager(models.Manager):
|
||||||
@@ -92,6 +93,10 @@ class LogEntry(models.Model):
|
|||||||
indexes = [models.Index(fields=["datetime", "id"])]
|
indexes = [models.Index(fields=["datetime", "id"])]
|
||||||
|
|
||||||
def display(self):
|
def display(self):
|
||||||
|
log_entry_type, meta = log_entry_types.find(action_type=self.action_type)
|
||||||
|
if log_entry_type:
|
||||||
|
return log_entry_type.display(self)
|
||||||
|
|
||||||
from ..signals import logentry_display
|
from ..signals import logentry_display
|
||||||
|
|
||||||
for receiver, response in logentry_display.send(self.event, logentry=self):
|
for receiver, response in logentry_display.send(self.event, logentry=self):
|
||||||
@@ -126,10 +131,18 @@ class LogEntry(models.Model):
|
|||||||
@cached_property
|
@cached_property
|
||||||
def display_object(self):
|
def display_object(self):
|
||||||
from . import (
|
from . import (
|
||||||
Discount, Event, Item, ItemCategory, Order, Question, Quota,
|
Discount, Event, Item, Order, Question, Quota, SubEvent, Voucher,
|
||||||
SubEvent, TaxRule, Voucher,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
log_entry_type, meta = log_entry_types.find(action_type=self.action_type)
|
||||||
|
if log_entry_type:
|
||||||
|
link_info = log_entry_type.get_object_link_info(self)
|
||||||
|
if is_app_active(self.event, meta['plugin']):
|
||||||
|
return make_link(link_info, log_entry_type.object_link_wrapper)
|
||||||
|
else:
|
||||||
|
return make_link(link_info, log_entry_type.object_link_wrapper, is_active=False,
|
||||||
|
event=self.event, plugin_name=meta['plugin'] and getattr(meta['plugin'], 'name'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if self.content_type.model_class() is Event:
|
if self.content_type.model_class() is Event:
|
||||||
return ''
|
return ''
|
||||||
@@ -137,110 +150,15 @@ class LogEntry(models.Model):
|
|||||||
co = self.content_object
|
co = self.content_object
|
||||||
except:
|
except:
|
||||||
return ''
|
return ''
|
||||||
a_map = None
|
|
||||||
a_text = None
|
|
||||||
|
|
||||||
if isinstance(co, Order):
|
for receiver, response in logentry_object_link.send(self.event, logentry=self):
|
||||||
a_text = _('Order {val}')
|
if response:
|
||||||
a_map = {
|
return response
|
||||||
'href': reverse('control:event.order', kwargs={
|
|
||||||
'event': self.event.slug,
|
|
||||||
'organizer': self.event.organizer.slug,
|
|
||||||
'code': co.code
|
|
||||||
}),
|
|
||||||
'val': escape(co.code),
|
|
||||||
}
|
|
||||||
elif isinstance(co, Voucher):
|
|
||||||
a_text = _('Voucher {val}…')
|
|
||||||
a_map = {
|
|
||||||
'href': reverse('control:event.voucher', kwargs={
|
|
||||||
'event': self.event.slug,
|
|
||||||
'organizer': self.event.organizer.slug,
|
|
||||||
'voucher': co.id
|
|
||||||
}),
|
|
||||||
'val': escape(co.code[:6]),
|
|
||||||
}
|
|
||||||
elif isinstance(co, Item):
|
|
||||||
a_text = _('Product {val}')
|
|
||||||
a_map = {
|
|
||||||
'href': reverse('control:event.item', kwargs={
|
|
||||||
'event': self.event.slug,
|
|
||||||
'organizer': self.event.organizer.slug,
|
|
||||||
'item': co.id
|
|
||||||
}),
|
|
||||||
'val': escape(co.name),
|
|
||||||
}
|
|
||||||
elif isinstance(co, SubEvent):
|
|
||||||
a_text = pgettext_lazy('subevent', 'Date {val}')
|
|
||||||
a_map = {
|
|
||||||
'href': reverse('control:event.subevent', kwargs={
|
|
||||||
'event': self.event.slug,
|
|
||||||
'organizer': self.event.organizer.slug,
|
|
||||||
'subevent': co.id
|
|
||||||
}),
|
|
||||||
'val': escape(str(co))
|
|
||||||
}
|
|
||||||
elif isinstance(co, Quota):
|
|
||||||
a_text = _('Quota {val}')
|
|
||||||
a_map = {
|
|
||||||
'href': reverse('control:event.items.quotas.show', kwargs={
|
|
||||||
'event': self.event.slug,
|
|
||||||
'organizer': self.event.organizer.slug,
|
|
||||||
'quota': co.id
|
|
||||||
}),
|
|
||||||
'val': escape(co.name),
|
|
||||||
}
|
|
||||||
elif isinstance(co, Discount):
|
|
||||||
a_text = _('Discount {val}')
|
|
||||||
a_map = {
|
|
||||||
'href': reverse('control:event.items.discounts.edit', kwargs={
|
|
||||||
'event': self.event.slug,
|
|
||||||
'organizer': self.event.organizer.slug,
|
|
||||||
'discount': co.id
|
|
||||||
}),
|
|
||||||
'val': escape(co.internal_name),
|
|
||||||
}
|
|
||||||
elif isinstance(co, ItemCategory):
|
|
||||||
a_text = _('Category {val}')
|
|
||||||
a_map = {
|
|
||||||
'href': reverse('control:event.items.categories.edit', kwargs={
|
|
||||||
'event': self.event.slug,
|
|
||||||
'organizer': self.event.organizer.slug,
|
|
||||||
'category': co.id
|
|
||||||
}),
|
|
||||||
'val': escape(co.name),
|
|
||||||
}
|
|
||||||
elif isinstance(co, Question):
|
|
||||||
a_text = _('Question {val}')
|
|
||||||
a_map = {
|
|
||||||
'href': reverse('control:event.items.questions.show', kwargs={
|
|
||||||
'event': self.event.slug,
|
|
||||||
'organizer': self.event.organizer.slug,
|
|
||||||
'question': co.id
|
|
||||||
}),
|
|
||||||
'val': escape(co.question),
|
|
||||||
}
|
|
||||||
elif isinstance(co, TaxRule):
|
|
||||||
a_text = _('Tax rule {val}')
|
|
||||||
a_map = {
|
|
||||||
'href': reverse('control:event.settings.tax.edit', kwargs={
|
|
||||||
'event': self.event.slug,
|
|
||||||
'organizer': self.event.organizer.slug,
|
|
||||||
'rule': co.id
|
|
||||||
}),
|
|
||||||
'val': escape(co.name),
|
|
||||||
}
|
|
||||||
|
|
||||||
if a_text and a_map:
|
if isinstance(co, (Order, Voucher, Item, SubEvent, Quota, Discount, Question)):
|
||||||
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
|
logging.warning("LogEntryType missing or ill-defined: %s", self.action_type)
|
||||||
return a_text.format_map(a_map)
|
|
||||||
elif a_text:
|
return ''
|
||||||
return a_text
|
|
||||||
else:
|
|
||||||
for receiver, response in logentry_object_link.send(self.event, logentry=self):
|
|
||||||
if response:
|
|
||||||
return response
|
|
||||||
return ''
|
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def parsed_data(self):
|
def parsed_data(self):
|
||||||
|
|||||||
@@ -2836,12 +2836,12 @@ class OrderPosition(AbstractPosition):
|
|||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def code(self):
|
def full_code(self):
|
||||||
"""
|
"""
|
||||||
A ticket code which is unique among all events of a single organizer,
|
A ticket code which is unique among all events of a single organizer,
|
||||||
built by the order code and the position number.
|
built by concatenating the event slug and the order code.
|
||||||
"""
|
"""
|
||||||
return '{order_code}-{position}'.format(order_code=self.order.code, position=self.positionid)
|
return '{order}-{position}'.format(order=self.order.full_code, position=self.positionid)
|
||||||
|
|
||||||
|
|
||||||
class Transaction(models.Model):
|
class Transaction(models.Model):
|
||||||
|
|||||||
@@ -91,6 +91,10 @@ class Organizer(LoggedModel):
|
|||||||
verbose_name=_("Short form"),
|
verbose_name=_("Short form"),
|
||||||
unique=True
|
unique=True
|
||||||
)
|
)
|
||||||
|
plugins = models.TextField(
|
||||||
|
null=True, blank=True,
|
||||||
|
verbose_name=_("Plugins"),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Organizer")
|
verbose_name = _("Organizer")
|
||||||
@@ -119,6 +123,14 @@ class Organizer(LoggedModel):
|
|||||||
"""
|
"""
|
||||||
self.settings.cookie_consent = True
|
self.settings.cookie_consent = True
|
||||||
|
|
||||||
|
def get_plugins(self):
|
||||||
|
"""
|
||||||
|
Returns the names of the plugins activated for this organizer as a list.
|
||||||
|
"""
|
||||||
|
if self.plugins is None:
|
||||||
|
return []
|
||||||
|
return self.plugins.split(",")
|
||||||
|
|
||||||
def get_cache(self):
|
def get_cache(self):
|
||||||
"""
|
"""
|
||||||
Returns an :py:class:`ObjectRelatedCache` object. This behaves equivalent to
|
Returns an :py:class:`ObjectRelatedCache` object. This behaves equivalent to
|
||||||
|
|||||||
@@ -29,8 +29,6 @@ from django.core.validators import MaxValueValidator, MinValueValidator
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.deconstruct import deconstructible
|
from django.utils.deconstruct import deconstructible
|
||||||
from django.utils.formats import localize
|
from django.utils.formats import localize
|
||||||
from django.utils.functional import lazy
|
|
||||||
from django.utils.html import format_html
|
|
||||||
from django.utils.translation import gettext_lazy as _, pgettext
|
from django.utils.translation import gettext_lazy as _, pgettext
|
||||||
from i18nfield.fields import I18nCharField
|
from i18nfield.fields import I18nCharField
|
||||||
from i18nfield.strings import LazyI18nString
|
from i18nfield.strings import LazyI18nString
|
||||||
@@ -122,8 +120,6 @@ EU_CURRENCIES = {
|
|||||||
}
|
}
|
||||||
VAT_ID_COUNTRIES = EU_COUNTRIES | {'CH', 'NO'}
|
VAT_ID_COUNTRIES = EU_COUNTRIES | {'CH', 'NO'}
|
||||||
|
|
||||||
format_html_lazy = lazy(format_html, str)
|
|
||||||
|
|
||||||
|
|
||||||
def is_eu_country(cc):
|
def is_eu_country(cc):
|
||||||
cc = str(cc)
|
cc = str(cc)
|
||||||
@@ -197,17 +193,11 @@ class TaxRule(LoggedModel):
|
|||||||
eu_reverse_charge = models.BooleanField(
|
eu_reverse_charge = models.BooleanField(
|
||||||
verbose_name=_("Use EU reverse charge taxation rules"),
|
verbose_name=_("Use EU reverse charge taxation rules"),
|
||||||
default=False,
|
default=False,
|
||||||
help_text=format_html_lazy(
|
help_text=_("Not recommended. Most events will NOT be qualified for reverse charge since the place of "
|
||||||
'<span class="label label-warning" data-toggle="tooltip" title="{}">{}</span> {}',
|
"taxation is the location of the event. This option disables charging VAT for all customers "
|
||||||
_('This feature will be removed in the future as it does not handle VAT for non-business customers in '
|
"outside the EU and for business customers in different EU countries who entered a valid EU VAT "
|
||||||
'other EU countries in a way that works for all organizers. Use custom rules instead.'),
|
"ID. Only enable this option after consulting a tax counsel. No warranty given for correct tax "
|
||||||
_('DEPRECATED'),
|
"calculation. USE AT YOUR OWN RISK.")
|
||||||
_("Not recommended. Most events will NOT be qualified for reverse charge since the place of "
|
|
||||||
"taxation is the location of the event. This option disables charging VAT for all customers "
|
|
||||||
"outside the EU and for business customers in different EU countries who entered a valid EU VAT "
|
|
||||||
"ID. Only enable this option after consulting a tax counsel. No warranty given for correct tax "
|
|
||||||
"calculation. USE AT YOUR OWN RISK.")
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
home_country = FastCountryField(
|
home_country = FastCountryField(
|
||||||
verbose_name=_('Merchant country'),
|
verbose_name=_('Merchant country'),
|
||||||
|
|||||||
@@ -1182,11 +1182,10 @@ def process_exit_all(sender, **kwargs):
|
|||||||
positions = cl.positions_inside_query(ignore_status=True, at_time=cl.exit_all_at)
|
positions = cl.positions_inside_query(ignore_status=True, at_time=cl.exit_all_at)
|
||||||
for p in positions:
|
for p in positions:
|
||||||
with scope(organizer=cl.event.organizer):
|
with scope(organizer=cl.event.organizer):
|
||||||
ci, created = Checkin.objects.get_or_create(
|
ci = Checkin.objects.create(
|
||||||
position=p, list=cl, auto_checked_in=True, type=Checkin.TYPE_EXIT, datetime=cl.exit_all_at
|
position=p, list=cl, auto_checked_in=True, type=Checkin.TYPE_EXIT, datetime=cl.exit_all_at
|
||||||
)
|
)
|
||||||
if created:
|
checkin_created.send(cl.event, checkin=ci)
|
||||||
checkin_created.send(cl.event, checkin=ci)
|
|
||||||
d = cl.exit_all_at.astimezone(cl.event.timezone)
|
d = cl.exit_all_at.astimezone(cl.event.timezone)
|
||||||
if cl.event.settings.get(f'autocheckin_dst_hack_{cl.pk}'): # move time back if yesterday was DST switch
|
if cl.event.settings.get(f'autocheckin_dst_hack_{cl.pk}'): # move time back if yesterday was DST switch
|
||||||
d -= timedelta(hours=1)
|
d -= timedelta(hours=1)
|
||||||
|
|||||||
+106
-43
@@ -52,49 +52,71 @@ def _populate_app_cache():
|
|||||||
app_cache[ac.name] = ac
|
app_cache[ac.name] = ac
|
||||||
|
|
||||||
|
|
||||||
class EventPluginSignal(django.dispatch.Signal):
|
def get_defining_app(o):
|
||||||
|
# If sentry packed this in a wrapper, unpack that
|
||||||
|
if "sentry" in o.__module__:
|
||||||
|
o = o.__wrapped__
|
||||||
|
|
||||||
|
# Find the Django application this belongs to
|
||||||
|
searchpath = o.__module__
|
||||||
|
|
||||||
|
# Core modules are always active
|
||||||
|
if any(searchpath.startswith(cm) for cm in settings.CORE_MODULES):
|
||||||
|
return 'CORE'
|
||||||
|
|
||||||
|
if not app_cache:
|
||||||
|
_populate_app_cache()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
app = app_cache.get(searchpath)
|
||||||
|
if "." not in searchpath or app:
|
||||||
|
break
|
||||||
|
searchpath, _ = searchpath.rsplit(".", 1)
|
||||||
|
return app
|
||||||
|
|
||||||
|
|
||||||
|
def is_app_active(sender, app):
|
||||||
|
if app == 'CORE':
|
||||||
|
return True
|
||||||
|
|
||||||
|
excluded = settings.PRETIX_PLUGINS_EXCLUDE
|
||||||
|
if sender and app and app.name in sender.get_plugins() and app.name not in excluded:
|
||||||
|
if not hasattr(app, 'compatibility_errors') or not app.compatibility_errors:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def is_receiver_active(sender, receiver):
|
||||||
|
if sender is None:
|
||||||
|
# Send to all events!
|
||||||
|
return True
|
||||||
|
|
||||||
|
app = get_defining_app(receiver)
|
||||||
|
|
||||||
|
return is_app_active(sender, app)
|
||||||
|
|
||||||
|
|
||||||
|
def is_plugin_host(sender):
|
||||||
|
return hasattr(sender, 'get_plugins')
|
||||||
|
|
||||||
|
|
||||||
|
class PluginSignal(django.dispatch.Signal):
|
||||||
"""
|
"""
|
||||||
This is an extension to Django's built-in signals which differs in a way that it sends
|
This is an extension to Django's built-in signals which differs in a way that it sends
|
||||||
out it's events only to receivers which belong to plugins that are enabled for the given
|
out it's events only to receivers which belong to plugins that are enabled for the given
|
||||||
Event.
|
Event.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _is_active(self, sender, receiver):
|
def send(self, sender, **named) -> List[Tuple[Callable, Any]]:
|
||||||
if sender is None:
|
|
||||||
# Send to all events!
|
|
||||||
return True
|
|
||||||
|
|
||||||
# If sentry packed this in a wrapper, unpack that
|
|
||||||
if "sentry" in receiver.__module__:
|
|
||||||
receiver = receiver.__wrapped__
|
|
||||||
|
|
||||||
# Find the Django application this belongs to
|
|
||||||
searchpath = receiver.__module__
|
|
||||||
core_module = any([searchpath.startswith(cm) for cm in settings.CORE_MODULES])
|
|
||||||
app = None
|
|
||||||
if not core_module:
|
|
||||||
while True:
|
|
||||||
app = app_cache.get(searchpath)
|
|
||||||
if "." not in searchpath or app:
|
|
||||||
break
|
|
||||||
searchpath, _ = searchpath.rsplit(".", 1)
|
|
||||||
|
|
||||||
# Only fire receivers from active plugins and core modules
|
|
||||||
excluded = settings.PRETIX_PLUGINS_EXCLUDE
|
|
||||||
if core_module or (sender and app and app.name in sender.get_plugins() and app.name not in excluded):
|
|
||||||
if not hasattr(app, 'compatibility_errors') or not app.compatibility_errors:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def send(self, sender: Event, **named) -> List[Tuple[Callable, Any]]:
|
|
||||||
"""
|
"""
|
||||||
Send signal from sender to all connected receivers that belong to
|
Send signal from sender to all connected receivers that belong to
|
||||||
plugins enabled for the given Event.
|
plugins enabled for the given Event.
|
||||||
|
|
||||||
sender is required to be an instance of ``pretix.base.models.Event``.
|
sender is required to be a plugin host (an object with a `get_plugins` method),
|
||||||
|
for example a ``pretix.base.models.Event``.
|
||||||
"""
|
"""
|
||||||
if sender and not isinstance(sender, Event):
|
if sender and not is_plugin_host(sender):
|
||||||
raise ValueError("Sender needs to be an event.")
|
raise ValueError("Sender needs to be a plugin host.")
|
||||||
|
|
||||||
responses = []
|
responses = []
|
||||||
if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
|
if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
|
||||||
@@ -104,21 +126,22 @@ class EventPluginSignal(django.dispatch.Signal):
|
|||||||
_populate_app_cache()
|
_populate_app_cache()
|
||||||
|
|
||||||
for receiver in self._sorted_receivers(sender):
|
for receiver in self._sorted_receivers(sender):
|
||||||
if self._is_active(sender, receiver):
|
if is_receiver_active(sender, receiver):
|
||||||
response = receiver(signal=self, sender=sender, **named)
|
response = receiver(signal=self, sender=sender, **named)
|
||||||
responses.append((receiver, response))
|
responses.append((receiver, response))
|
||||||
return responses
|
return responses
|
||||||
|
|
||||||
def send_chained(self, sender: Event, chain_kwarg_name, **named) -> List[Tuple[Callable, Any]]:
|
def send_chained(self, sender, chain_kwarg_name, **named) -> List[Tuple[Callable, Any]]:
|
||||||
"""
|
"""
|
||||||
Send signal from sender to all connected receivers. The return value of the first receiver
|
Send signal from sender to all connected receivers. The return value of the first receiver
|
||||||
will be used as the keyword argument specified by ``chain_kwarg_name`` in the input to the
|
will be used as the keyword argument specified by ``chain_kwarg_name`` in the input to the
|
||||||
second receiver and so on. The return value of the last receiver is returned by this method.
|
second receiver and so on. The return value of the last receiver is returned by this method.
|
||||||
|
|
||||||
sender is required to be an instance of ``pretix.base.models.Event``.
|
sender is required to be a plugin host (an object with a `get_plugins` method),
|
||||||
|
for example a ``pretix.base.models.Event``.
|
||||||
"""
|
"""
|
||||||
if sender and not isinstance(sender, Event):
|
if sender and not is_plugin_host(sender):
|
||||||
raise ValueError("Sender needs to be an event.")
|
raise ValueError("Sender needs to be a plugin host.")
|
||||||
|
|
||||||
response = named.get(chain_kwarg_name)
|
response = named.get(chain_kwarg_name)
|
||||||
if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
|
if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
|
||||||
@@ -128,21 +151,22 @@ class EventPluginSignal(django.dispatch.Signal):
|
|||||||
_populate_app_cache()
|
_populate_app_cache()
|
||||||
|
|
||||||
for receiver in self._sorted_receivers(sender):
|
for receiver in self._sorted_receivers(sender):
|
||||||
if self._is_active(sender, receiver):
|
if is_receiver_active(sender, receiver):
|
||||||
named[chain_kwarg_name] = response
|
named[chain_kwarg_name] = response
|
||||||
response = receiver(signal=self, sender=sender, **named)
|
response = receiver(signal=self, sender=sender, **named)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def send_robust(self, sender: Event, **named) -> List[Tuple[Callable, Any]]:
|
def send_robust(self, sender, **named) -> List[Tuple[Callable, Any]]:
|
||||||
"""
|
"""
|
||||||
Send signal from sender to all connected receivers. If a receiver raises an exception
|
Send signal from sender to all connected receivers. If a receiver raises an exception
|
||||||
instead of returning a value, the exception is included as the result instead of
|
instead of returning a value, the exception is included as the result instead of
|
||||||
stopping the response chain at the offending receiver.
|
stopping the response chain at the offending receiver.
|
||||||
|
|
||||||
sender is required to be an instance of ``pretix.base.models.Event``.
|
sender is required to be a plugin host (an object with a `get_plugins` method),
|
||||||
|
for example a ``pretix.base.models.Event``.
|
||||||
"""
|
"""
|
||||||
if sender and not isinstance(sender, Event):
|
if sender and not is_plugin_host(sender):
|
||||||
raise ValueError("Sender needs to be an event.")
|
raise ValueError("Sender needs to be a plugin host.")
|
||||||
|
|
||||||
responses = []
|
responses = []
|
||||||
if (
|
if (
|
||||||
@@ -155,7 +179,7 @@ class EventPluginSignal(django.dispatch.Signal):
|
|||||||
_populate_app_cache()
|
_populate_app_cache()
|
||||||
|
|
||||||
for receiver in self._sorted_receivers(sender):
|
for receiver in self._sorted_receivers(sender):
|
||||||
if self._is_active(sender, receiver):
|
if is_receiver_active(sender, receiver):
|
||||||
try:
|
try:
|
||||||
response = receiver(signal=self, sender=sender, **named)
|
response = receiver(signal=self, sender=sender, **named)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
@@ -177,6 +201,14 @@ class EventPluginSignal(django.dispatch.Signal):
|
|||||||
return sorted_list
|
return sorted_list
|
||||||
|
|
||||||
|
|
||||||
|
class OrganizerPluginSignal(PluginSignal):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class EventPluginSignal(PluginSignal):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class GlobalSignal(django.dispatch.Signal):
|
class GlobalSignal(django.dispatch.Signal):
|
||||||
def send_chained(self, sender: Event, chain_kwarg_name, **named) -> List[Tuple[Callable, Any]]:
|
def send_chained(self, sender: Event, chain_kwarg_name, **named) -> List[Tuple[Callable, Any]]:
|
||||||
"""
|
"""
|
||||||
@@ -202,6 +234,37 @@ class DeprecatedSignal(django.dispatch.Signal):
|
|||||||
super().connect(receiver, sender=None, weak=True, dispatch_uid=None)
|
super().connect(receiver, sender=None, weak=True, dispatch_uid=None)
|
||||||
|
|
||||||
|
|
||||||
|
class Registry:
|
||||||
|
def __init__(self, keys):
|
||||||
|
self.registered_items = list()
|
||||||
|
self.keys = keys
|
||||||
|
self.by_key = {key: {} for key in self.keys.keys()}
|
||||||
|
|
||||||
|
def register(self, *objs):
|
||||||
|
for obj in objs:
|
||||||
|
meta = {k: accessor(obj) for k, accessor in self.keys.items()}
|
||||||
|
tup = (obj, meta)
|
||||||
|
for key, accessor in self.keys.items():
|
||||||
|
self.by_key[key][accessor(obj)] = tup
|
||||||
|
self.registered_items.append(tup)
|
||||||
|
|
||||||
|
def new(self, *args, **kwargs):
|
||||||
|
def reg(clz):
|
||||||
|
obj = clz(*args, **kwargs)
|
||||||
|
self.register(obj)
|
||||||
|
return clz
|
||||||
|
return reg
|
||||||
|
|
||||||
|
def find(self, **kwargs):
|
||||||
|
(key, value), = kwargs.items()
|
||||||
|
return self.by_key.get(key).get(value, (None, None))
|
||||||
|
|
||||||
|
|
||||||
|
class PluginRegistry(Registry):
|
||||||
|
def __init__(self, keys):
|
||||||
|
super().__init__({"plugin": lambda o: get_defining_app(o), **keys})
|
||||||
|
|
||||||
|
|
||||||
event_live_issues = EventPluginSignal()
|
event_live_issues = EventPluginSignal()
|
||||||
"""
|
"""
|
||||||
This signal is sent out to determine whether an event can be taken live. If you want to
|
This signal is sent out to determine whether an event can be taken live. If you want to
|
||||||
|
|||||||
@@ -30,9 +30,7 @@ from celery import states
|
|||||||
from celery.result import AsyncResult
|
from celery.result import AsyncResult
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.exceptions import (
|
from django.core.exceptions import PermissionDenied, ValidationError
|
||||||
BadRequest, PermissionDenied, ValidationError,
|
|
||||||
)
|
|
||||||
from django.core.files.uploadedfile import UploadedFile
|
from django.core.files.uploadedfile import UploadedFile
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.http import HttpResponse, JsonResponse, QueryDict
|
from django.http import HttpResponse, JsonResponse, QueryDict
|
||||||
@@ -133,8 +131,6 @@ class AsyncMixin:
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
def get_result(self, request):
|
def get_result(self, request):
|
||||||
if not request.GET.get('async_id'):
|
|
||||||
raise BadRequest("No async_id given")
|
|
||||||
res = AsyncResult(request.GET.get('async_id'))
|
res = AsyncResult(request.GET.get('async_id'))
|
||||||
if 'ajax' in self.request.GET:
|
if 'ajax' in self.request.GET:
|
||||||
return JsonResponse(self._return_ajax_result(res, timeout=0.25))
|
return JsonResponse(self._return_ajax_result(res, timeout=0.25))
|
||||||
@@ -144,12 +140,7 @@ class AsyncMixin:
|
|||||||
return self.success(res.info)
|
return self.success(res.info)
|
||||||
else:
|
else:
|
||||||
return self.error(res.info)
|
return self.error(res.info)
|
||||||
state, info = res.state, res.info
|
return render(request, 'pretixpresale/waiting.html')
|
||||||
return render(request, 'pretixpresale/waiting.html', {
|
|
||||||
'started': state in ('PROGRESS', 'STARTED'),
|
|
||||||
'percentage': info.get('value', 0) if isinstance(info, dict) else 0,
|
|
||||||
'steps': info.get('steps', []) if isinstance(info, dict) else None,
|
|
||||||
})
|
|
||||||
|
|
||||||
def success(self, value):
|
def success(self, value):
|
||||||
smes = self.get_success_message(value)
|
smes = self.get_success_message(value)
|
||||||
@@ -217,8 +208,6 @@ class AsyncAction(AsyncMixin):
|
|||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
if 'async_id' in request.GET and settings.HAS_CELERY:
|
if 'async_id' in request.GET and settings.HAS_CELERY:
|
||||||
if not request.GET.get('async_id'):
|
|
||||||
raise BadRequest("No async_id given")
|
|
||||||
return self.get_result(request)
|
return self.get_result(request)
|
||||||
return self.http_method_not_allowed(request)
|
return self.http_method_not_allowed(request)
|
||||||
|
|
||||||
|
|||||||
@@ -1143,12 +1143,12 @@ class MailSettingsForm(FormPlaceholderMixin, SettingsForm):
|
|||||||
widget=I18nTextInput,
|
widget=I18nTextInput,
|
||||||
)
|
)
|
||||||
mail_subject_order_incomplete_payment = I18nFormField(
|
mail_subject_order_incomplete_payment = I18nFormField(
|
||||||
label=_("Subject (if an incomplete payment was received)"),
|
label=_("Subject"),
|
||||||
required=False,
|
required=False,
|
||||||
widget=I18nTextInput,
|
widget=I18nTextInput,
|
||||||
)
|
)
|
||||||
mail_text_order_incomplete_payment = I18nFormField(
|
mail_text_order_incomplete_payment = I18nFormField(
|
||||||
label=_("Text (if an incomplete payment was received)"),
|
label=_("Text"),
|
||||||
required=False,
|
required=False,
|
||||||
widget=I18nMarkdownTextarea,
|
widget=I18nMarkdownTextarea,
|
||||||
help_text=_("This email only applies to payment methods that can receive incomplete payments, "
|
help_text=_("This email only applies to payment methods that can receive incomplete payments, "
|
||||||
|
|||||||
+468
-345
@@ -47,11 +47,19 @@ from django.utils.safestring import mark_safe
|
|||||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||||
from i18nfield.strings import LazyI18nString
|
from i18nfield.strings import LazyI18nString
|
||||||
|
|
||||||
|
from pretix.base.logentrytypes import (
|
||||||
|
DiscountLogEntryType, EventLogEntryType, ItemCategoryLogEntryType,
|
||||||
|
ItemLogEntryType, LogEntryType, OrderLogEntryType, QuestionLogEntryType,
|
||||||
|
QuotaLogEntryType, TaxRuleLogEntryType, VoucherLogEntryType,
|
||||||
|
log_entry_types,
|
||||||
|
)
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
Checkin, CheckinList, Event, ItemVariation, LogEntry, OrderPosition,
|
Checkin, CheckinList, Event, ItemVariation, LogEntry, OrderPosition,
|
||||||
TaxRule,
|
TaxRule,
|
||||||
)
|
)
|
||||||
from pretix.base.signals import logentry_display, orderposition_blocked_display
|
from pretix.base.signals import (
|
||||||
|
app_cache, logentry_display, orderposition_blocked_display,
|
||||||
|
)
|
||||||
from pretix.base.templatetags.money import money_filter
|
from pretix.base.templatetags.money import money_filter
|
||||||
|
|
||||||
OVERVIEW_BANLIST = [
|
OVERVIEW_BANLIST = [
|
||||||
@@ -328,278 +336,6 @@ def _display_checkin(event, logentry):
|
|||||||
|
|
||||||
@receiver(signal=logentry_display, dispatch_uid="pretixcontrol_logentry_display")
|
@receiver(signal=logentry_display, dispatch_uid="pretixcontrol_logentry_display")
|
||||||
def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
||||||
plains = {
|
|
||||||
'pretix.object.cloned': _('This object has been created by cloning.'),
|
|
||||||
'pretix.organizer.changed': _('The organizer has been changed.'),
|
|
||||||
'pretix.organizer.settings': _('The organizer settings have been changed.'),
|
|
||||||
'pretix.organizer.footerlinks.changed': _('The footer links have been changed.'),
|
|
||||||
'pretix.organizer.export.schedule.added': _('A scheduled export has been added.'),
|
|
||||||
'pretix.organizer.export.schedule.changed': _('A scheduled export has been changed.'),
|
|
||||||
'pretix.organizer.export.schedule.deleted': _('A scheduled export has been deleted.'),
|
|
||||||
'pretix.organizer.export.schedule.executed': _('A scheduled export has been executed.'),
|
|
||||||
'pretix.organizer.export.schedule.failed': _('A scheduled export has failed: {reason}.'),
|
|
||||||
'pretix.giftcards.acceptance.added': _('Gift card acceptance for another organizer has been added.'),
|
|
||||||
'pretix.giftcards.acceptance.removed': _('Gift card acceptance for another organizer has been removed.'),
|
|
||||||
'pretix.giftcards.acceptance.acceptor.invited': _('A new gift card acceptor has been invited.'),
|
|
||||||
'pretix.giftcards.acceptance.acceptor.removed': _('A gift card acceptor has been removed.'),
|
|
||||||
'pretix.giftcards.acceptance.issuer.removed': _('A gift card issuer has been removed or declined.'),
|
|
||||||
'pretix.giftcards.acceptance.issuer.accepted': _('A new gift card issuer has been accepted.'),
|
|
||||||
'pretix.webhook.created': _('The webhook has been created.'),
|
|
||||||
'pretix.webhook.changed': _('The webhook has been changed.'),
|
|
||||||
'pretix.webhook.retries.expedited': _('The webhook call retry jobs have been manually expedited.'),
|
|
||||||
'pretix.webhook.retries.dropped': _('The webhook call retry jobs have been dropped.'),
|
|
||||||
'pretix.ssoprovider.created': _('The SSO provider has been created.'),
|
|
||||||
'pretix.ssoprovider.changed': _('The SSO provider has been changed.'),
|
|
||||||
'pretix.ssoprovider.deleted': _('The SSO provider has been deleted.'),
|
|
||||||
'pretix.ssoclient.created': _('The SSO client has been created.'),
|
|
||||||
'pretix.ssoclient.changed': _('The SSO client has been changed.'),
|
|
||||||
'pretix.ssoclient.deleted': _('The SSO client has been deleted.'),
|
|
||||||
'pretix.membershiptype.created': _('The membership type has been created.'),
|
|
||||||
'pretix.membershiptype.changed': _('The membership type has been changed.'),
|
|
||||||
'pretix.membershiptype.deleted': _('The membership type has been deleted.'),
|
|
||||||
'pretix.saleschannel.created': _('The sales channel has been created.'),
|
|
||||||
'pretix.saleschannel.changed': _('The sales channel has been changed.'),
|
|
||||||
'pretix.saleschannel.deleted': _('The sales channel has been deleted.'),
|
|
||||||
'pretix.customer.created': _('The account has been created.'),
|
|
||||||
'pretix.customer.changed': _('The account has been changed.'),
|
|
||||||
'pretix.customer.membership.created': _('A membership for this account has been added.'),
|
|
||||||
'pretix.customer.membership.changed': _('A membership of this account has been changed.'),
|
|
||||||
'pretix.customer.membership.deleted': _('A membership of this account has been deleted.'),
|
|
||||||
'pretix.customer.anonymized': _('The account has been disabled and anonymized.'),
|
|
||||||
'pretix.customer.password.resetrequested': _('A new password has been requested.'),
|
|
||||||
'pretix.customer.password.set': _('A new password has been set.'),
|
|
||||||
'pretix.reusable_medium.created': _('The reusable medium has been created.'),
|
|
||||||
'pretix.reusable_medium.created.auto': _('The reusable medium has been created automatically.'),
|
|
||||||
'pretix.reusable_medium.changed': _('The reusable medium has been changed.'),
|
|
||||||
'pretix.reusable_medium.linked_orderposition.changed': _('The medium has been connected to a new ticket.'),
|
|
||||||
'pretix.reusable_medium.linked_giftcard.changed': _('The medium has been connected to a new gift card.'),
|
|
||||||
'pretix.email.error': _('Sending of an email has failed.'),
|
|
||||||
'pretix.event.comment': _('The event\'s internal comment has been updated.'),
|
|
||||||
'pretix.event.canceled': _('The event has been canceled.'),
|
|
||||||
'pretix.event.deleted': _('An event has been deleted.'),
|
|
||||||
'pretix.event.shredder.started': _('A removal process for personal data has been started.'),
|
|
||||||
'pretix.event.shredder.completed': _('A removal process for personal data has been completed.'),
|
|
||||||
'pretix.event.order.modified': _('The order details have been changed.'),
|
|
||||||
'pretix.event.order.unpaid': _('The order has been marked as unpaid.'),
|
|
||||||
'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'),
|
|
||||||
'pretix.event.order.expirychanged': _('The order\'s expiry date has been changed.'),
|
|
||||||
'pretix.event.order.valid_if_pending.set': _('The order has been set to be usable before it is paid.'),
|
|
||||||
'pretix.event.order.valid_if_pending.unset': _('The order has been set to require payment before use.'),
|
|
||||||
'pretix.event.order.expired': _('The order has been marked as expired.'),
|
|
||||||
'pretix.event.order.paid': _('The order has been marked as paid.'),
|
|
||||||
'pretix.event.order.cancellationrequest.deleted': _('The cancellation request has been deleted.'),
|
|
||||||
'pretix.event.order.refunded': _('The order has been refunded.'),
|
|
||||||
'pretix.event.order.reactivated': _('The order has been reactivated.'),
|
|
||||||
'pretix.event.order.deleted': _('The test mode order {code} has been deleted.'),
|
|
||||||
'pretix.event.order.placed': _('The order has been created.'),
|
|
||||||
'pretix.event.order.placed.require_approval': _('The order requires approval before it can continue to be processed.'),
|
|
||||||
'pretix.event.order.approved': _('The order has been approved.'),
|
|
||||||
'pretix.event.order.denied': _('The order has been denied (comment: "{comment}").'),
|
|
||||||
'pretix.event.order.contact.changed': _('The email address has been changed from "{old_email}" '
|
|
||||||
'to "{new_email}".'),
|
|
||||||
'pretix.event.order.contact.confirmed': _('The email address has been confirmed to be working (the user clicked on a link '
|
|
||||||
'in the email for the first time).'),
|
|
||||||
'pretix.event.order.phone.changed': _('The phone number has been changed from "{old_phone}" '
|
|
||||||
'to "{new_phone}".'),
|
|
||||||
'pretix.event.order.customer.changed': _('The customer account has been changed.'),
|
|
||||||
'pretix.event.order.locale.changed': _('The order locale has been changed.'),
|
|
||||||
'pretix.event.order.invoice.generated': _('The invoice has been generated.'),
|
|
||||||
'pretix.event.order.invoice.regenerated': _('The invoice has been regenerated.'),
|
|
||||||
'pretix.event.order.invoice.reissued': _('The invoice has been reissued.'),
|
|
||||||
'pretix.event.order.comment': _('The order\'s internal comment has been updated.'),
|
|
||||||
'pretix.event.order.custom_followup_at': _('The order\'s follow-up date has been updated.'),
|
|
||||||
'pretix.event.order.checkin_attention': _('The order\'s flag to require attention at check-in has been '
|
|
||||||
'toggled.'),
|
|
||||||
'pretix.event.order.checkin_text': _('The order\'s check-in text has been changed.'),
|
|
||||||
'pretix.event.order.pretix.event.order.valid_if_pending': _('The order\'s flag to be considered valid even if '
|
|
||||||
'unpaid has been toggled.'),
|
|
||||||
'pretix.event.order.payment.changed': _('A new payment {local_id} has been started instead of the previous one.'),
|
|
||||||
'pretix.event.order.email.sent': _('An unidentified type email has been sent.'),
|
|
||||||
'pretix.event.order.email.error': _('Sending of an email has failed.'),
|
|
||||||
'pretix.event.order.email.attachments.skipped': _('The email has been sent without attached tickets since they '
|
|
||||||
'would have been too large to be likely to arrive.'),
|
|
||||||
'pretix.event.order.email.custom_sent': _('A custom email has been sent.'),
|
|
||||||
'pretix.event.order.position.email.custom_sent': _('A custom email has been sent to an attendee.'),
|
|
||||||
'pretix.event.order.email.download_reminder_sent': _('An email has been sent with a reminder that the ticket '
|
|
||||||
'is available for download.'),
|
|
||||||
'pretix.event.order.email.expire_warning_sent': _('An email has been sent with a warning that the order is about '
|
|
||||||
'to expire.'),
|
|
||||||
'pretix.event.order.email.order_canceled': _('An email has been sent to notify the user that the order has been canceled.'),
|
|
||||||
'pretix.event.order.email.event_canceled': _('An email has been sent to notify the user that the event has '
|
|
||||||
'been canceled.'),
|
|
||||||
'pretix.event.order.email.order_changed': _('An email has been sent to notify the user that the order has been changed.'),
|
|
||||||
'pretix.event.order.email.order_free': _('An email has been sent to notify the user that the order has been received.'),
|
|
||||||
'pretix.event.order.email.order_paid': _('An email has been sent to notify the user that payment has been received.'),
|
|
||||||
'pretix.event.order.email.order_denied': _('An email has been sent to notify the user that the order has been denied.'),
|
|
||||||
'pretix.event.order.email.order_approved': _('An email has been sent to notify the user that the order has '
|
|
||||||
'been approved.'),
|
|
||||||
'pretix.event.order.email.order_placed': _('An email has been sent to notify the user that the order has been received and requires payment.'),
|
|
||||||
'pretix.event.order.email.order_placed_require_approval': _('An email has been sent to notify the user that '
|
|
||||||
'the order has been received and requires '
|
|
||||||
'approval.'),
|
|
||||||
'pretix.event.order.email.resend': _('An email with a link to the order detail page has been resent to the user.'),
|
|
||||||
'pretix.event.order.email.payment_failed': _('An email has been sent to notify the user that the payment failed.'),
|
|
||||||
'pretix.event.order.payment.confirmed': _('Payment {local_id} has been confirmed.'),
|
|
||||||
'pretix.event.order.payment.canceled': _('Payment {local_id} has been canceled.'),
|
|
||||||
'pretix.event.order.payment.canceled.failed': _('Canceling payment {local_id} has failed.'),
|
|
||||||
'pretix.event.order.payment.started': _('Payment {local_id} has been started.'),
|
|
||||||
'pretix.event.order.payment.failed': _('Payment {local_id} has failed.'),
|
|
||||||
'pretix.event.order.quotaexceeded': _('The order could not be marked as paid: {message}'),
|
|
||||||
'pretix.event.order.overpaid': _('The order has been overpaid.'),
|
|
||||||
'pretix.event.order.refund.created': _('Refund {local_id} has been created.'),
|
|
||||||
'pretix.event.order.refund.created.externally': _('Refund {local_id} has been created by an external entity.'),
|
|
||||||
'pretix.event.order.refund.requested': _('The customer requested you to issue a refund.'),
|
|
||||||
'pretix.event.order.refund.done': _('Refund {local_id} has been completed.'),
|
|
||||||
'pretix.event.order.refund.canceled': _('Refund {local_id} has been canceled.'),
|
|
||||||
'pretix.event.order.refund.failed': _('Refund {local_id} has failed.'),
|
|
||||||
'pretix.event.export.schedule.added': _('A scheduled export has been added.'),
|
|
||||||
'pretix.event.export.schedule.changed': _('A scheduled export has been changed.'),
|
|
||||||
'pretix.event.export.schedule.deleted': _('A scheduled export has been deleted.'),
|
|
||||||
'pretix.event.export.schedule.executed': _('A scheduled export has been executed.'),
|
|
||||||
'pretix.event.export.schedule.failed': _('A scheduled export has failed: {reason}.'),
|
|
||||||
'pretix.control.auth.user.created': _('The user has been created.'),
|
|
||||||
'pretix.control.auth.user.new_source': _('A first login using {agent_type} on {os_type} from {country} has '
|
|
||||||
'been detected.'),
|
|
||||||
'pretix.user.settings.2fa.enabled': _('Two-factor authentication has been enabled.'),
|
|
||||||
'pretix.user.settings.2fa.disabled': _('Two-factor authentication has been disabled.'),
|
|
||||||
'pretix.user.settings.2fa.regenemergency': _('Your two-factor emergency codes have been regenerated.'),
|
|
||||||
'pretix.user.settings.2fa.emergency': _('A two-factor emergency code has been generated.'),
|
|
||||||
'pretix.user.settings.2fa.device.added': _('A new two-factor authentication device "{name}" has been added to '
|
|
||||||
'your account.'),
|
|
||||||
'pretix.user.settings.2fa.device.deleted': _('The two-factor authentication device "{name}" has been removed '
|
|
||||||
'from your account.'),
|
|
||||||
'pretix.user.settings.notifications.enabled': _('Notifications have been enabled.'),
|
|
||||||
'pretix.user.settings.notifications.disabled': _('Notifications have been disabled.'),
|
|
||||||
'pretix.user.settings.notifications.changed': _('Your notification settings have been changed.'),
|
|
||||||
'pretix.user.anonymized': _('This user has been anonymized.'),
|
|
||||||
'pretix.user.oauth.authorized': _('The application "{application_name}" has been authorized to access your '
|
|
||||||
'account.'),
|
|
||||||
'pretix.control.auth.user.forgot_password.mail_sent': _('Password reset mail sent.'),
|
|
||||||
'pretix.control.auth.user.forgot_password.recovered': _('The password has been reset.'),
|
|
||||||
'pretix.control.auth.user.forgot_password.denied.repeated': _('A repeated password reset has been denied, as '
|
|
||||||
'the last request was less than 24 hours ago.'),
|
|
||||||
'pretix.organizer.deleted': _('The organizer "{name}" has been deleted.'),
|
|
||||||
'pretix.voucher.added': _('The voucher has been created.'),
|
|
||||||
'pretix.voucher.sent': _('The voucher has been sent to {recipient}.'),
|
|
||||||
'pretix.voucher.added.waitinglist': _('The voucher has been created and sent to a person on the waiting list.'),
|
|
||||||
'pretix.voucher.expired.waitinglist': _('The voucher has been set to expire because the recipient removed themselves from the waiting list.'),
|
|
||||||
'pretix.voucher.changed': _('The voucher has been changed.'),
|
|
||||||
'pretix.voucher.deleted': _('The voucher has been deleted.'),
|
|
||||||
'pretix.voucher.redeemed': _('The voucher has been redeemed in order {order_code}.'),
|
|
||||||
'pretix.event.item.added': _('The product has been created.'),
|
|
||||||
'pretix.event.item.changed': _('The product has been changed.'),
|
|
||||||
'pretix.event.item.reordered': _('The product has been reordered.'),
|
|
||||||
'pretix.event.item.deleted': _('The product has been deleted.'),
|
|
||||||
'pretix.event.item.variation.added': _('The variation "{value}" has been created.'),
|
|
||||||
'pretix.event.item.variation.deleted': _('The variation "{value}" has been deleted.'),
|
|
||||||
'pretix.event.item.variation.changed': _('The variation "{value}" has been changed.'),
|
|
||||||
'pretix.event.item.addons.added': _('An add-on has been added to this product.'),
|
|
||||||
'pretix.event.item.addons.removed': _('An add-on has been removed from this product.'),
|
|
||||||
'pretix.event.item.addons.changed': _('An add-on has been changed on this product.'),
|
|
||||||
'pretix.event.item.bundles.added': _('A bundled item has been added to this product.'),
|
|
||||||
'pretix.event.item.bundles.removed': _('A bundled item has been removed from this product.'),
|
|
||||||
'pretix.event.item.bundles.changed': _('A bundled item has been changed on this product.'),
|
|
||||||
'pretix.event.item_meta_property.added': _('A meta property has been added to this event.'),
|
|
||||||
'pretix.event.item_meta_property.deleted': _('A meta property has been removed from this event.'),
|
|
||||||
'pretix.event.item_meta_property.changed': _('A meta property has been changed on this event.'),
|
|
||||||
'pretix.event.quota.added': _('The quota has been added.'),
|
|
||||||
'pretix.event.quota.deleted': _('The quota has been deleted.'),
|
|
||||||
'pretix.event.quota.changed': _('The quota has been changed.'),
|
|
||||||
'pretix.event.quota.closed': _('The quota has closed.'),
|
|
||||||
'pretix.event.quota.opened': _('The quota has been re-opened.'),
|
|
||||||
'pretix.event.category.added': _('The category has been added.'),
|
|
||||||
'pretix.event.category.deleted': _('The category has been deleted.'),
|
|
||||||
'pretix.event.category.changed': _('The category has been changed.'),
|
|
||||||
'pretix.event.category.reordered': _('The category has been reordered.'),
|
|
||||||
'pretix.event.question.added': _('The question has been added.'),
|
|
||||||
'pretix.event.question.deleted': _('The question has been deleted.'),
|
|
||||||
'pretix.event.question.changed': _('The question has been changed.'),
|
|
||||||
'pretix.event.question.reordered': _('The question has been reordered.'),
|
|
||||||
'pretix.event.discount.added': _('The discount has been added.'),
|
|
||||||
'pretix.event.discount.deleted': _('The discount has been deleted.'),
|
|
||||||
'pretix.event.discount.changed': _('The discount has been changed.'),
|
|
||||||
'pretix.event.taxrule.added': _('The tax rule has been added.'),
|
|
||||||
'pretix.event.taxrule.deleted': _('The tax rule has been deleted.'),
|
|
||||||
'pretix.event.taxrule.changed': _('The tax rule has been changed.'),
|
|
||||||
'pretix.event.checkinlist.added': _('The check-in list has been added.'),
|
|
||||||
'pretix.event.checkinlist.deleted': _('The check-in list has been deleted.'),
|
|
||||||
'pretix.event.checkinlists.deleted': _('The check-in list has been deleted.'), # backwards compatibility
|
|
||||||
'pretix.event.checkinlist.changed': _('The check-in list has been changed.'),
|
|
||||||
'pretix.event.settings': _('The event settings have been changed.'),
|
|
||||||
'pretix.event.tickets.settings': _('The ticket download settings have been changed.'),
|
|
||||||
'pretix.event.plugins.enabled': _('A plugin has been enabled.'),
|
|
||||||
'pretix.event.plugins.disabled': _('A plugin has been disabled.'),
|
|
||||||
'pretix.event.live.activated': _('The shop has been taken live.'),
|
|
||||||
'pretix.event.live.deactivated': _('The shop has been taken offline.'),
|
|
||||||
'pretix.event.testmode.activated': _('The shop has been taken into test mode.'),
|
|
||||||
'pretix.event.testmode.deactivated': _('The test mode has been disabled.'),
|
|
||||||
'pretix.event.added': _('The event has been created.'),
|
|
||||||
'pretix.event.changed': _('The event details have been changed.'),
|
|
||||||
'pretix.event.footerlinks.changed': _('The footer links have been changed.'),
|
|
||||||
'pretix.event.question.option.added': _('An answer option has been added to the question.'),
|
|
||||||
'pretix.event.question.option.deleted': _('An answer option has been removed from the question.'),
|
|
||||||
'pretix.event.question.option.changed': _('An answer option has been changed.'),
|
|
||||||
'pretix.event.permissions.added': _('A user has been added to the event team.'),
|
|
||||||
'pretix.event.permissions.invited': _('A user has been invited to the event team.'),
|
|
||||||
'pretix.event.permissions.changed': _('A user\'s permissions have been changed.'),
|
|
||||||
'pretix.event.permissions.deleted': _('A user has been removed from the event team.'),
|
|
||||||
'pretix.waitinglist.voucher': _('A voucher has been sent to a person on the waiting list.'), # legacy
|
|
||||||
'pretix.event.orders.waitinglist.voucher_assigned': _('A voucher has been sent to a person on the waiting list.'),
|
|
||||||
'pretix.event.orders.waitinglist.deleted': _('An entry has been removed from the waiting list.'),
|
|
||||||
'pretix.event.order.waitinglist.transferred': _('An entry has been transferred to another waiting list.'), # legacy
|
|
||||||
'pretix.event.orders.waitinglist.changed': _('An entry has been changed on the waiting list.'),
|
|
||||||
'pretix.event.orders.waitinglist.added': _('An entry has been added to the waiting list.'),
|
|
||||||
'pretix.team.created': _('The team has been created.'),
|
|
||||||
'pretix.team.changed': _('The team settings have been changed.'),
|
|
||||||
'pretix.team.deleted': _('The team has been deleted.'),
|
|
||||||
'pretix.gate.created': _('The gate has been created.'),
|
|
||||||
'pretix.gate.changed': _('The gate has been changed.'),
|
|
||||||
'pretix.gate.deleted': _('The gate has been deleted.'),
|
|
||||||
'pretix.subevent.deleted': pgettext_lazy('subevent', 'The event date has been deleted.'),
|
|
||||||
'pretix.subevent.canceled': pgettext_lazy('subevent', 'The event date has been canceled.'),
|
|
||||||
'pretix.subevent.changed': pgettext_lazy('subevent', 'The event date has been changed.'),
|
|
||||||
'pretix.subevent.added': pgettext_lazy('subevent', 'The event date has been created.'),
|
|
||||||
'pretix.subevent.quota.added': pgettext_lazy('subevent', 'A quota has been added to the event date.'),
|
|
||||||
'pretix.subevent.quota.changed': pgettext_lazy('subevent', 'A quota has been changed on the event date.'),
|
|
||||||
'pretix.subevent.quota.deleted': pgettext_lazy('subevent', 'A quota has been removed from the event date.'),
|
|
||||||
'pretix.device.created': _('The device has been created.'),
|
|
||||||
'pretix.device.changed': _('The device has been changed.'),
|
|
||||||
'pretix.device.revoked': _('Access of the device has been revoked.'),
|
|
||||||
'pretix.device.initialized': _('The device has been initialized.'),
|
|
||||||
'pretix.device.keyroll': _('The access token of the device has been regenerated.'),
|
|
||||||
'pretix.device.updated': _('The device has notified the server of an hardware or software update.'),
|
|
||||||
'pretix.giftcards.created': _('The gift card has been created.'),
|
|
||||||
'pretix.giftcards.modified': _('The gift card has been changed.'),
|
|
||||||
'pretix.giftcards.transaction.manual': _('A manual transaction has been performed.'),
|
|
||||||
}
|
|
||||||
|
|
||||||
data = json.loads(logentry.data)
|
|
||||||
|
|
||||||
if logentry.action_type.startswith('pretix.event.item.variation'):
|
|
||||||
if 'value' not in data:
|
|
||||||
# Backwards compatibility
|
|
||||||
var = ItemVariation.objects.filter(id=data['id']).first()
|
|
||||||
if var:
|
|
||||||
data['value'] = str(var.value)
|
|
||||||
else:
|
|
||||||
data['value'] = '?'
|
|
||||||
else:
|
|
||||||
data['value'] = LazyI18nString(data['value'])
|
|
||||||
|
|
||||||
if logentry.action_type == "pretix.voucher.redeemed":
|
|
||||||
data = defaultdict(lambda: '?', data)
|
|
||||||
url = reverse('control:event.order', kwargs={
|
|
||||||
'event': logentry.event.slug,
|
|
||||||
'organizer': logentry.event.organizer.slug,
|
|
||||||
'code': data['order_code']
|
|
||||||
})
|
|
||||||
return mark_safe(plains[logentry.action_type].format(
|
|
||||||
order_code='<a href="{}">{}</a>'.format(url, data['order_code']),
|
|
||||||
))
|
|
||||||
|
|
||||||
if logentry.action_type in plains:
|
|
||||||
data = defaultdict(lambda: '?', data)
|
|
||||||
return plains[logentry.action_type].format_map(data)
|
|
||||||
|
|
||||||
if logentry.action_type.startswith('pretix.event.order.changed'):
|
if logentry.action_type.startswith('pretix.event.order.changed'):
|
||||||
return _display_order_changed(sender, logentry)
|
return _display_order_changed(sender, logentry)
|
||||||
@@ -623,91 +359,22 @@ def pretixcontrol_logentry_display(sender: Event, logentry: LogEntry, **kwargs):
|
|||||||
return _('The order has been canceled.')
|
return _('The order has been canceled.')
|
||||||
|
|
||||||
if logentry.action_type in ('pretix.control.views.checkin.reverted', 'pretix.event.checkin.reverted'):
|
if logentry.action_type in ('pretix.control.views.checkin.reverted', 'pretix.event.checkin.reverted'):
|
||||||
if 'list' in data:
|
if 'list' in logentry.parsed_data:
|
||||||
try:
|
try:
|
||||||
checkin_list = sender.checkin_lists.get(pk=data.get('list')).name
|
checkin_list = sender.checkin_lists.get(pk=logentry.parsed_data.get('list')).name
|
||||||
except CheckinList.DoesNotExist:
|
except CheckinList.DoesNotExist:
|
||||||
checkin_list = _("(unknown)")
|
checkin_list = _("(unknown)")
|
||||||
else:
|
else:
|
||||||
checkin_list = _("(unknown)")
|
checkin_list = _("(unknown)")
|
||||||
|
|
||||||
return _('The check-in of position #{posid} on list "{list}" has been reverted.').format(
|
return _('The check-in of position #{posid} on list "{list}" has been reverted.').format(
|
||||||
posid=data.get('positionid'),
|
posid=logentry.parsed_data.get('positionid'),
|
||||||
list=checkin_list,
|
list=checkin_list,
|
||||||
)
|
)
|
||||||
|
|
||||||
if sender and logentry.action_type.startswith('pretix.event.checkin'):
|
if sender and logentry.action_type.startswith('pretix.event.checkin'):
|
||||||
return _display_checkin(sender, logentry)
|
return _display_checkin(sender, logentry)
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.control.views.checkin':
|
|
||||||
# deprecated
|
|
||||||
dt = dateutil.parser.parse(data.get('datetime'))
|
|
||||||
tz = sender.timezone
|
|
||||||
dt_formatted = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT")
|
|
||||||
if 'list' in data:
|
|
||||||
try:
|
|
||||||
checkin_list = sender.checkin_lists.get(pk=data.get('list')).name
|
|
||||||
except CheckinList.DoesNotExist:
|
|
||||||
checkin_list = _("(unknown)")
|
|
||||||
else:
|
|
||||||
checkin_list = _("(unknown)")
|
|
||||||
|
|
||||||
if data.get('first'):
|
|
||||||
return _('Position #{posid} has been checked in manually at {datetime} on list "{list}".').format(
|
|
||||||
posid=data.get('positionid'),
|
|
||||||
datetime=dt_formatted,
|
|
||||||
list=checkin_list,
|
|
||||||
)
|
|
||||||
return _('Position #{posid} has been checked in again at {datetime} on list "{list}".').format(
|
|
||||||
posid=data.get('positionid'),
|
|
||||||
datetime=dt_formatted,
|
|
||||||
list=checkin_list
|
|
||||||
)
|
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.team.member.added':
|
|
||||||
return _('{user} has been added to the team.').format(user=data.get('email'))
|
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.team.member.removed':
|
|
||||||
return _('{user} has been removed from the team.').format(user=data.get('email'))
|
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.team.member.joined':
|
|
||||||
return _('{user} has joined the team using the invite sent to {email}.').format(
|
|
||||||
user=data.get('email'), email=data.get('invite_email')
|
|
||||||
)
|
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.team.invite.created':
|
|
||||||
return _('{user} has been invited to the team.').format(user=data.get('email'))
|
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.team.invite.resent':
|
|
||||||
return _('Invite for {user} has been resent.').format(user=data.get('email'))
|
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.team.invite.deleted':
|
|
||||||
return _('The invite for {user} has been revoked.').format(user=data.get('email'))
|
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.team.token.created':
|
|
||||||
return _('The token "{name}" has been created.').format(name=data.get('name'))
|
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.team.token.deleted':
|
|
||||||
return _('The token "{name}" has been revoked.').format(name=data.get('name'))
|
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.user.settings.changed':
|
|
||||||
text = str(_('Your account settings have been changed.'))
|
|
||||||
if 'email' in data:
|
|
||||||
text = text + ' ' + str(_('Your email address has been changed to {email}.').format(email=data['email']))
|
|
||||||
if 'new_pw' in data:
|
|
||||||
text = text + ' ' + str(_('Your password has been changed.'))
|
|
||||||
if data.get('is_active') is True:
|
|
||||||
text = text + ' ' + str(_('Your account has been enabled.'))
|
|
||||||
elif data.get('is_active') is False:
|
|
||||||
text = text + ' ' + str(_('Your account has been disabled.'))
|
|
||||||
return text
|
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.control.auth.user.impersonated':
|
|
||||||
return str(_('You impersonated {}.')).format(data['other_email'])
|
|
||||||
|
|
||||||
if logentry.action_type == 'pretix.control.auth.user.impersonate_stopped':
|
|
||||||
return str(_('You stopped impersonating {}.')).format(data['other_email'])
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(signal=orderposition_blocked_display, dispatch_uid="pretixcontrol_orderposition_blocked_display")
|
@receiver(signal=orderposition_blocked_display, dispatch_uid="pretixcontrol_orderposition_blocked_display")
|
||||||
def pretixcontrol_orderposition_blocked_display(sender: Event, orderposition, block_name, **kwargs):
|
def pretixcontrol_orderposition_blocked_display(sender: Event, orderposition, block_name, **kwargs):
|
||||||
@@ -715,3 +382,459 @@ def pretixcontrol_orderposition_blocked_display(sender: Event, orderposition, bl
|
|||||||
return _('Blocked manually')
|
return _('Blocked manually')
|
||||||
elif block_name.startswith('api:'):
|
elif block_name.startswith('api:'):
|
||||||
return _('Blocked because of an API integration')
|
return _('Blocked because of an API integration')
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.event.order.modified': _('The order details have been changed.'),
|
||||||
|
'pretix.event.order.unpaid': _('The order has been marked as unpaid.'),
|
||||||
|
'pretix.event.order.secret.changed': _('The order\'s secret has been changed.'),
|
||||||
|
'pretix.event.order.expirychanged': _('The order\'s expiry date has been changed.'),
|
||||||
|
'pretix.event.order.valid_if_pending.set': _('The order has been set to be usable before it is paid.'),
|
||||||
|
'pretix.event.order.valid_if_pending.unset': _('The order has been set to require payment before use.'),
|
||||||
|
'pretix.event.order.expired': _('The order has been marked as expired.'),
|
||||||
|
'pretix.event.order.paid': _('The order has been marked as paid.'),
|
||||||
|
'pretix.event.order.cancellationrequest.deleted': _('The cancellation request has been deleted.'),
|
||||||
|
'pretix.event.order.refunded': _('The order has been refunded.'),
|
||||||
|
'pretix.event.order.reactivated': _('The order has been reactivated.'),
|
||||||
|
'pretix.event.order.deleted': _('The test mode order {code} has been deleted.'),
|
||||||
|
'pretix.event.order.placed': _('The order has been created.'),
|
||||||
|
'pretix.event.order.placed.require_approval': _(
|
||||||
|
'The order requires approval before it can continue to be processed.'),
|
||||||
|
'pretix.event.order.approved': _('The order has been approved.'),
|
||||||
|
'pretix.event.order.denied': _('The order has been denied (comment: "{comment}").'),
|
||||||
|
'pretix.event.order.contact.changed': _('The email address has been changed from "{old_email}" '
|
||||||
|
'to "{new_email}".'),
|
||||||
|
'pretix.event.order.contact.confirmed': _(
|
||||||
|
'The email address has been confirmed to be working (the user clicked on a link '
|
||||||
|
'in the email for the first time).'),
|
||||||
|
'pretix.event.order.phone.changed': _('The phone number has been changed from "{old_phone}" '
|
||||||
|
'to "{new_phone}".'),
|
||||||
|
'pretix.event.order.customer.changed': _('The customer account has been changed.'),
|
||||||
|
'pretix.event.order.locale.changed': _('The order locale has been changed.'),
|
||||||
|
'pretix.event.order.invoice.generated': _('The invoice has been generated.'),
|
||||||
|
'pretix.event.order.invoice.regenerated': _('The invoice has been regenerated.'),
|
||||||
|
'pretix.event.order.invoice.reissued': _('The invoice has been reissued.'),
|
||||||
|
'pretix.event.order.comment': _('The order\'s internal comment has been updated.'),
|
||||||
|
'pretix.event.order.custom_followup_at': _('The order\'s follow-up date has been updated.'),
|
||||||
|
'pretix.event.order.checkin_attention': _('The order\'s flag to require attention at check-in has been '
|
||||||
|
'toggled.'),
|
||||||
|
'pretix.event.order.checkin_text': _('The order\'s check-in text has been changed.'),
|
||||||
|
'pretix.event.order.pretix.event.order.valid_if_pending': _('The order\'s flag to be considered valid even if '
|
||||||
|
'unpaid has been toggled.'),
|
||||||
|
'pretix.event.order.payment.changed': _('A new payment {local_id} has been started instead of the previous one.'),
|
||||||
|
'pretix.event.order.email.sent': _('An unidentified type email has been sent.'),
|
||||||
|
'pretix.event.order.email.error': _('Sending of an email has failed.'),
|
||||||
|
'pretix.event.order.email.attachments.skipped': _('The email has been sent without attached tickets since they '
|
||||||
|
'would have been too large to be likely to arrive.'),
|
||||||
|
'pretix.event.order.email.custom_sent': _('A custom email has been sent.'),
|
||||||
|
'pretix.event.order.position.email.custom_sent': _('A custom email has been sent to an attendee.'),
|
||||||
|
'pretix.event.order.email.download_reminder_sent': _('An email has been sent with a reminder that the ticket '
|
||||||
|
'is available for download.'),
|
||||||
|
'pretix.event.order.email.expire_warning_sent': _('An email has been sent with a warning that the order is about '
|
||||||
|
'to expire.'),
|
||||||
|
'pretix.event.order.email.order_canceled': _(
|
||||||
|
'An email has been sent to notify the user that the order has been canceled.'),
|
||||||
|
'pretix.event.order.email.event_canceled': _('An email has been sent to notify the user that the event has '
|
||||||
|
'been canceled.'),
|
||||||
|
'pretix.event.order.email.order_changed': _(
|
||||||
|
'An email has been sent to notify the user that the order has been changed.'),
|
||||||
|
'pretix.event.order.email.order_free': _(
|
||||||
|
'An email has been sent to notify the user that the order has been received.'),
|
||||||
|
'pretix.event.order.email.order_paid': _(
|
||||||
|
'An email has been sent to notify the user that payment has been received.'),
|
||||||
|
'pretix.event.order.email.order_denied': _(
|
||||||
|
'An email has been sent to notify the user that the order has been denied.'),
|
||||||
|
'pretix.event.order.email.order_approved': _('An email has been sent to notify the user that the order has '
|
||||||
|
'been approved.'),
|
||||||
|
'pretix.event.order.email.order_placed': _(
|
||||||
|
'An email has been sent to notify the user that the order has been received and requires payment.'),
|
||||||
|
'pretix.event.order.email.order_placed_require_approval': _('An email has been sent to notify the user that '
|
||||||
|
'the order has been received and requires '
|
||||||
|
'approval.'),
|
||||||
|
'pretix.event.order.email.resend': _('An email with a link to the order detail page has been resent to the user.'),
|
||||||
|
'pretix.event.order.email.payment_failed': _('An email has been sent to notify the user that the payment failed.'),
|
||||||
|
})
|
||||||
|
class CoreOrderLogEntryType(OrderLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.voucher.added': _('The voucher has been created.'),
|
||||||
|
'pretix.voucher.sent': _('The voucher has been sent to {recipient}.'),
|
||||||
|
'pretix.voucher.added.waitinglist': _('The voucher has been created and sent to a person on the waiting list.'),
|
||||||
|
'pretix.voucher.expired.waitinglist': _(
|
||||||
|
'The voucher has been set to expire because the recipient removed themselves from the waiting list.'),
|
||||||
|
'pretix.voucher.changed': _('The voucher has been changed.'),
|
||||||
|
'pretix.voucher.deleted': _('The voucher has been deleted.'),
|
||||||
|
})
|
||||||
|
class CoreVoucherLogEntryType(VoucherLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new()
|
||||||
|
class VoucherRedeemedLogEntryType(VoucherLogEntryType):
|
||||||
|
action_type = 'pretix.voucher.redeemed'
|
||||||
|
plain = _('The voucher has been redeemed in order {order_code}.')
|
||||||
|
|
||||||
|
def display(self, logentry):
|
||||||
|
data = json.loads(logentry.data)
|
||||||
|
data = defaultdict(lambda: '?', data)
|
||||||
|
url = reverse('control:event.order', kwargs={
|
||||||
|
'event': logentry.event.slug,
|
||||||
|
'organizer': logentry.event.organizer.slug,
|
||||||
|
'code': data['order_code']
|
||||||
|
})
|
||||||
|
return mark_safe(self.plain.format(
|
||||||
|
order_code='<a href="{}">{}</a>'.format(url, data['order_code']),
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.event.category.added': _('The category has been added.'),
|
||||||
|
'pretix.event.category.deleted': _('The category has been deleted.'),
|
||||||
|
'pretix.event.category.changed': _('The category has been changed.'),
|
||||||
|
'pretix.event.category.reordered': _('The category has been reordered.'),
|
||||||
|
})
|
||||||
|
class CoreItemCategoryLogEntryType(ItemCategoryLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.event.taxrule.added': _('The tax rule has been added.'),
|
||||||
|
'pretix.event.taxrule.deleted': _('The tax rule has been deleted.'),
|
||||||
|
'pretix.event.taxrule.changed': _('The tax rule has been changed.'),
|
||||||
|
})
|
||||||
|
class CoreTaxRuleLogEntryType(TaxRuleLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TeamMembershipLogEntryType(LogEntryType):
|
||||||
|
def display(self, logentry):
|
||||||
|
return self.plain.format(user=logentry.parsed_data.get('email'))
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.team.member.added': _('{user} has been added to the team.'),
|
||||||
|
'pretix.team.member.removed': _('{user} has been removed from the team.'),
|
||||||
|
'pretix.team.invite.created': _('{user} has been invited to the team.'),
|
||||||
|
'pretix.team.invite.resent': _('Invite for {user} has been resent.'),
|
||||||
|
})
|
||||||
|
class CoreTeamMembershipLogEntryType(TeamMembershipLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new()
|
||||||
|
class TeamMemberJoinedLogEntryType(LogEntryType):
|
||||||
|
action_type = 'pretix.team.member.joined'
|
||||||
|
|
||||||
|
def display(self, logentry):
|
||||||
|
return _('{user} has joined the team using the invite sent to {email}.').format(
|
||||||
|
user=logentry.parsed_data.get('email'), email=logentry.parsed_data.get('invite_email')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new()
|
||||||
|
class UserSettingsChangedLogEntryType(LogEntryType):
|
||||||
|
action_type = 'pretix.user.settings.changed'
|
||||||
|
|
||||||
|
def display(self, logentry):
|
||||||
|
text = str(_('Your account settings have been changed.'))
|
||||||
|
if 'email' in logentry.parsed_data:
|
||||||
|
text = text + ' ' + str(
|
||||||
|
_('Your email address has been changed to {email}.').format(email=logentry.parsed_data['email']))
|
||||||
|
if 'new_pw' in logentry.parsed_data:
|
||||||
|
text = text + ' ' + str(_('Your password has been changed.'))
|
||||||
|
if logentry.parsed_data.get('is_active') is True:
|
||||||
|
text = text + ' ' + str(_('Your account has been enabled.'))
|
||||||
|
elif logentry.parsed_data.get('is_active') is False:
|
||||||
|
text = text + ' ' + str(_('Your account has been disabled.'))
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
class UserImpersonatedLogEntryType(LogEntryType):
|
||||||
|
def display(self, logentry):
|
||||||
|
return self.plain.format(logentry.parsed_data['other_email'])
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.control.auth.user.impersonated': _('You impersonated {}.'),
|
||||||
|
'pretix.control.auth.user.impersonate_stopped': _('You stopped impersonating {}.'),
|
||||||
|
})
|
||||||
|
class CoreUserImpersonatedLogEntryType(UserImpersonatedLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.object.cloned': _('This object has been created by cloning.'),
|
||||||
|
'pretix.organizer.changed': _('The organizer has been changed.'),
|
||||||
|
'pretix.organizer.settings': _('The organizer settings have been changed.'),
|
||||||
|
'pretix.organizer.footerlinks.changed': _('The footer links have been changed.'),
|
||||||
|
'pretix.organizer.export.schedule.added': _('A scheduled export has been added.'),
|
||||||
|
'pretix.organizer.export.schedule.changed': _('A scheduled export has been changed.'),
|
||||||
|
'pretix.organizer.export.schedule.deleted': _('A scheduled export has been deleted.'),
|
||||||
|
'pretix.organizer.export.schedule.executed': _('A scheduled export has been executed.'),
|
||||||
|
'pretix.organizer.export.schedule.failed': _('A scheduled export has failed: {reason}.'),
|
||||||
|
'pretix.giftcards.acceptance.added': _('Gift card acceptance for another organizer has been added.'),
|
||||||
|
'pretix.giftcards.acceptance.removed': _('Gift card acceptance for another organizer has been removed.'),
|
||||||
|
'pretix.giftcards.acceptance.acceptor.invited': _('A new gift card acceptor has been invited.'),
|
||||||
|
'pretix.giftcards.acceptance.acceptor.removed': _('A gift card acceptor has been removed.'),
|
||||||
|
'pretix.giftcards.acceptance.issuer.removed': _('A gift card issuer has been removed or declined.'),
|
||||||
|
'pretix.giftcards.acceptance.issuer.accepted': _('A new gift card issuer has been accepted.'),
|
||||||
|
'pretix.webhook.created': _('The webhook has been created.'),
|
||||||
|
'pretix.webhook.changed': _('The webhook has been changed.'),
|
||||||
|
'pretix.webhook.retries.expedited': _('The webhook call retry jobs have been manually expedited.'),
|
||||||
|
'pretix.webhook.retries.dropped': _('The webhook call retry jobs have been dropped.'),
|
||||||
|
'pretix.ssoprovider.created': _('The SSO provider has been created.'),
|
||||||
|
'pretix.ssoprovider.changed': _('The SSO provider has been changed.'),
|
||||||
|
'pretix.ssoprovider.deleted': _('The SSO provider has been deleted.'),
|
||||||
|
'pretix.ssoclient.created': _('The SSO client has been created.'),
|
||||||
|
'pretix.ssoclient.changed': _('The SSO client has been changed.'),
|
||||||
|
'pretix.ssoclient.deleted': _('The SSO client has been deleted.'),
|
||||||
|
'pretix.membershiptype.created': _('The membership type has been created.'),
|
||||||
|
'pretix.membershiptype.changed': _('The membership type has been changed.'),
|
||||||
|
'pretix.membershiptype.deleted': _('The membership type has been deleted.'),
|
||||||
|
'pretix.saleschannel.created': _('The sales channel has been created.'),
|
||||||
|
'pretix.saleschannel.changed': _('The sales channel has been changed.'),
|
||||||
|
'pretix.saleschannel.deleted': _('The sales channel has been deleted.'),
|
||||||
|
'pretix.customer.created': _('The account has been created.'),
|
||||||
|
'pretix.customer.changed': _('The account has been changed.'),
|
||||||
|
'pretix.customer.membership.created': _('A membership for this account has been added.'),
|
||||||
|
'pretix.customer.membership.changed': _('A membership of this account has been changed.'),
|
||||||
|
'pretix.customer.membership.deleted': _('A membership of this account has been deleted.'),
|
||||||
|
'pretix.customer.anonymized': _('The account has been disabled and anonymized.'),
|
||||||
|
'pretix.customer.password.resetrequested': _('A new password has been requested.'),
|
||||||
|
'pretix.customer.password.set': _('A new password has been set.'),
|
||||||
|
'pretix.reusable_medium.created': _('The reusable medium has been created.'),
|
||||||
|
'pretix.reusable_medium.created.auto': _('The reusable medium has been created automatically.'),
|
||||||
|
'pretix.reusable_medium.changed': _('The reusable medium has been changed.'),
|
||||||
|
'pretix.reusable_medium.linked_orderposition.changed': _('The medium has been connected to a new ticket.'),
|
||||||
|
'pretix.reusable_medium.linked_giftcard.changed': _('The medium has been connected to a new gift card.'),
|
||||||
|
'pretix.email.error': _('Sending of an email has failed.'),
|
||||||
|
'pretix.event.comment': _('The event\'s internal comment has been updated.'),
|
||||||
|
'pretix.event.canceled': _('The event has been canceled.'),
|
||||||
|
'pretix.event.deleted': _('An event has been deleted.'),
|
||||||
|
'pretix.event.shredder.started': _('A removal process for personal data has been started.'),
|
||||||
|
'pretix.event.shredder.completed': _('A removal process for personal data has been completed.'),
|
||||||
|
'pretix.event.export.schedule.added': _('A scheduled export has been added.'),
|
||||||
|
'pretix.event.export.schedule.changed': _('A scheduled export has been changed.'),
|
||||||
|
'pretix.event.export.schedule.deleted': _('A scheduled export has been deleted.'),
|
||||||
|
'pretix.event.export.schedule.executed': _('A scheduled export has been executed.'),
|
||||||
|
'pretix.event.export.schedule.failed': _('A scheduled export has failed: {reason}.'),
|
||||||
|
'pretix.control.auth.user.created': _('The user has been created.'),
|
||||||
|
'pretix.control.auth.user.new_source': _('A first login using {agent_type} on {os_type} from {country} has '
|
||||||
|
'been detected.'),
|
||||||
|
'pretix.user.settings.2fa.enabled': _('Two-factor authentication has been enabled.'),
|
||||||
|
'pretix.user.settings.2fa.disabled': _('Two-factor authentication has been disabled.'),
|
||||||
|
'pretix.user.settings.2fa.regenemergency': _('Your two-factor emergency codes have been regenerated.'),
|
||||||
|
'pretix.user.settings.2fa.emergency': _('A two-factor emergency code has been generated.'),
|
||||||
|
'pretix.user.settings.2fa.device.added': _('A new two-factor authentication device "{name}" has been added to '
|
||||||
|
'your account.'),
|
||||||
|
'pretix.user.settings.2fa.device.deleted': _('The two-factor authentication device "{name}" has been removed '
|
||||||
|
'from your account.'),
|
||||||
|
'pretix.user.settings.notifications.enabled': _('Notifications have been enabled.'),
|
||||||
|
'pretix.user.settings.notifications.disabled': _('Notifications have been disabled.'),
|
||||||
|
'pretix.user.settings.notifications.changed': _('Your notification settings have been changed.'),
|
||||||
|
'pretix.user.anonymized': _('This user has been anonymized.'),
|
||||||
|
'pretix.user.oauth.authorized': _('The application "{application_name}" has been authorized to access your '
|
||||||
|
'account.'),
|
||||||
|
'pretix.control.auth.user.forgot_password.mail_sent': _('Password reset mail sent.'),
|
||||||
|
'pretix.control.auth.user.forgot_password.recovered': _('The password has been reset.'),
|
||||||
|
'pretix.control.auth.user.forgot_password.denied.repeated': _('A repeated password reset has been denied, as '
|
||||||
|
'the last request was less than 24 hours ago.'),
|
||||||
|
'pretix.organizer.deleted': _('The organizer "{name}" has been deleted.'),
|
||||||
|
'pretix.waitinglist.voucher': _('A voucher has been sent to a person on the waiting list.'), # legacy
|
||||||
|
'pretix.event.orders.waitinglist.voucher_assigned': _('A voucher has been sent to a person on the waiting list.'),
|
||||||
|
'pretix.event.orders.waitinglist.deleted': _('An entry has been removed from the waiting list.'),
|
||||||
|
'pretix.event.order.waitinglist.transferred': _('An entry has been transferred to another waiting list.'), # legacy
|
||||||
|
'pretix.event.orders.waitinglist.changed': _('An entry has been changed on the waiting list.'),
|
||||||
|
'pretix.event.orders.waitinglist.added': _('An entry has been added to the waiting list.'),
|
||||||
|
'pretix.team.created': _('The team has been created.'),
|
||||||
|
'pretix.team.changed': _('The team settings have been changed.'),
|
||||||
|
'pretix.team.deleted': _('The team has been deleted.'),
|
||||||
|
'pretix.gate.created': _('The gate has been created.'),
|
||||||
|
'pretix.gate.changed': _('The gate has been changed.'),
|
||||||
|
'pretix.gate.deleted': _('The gate has been deleted.'),
|
||||||
|
'pretix.subevent.deleted': pgettext_lazy('subevent', 'The event date has been deleted.'),
|
||||||
|
'pretix.subevent.canceled': pgettext_lazy('subevent', 'The event date has been canceled.'),
|
||||||
|
'pretix.subevent.changed': pgettext_lazy('subevent', 'The event date has been changed.'),
|
||||||
|
'pretix.subevent.added': pgettext_lazy('subevent', 'The event date has been created.'),
|
||||||
|
'pretix.subevent.quota.added': pgettext_lazy('subevent', 'A quota has been added to the event date.'),
|
||||||
|
'pretix.subevent.quota.changed': pgettext_lazy('subevent', 'A quota has been changed on the event date.'),
|
||||||
|
'pretix.subevent.quota.deleted': pgettext_lazy('subevent', 'A quota has been removed from the event date.'),
|
||||||
|
'pretix.device.created': _('The device has been created.'),
|
||||||
|
'pretix.device.changed': _('The device has been changed.'),
|
||||||
|
'pretix.device.revoked': _('Access of the device has been revoked.'),
|
||||||
|
'pretix.device.initialized': _('The device has been initialized.'),
|
||||||
|
'pretix.device.keyroll': _('The access token of the device has been regenerated.'),
|
||||||
|
'pretix.device.updated': _('The device has notified the server of an hardware or software update.'),
|
||||||
|
'pretix.giftcards.created': _('The gift card has been created.'),
|
||||||
|
'pretix.giftcards.modified': _('The gift card has been changed.'),
|
||||||
|
'pretix.giftcards.transaction.manual': _('A manual transaction has been performed.'),
|
||||||
|
'pretix.team.token.created': _('The token "{name}" has been created.'),
|
||||||
|
'pretix.team.token.deleted': _('The token "{name}" has been revoked.'),
|
||||||
|
})
|
||||||
|
class CoreLogEntryType(LogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.event.item_meta_property.added': _('A meta property has been added to this event.'),
|
||||||
|
'pretix.event.item_meta_property.deleted': _('A meta property has been removed from this event.'),
|
||||||
|
'pretix.event.item_meta_property.changed': _('A meta property has been changed on this event.'),
|
||||||
|
'pretix.event.checkinlist.added': _('The check-in list has been added.'),
|
||||||
|
'pretix.event.checkinlist.deleted': _('The check-in list has been deleted.'),
|
||||||
|
'pretix.event.checkinlists.deleted': _('The check-in list has been deleted.'), # backwards compatibility
|
||||||
|
'pretix.event.checkinlist.changed': _('The check-in list has been changed.'),
|
||||||
|
'pretix.event.settings': _('The event settings have been changed.'),
|
||||||
|
'pretix.event.tickets.settings': _('The ticket download settings have been changed.'),
|
||||||
|
'pretix.event.live.activated': _('The shop has been taken live.'),
|
||||||
|
'pretix.event.live.deactivated': _('The shop has been taken offline.'),
|
||||||
|
'pretix.event.testmode.activated': _('The shop has been taken into test mode.'),
|
||||||
|
'pretix.event.testmode.deactivated': _('The test mode has been disabled.'),
|
||||||
|
'pretix.event.added': _('The event has been created.'),
|
||||||
|
'pretix.event.changed': _('The event details have been changed.'),
|
||||||
|
'pretix.event.footerlinks.changed': _('The footer links have been changed.'),
|
||||||
|
'pretix.event.question.option.added': _('An answer option has been added to the question.'),
|
||||||
|
'pretix.event.question.option.deleted': _('An answer option has been removed from the question.'),
|
||||||
|
'pretix.event.question.option.changed': _('An answer option has been changed.'),
|
||||||
|
'pretix.event.permissions.added': _('A user has been added to the event team.'),
|
||||||
|
'pretix.event.permissions.invited': _('A user has been invited to the event team.'),
|
||||||
|
'pretix.event.permissions.changed': _('A user\'s permissions have been changed.'),
|
||||||
|
'pretix.event.permissions.deleted': _('A user has been removed from the event team.'),
|
||||||
|
})
|
||||||
|
class CoreEventLogEntryType(EventLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.event.plugins.enabled': _('The plugin has been enabled.'),
|
||||||
|
'pretix.event.plugins.disabled': _('The plugin has been disabled.'),
|
||||||
|
})
|
||||||
|
class EventPluginStateLogEntryType(EventLogEntryType):
|
||||||
|
object_link_wrapper = _('Plugin {val}')
|
||||||
|
|
||||||
|
def get_object_link_info(self, logentry) -> dict:
|
||||||
|
if 'plugin' in logentry.parsed_data:
|
||||||
|
app = app_cache.get(logentry.parsed_data['plugin'])
|
||||||
|
if app and hasattr(app, 'PretixPluginMeta'):
|
||||||
|
return {
|
||||||
|
'href': reverse('control:event.settings.plugins', kwargs={
|
||||||
|
'organizer': logentry.event.organizer.slug,
|
||||||
|
'event': logentry.event.slug,
|
||||||
|
}) + '#plugin_' + logentry.parsed_data['plugin'],
|
||||||
|
'val': app.PretixPluginMeta.name
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.event.item.added': _('The product has been created.'),
|
||||||
|
'pretix.event.item.changed': _('The product has been changed.'),
|
||||||
|
'pretix.event.item.reordered': _('The product has been reordered.'),
|
||||||
|
'pretix.event.item.deleted': _('The product has been deleted.'),
|
||||||
|
'pretix.event.item.addons.added': _('An add-on has been added to this product.'),
|
||||||
|
'pretix.event.item.addons.removed': _('An add-on has been removed from this product.'),
|
||||||
|
'pretix.event.item.addons.changed': _('An add-on has been changed on this product.'),
|
||||||
|
'pretix.event.item.bundles.added': _('A bundled item has been added to this product.'),
|
||||||
|
'pretix.event.item.bundles.removed': _('A bundled item has been removed from this product.'),
|
||||||
|
'pretix.event.item.bundles.changed': _('A bundled item has been changed on this product.'),
|
||||||
|
})
|
||||||
|
class CoreItemLogEntryType(ItemLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.event.item.variation.added': _('The variation "{value}" has been created.'),
|
||||||
|
'pretix.event.item.variation.deleted': _('The variation "{value}" has been deleted.'),
|
||||||
|
'pretix.event.item.variation.changed': _('The variation "{value}" has been changed.'),
|
||||||
|
})
|
||||||
|
class VariationLogEntryType(ItemLogEntryType):
|
||||||
|
def display(self, logentry):
|
||||||
|
if 'value' not in logentry.parsed_data:
|
||||||
|
# Backwards compatibility
|
||||||
|
var = ItemVariation.objects.filter(id=logentry.parsed_data['id']).first()
|
||||||
|
if var:
|
||||||
|
logentry.parsed_data['value'] = str(var.value)
|
||||||
|
else:
|
||||||
|
logentry.parsed_data['value'] = '?'
|
||||||
|
else:
|
||||||
|
logentry.parsed_data['value'] = LazyI18nString(logentry.parsed_data['value'])
|
||||||
|
return super().display(logentry)
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.event.order.payment.confirmed': _('Payment {local_id} has been confirmed.'),
|
||||||
|
'pretix.event.order.payment.canceled': _('Payment {local_id} has been canceled.'),
|
||||||
|
'pretix.event.order.payment.canceled.failed': _('Canceling payment {local_id} has failed.'),
|
||||||
|
'pretix.event.order.payment.started': _('Payment {local_id} has been started.'),
|
||||||
|
'pretix.event.order.payment.failed': _('Payment {local_id} has failed.'),
|
||||||
|
'pretix.event.order.quotaexceeded': _('The order could not be marked as paid: {message}'),
|
||||||
|
'pretix.event.order.overpaid': _('The order has been overpaid.'),
|
||||||
|
'pretix.event.order.refund.created': _('Refund {local_id} has been created.'),
|
||||||
|
'pretix.event.order.refund.created.externally': _('Refund {local_id} has been created by an external entity.'),
|
||||||
|
'pretix.event.order.refund.requested': _('The customer requested you to issue a refund.'),
|
||||||
|
'pretix.event.order.refund.done': _('Refund {local_id} has been completed.'),
|
||||||
|
'pretix.event.order.refund.canceled': _('Refund {local_id} has been canceled.'),
|
||||||
|
'pretix.event.order.refund.failed': _('Refund {local_id} has failed.'),
|
||||||
|
})
|
||||||
|
class CoreOrderPaymentLogEntryType(OrderLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.event.quota.added': _('The quota has been added.'),
|
||||||
|
'pretix.event.quota.deleted': _('The quota has been deleted.'),
|
||||||
|
'pretix.event.quota.changed': _('The quota has been changed.'),
|
||||||
|
'pretix.event.quota.closed': _('The quota has closed.'),
|
||||||
|
'pretix.event.quota.opened': _('The quota has been re-opened.'),
|
||||||
|
})
|
||||||
|
class CoreQuotaLogEntryType(QuotaLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.event.question.added': _('The question has been added.'),
|
||||||
|
'pretix.event.question.deleted': _('The question has been deleted.'),
|
||||||
|
'pretix.event.question.changed': _('The question has been changed.'),
|
||||||
|
'pretix.event.question.reordered': _('The question has been reordered.'),
|
||||||
|
})
|
||||||
|
class CoreQuestionLogEntryType(QuestionLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new_from_dict({
|
||||||
|
'pretix.event.discount.added': _('The discount has been added.'),
|
||||||
|
'pretix.event.discount.deleted': _('The discount has been deleted.'),
|
||||||
|
'pretix.event.discount.changed': _('The discount has been changed.'),
|
||||||
|
})
|
||||||
|
class CoreDiscountLogEntryType(DiscountLogEntryType):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@log_entry_types.new()
|
||||||
|
class LegacyCheckinLogEntryType(OrderLogEntryType):
|
||||||
|
action_type = 'pretix.control.views.checkin'
|
||||||
|
|
||||||
|
def display(self, logentry):
|
||||||
|
# deprecated
|
||||||
|
dt = dateutil.parser.parse(logentry.parsed_data.get('datetime'))
|
||||||
|
tz = logentry.event.timezone
|
||||||
|
dt_formatted = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT")
|
||||||
|
if 'list' in logentry.parsed_data:
|
||||||
|
try:
|
||||||
|
checkin_list = logentry.event.checkin_lists.get(pk=logentry.parsed_data.get('list')).name
|
||||||
|
except CheckinList.DoesNotExist:
|
||||||
|
checkin_list = _("(unknown)")
|
||||||
|
else:
|
||||||
|
checkin_list = _("(unknown)")
|
||||||
|
|
||||||
|
if logentry.parsed_data.get('first'):
|
||||||
|
return _('Position #{posid} has been checked in manually at {datetime} on list "{list}".').format(
|
||||||
|
posid=logentry.parsed_data.get('positionid'),
|
||||||
|
datetime=dt_formatted,
|
||||||
|
list=checkin_list,
|
||||||
|
)
|
||||||
|
return _('Position #{posid} has been checked in again at {datetime} on list "{list}".').format(
|
||||||
|
posid=logentry.parsed_data.get('positionid'),
|
||||||
|
datetime=dt_formatted,
|
||||||
|
list=checkin_list
|
||||||
|
)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
from django.dispatch import Signal
|
from django.dispatch import Signal
|
||||||
|
|
||||||
from pretix.base.signals import DeprecatedSignal, EventPluginSignal
|
from pretix.base.signals import DeprecatedSignal, EventPluginSignal, OrganizerPluginSignal
|
||||||
|
|
||||||
html_page_start = Signal()
|
html_page_start = Signal()
|
||||||
"""
|
"""
|
||||||
@@ -221,7 +221,7 @@ Deprecated signal, no longer works. We just keep the definition so old plugins d
|
|||||||
break the installation.
|
break the installation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
nav_organizer = Signal()
|
nav_organizer = OrganizerPluginSignal()
|
||||||
"""
|
"""
|
||||||
Arguments: 'organizer', 'request'
|
Arguments: 'organizer', 'request'
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<legend>{{ catlabel }}</legend>
|
<legend>{{ catlabel }}</legend>
|
||||||
<div class="plugin-list">
|
<div class="plugin-list">
|
||||||
{% for plugin in plist %}
|
{% for plugin in plist %}
|
||||||
<div class="plugin-container {% if plugin.featured %}featured-plugin{% endif %}">
|
<div class="plugin-container {% if plugin.featured %}featured-plugin{% endif %}" id="plugin_{{ plugin.module }}">
|
||||||
{% if plugin.featured %}
|
{% if plugin.featured %}
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
{% bootstrap_field form.eu_reverse_charge layout="control" %}
|
{% bootstrap_field form.eu_reverse_charge layout="control" %}
|
||||||
{% bootstrap_field form.home_country layout="control" %}
|
{% bootstrap_field form.home_country layout="control" %}
|
||||||
{% bootstrap_field form.keep_gross_if_rate_changes layout="control" %}
|
{% bootstrap_field form.keep_gross_if_rate_changes layout="control" %}
|
||||||
<h3>{% trans "Custom rules" %}</h3>
|
<h3>{% trans "Custom taxation rules" %}</h3>
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
{% blocktrans trimmed %}
|
{% blocktrans trimmed %}
|
||||||
These settings are intended for professional users with very specific taxation situations.
|
These settings are intended for professional users with very specific taxation situations.
|
||||||
|
|||||||
@@ -133,7 +133,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{{ i.default_price|money:request.event.currency }}
|
{{ i.default_price|money:request.event.currency }}
|
||||||
{% if i.original_price %}<strike class="text-muted">{{ i.original_price|money:request.event.currency }}</strike>{% endif %}
|
{% if i.original_price %}<strike class="text-muted">{{ i.original_price|money:request.event.currency }}</strike>{% endif %}
|
||||||
{% if i.tax_rule %}
|
{% if i.tax_rule and i.default_price %}
|
||||||
<br/>
|
<br/>
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
{% if not i.tax_rule.price_includes_tax %}
|
{% if not i.tax_rule.price_includes_tax %}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
||||||
"PO-Revision-Date: 2024-09-10 07:17+0000\n"
|
"PO-Revision-Date: 2024-08-27 16:02+0000\n"
|
||||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||||
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||||
"de/>\n"
|
"de/>\n"
|
||||||
@@ -572,8 +572,10 @@ msgid "Group of objects"
|
|||||||
msgstr "Gruppe von Objekten"
|
msgstr "Gruppe von Objekten"
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:899
|
#: pretix/static/pretixcontrol/js/ui/editor.js:899
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Text object"
|
||||||
msgid "Text object (deprecated)"
|
msgid "Text object (deprecated)"
|
||||||
msgstr "Text-Objekt (veraltet)"
|
msgstr "Text-Objekt"
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:901
|
#: pretix/static/pretixcontrol/js/ui/editor.js:901
|
||||||
msgid "Text box"
|
msgid "Text box"
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ AES
|
|||||||
Absenderadresse
|
Absenderadresse
|
||||||
Absenderinformation
|
Absenderinformation
|
||||||
Absendername
|
Absendername
|
||||||
ABGEKÜNDIGT
|
|
||||||
Admin
|
Admin
|
||||||
Adminbereich
|
Adminbereich
|
||||||
Affirm
|
Affirm
|
||||||
@@ -26,7 +25,6 @@ Ausgangsscans
|
|||||||
ausgeklappt
|
ausgeklappt
|
||||||
ausgecheckt
|
ausgecheckt
|
||||||
auswahl
|
auswahl
|
||||||
Auth
|
|
||||||
Authentication
|
Authentication
|
||||||
Authenticator
|
Authenticator
|
||||||
Authentifizierungsmechanismus
|
Authentifizierungsmechanismus
|
||||||
@@ -38,7 +36,6 @@ Bancontact
|
|||||||
BankID
|
BankID
|
||||||
Banking
|
Banking
|
||||||
barcodes
|
barcodes
|
||||||
Baskisch
|
|
||||||
Bcc
|
Bcc
|
||||||
BCC
|
BCC
|
||||||
Beispielevent
|
Beispielevent
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
||||||
"PO-Revision-Date: 2024-09-10 07:17+0000\n"
|
"PO-Revision-Date: 2024-08-27 16:00+0000\n"
|
||||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||||
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
|
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
|
||||||
"pretix/pretix-js/de_Informal/>\n"
|
"pretix/pretix-js/de_Informal/>\n"
|
||||||
@@ -571,8 +571,10 @@ msgid "Group of objects"
|
|||||||
msgstr "Gruppe von Objekten"
|
msgstr "Gruppe von Objekten"
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:899
|
#: pretix/static/pretixcontrol/js/ui/editor.js:899
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Text object"
|
||||||
msgid "Text object (deprecated)"
|
msgid "Text object (deprecated)"
|
||||||
msgstr "Text-Objekt (veraltet)"
|
msgstr "Text-Objekt"
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:901
|
#: pretix/static/pretixcontrol/js/ui/editor.js:901
|
||||||
msgid "Text box"
|
msgid "Text box"
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ AES
|
|||||||
Absenderadresse
|
Absenderadresse
|
||||||
Absenderinformation
|
Absenderinformation
|
||||||
Absendername
|
Absendername
|
||||||
ABGEKÜNDIGT
|
|
||||||
Admin
|
Admin
|
||||||
Adminbereich
|
Adminbereich
|
||||||
Affirm
|
Affirm
|
||||||
@@ -26,7 +25,6 @@ Ausgangsscans
|
|||||||
ausgeklappt
|
ausgeklappt
|
||||||
ausgecheckt
|
ausgecheckt
|
||||||
auswahl
|
auswahl
|
||||||
Auth
|
|
||||||
Authentication
|
Authentication
|
||||||
Authenticator
|
Authenticator
|
||||||
Authentifizierungsmechanismus
|
Authentifizierungsmechanismus
|
||||||
@@ -38,7 +36,6 @@ Bancontact
|
|||||||
BankID
|
BankID
|
||||||
Banking
|
Banking
|
||||||
barcodes
|
barcodes
|
||||||
Baskisch
|
|
||||||
Bcc
|
Bcc
|
||||||
BCC
|
BCC
|
||||||
Beispielevent
|
Beispielevent
|
||||||
|
|||||||
+701
-751
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-09-26 11:23+0000\n"
|
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1628
-1218
File diff suppressed because it is too large
Load Diff
@@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-09-26 11:23+0000\n"
|
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
||||||
"PO-Revision-Date: 2024-09-06 08:47+0000\n"
|
"PO-Revision-Date: 2024-08-29 10:36+0000\n"
|
||||||
"Last-Translator: Albizuri <oier@puntu.eus>\n"
|
"Last-Translator: Albizuri <oier@puntu.eus>\n"
|
||||||
"Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
"Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||||
"eu/>\n"
|
"eu/>\n"
|
||||||
@@ -557,14 +557,17 @@ msgid "absent"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:171
|
#: pretix/static/pretixcontrol/js/ui/editor.js:171
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:72
|
||||||
msgid "Check-in QR"
|
msgid "Check-in QR"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:543
|
#: pretix/static/pretixcontrol/js/ui/editor.js:543
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:387
|
||||||
msgid "The PDF background file could not be loaded for the following reason:"
|
msgid "The PDF background file could not be loaded for the following reason:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:894
|
#: pretix/static/pretixcontrol/js/ui/editor.js:894
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:656
|
||||||
msgid "Group of objects"
|
msgid "Group of objects"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -577,35 +580,44 @@ msgid "Text box"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:903
|
#: pretix/static/pretixcontrol/js/ui/editor.js:903
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:663
|
||||||
msgid "Barcode area"
|
msgid "Barcode area"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:905
|
#: pretix/static/pretixcontrol/js/ui/editor.js:905
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:665
|
||||||
msgid "Image area"
|
msgid "Image area"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:907
|
#: pretix/static/pretixcontrol/js/ui/editor.js:907
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:667
|
||||||
msgid "Powered by pretix"
|
msgid "Powered by pretix"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:909
|
#: pretix/static/pretixcontrol/js/ui/editor.js:909
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:669
|
||||||
msgid "Object"
|
msgid "Object"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:913
|
#: pretix/static/pretixcontrol/js/ui/editor.js:913
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:673
|
||||||
msgid "Ticket design"
|
msgid "Ticket design"
|
||||||
msgstr "Sarrera diseinua"
|
msgstr "Sarrera diseinua"
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:1250
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1250
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:972
|
||||||
msgid "Saving failed."
|
msgid "Saving failed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:1319
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1319
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:1370
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1370
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1041
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1091
|
||||||
msgid "Error while uploading your PDF file, please try again."
|
msgid "Error while uploading your PDF file, please try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:1353
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1353
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1074
|
||||||
msgid "Do you really want to leave the editor without saving your changes?"
|
msgid "Do you really want to leave the editor without saving your changes?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -622,14 +634,17 @@ msgid "Unknown error."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:318
|
#: pretix/static/pretixcontrol/js/ui/main.js:318
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:313
|
||||||
msgid "Your color has great contrast and is very easy to read!"
|
msgid "Your color has great contrast and is very easy to read!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:322
|
#: pretix/static/pretixcontrol/js/ui/main.js:322
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:317
|
||||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:326
|
#: pretix/static/pretixcontrol/js/ui/main.js:326
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:321
|
||||||
msgid ""
|
msgid ""
|
||||||
"Your color has bad contrast for text on white background, please choose a "
|
"Your color has bad contrast for text on white background, please choose a "
|
||||||
"darker shade."
|
"darker shade."
|
||||||
@@ -637,38 +652,48 @@ msgstr ""
|
|||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:491
|
#: pretix/static/pretixcontrol/js/ui/main.js:491
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:511
|
#: pretix/static/pretixcontrol/js/ui/main.js:511
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:475
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:495
|
||||||
msgid "Search query"
|
msgid "Search query"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:509
|
#: pretix/static/pretixcontrol/js/ui/main.js:509
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:493
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Guztiak"
|
msgstr "Guztiak"
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:510
|
#: pretix/static/pretixcontrol/js/ui/main.js:510
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:494
|
||||||
msgid "None"
|
msgid "None"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:498
|
||||||
msgid "Selected only"
|
msgid "Selected only"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:847
|
#: pretix/static/pretixcontrol/js/ui/main.js:847
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:828
|
||||||
msgid "Enter page number between 1 and %(max)s."
|
msgid "Enter page number between 1 and %(max)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:850
|
#: pretix/static/pretixcontrol/js/ui/main.js:850
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:831
|
||||||
msgid "Invalid page number."
|
msgid "Invalid page number."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:1008
|
#: pretix/static/pretixcontrol/js/ui/main.js:1008
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:989
|
||||||
msgid "Use a different name internally"
|
msgid "Use a different name internally"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:1048
|
#: pretix/static/pretixcontrol/js/ui/main.js:1048
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:1029
|
||||||
msgid "Click to close"
|
msgid "Click to close"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:1123
|
#: pretix/static/pretixcontrol/js/ui/main.js:1123
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:1104
|
||||||
msgid "You have unsaved changes!"
|
msgid "You have unsaved changes!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -695,7 +720,7 @@ msgid ""
|
|||||||
"The items in your cart are no longer reserved for you. You can still "
|
"The items in your cart are no longer reserved for you. You can still "
|
||||||
"complete your order as long as they’re available."
|
"complete your order as long as they’re available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Zure saskiko produktuak ez daude zuretzat erreserbatuta. Oraindik ere zure "
|
"Zure saskiko artikuluak ez daude zuretzat erreserbatuta. Oraindik ere zure "
|
||||||
"eskaera bete dezakezu, baldin eta eskuragarri badaude."
|
"eskaera bete dezakezu, baldin eta eskuragarri badaude."
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/cart.js:45
|
#: pretix/static/pretixpresale/js/ui/cart.js:45
|
||||||
@@ -705,9 +730,8 @@ msgstr "Saskia iraungita"
|
|||||||
#: pretix/static/pretixpresale/js/ui/cart.js:50
|
#: pretix/static/pretixpresale/js/ui/cart.js:50
|
||||||
msgid "The items in your cart are reserved for you for one minute."
|
msgid "The items in your cart are reserved for you for one minute."
|
||||||
msgid_plural "The items in your cart are reserved for you for {num} minutes."
|
msgid_plural "The items in your cart are reserved for you for {num} minutes."
|
||||||
msgstr[0] "Zure saskiko produktuak minutu -ez erreserbatuta daude zuretzat."
|
msgstr[0] ""
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
"Zure saskiko produktuak {num} minutuz erreserbatuta daude zuretzat."
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/main.js:203
|
#: pretix/static/pretixpresale/js/ui/main.js:203
|
||||||
msgid "The organizer keeps %(currency)s %(amount)s"
|
msgid "The organizer keeps %(currency)s %(amount)s"
|
||||||
@@ -1075,3 +1099,7 @@ msgstr ""
|
|||||||
#: pretix/static/pretixpresale/js/widget/widget.js:89
|
#: pretix/static/pretixpresale/js/widget/widget.js:89
|
||||||
msgid "December"
|
msgid "December"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:661
|
||||||
|
msgid "Text object"
|
||||||
|
msgstr ""
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,8 @@ msgstr ""
|
|||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
||||||
"PO-Revision-Date: 2024-09-08 11:04+0000\n"
|
"PO-Revision-Date: 2024-06-08 18:00+0000\n"
|
||||||
"Last-Translator: Martin Gross <gross@rami.io>\n"
|
"Last-Translator: David Vaz <davidmgvaz@gmail.com>\n"
|
||||||
"Language-Team: Portuguese (Portugal) <https://translate.pretix.eu/projects/"
|
"Language-Team: Portuguese (Portugal) <https://translate.pretix.eu/projects/"
|
||||||
"pretix/pretix-js/pt_PT/>\n"
|
"pretix/pretix-js/pt_PT/>\n"
|
||||||
"Language: pt_PT\n"
|
"Language: pt_PT\n"
|
||||||
@@ -17,7 +17,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||||
"X-Generator: Weblate 5.7\n"
|
"X-Generator: Weblate 5.5.5\n"
|
||||||
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||||
@@ -292,8 +292,10 @@ msgid "Information required"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:58
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:58
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Unknown error."
|
||||||
msgid "Unknown ticket"
|
msgid "Unknown ticket"
|
||||||
msgstr "Bilhete desconhecido"
|
msgstr "Erro desconhecido."
|
||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:59
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:59
|
||||||
msgid "Ticket type not allowed here"
|
msgid "Ticket type not allowed here"
|
||||||
@@ -803,19 +805,21 @@ msgstr ""
|
|||||||
#: pretix/static/pretixpresale/js/widget/widget.js:20
|
#: pretix/static/pretixpresale/js/widget/widget.js:20
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr "Selecionar"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Select %s"
|
msgid "Select %s"
|
||||||
msgstr "Selecionados %s"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
||||||
#, javascript-format
|
#, fuzzy, javascript-format
|
||||||
|
#| msgctxt "widget"
|
||||||
|
#| msgid "See variations"
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Select variant %s"
|
msgid "Select variant %s"
|
||||||
msgstr "Selecione variantes %s"
|
msgstr "Ver alternativas"
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1111
-1208
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
||||||
"PO-Revision-Date: 2024-09-15 18:00+0000\n"
|
"PO-Revision-Date: 2024-06-26 22:00+0000\n"
|
||||||
"Last-Translator: Kristian Feldsam <feldsam@gmail.com>\n"
|
"Last-Translator: Kristian Feldsam <feldsam@gmail.com>\n"
|
||||||
"Language-Team: Slovak <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
"Language-Team: Slovak <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||||
"sk/>\n"
|
"sk/>\n"
|
||||||
@@ -17,7 +17,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||||
"X-Generator: Weblate 5.7\n"
|
"X-Generator: Weblate 5.6.1\n"
|
||||||
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||||
@@ -156,7 +156,7 @@ msgstr ""
|
|||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
||||||
msgid "Paid orders"
|
msgid "Paid orders"
|
||||||
msgstr "Zaplatené objednávky"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
|
||||||
msgid "Total revenue"
|
msgid "Total revenue"
|
||||||
@@ -176,15 +176,15 @@ msgstr ""
|
|||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:30
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:30
|
||||||
msgid "Select a check-in list"
|
msgid "Select a check-in list"
|
||||||
msgstr "Vyberte zoznam na odbavenie"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:31
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:31
|
||||||
msgid "No active check-in lists found."
|
msgid "No active check-in lists found."
|
||||||
msgstr "Nenašli sa žiadne aktívne zoznamy na odbavenie."
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:32
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:32
|
||||||
msgid "Switch check-in list"
|
msgid "Switch check-in list"
|
||||||
msgstr "Prepnúť zoznam odbavení"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:33
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:33
|
||||||
msgid "Search results"
|
msgid "Search results"
|
||||||
@@ -274,7 +274,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:56
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:56
|
||||||
msgid "Ticket already used"
|
msgid "Ticket already used"
|
||||||
msgstr "Už použitá vstupenka"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:57
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:57
|
||||||
msgid "Information required"
|
msgid "Information required"
|
||||||
@@ -282,7 +282,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:58
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:58
|
||||||
msgid "Unknown ticket"
|
msgid "Unknown ticket"
|
||||||
msgstr "Neznáma vstupenka"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:59
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:59
|
||||||
msgid "Ticket type not allowed here"
|
msgid "Ticket type not allowed here"
|
||||||
@@ -318,7 +318,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:68
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:68
|
||||||
msgid "Checked-in Tickets"
|
msgid "Checked-in Tickets"
|
||||||
msgstr "Odbavené vstupenky"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:69
|
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:69
|
||||||
msgid "Valid Tickets"
|
msgid "Valid Tickets"
|
||||||
@@ -398,9 +398,6 @@ msgid ""
|
|||||||
"than one minute, please check your internet connection and then reload this "
|
"than one minute, please check your internet connection and then reload this "
|
||||||
"page and try again."
|
"page and try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Momentálne odosielame vašu požiadavku na server. Ak to trvá dlhšie ako jednu "
|
|
||||||
"minútu, skontrolujte svoje internetové pripojenie a potom znovu načítajte "
|
|
||||||
"túto stránku a skúste to znova."
|
|
||||||
|
|
||||||
#: pretix/static/pretixbase/js/asynctask.js:301
|
#: pretix/static/pretixbase/js/asynctask.js:301
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:71
|
#: pretix/static/pretixcontrol/js/ui/main.js:71
|
||||||
@@ -549,7 +546,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:171
|
#: pretix/static/pretixcontrol/js/ui/editor.js:171
|
||||||
msgid "Check-in QR"
|
msgid "Check-in QR"
|
||||||
msgstr "QR na odbavenie"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:543
|
#: pretix/static/pretixcontrol/js/ui/editor.js:543
|
||||||
msgid "The PDF background file could not be loaded for the following reason:"
|
msgid "The PDF background file could not be loaded for the following reason:"
|
||||||
@@ -686,8 +683,6 @@ msgid ""
|
|||||||
"The items in your cart are no longer reserved for you. You can still "
|
"The items in your cart are no longer reserved for you. You can still "
|
||||||
"complete your order as long as they’re available."
|
"complete your order as long as they’re available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vstupenky v košíku už nie sú pre Vás rezervované. Objednávku môžete "
|
|
||||||
"dokončiť, ak sú stále k dispozícii."
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/cart.js:45
|
#: pretix/static/pretixpresale/js/ui/cart.js:45
|
||||||
msgid "Cart expired"
|
msgid "Cart expired"
|
||||||
@@ -696,9 +691,8 @@ msgstr ""
|
|||||||
#: pretix/static/pretixpresale/js/ui/cart.js:50
|
#: pretix/static/pretixpresale/js/ui/cart.js:50
|
||||||
msgid "The items in your cart are reserved for you for one minute."
|
msgid "The items in your cart are reserved for you for one minute."
|
||||||
msgid_plural "The items in your cart are reserved for you for {num} minutes."
|
msgid_plural "The items in your cart are reserved for you for {num} minutes."
|
||||||
msgstr[0] "Vstupenky v košíku sú pre Vás rezervované jednu minútu."
|
msgstr[0] ""
|
||||||
msgstr[1] "Vstupenky v košíku sú pre Vás rezervované {num} minúty."
|
msgstr[1] ""
|
||||||
msgstr[2] "Vstupenky v košíku sú pre Vás rezervované {num} minút."
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/main.js:203
|
#: pretix/static/pretixpresale/js/ui/main.js:203
|
||||||
msgid "The organizer keeps %(currency)s %(amount)s"
|
msgid "The organizer keeps %(currency)s %(amount)s"
|
||||||
@@ -710,11 +704,11 @@ msgstr ""
|
|||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/main.js:227
|
#: pretix/static/pretixpresale/js/ui/main.js:227
|
||||||
msgid "Please enter the amount the organizer can keep."
|
msgid "Please enter the amount the organizer can keep."
|
||||||
msgstr "Zadajte sumu, ktorú si organizátor môže ponechať."
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/main.js:449
|
#: pretix/static/pretixpresale/js/ui/main.js:449
|
||||||
msgid "Please enter a quantity for one of the ticket types."
|
msgid "Please enter a quantity for one of the ticket types."
|
||||||
msgstr "Vyberte si prosím aspoň jednu vstupenku."
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/main.js:485
|
#: pretix/static/pretixpresale/js/ui/main.js:485
|
||||||
msgid "required"
|
msgid "required"
|
||||||
@@ -736,131 +730,131 @@ msgstr ""
|
|||||||
#: pretix/static/pretixpresale/js/widget/widget.js:16
|
#: pretix/static/pretixpresale/js/widget/widget.js:16
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Quantity"
|
msgid "Quantity"
|
||||||
msgstr "Počet"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:17
|
#: pretix/static/pretixpresale/js/widget/widget.js:17
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Decrease quantity"
|
msgid "Decrease quantity"
|
||||||
msgstr "Znížiť počet"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:18
|
#: pretix/static/pretixpresale/js/widget/widget.js:18
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Increase quantity"
|
msgid "Increase quantity"
|
||||||
msgstr "Zvýšiť počet"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:19
|
#: pretix/static/pretixpresale/js/widget/widget.js:19
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Price"
|
msgid "Price"
|
||||||
msgstr "Cena"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:20
|
#: pretix/static/pretixpresale/js/widget/widget.js:20
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr "Vybrať"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Select %s"
|
msgid "Select %s"
|
||||||
msgstr "Vybrať %s"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Select variant %s"
|
msgid "Select variant %s"
|
||||||
msgstr "Vybrať variantu %s"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Sold out"
|
msgid "Sold out"
|
||||||
msgstr "Vypredané"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:24
|
#: pretix/static/pretixpresale/js/widget/widget.js:24
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Buy"
|
msgid "Buy"
|
||||||
msgstr "Kúpiť"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:25
|
#: pretix/static/pretixpresale/js/widget/widget.js:25
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Register"
|
msgid "Register"
|
||||||
msgstr "Registrovať sa"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:26
|
#: pretix/static/pretixpresale/js/widget/widget.js:26
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Reserved"
|
msgid "Reserved"
|
||||||
msgstr "Rezervované"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:27
|
#: pretix/static/pretixpresale/js/widget/widget.js:27
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "FREE"
|
msgid "FREE"
|
||||||
msgstr "ZADARMO"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:28
|
#: pretix/static/pretixpresale/js/widget/widget.js:28
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "from %(currency)s %(price)s"
|
msgid "from %(currency)s %(price)s"
|
||||||
msgstr "z %(currency)s %(price)s"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:29
|
#: pretix/static/pretixpresale/js/widget/widget.js:29
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "incl. %(rate)s% %(taxname)s"
|
msgid "incl. %(rate)s% %(taxname)s"
|
||||||
msgstr "vrátane %(rate)s% %(taxname)s"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:30
|
#: pretix/static/pretixpresale/js/widget/widget.js:30
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "plus %(rate)s% %(taxname)s"
|
msgid "plus %(rate)s% %(taxname)s"
|
||||||
msgstr "plus %(rate)s% %(taxname)s"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:31
|
#: pretix/static/pretixpresale/js/widget/widget.js:31
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "incl. taxes"
|
msgid "incl. taxes"
|
||||||
msgstr "vrátane dane"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:32
|
#: pretix/static/pretixpresale/js/widget/widget.js:32
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "plus taxes"
|
msgid "plus taxes"
|
||||||
msgstr "plus daň"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:33
|
#: pretix/static/pretixpresale/js/widget/widget.js:33
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "currently available: %s"
|
msgid "currently available: %s"
|
||||||
msgstr "aktuálne k dispozícii: %s"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:34
|
#: pretix/static/pretixpresale/js/widget/widget.js:34
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Only available with a voucher"
|
msgid "Only available with a voucher"
|
||||||
msgstr "K dispozícii len s poukážkou"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:35
|
#: pretix/static/pretixpresale/js/widget/widget.js:35
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Not yet available"
|
msgid "Not yet available"
|
||||||
msgstr "Zatiaľ nedostupné"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:36
|
#: pretix/static/pretixpresale/js/widget/widget.js:36
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Not available anymore"
|
msgid "Not available anymore"
|
||||||
msgstr "Už nie je k dispozícii"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:37
|
#: pretix/static/pretixpresale/js/widget/widget.js:37
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Currently not available"
|
msgid "Currently not available"
|
||||||
msgstr "Momentálne nie je k dispozícii"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:38
|
#: pretix/static/pretixpresale/js/widget/widget.js:38
|
||||||
#, javascript-format
|
#, javascript-format
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "minimum amount to order: %s"
|
msgid "minimum amount to order: %s"
|
||||||
msgstr "minimálna suma na objednávku: %s"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:39
|
#: pretix/static/pretixpresale/js/widget/widget.js:39
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Close ticket shop"
|
msgid "Close ticket shop"
|
||||||
msgstr "Zatvoriť obchod so vstupenkami"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:40
|
#: pretix/static/pretixpresale/js/widget/widget.js:40
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "The ticket shop could not be loaded."
|
msgid "The ticket shop could not be loaded."
|
||||||
msgstr "Obchod so vstupenkami sa nepodarilo načítať."
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
@@ -868,18 +862,16 @@ msgid ""
|
|||||||
"There are currently a lot of users in this ticket shop. Please open the shop "
|
"There are currently a lot of users in this ticket shop. Please open the shop "
|
||||||
"in a new tab to continue."
|
"in a new tab to continue."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"V súčasnosti je v tomto obchode so vstupenkami veľa používateľov. Ak chcete "
|
|
||||||
"pokračovať, otvorte obchod v novej karte."
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:43
|
#: pretix/static/pretixpresale/js/widget/widget.js:43
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Open ticket shop"
|
msgid "Open ticket shop"
|
||||||
msgstr "Otvoriť obchod so vstupenkami"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "The cart could not be created. Please try again later"
|
msgid "The cart could not be created. Please try again later"
|
||||||
msgstr "Nákupný košík sa nepodarilo vytvoriť. Skúste to prosím neskôr"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:45
|
#: pretix/static/pretixpresale/js/widget/widget.js:45
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
@@ -887,14 +879,11 @@ msgid ""
|
|||||||
"We could not create your cart, since there are currently too many users in "
|
"We could not create your cart, since there are currently too many users in "
|
||||||
"this ticket shop. Please click \"Continue\" to retry in a new tab."
|
"this ticket shop. Please click \"Continue\" to retry in a new tab."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Nepodarilo sa nám vytvoriť Váš nákupný košík, pretože v tomto obchode je "
|
|
||||||
"momentálne príliš veľa používateľov. Kliknutím na tlačidlo „Pokračovať“ to "
|
|
||||||
"skúste znova v novej karte."
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:47
|
#: pretix/static/pretixpresale/js/widget/widget.js:47
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Waiting list"
|
msgid "Waiting list"
|
||||||
msgstr "Čakací zoznam"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:48
|
#: pretix/static/pretixpresale/js/widget/widget.js:48
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
@@ -902,88 +891,86 @@ msgid ""
|
|||||||
"You currently have an active cart for this event. If you select more "
|
"You currently have an active cart for this event. If you select more "
|
||||||
"products, they will be added to your existing cart."
|
"products, they will be added to your existing cart."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"V súčasnosti máte aktívny nákupný košík pre toto podujatie. Ak si vyberiete "
|
|
||||||
"ďalšie vstupenky, pridajú sa do vášho existujúceho košíka."
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:50
|
#: pretix/static/pretixpresale/js/widget/widget.js:50
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Resume checkout"
|
msgid "Resume checkout"
|
||||||
msgstr "Pokračovať v objednávke"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:51
|
#: pretix/static/pretixpresale/js/widget/widget.js:51
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Redeem a voucher"
|
msgid "Redeem a voucher"
|
||||||
msgstr "Uplatnenie poukážky"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:52
|
#: pretix/static/pretixpresale/js/widget/widget.js:52
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Redeem"
|
msgid "Redeem"
|
||||||
msgstr "Uplatniť"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:53
|
#: pretix/static/pretixpresale/js/widget/widget.js:53
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Voucher code"
|
msgid "Voucher code"
|
||||||
msgstr "Kód poukážky"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:54
|
#: pretix/static/pretixpresale/js/widget/widget.js:54
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Zatvoriť"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:55
|
#: pretix/static/pretixpresale/js/widget/widget.js:55
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Continue"
|
msgid "Continue"
|
||||||
msgstr "Pokračovať"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:56
|
#: pretix/static/pretixpresale/js/widget/widget.js:56
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Show variants"
|
msgid "Show variants"
|
||||||
msgstr "Zobraziť varianty"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:57
|
#: pretix/static/pretixpresale/js/widget/widget.js:57
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Hide variants"
|
msgid "Hide variants"
|
||||||
msgstr "Skryť varianty"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:58
|
#: pretix/static/pretixpresale/js/widget/widget.js:58
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Choose a different event"
|
msgid "Choose a different event"
|
||||||
msgstr "Vybrať iné podujatie"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:59
|
#: pretix/static/pretixpresale/js/widget/widget.js:59
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Choose a different date"
|
msgid "Choose a different date"
|
||||||
msgstr "Vybrať iný dátum"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:60
|
#: pretix/static/pretixpresale/js/widget/widget.js:60
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Back"
|
msgid "Back"
|
||||||
msgstr "Späť"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:61
|
#: pretix/static/pretixpresale/js/widget/widget.js:61
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Next month"
|
msgid "Next month"
|
||||||
msgstr "Nasledujúci mesiac"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:62
|
#: pretix/static/pretixpresale/js/widget/widget.js:62
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Previous month"
|
msgid "Previous month"
|
||||||
msgstr "Predchádzajúci mesiac"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:63
|
#: pretix/static/pretixpresale/js/widget/widget.js:63
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Next week"
|
msgid "Next week"
|
||||||
msgstr "Nasledujúci týždeň"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:64
|
#: pretix/static/pretixpresale/js/widget/widget.js:64
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Previous week"
|
msgid "Previous week"
|
||||||
msgstr "Predchádzajúci týždeň"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:65
|
#: pretix/static/pretixpresale/js/widget/widget.js:65
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Open seat selection"
|
msgid "Open seat selection"
|
||||||
msgstr "Zobraziť výber sedadiel"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:66
|
#: pretix/static/pretixpresale/js/widget/widget.js:66
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
@@ -992,14 +979,11 @@ msgid ""
|
|||||||
"add yourself to the waiting list. We will then notify if seats are available "
|
"add yourself to the waiting list. We will then notify if seats are available "
|
||||||
"again."
|
"again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Niektoré alebo všetky kategórie vstupeniek sú v súčasnosti vypredané. Ak "
|
|
||||||
"chcete, môžete sa pridať na zoznam čakateľov. Budeme vás informovať, ak sa "
|
|
||||||
"miesta uvoľnia."
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:67
|
#: pretix/static/pretixpresale/js/widget/widget.js:67
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Load more"
|
msgid "Load more"
|
||||||
msgstr "Načítať viac"
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:69
|
#: pretix/static/pretixpresale/js/widget/widget.js:69
|
||||||
msgid "Mo"
|
msgid "Mo"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+1481
-1507
File diff suppressed because it is too large
Load Diff
@@ -8,16 +8,16 @@ msgstr ""
|
|||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
||||||
"PO-Revision-Date: 2024-09-12 03:00+0000\n"
|
"PO-Revision-Date: 2024-06-27 17:00+0000\n"
|
||||||
"Last-Translator: Tinna Sandström <tinna@coeo.events>\n"
|
"Last-Translator: Erik Löfman <erik@disruptiveventures.se>\n"
|
||||||
"Language-Team: Swedish <https://translate.pretix.eu/projects/pretix/"
|
"Language-Team: Swedish <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||||
"pretix-js/sv/>\n"
|
"js/sv/>\n"
|
||||||
"Language: sv\n"
|
"Language: sv\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 5.7\n"
|
"X-Generator: Weblate 5.6.1\n"
|
||||||
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||||
@@ -727,8 +727,8 @@ msgstr "Varukorgen har gått ut"
|
|||||||
#: pretix/static/pretixpresale/js/ui/cart.js:50
|
#: pretix/static/pretixpresale/js/ui/cart.js:50
|
||||||
msgid "The items in your cart are reserved for you for one minute."
|
msgid "The items in your cart are reserved for you for one minute."
|
||||||
msgid_plural "The items in your cart are reserved for you for {num} minutes."
|
msgid_plural "The items in your cart are reserved for you for {num} minutes."
|
||||||
msgstr[0] "Produkterna i din bokning är reserverade för dig i en minut."
|
msgstr[0] "Artiklarna i din varukorg är reserverade för dig i en minut."
|
||||||
msgstr[1] "Produkterna i din bokning är reserverade för dig i {num} minuter."
|
msgstr[1] "Artiklarna i din varukorg är reserverade för dig i {num} minuter."
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/main.js:203
|
#: pretix/static/pretixpresale/js/ui/main.js:203
|
||||||
msgid "The organizer keeps %(currency)s %(amount)s"
|
msgid "The organizer keeps %(currency)s %(amount)s"
|
||||||
@@ -819,7 +819,7 @@ msgstr "Köp"
|
|||||||
#: pretix/static/pretixpresale/js/widget/widget.js:25
|
#: pretix/static/pretixpresale/js/widget/widget.js:25
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Register"
|
msgid "Register"
|
||||||
msgstr "BOKA"
|
msgstr "Registrera"
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:26
|
#: pretix/static/pretixpresale/js/widget/widget.js:26
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
@@ -829,7 +829,7 @@ msgstr "Reserverad"
|
|||||||
#: pretix/static/pretixpresale/js/widget/widget.js:27
|
#: pretix/static/pretixpresale/js/widget/widget.js:27
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "FREE"
|
msgid "FREE"
|
||||||
msgstr "ANTAL"
|
msgstr "GRATIS"
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:28
|
#: pretix/static/pretixpresale/js/widget/widget.js:28
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
@@ -921,7 +921,7 @@ msgstr "Öppna biljettbutik"
|
|||||||
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
#: pretix/static/pretixpresale/js/widget/widget.js:44
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "The cart could not be created. Please try again later"
|
msgid "The cart could not be created. Please try again later"
|
||||||
msgstr "Bokningen kunde inte skapas. Vänligen försök senare."
|
msgstr "Varukorgen kunde inte skapas. Vänligen försök senare"
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:45
|
#: pretix/static/pretixpresale/js/widget/widget.js:45
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
@@ -929,8 +929,9 @@ msgid ""
|
|||||||
"We could not create your cart, since there are currently too many users in "
|
"We could not create your cart, since there are currently too many users in "
|
||||||
"this ticket shop. Please click \"Continue\" to retry in a new tab."
|
"this ticket shop. Please click \"Continue\" to retry in a new tab."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vi kunde inte skapa din bokning, då det just nu är många användare i den här "
|
"Vi kunde inte skapa din varukorg, då det just nu är många användare i den "
|
||||||
"biljettbutiken. Klicka på \"Fortsätt\" för att försöka på nytt i en ny flik."
|
"här biljettbutiken. Klicka på \"Fortsätt\" för att försöka på nytt i en ny "
|
||||||
|
"flik."
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:47
|
#: pretix/static/pretixpresale/js/widget/widget.js:47
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
@@ -943,13 +944,13 @@ msgid ""
|
|||||||
"You currently have an active cart for this event. If you select more "
|
"You currently have an active cart for this event. If you select more "
|
||||||
"products, they will be added to your existing cart."
|
"products, they will be added to your existing cart."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Du har för tillfället en pågående bokning för den här eventet. Om du väljer "
|
"Du har för tillfället en aktiv varukorg för den här eventet. Om du väljer "
|
||||||
"fler produkter, kommer de att läggas till din befintliga bokning."
|
"fler artiklar, kommer de att läggas till din befintliga varukorg."
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:50
|
#: pretix/static/pretixpresale/js/widget/widget.js:50
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
msgid "Resume checkout"
|
msgid "Resume checkout"
|
||||||
msgstr "Fortsätt med ditt bokningen"
|
msgstr "Fortsätt med ditt köp"
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/widget/widget.js:51
|
#: pretix/static/pretixpresale/js/widget/widget.js:51
|
||||||
msgctxt "widget"
|
msgctxt "widget"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,6 @@ acceptor
|
|||||||
analytics
|
analytics
|
||||||
anonymize
|
anonymize
|
||||||
anonymized
|
anonymized
|
||||||
Auth
|
|
||||||
authenticator
|
authenticator
|
||||||
automatical
|
automatical
|
||||||
availabilities
|
availabilities
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -26,13 +26,12 @@ from collections import defaultdict
|
|||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.urls import resolve, reverse
|
from django.urls import resolve, reverse
|
||||||
from django.utils.html import escape
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from pretix.base.logentrytypes import EventLogEntryType, log_entry_types
|
||||||
from pretix.base.models import Event, Order
|
from pretix.base.models import Event, Order
|
||||||
from pretix.base.signals import (
|
from pretix.base.signals import (
|
||||||
event_copy_data, item_copy_data, logentry_display, logentry_object_link,
|
event_copy_data, item_copy_data, register_data_exporters,
|
||||||
register_data_exporters,
|
|
||||||
)
|
)
|
||||||
from pretix.control.signals import (
|
from pretix.control.signals import (
|
||||||
item_forms, nav_event, order_info, order_position_buttons,
|
item_forms, nav_event, order_info, order_position_buttons,
|
||||||
@@ -173,35 +172,13 @@ def control_order_info(sender: Event, request, order: Order, **kwargs):
|
|||||||
return template.render(ctx, request=request)
|
return template.render(ctx, request=request)
|
||||||
|
|
||||||
|
|
||||||
@receiver(signal=logentry_display, dispatch_uid="badges_logentry_display")
|
@log_entry_types.new_from_dict({
|
||||||
def badges_logentry_display(sender, logentry, **kwargs):
|
'pretix.plugins.badges.layout.added': _('Badge layout created.'),
|
||||||
if not logentry.action_type.startswith('pretix.plugins.badges'):
|
'pretix.plugins.badges.layout.deleted': _('Badge layout deleted.'),
|
||||||
return
|
'pretix.plugins.badges.layout.changed': _('Badge layout changed.'),
|
||||||
|
})
|
||||||
plains = {
|
class BadgeLogEntryType(EventLogEntryType):
|
||||||
'pretix.plugins.badges.layout.added': _('Badge layout created.'),
|
object_type = BadgeLayout
|
||||||
'pretix.plugins.badges.layout.deleted': _('Badge layout deleted.'),
|
object_link_wrapper = _('Badge layout {val}')
|
||||||
'pretix.plugins.badges.layout.changed': _('Badge layout changed.'),
|
object_link_viewname = 'plugins:badges:edit'
|
||||||
}
|
object_link_argname = 'layout'
|
||||||
|
|
||||||
if logentry.action_type in plains:
|
|
||||||
return plains[logentry.action_type]
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(signal=logentry_object_link, dispatch_uid="badges_logentry_object_link")
|
|
||||||
def badges_logentry_object_link(sender, logentry, **kwargs):
|
|
||||||
if not logentry.action_type.startswith('pretix.plugins.badges.layout') or not isinstance(logentry.content_object,
|
|
||||||
BadgeLayout):
|
|
||||||
return
|
|
||||||
|
|
||||||
a_text = _('Badge layout {val}')
|
|
||||||
a_map = {
|
|
||||||
'href': reverse('plugins:badges:edit', kwargs={
|
|
||||||
'event': sender.slug,
|
|
||||||
'organizer': sender.organizer.slug,
|
|
||||||
'layout': logentry.content_object.id
|
|
||||||
}),
|
|
||||||
'val': escape(logentry.content_object.name),
|
|
||||||
}
|
|
||||||
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
|
|
||||||
return a_text.format_map(a_map)
|
|
||||||
|
|||||||
@@ -25,9 +25,12 @@ from django.urls import resolve, reverse
|
|||||||
from django.utils.translation import gettext_lazy as _, gettext_noop
|
from django.utils.translation import gettext_lazy as _, gettext_noop
|
||||||
from i18nfield.strings import LazyI18nString
|
from i18nfield.strings import LazyI18nString
|
||||||
|
|
||||||
from pretix.base.signals import logentry_display, register_payment_providers
|
from pretix.base.signals import register_payment_providers
|
||||||
from pretix.control.signals import html_head, nav_event, nav_organizer
|
from pretix.control.signals import html_head, nav_event, nav_organizer
|
||||||
|
|
||||||
|
from ...base.logentrytypes import (
|
||||||
|
ClearDataShredderMixin, OrderLogEntryType, log_entry_types,
|
||||||
|
)
|
||||||
from ...base.settings import settings_hierarkey
|
from ...base.settings import settings_hierarkey
|
||||||
from .payment import BankTransfer
|
from .payment import BankTransfer
|
||||||
|
|
||||||
@@ -117,13 +120,10 @@ def html_head_presale(sender, request=None, **kwargs):
|
|||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
@receiver(signal=logentry_display)
|
@log_entry_types.new()
|
||||||
def pretixcontrol_logentry_display(sender, logentry, **kwargs):
|
class BanktransferOrderEmailInvoiceLogEntryType(OrderLogEntryType, ClearDataShredderMixin):
|
||||||
plains = {
|
action_type = 'pretix.plugins.banktransfer.order.email.invoice'
|
||||||
'pretix.plugins.banktransfer.order.email.invoice': _('The invoice was sent to the designated email address.'),
|
plain = _('The invoice was sent to the designated email address.')
|
||||||
}
|
|
||||||
if logentry.action_type in plains:
|
|
||||||
return plains[logentry.action_type]
|
|
||||||
|
|
||||||
|
|
||||||
settings_hierarkey.add_default(
|
settings_hierarkey.add_default(
|
||||||
|
|||||||
@@ -669,7 +669,7 @@ class OrganizerActionView(OrganizerBanktransferView, OrganizerPermissionRequired
|
|||||||
|
|
||||||
|
|
||||||
def _row_key_func(row):
|
def _row_key_func(row):
|
||||||
return row['iban'], row.get('bic') or ''
|
return row['iban'], row['bic']
|
||||||
|
|
||||||
|
|
||||||
def _unite_transaction_rows(transaction_rows):
|
def _unite_transaction_rows(transaction_rows):
|
||||||
|
|||||||
@@ -22,17 +22,10 @@
|
|||||||
|
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from pretix.base.signals import logentry_display, register_payment_providers
|
from pretix.base.signals import register_payment_providers
|
||||||
|
|
||||||
|
|
||||||
@receiver(register_payment_providers, dispatch_uid="payment_paypal")
|
@receiver(register_payment_providers, dispatch_uid="payment_paypal")
|
||||||
def register_payment_provider(sender, **kwargs):
|
def register_payment_provider(sender, **kwargs):
|
||||||
from .payment import Paypal
|
from .payment import Paypal
|
||||||
return Paypal
|
return Paypal
|
||||||
|
|
||||||
|
|
||||||
@receiver(signal=logentry_display, dispatch_uid="paypal_logentry_display")
|
|
||||||
def pretixcontrol_logentry_display(sender, logentry, **kwargs):
|
|
||||||
from pretix.plugins.paypal2.signals import pretixcontrol_logentry_display
|
|
||||||
|
|
||||||
return pretixcontrol_logentry_display(sender, logentry, **kwargs)
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||||
# <https://www.gnu.org/licenses/>.
|
# <https://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
import json
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
@@ -32,10 +31,11 @@ from django.utils.crypto import get_random_string
|
|||||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||||
|
|
||||||
from pretix.base.forms import SecretKeySettingsField
|
from pretix.base.forms import SecretKeySettingsField
|
||||||
|
from pretix.base.logentrytypes import EventLogEntryType, log_entry_types
|
||||||
from pretix.base.middleware import _merge_csp, _parse_csp, _render_csp
|
from pretix.base.middleware import _merge_csp, _parse_csp, _render_csp
|
||||||
from pretix.base.settings import settings_hierarkey
|
from pretix.base.settings import settings_hierarkey
|
||||||
from pretix.base.signals import (
|
from pretix.base.signals import (
|
||||||
logentry_display, register_global_settings, register_payment_providers,
|
register_global_settings, register_payment_providers,
|
||||||
)
|
)
|
||||||
from pretix.plugins.paypal2.payment import PaypalMethod
|
from pretix.plugins.paypal2.payment import PaypalMethod
|
||||||
from pretix.presale.signals import html_head, process_response
|
from pretix.presale.signals import html_head, process_response
|
||||||
@@ -47,33 +47,32 @@ def register_payment_provider(sender, **kwargs):
|
|||||||
return [PaypalSettingsHolder, PaypalWallet, PaypalAPM]
|
return [PaypalSettingsHolder, PaypalWallet, PaypalAPM]
|
||||||
|
|
||||||
|
|
||||||
@receiver(signal=logentry_display, dispatch_uid="paypal2_logentry_display")
|
@log_entry_types.new()
|
||||||
def pretixcontrol_logentry_display(sender, logentry, **kwargs):
|
class PaypalEventLogEntryType(EventLogEntryType):
|
||||||
if logentry.action_type != 'pretix.plugins.paypal.event':
|
action_type = 'pretix.plugins.paypal.event'
|
||||||
return
|
|
||||||
|
|
||||||
data = json.loads(logentry.data)
|
def display(self, logentry):
|
||||||
event_type = data.get('event_type')
|
event_type = logentry.parsed_data.get('event_type')
|
||||||
text = None
|
text = None
|
||||||
plains = {
|
plains = {
|
||||||
'PAYMENT.SALE.COMPLETED': _('Payment completed.'),
|
'PAYMENT.SALE.COMPLETED': _('Payment completed.'),
|
||||||
'PAYMENT.SALE.DENIED': _('Payment denied.'),
|
'PAYMENT.SALE.DENIED': _('Payment denied.'),
|
||||||
'PAYMENT.SALE.REFUNDED': _('Payment refunded.'),
|
'PAYMENT.SALE.REFUNDED': _('Payment refunded.'),
|
||||||
'PAYMENT.SALE.REVERSED': _('Payment reversed.'),
|
'PAYMENT.SALE.REVERSED': _('Payment reversed.'),
|
||||||
'PAYMENT.SALE.PENDING': _('Payment pending.'),
|
'PAYMENT.SALE.PENDING': _('Payment pending.'),
|
||||||
'CHECKOUT.ORDER.APPROVED': pgettext_lazy('paypal', 'Order approved.'),
|
'CHECKOUT.ORDER.APPROVED': pgettext_lazy('paypal', 'Order approved.'),
|
||||||
'CHECKOUT.ORDER.COMPLETED': pgettext_lazy('paypal', 'Order completed.'),
|
'CHECKOUT.ORDER.COMPLETED': pgettext_lazy('paypal', 'Order completed.'),
|
||||||
'PAYMENT.CAPTURE.COMPLETED': pgettext_lazy('paypal', 'Capture completed.'),
|
'PAYMENT.CAPTURE.COMPLETED': pgettext_lazy('paypal', 'Capture completed.'),
|
||||||
'PAYMENT.CAPTURE.PENDING': pgettext_lazy('paypal', 'Capture pending.'),
|
'PAYMENT.CAPTURE.PENDING': pgettext_lazy('paypal', 'Capture pending.'),
|
||||||
}
|
}
|
||||||
|
|
||||||
if event_type in plains:
|
if event_type in plains:
|
||||||
text = plains[event_type]
|
text = plains[event_type]
|
||||||
else:
|
else:
|
||||||
text = event_type
|
text = event_type
|
||||||
|
|
||||||
if text:
|
if text:
|
||||||
return _('PayPal reported an event: {}').format(text)
|
return _('PayPal reported an event: {}').format(text)
|
||||||
|
|
||||||
|
|
||||||
@receiver(register_global_settings, dispatch_uid='paypal2_global_settings')
|
@receiver(register_global_settings, dispatch_uid='paypal2_global_settings')
|
||||||
|
|||||||
@@ -46,13 +46,16 @@ from django.utils.timezone import now
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_scopes import scope, scopes_disabled
|
from django_scopes import scope, scopes_disabled
|
||||||
|
|
||||||
|
from pretix.base.logentrytypes import (
|
||||||
|
EventLogEntryType, OrderLogEntryType, log_entry_types,
|
||||||
|
)
|
||||||
from pretix.base.models import SubEvent
|
from pretix.base.models import SubEvent
|
||||||
from pretix.base.signals import (
|
from pretix.base.signals import (
|
||||||
EventPluginSignal, event_copy_data, logentry_display, periodic_task,
|
EventPluginSignal, event_copy_data, periodic_task,
|
||||||
)
|
)
|
||||||
from pretix.control.signals import nav_event
|
from pretix.control.signals import nav_event
|
||||||
from pretix.helpers import OF_SELF
|
from pretix.helpers import OF_SELF
|
||||||
from pretix.plugins.sendmail.models import ScheduledMail
|
from pretix.plugins.sendmail.models import Rule, ScheduledMail
|
||||||
from pretix.plugins.sendmail.views import OrderSendView, WaitinglistSendView
|
from pretix.plugins.sendmail.views import OrderSendView, WaitinglistSendView
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -116,21 +119,28 @@ def control_nav_import(sender, request=None, **kwargs):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@receiver(signal=logentry_display)
|
@log_entry_types.new('pretix.plugins.sendmail.sent', _('Mass email was sent to customers or attendees.'))
|
||||||
def pretixcontrol_logentry_display(sender, logentry, **kwargs):
|
@log_entry_types.new('pretix.plugins.sendmail.sent.waitinglist', _('Mass email was sent to waiting list entries.'))
|
||||||
plains = {
|
class SendmailPluginLogEntryType(EventLogEntryType):
|
||||||
'pretix.plugins.sendmail.sent': _('Mass email was sent to customers or attendees.'),
|
pass
|
||||||
'pretix.plugins.sendmail.sent.waitinglist': _('Mass email was sent to waiting list entries.'),
|
|
||||||
'pretix.plugins.sendmail.order.email.sent': _('The order received a mass email.'),
|
|
||||||
'pretix.plugins.sendmail.order.email.sent.attendee': _('A ticket holder of this order received a mass email.'),
|
@log_entry_types.new('pretix.plugins.sendmail.order.email.sent', _('The order received a mass email.'))
|
||||||
'pretix.plugins.sendmail.rule.added': _('An email rule was created'),
|
@log_entry_types.new('pretix.plugins.sendmail.order.email.sent.attendee', _('A ticket holder of this order received a mass email.'))
|
||||||
'pretix.plugins.sendmail.rule.changed': _('An email rule was updated'),
|
class SendmailPluginOrderLogEntryType(OrderLogEntryType):
|
||||||
'pretix.plugins.sendmail.rule.order.email.sent': _('A scheduled email was sent to the order'),
|
pass
|
||||||
'pretix.plugins.sendmail.rule.order.position.email.sent': _('A scheduled email was sent to a ticket holder'),
|
|
||||||
'pretix.plugins.sendmail.rule.deleted': _('An email rule was deleted'),
|
|
||||||
}
|
@log_entry_types.new('pretix.plugins.sendmail.rule.added', _('An email rule was created'))
|
||||||
if logentry.action_type in plains:
|
@log_entry_types.new('pretix.plugins.sendmail.rule.changed', _('An email rule was updated'))
|
||||||
return plains[logentry.action_type]
|
@log_entry_types.new('pretix.plugins.sendmail.rule.order.email.sent', _('A scheduled email was sent to the order'))
|
||||||
|
@log_entry_types.new('pretix.plugins.sendmail.rule.order.position.email.sent', _('A scheduled email was sent to a ticket holder'))
|
||||||
|
@log_entry_types.new('pretix.plugins.sendmail.rule.deleted', _('An email rule was deleted'))
|
||||||
|
class SendmailPluginRuleLogEntryType(EventLogEntryType):
|
||||||
|
object_type = Rule
|
||||||
|
object_link_wrapper = _('Mail rule {val}')
|
||||||
|
object_link_viewname = 'plugins:sendmail:rule.update'
|
||||||
|
object_link_argname = 'rule'
|
||||||
|
|
||||||
|
|
||||||
@receiver(periodic_task)
|
@receiver(periodic_task)
|
||||||
|
|||||||
@@ -31,8 +31,6 @@
|
|||||||
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
|
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
|
||||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations under the License.
|
# License for the specific language governing permissions and limitations under the License.
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from django.db.models import Exists, OuterRef, Q
|
from django.db.models import Exists, OuterRef, Q
|
||||||
from i18nfield.strings import LazyI18nString
|
from i18nfield.strings import LazyI18nString
|
||||||
|
|
||||||
@@ -47,7 +45,6 @@ from pretix.helpers.format import format_map
|
|||||||
|
|
||||||
@app.task(base=ProfiledEventTask, acks_late=True)
|
@app.task(base=ProfiledEventTask, acks_late=True)
|
||||||
def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict, objects: list, items: list,
|
def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict, objects: list, items: list,
|
||||||
subevent: int, subevents_from: datetime, subevents_to: datetime,
|
|
||||||
recipients: str, filter_checkins: bool, not_checked_in: bool, checkin_lists: list,
|
recipients: str, filter_checkins: bool, not_checked_in: bool, checkin_lists: list,
|
||||||
attachments: list = None, attach_tickets: bool = False,
|
attachments: list = None, attach_tickets: bool = False,
|
||||||
attach_ical: bool = False) -> None:
|
attach_ical: bool = False) -> None:
|
||||||
@@ -79,7 +76,7 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
|
|||||||
list_id__in=checkin_lists or []
|
list_id__in=checkin_lists or []
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
).prefetch_related('addons', 'subevent'):
|
).prefetch_related('addons'):
|
||||||
if p.addon_to_id is not None:
|
if p.addon_to_id is not None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -102,15 +99,6 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
|
|||||||
if p.attendee_email == o.email and send_to_order:
|
if p.attendee_email == o.email and send_to_order:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if subevent and p.subevent_id != subevent:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if subevents_from and p.subevent.date_from < subevents_from:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if subevents_to and p.subevent.date_from >= subevents_to:
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with language(o.locale, event.settings.region):
|
with language(o.locale, event.settings.region):
|
||||||
email_context = get_email_context(event=event, order=o, invoice_address=ia, position=p)
|
email_context = get_email_context(event=event, order=o, invoice_address=ia, position=p)
|
||||||
|
|||||||
@@ -429,9 +429,6 @@ class OrderSendView(BaseSenderView):
|
|||||||
kwargs.update({
|
kwargs.update({
|
||||||
'recipients': form.cleaned_data['recipients'],
|
'recipients': form.cleaned_data['recipients'],
|
||||||
'items': [i.pk for i in form.cleaned_data.get('items')],
|
'items': [i.pk for i in form.cleaned_data.get('items')],
|
||||||
'subevent': form.cleaned_data['subevent'].pk if form.cleaned_data.get('subevent') else None,
|
|
||||||
'subevents_from': form.cleaned_data.get('subevents_from'),
|
|
||||||
'subevents_to': form.cleaned_data.get('subevents_to'),
|
|
||||||
'not_checked_in': form.cleaned_data.get('not_checked_in'),
|
'not_checked_in': form.cleaned_data.get('not_checked_in'),
|
||||||
'checkin_lists': [i.pk for i in form.cleaned_data.get('checkin_lists')],
|
'checkin_lists': [i.pk for i in form.cleaned_data.get('checkin_lists')],
|
||||||
'filter_checkins': form.cleaned_data.get('filter_checkins'),
|
'filter_checkins': form.cleaned_data.get('filter_checkins'),
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<script type="text/plain" id="stripe_payment_intent_client_secret">{{ payment_intent_client_secret }}</script>
|
<script type="text/plain" id="stripe_payment_intent_client_secret">{{ payment_intent_client_secret }}</script>
|
||||||
{% if payment_intent_next_action_redirect_url %}
|
{% if payment_intent_next_action_redirect_url %}
|
||||||
<script type="text/plain" id="stripe_payment_intent_next_action_redirect_url">{{ payment_intent_next_action_redirect_url }}</script>
|
<script type="text/plain" id="stripe_payment_intent_next_action_redirect_url">{{ payment_intent_next_action_redirect_url }}</script>
|
||||||
{% endif %}
|
{% endif %}}
|
||||||
{% if payment_intent_redirect_action_handling %}
|
{% if payment_intent_redirect_action_handling %}
|
||||||
<script type="text/plain" id="stripe_payment_intent_redirect_action_handling">{{ payment_intent_redirect_action_handling }}</script>
|
<script type="text/plain" id="stripe_payment_intent_redirect_action_handling">{{ payment_intent_redirect_action_handling }}</script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ import json
|
|||||||
|
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.html import escape
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from pretix.base.logentrytypes import EventLogEntryType
|
||||||
from pretix.base.models import Event, SalesChannel
|
from pretix.base.models import Event, SalesChannel
|
||||||
|
from pretix.base.models.log import log_entry_types
|
||||||
from pretix.base.signals import ( # NOQA: legacy import
|
from pretix.base.signals import ( # NOQA: legacy import
|
||||||
EventPluginSignal, event_copy_data, item_copy_data, layout_text_variables,
|
EventPluginSignal, event_copy_data, item_copy_data, layout_text_variables,
|
||||||
logentry_display, logentry_object_link, register_data_exporters,
|
logentry_display, logentry_object_link, register_data_exporters,
|
||||||
@@ -134,38 +134,16 @@ def pdf_event_copy_data_receiver(sender, other, item_map, question_map, **kwargs
|
|||||||
return layout_map
|
return layout_map
|
||||||
|
|
||||||
|
|
||||||
@receiver(signal=logentry_display, dispatch_uid="pretix_ticketoutputpdf_logentry_display")
|
@log_entry_types.new_from_dict({
|
||||||
def pdf_logentry_display(sender, logentry, **kwargs):
|
'pretix.plugins.ticketoutputpdf.layout.added': _('Ticket layout created.'),
|
||||||
if not logentry.action_type.startswith('pretix.plugins.ticketoutputpdf'):
|
'pretix.plugins.ticketoutputpdf.layout.deleted': _('Ticket layout deleted.'),
|
||||||
return
|
'pretix.plugins.ticketoutputpdf.layout.changed': _('Ticket layout changed.'),
|
||||||
|
})
|
||||||
plains = {
|
class PdfTicketLayoutLogEntryType(EventLogEntryType):
|
||||||
'pretix.plugins.ticketoutputpdf.layout.added': _('Ticket layout created.'),
|
object_type = TicketLayout
|
||||||
'pretix.plugins.ticketoutputpdf.layout.deleted': _('Ticket layout deleted.'),
|
object_link_wrapper = _('Ticket layout {val}')
|
||||||
'pretix.plugins.ticketoutputpdf.layout.changed': _('Ticket layout changed.'),
|
object_link_viewname = 'plugins:ticketoutputpdf:edit'
|
||||||
}
|
object_link_argname = 'layout'
|
||||||
|
|
||||||
if logentry.action_type in plains:
|
|
||||||
return plains[logentry.action_type]
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(signal=logentry_object_link, dispatch_uid="pretix_ticketoutputpdf_logentry_object_link")
|
|
||||||
def pdf_logentry_object_link(sender, logentry, **kwargs):
|
|
||||||
if not logentry.action_type.startswith('pretix.plugins.ticketoutputpdf.layout') or not isinstance(
|
|
||||||
logentry.content_object, TicketLayout):
|
|
||||||
return
|
|
||||||
|
|
||||||
a_text = _('Ticket layout {val}')
|
|
||||||
a_map = {
|
|
||||||
'href': reverse('plugins:ticketoutputpdf:edit', kwargs={
|
|
||||||
'event': sender.slug,
|
|
||||||
'organizer': sender.organizer.slug,
|
|
||||||
'layout': logentry.content_object.id
|
|
||||||
}),
|
|
||||||
'val': escape(logentry.content_object.name),
|
|
||||||
}
|
|
||||||
a_map['val'] = '<a href="{href}">{val}</a>'.format_map(a_map)
|
|
||||||
return a_text.format_map(a_map)
|
|
||||||
|
|
||||||
|
|
||||||
def _ticket_layouts_for_item(request, item):
|
def _ticket_layouts_for_item(request, item):
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ from django.views.generic.base import TemplateResponseMixin
|
|||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
from pretix.base.models import Customer, Membership, Order
|
from pretix.base.models import Customer, Membership, Order
|
||||||
from pretix.base.models.items import ItemAddOn, ItemVariation, Question
|
from pretix.base.models.items import Question
|
||||||
from pretix.base.models.orders import (
|
from pretix.base.models.orders import (
|
||||||
InvoiceAddress, OrderPayment, QuestionAnswer,
|
InvoiceAddress, OrderPayment, QuestionAnswer,
|
||||||
)
|
)
|
||||||
@@ -486,33 +486,9 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep):
|
|||||||
label = pgettext_lazy('checkoutflow', 'Add-on products')
|
label = pgettext_lazy('checkoutflow', 'Add-on products')
|
||||||
icon = 'puzzle-piece'
|
icon = 'puzzle-piece'
|
||||||
|
|
||||||
def _is_applicable(self, request):
|
|
||||||
categories = set(ItemAddOn.objects.filter(
|
|
||||||
base_item_id__in=get_cart(request).values_list("item_id", flat=True)
|
|
||||||
).values_list("addon_category_id", flat=True))
|
|
||||||
if not categories:
|
|
||||||
return False
|
|
||||||
|
|
||||||
has_available_addons = (
|
|
||||||
self.event.items.filter_available(
|
|
||||||
channel=request.sales_channel,
|
|
||||||
allow_addons=True
|
|
||||||
).filter(
|
|
||||||
variations__isnull=True,
|
|
||||||
category__in=categories,
|
|
||||||
).exists() or ItemVariation.objects.filter_available(
|
|
||||||
channel=request.sales_channel,
|
|
||||||
allow_addons=True
|
|
||||||
).filter(
|
|
||||||
item__event=self.event,
|
|
||||||
item__category__in=categories,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return has_available_addons
|
|
||||||
|
|
||||||
def is_applicable(self, request):
|
def is_applicable(self, request):
|
||||||
if not hasattr(request, '_checkoutflow_addons_applicable'):
|
if not hasattr(request, '_checkoutflow_addons_applicable'):
|
||||||
request._checkoutflow_addons_applicable = self._is_applicable(request)
|
request._checkoutflow_addons_applicable = get_cart(request).filter(item__addons__isnull=False).exists()
|
||||||
return request._checkoutflow_addons_applicable
|
return request._checkoutflow_addons_applicable
|
||||||
|
|
||||||
def is_completed(self, request, warn=False):
|
def is_completed(self, request, warn=False):
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||||
# <https://www.gnu.org/licenses/>.
|
# <https://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
import functools
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import ipaddress
|
import ipaddress
|
||||||
import random
|
import random
|
||||||
@@ -28,7 +27,7 @@ from django import forms
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.hashers import check_password
|
from django.contrib.auth.hashers import check_password
|
||||||
from django.contrib.auth.password_validation import (
|
from django.contrib.auth.password_validation import (
|
||||||
get_password_validators, password_validators_help_texts, validate_password,
|
password_validators_help_texts, validate_password,
|
||||||
)
|
)
|
||||||
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
||||||
from django.core import signing
|
from django.core import signing
|
||||||
@@ -272,11 +271,6 @@ class RegistrationForm(forms.Form):
|
|||||||
return customer
|
return customer
|
||||||
|
|
||||||
|
|
||||||
@functools.lru_cache(maxsize=None)
|
|
||||||
def get_customer_password_validators():
|
|
||||||
return get_password_validators(settings.CUSTOMER_AUTH_PASSWORD_VALIDATORS)
|
|
||||||
|
|
||||||
|
|
||||||
class SetPasswordForm(forms.Form):
|
class SetPasswordForm(forms.Form):
|
||||||
required_css_class = 'required'
|
required_css_class = 'required'
|
||||||
error_messages = {
|
error_messages = {
|
||||||
@@ -317,7 +311,7 @@ class SetPasswordForm(forms.Form):
|
|||||||
|
|
||||||
def clean_password(self):
|
def clean_password(self):
|
||||||
password1 = self.cleaned_data.get('password', '')
|
password1 = self.cleaned_data.get('password', '')
|
||||||
if validate_password(password1, user=self.customer, password_validators=get_customer_password_validators()) is not None:
|
if validate_password(password1, user=self.customer) is not None:
|
||||||
raise forms.ValidationError(_(password_validators_help_texts()), code='pw_invalid')
|
raise forms.ValidationError(_(password_validators_help_texts()), code='pw_invalid')
|
||||||
return password1
|
return password1
|
||||||
|
|
||||||
@@ -411,7 +405,7 @@ class ChangePasswordForm(forms.Form):
|
|||||||
|
|
||||||
def clean_password(self):
|
def clean_password(self):
|
||||||
password1 = self.cleaned_data.get('password', '')
|
password1 = self.cleaned_data.get('password', '')
|
||||||
if validate_password(password1, user=self.customer, password_validators=get_customer_password_validators()) is not None:
|
if validate_password(password1, user=self.customer) is not None:
|
||||||
raise forms.ValidationError(_(password_validators_help_texts()), code='pw_invalid')
|
raise forms.ValidationError(_(password_validators_help_texts()), code='pw_invalid')
|
||||||
return password1
|
return password1
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
<span class="label label-success">{% trans "Book now" %}</span>
|
<span class="label label-success">{% trans "Book now" %}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif subev.waiting_list_active and subev.best_availability_state >= 0 %}
|
{% elif event.waiting_list_active and subev.best_availability_state >= 0 %}
|
||||||
<span class="label label-warning">{% trans "Waiting list" %}</span>
|
<span class="label label-warning">{% trans "Waiting list" %}</span>
|
||||||
{% elif subev.best_availability_state == 20 %}
|
{% elif subev.best_availability_state == 20 %}
|
||||||
<span class="label label-danger">{% trans "Reserved" %}</span>
|
<span class="label label-danger">{% trans "Reserved" %}</span>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
<script src="{% statici18n request.LANGUAGE_CODE %}" async></script>
|
<script src="{% statici18n request.LANGUAGE_CODE %}" async></script>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.session.iframe_session %}
|
{% if request.session.iframe_session %}
|
||||||
{% compress js file iframeresizer %}
|
{% compress js %}
|
||||||
<script type="text/javascript" src="{% static "iframeresizer/iframeResizer.contentWindow.js" %}"></script>
|
<script type="text/javascript" src="{% static "iframeresizer/iframeResizer.contentWindow.js" %}"></script>
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user