mirror of
https://github.com/pretix/pretix.git
synced 2026-08-19 12:16:26 +00:00
Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d15706f36f | ||
|
|
442145bde4 | ||
|
|
bcb8b0a85a | ||
|
|
8528b5d943 | ||
|
|
00783f5146 | ||
|
|
e3219c7403 | ||
|
|
abb1959d8a | ||
|
|
688fc8fedc | ||
|
|
eb7811a94f | ||
|
|
f709bdaa7d |
@@ -71,8 +71,6 @@ Checking a ticket in
|
||||
:>json object questions: List of questions to be answered for check-in, only set on status ``"incomplete"``.
|
||||
:>json object media_policy: Reusable media policy (see documentation on items), only set on status ``"exchange"``.
|
||||
:>json object media_type: Reusable media type (see documentation on items), only set on status ``"exchange"``.
|
||||
:>json boolean simulate: Do not actually perform the check-in, only simulate the response. The ``position`` response
|
||||
object will not reflect the simulated changes.
|
||||
|
||||
**Example request**:
|
||||
|
||||
|
||||
@@ -2038,7 +2038,7 @@ Manipulating individual positions
|
||||
|
||||
* ``order`` (mandatory, specified as a string mapping to a ``code``)
|
||||
|
||||
* ``addon_to`` (optional, specified as an integer mapping to ``positionid`` - the number of the position within the order, see :ref:`_order-position-resource` - of the parent position)
|
||||
* ``addon_to`` (optional, specified as an integer mapping to the ``positionid`` of the parent position)
|
||||
|
||||
* ``item`` (mandatory)
|
||||
|
||||
@@ -2348,7 +2348,7 @@ otherwise, such as splitting an order or changing fees.
|
||||
"subevent": 562,
|
||||
"seat": "seat-guid-2",
|
||||
"price": "99.99",
|
||||
"addon_to": 1,
|
||||
"addon_to": 12374,
|
||||
"attendee_name": "Peter",
|
||||
}
|
||||
],
|
||||
|
||||
@@ -83,7 +83,7 @@ Dashboards
|
||||
|
||||
.. automodule:: pretix.control.signals
|
||||
:no-index:
|
||||
:members: event_dashboard_widgets, user_dashboard_widgets, event_dashboard_top
|
||||
:members: event_dashboard_statistics, user_dashboard_widgets, event_dashboard_top
|
||||
|
||||
Ticket designs
|
||||
""""""""""""""
|
||||
|
||||
Generated
+7
-7
@@ -3176,9 +3176,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.16",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
|
||||
"integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==",
|
||||
"version": "3.3.12",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz",
|
||||
"integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -3352,9 +3352,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.23",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz",
|
||||
"integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==",
|
||||
"version": "8.5.15",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz",
|
||||
"integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
@@ -3371,7 +3371,7 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.16",
|
||||
"nanoid": "^3.3.12",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
|
||||
+7
-7
@@ -33,12 +33,12 @@ dependencies = [
|
||||
"bleach==6.4.*",
|
||||
"celery==5.6.*",
|
||||
"chardet==5.2.*",
|
||||
"cryptography>=50.0.0",
|
||||
"cryptography>=49.0.0",
|
||||
"css-inline==0.21.*",
|
||||
"defusedcsv>=3.0.0",
|
||||
"dnspython==2.*",
|
||||
"Django[argon2]==5.2.*",
|
||||
"django-bootstrap3==26.2",
|
||||
"django-bootstrap3==26.1",
|
||||
"django-compressor==4.6.0",
|
||||
"django-countries==9.0.*",
|
||||
"django-filter==26.1",
|
||||
@@ -48,11 +48,11 @@ dependencies = [
|
||||
"django-hijack==3.7.*",
|
||||
"django-i18nfield==1.11.*",
|
||||
"django-libsass==0.9",
|
||||
"django-localflavor==5.1",
|
||||
"django-localflavor==5.0",
|
||||
"django-markup",
|
||||
"django-oauth-toolkit==2.3.*",
|
||||
"django-otp==1.7.*",
|
||||
"django-phonenumber-field==8.5.*",
|
||||
"django-phonenumber-field==8.4.*",
|
||||
"django-querytagger==0.0.3",
|
||||
"django-redis==7.0.*",
|
||||
"django-scopes==2.1.*",
|
||||
@@ -67,7 +67,7 @@ dependencies = [
|
||||
"kombu==5.6.*",
|
||||
"libsass==0.23.*",
|
||||
"lxml",
|
||||
"markdown==3.10.3", # 3.3.5 requires importlib-metadata>=4.4, but django-bootstrap3 requires importlib-metadata<3.
|
||||
"markdown==3.10.2", # 3.3.5 requires importlib-metadata>=4.4, but django-bootstrap3 requires importlib-metadata<3.
|
||||
# We can upgrade markdown again once django-bootstrap3 upgrades or once we drop Python 3.6 and 3.7
|
||||
"mt-940==4.30.*",
|
||||
"oauthlib==3.3.*",
|
||||
@@ -94,11 +94,11 @@ dependencies = [
|
||||
"redis==7.4.*",
|
||||
"reportlab==5.0.*",
|
||||
"requests==2.34.*",
|
||||
"sentry-sdk==2.68.*",
|
||||
"sentry-sdk==2.66.*",
|
||||
"sepaxml==2.7.*",
|
||||
"stripe==7.9.*",
|
||||
"text-unidecode==1.*",
|
||||
"tlds>=2026072401",
|
||||
"tlds>=2026041800",
|
||||
"tqdm==4.*",
|
||||
"ua-parser==1.0.*",
|
||||
"vobject==0.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
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
__version__ = "2026.8.0.dev0"
|
||||
__version__ = "2026.7.0.dev0"
|
||||
|
||||
@@ -104,7 +104,6 @@ ALL_LANGUAGES = [
|
||||
('gl', _('Galician')),
|
||||
('el', _('Greek')),
|
||||
('he', _('Hebrew')),
|
||||
('hu', _('Hungarian')),
|
||||
('id', _('Indonesian')),
|
||||
('it', _('Italian')),
|
||||
('ja', _('Japanese')),
|
||||
|
||||
@@ -20,11 +20,8 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.db import DatabaseError
|
||||
from django.utils.timezone import now
|
||||
from django_scopes import scopes_disabled
|
||||
from rest_framework import exceptions
|
||||
from rest_framework.authentication import TokenAuthentication
|
||||
@@ -33,7 +30,6 @@ from pretix.api.auth.devicesecurity import (
|
||||
FullAccessSecurityProfile, get_all_security_profiles,
|
||||
)
|
||||
from pretix.base.models import Device
|
||||
from pretix.base.models.devices import DeviceLastSeen
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -46,7 +42,7 @@ class DeviceTokenAuthentication(TokenAuthentication):
|
||||
model = self.get_model()
|
||||
try:
|
||||
with scopes_disabled():
|
||||
device = model.objects.select_related('organizer', 'last_seen').get(api_token=key)
|
||||
device = model.objects.select_related('organizer').get(api_token=key)
|
||||
except model.DoesNotExist:
|
||||
raise exceptions.AuthenticationFailed('Invalid token.')
|
||||
|
||||
@@ -57,7 +53,6 @@ class DeviceTokenAuthentication(TokenAuthentication):
|
||||
logging.warning(f'Connection attempt of revoked device {device.pk}.')
|
||||
raise exceptions.AuthenticationFailed('Device access has been revoked.')
|
||||
|
||||
self._update_last_seen(device)
|
||||
return AnonymousUser(), device
|
||||
|
||||
def authenticate(self, request):
|
||||
@@ -68,22 +63,3 @@ class DeviceTokenAuthentication(TokenAuthentication):
|
||||
if not profile.is_allowed(request):
|
||||
raise exceptions.PermissionDenied('Request denied by device security profile.')
|
||||
return r
|
||||
|
||||
def _update_last_seen(self, device: Device):
|
||||
try:
|
||||
try:
|
||||
last_seen_obj = device.last_seen
|
||||
except DeviceLastSeen.DoesNotExist:
|
||||
# First request from device, create model, ignore result. Use get_or_create to be safe
|
||||
# against concurrent create requests
|
||||
DeviceLastSeen.objects.get_or_create(device=device, last_seen=now())
|
||||
else:
|
||||
if now() - last_seen_obj.last_seen < timedelta(seconds=10):
|
||||
# We don't need to know the last seen info of a device to more precision than this,
|
||||
# so we can avoid some database writes if the device is bursting a lot of requests.
|
||||
return
|
||||
last_seen_obj.last_seen = now()
|
||||
last_seen_obj.save(update_fields=["last_seen"])
|
||||
except DatabaseError:
|
||||
# Do not stop the request from happening
|
||||
logger.exception("Database error while updating last_seen")
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import logging
|
||||
from collections import OrderedDict
|
||||
|
||||
from django.dispatch import receiver
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@@ -51,18 +52,10 @@ class BaseSecurityProfile:
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def priority(self) -> int:
|
||||
"""
|
||||
Priority for ordering, higher will come first.
|
||||
"""
|
||||
return 100
|
||||
|
||||
|
||||
class FullAccessSecurityProfile(BaseSecurityProfile):
|
||||
identifier = 'full'
|
||||
verbose_name = _('Full device access (reading and changing orders and gift cards, reading of products and settings)')
|
||||
priority = 1000
|
||||
|
||||
def is_allowed(self, request):
|
||||
return True
|
||||
@@ -115,7 +108,7 @@ class PretixScanSecurityProfile(AllowListSecurityProfile):
|
||||
('GET', 'api-v1:event.settings'),
|
||||
('POST', 'api-v1:upload'),
|
||||
('POST', 'api-v1:checkinrpc.redeem'),
|
||||
('POST', 'api-v1:checkinrpc.annul'),
|
||||
('POST', 'api-v1:checkinrpc.annull'),
|
||||
('GET', 'api-v1:checkinrpc.search'),
|
||||
('GET', 'api-v1:reusablemedium-list'),
|
||||
('POST', 'api-v1:reusablemedium-lookup'),
|
||||
@@ -154,7 +147,7 @@ class PretixScanNoSyncNoSearchSecurityProfile(AllowListSecurityProfile):
|
||||
('GET', 'api-v1:event.settings'),
|
||||
('POST', 'api-v1:upload'),
|
||||
('POST', 'api-v1:checkinrpc.redeem'),
|
||||
('POST', 'api-v1:checkinrpc.annul'),
|
||||
('POST', 'api-v1:checkinrpc.annull'),
|
||||
('GET', 'api-v1:checkinrpc.search'),
|
||||
)
|
||||
|
||||
@@ -191,7 +184,7 @@ class PretixScanNoSyncSecurityProfile(AllowListSecurityProfile):
|
||||
('GET', 'api-v1:event.settings'),
|
||||
('POST', 'api-v1:upload'),
|
||||
('POST', 'api-v1:checkinrpc.redeem'),
|
||||
('POST', 'api-v1:checkinrpc.annul'),
|
||||
('POST', 'api-v1:checkinrpc.annull'),
|
||||
('GET', 'api-v1:checkinrpc.search'),
|
||||
)
|
||||
|
||||
@@ -202,15 +195,13 @@ def get_all_security_profiles():
|
||||
if _ALL_PROFILES:
|
||||
return _ALL_PROFILES
|
||||
|
||||
types = []
|
||||
types = OrderedDict()
|
||||
for recv, ret in register_device_security_profile.send(None):
|
||||
if isinstance(ret, (list, tuple)):
|
||||
for r in ret:
|
||||
types.append(r)
|
||||
types[r.identifier] = r
|
||||
else:
|
||||
types.append(ret)
|
||||
types.sort(key=lambda el: el.priority, reverse=True)
|
||||
types = {r.identifier: r for r in types}
|
||||
types[ret.identifier] = ret
|
||||
_ALL_PROFILES = types
|
||||
return types
|
||||
|
||||
|
||||
@@ -90,7 +90,6 @@ class CheckinRPCRedeemInputSerializer(serializers.Serializer):
|
||||
answers = serializers.JSONField(required=False, allow_null=True)
|
||||
exchange_medium_type = serializers.ChoiceField(required=False, choices=MEDIA_TYPES)
|
||||
exchange_medium_identifier = serializers.CharField(required=False)
|
||||
simulate = serializers.BooleanField(default=False, required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -619,7 +619,7 @@ class QuestionSerializer(I18nAwareModelSerializer):
|
||||
options_data = validated_data.pop('options') if 'options' in validated_data else []
|
||||
items = validated_data.pop('items', [])
|
||||
|
||||
question = Question.objects.create(**validated_data, container_type=Question.ContainerType.ORDERPOSITION)
|
||||
question = Question.objects.create(**validated_data)
|
||||
question.items.set(items)
|
||||
for opt_data in options_data:
|
||||
QuestionOption.objects.create(question=question, **opt_data)
|
||||
|
||||
@@ -139,7 +139,6 @@ class CheckinListViewSet(viewsets.ModelViewSet):
|
||||
)
|
||||
return qs
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -154,7 +153,6 @@ class CheckinListViewSet(viewsets.ModelViewSet):
|
||||
ctx['event'] = self.request.event
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -839,11 +837,6 @@ def _redeem_process(*, checkinlists, raw_barcode, answers_data, datetime, force,
|
||||
)
|
||||
|
||||
if exchange_medium_identifier: # other fields are filled, see CheckinRPCRedeemInputSerializer.validate
|
||||
if simulate:
|
||||
raise CheckInError(
|
||||
gettext('You cannot simulate a medium exchange.'),
|
||||
'error'
|
||||
)
|
||||
with transaction.atomic():
|
||||
# Do exchange and check-in atomically, i.e. both succeed or both fail
|
||||
medium = perform_media_exchange(
|
||||
@@ -1071,7 +1064,6 @@ class CheckinRPCRedeemView(views.APIView):
|
||||
legacy_url_support=False,
|
||||
exchange_medium_type=s.validated_data.get('exchange_medium_type'),
|
||||
exchange_medium_identifier=s.validated_data.get('exchange_medium_identifier'),
|
||||
simulate=s.validated_data.get('simulate'),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
# 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.
|
||||
|
||||
from django.db import transaction
|
||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||
from django_scopes import scopes_disabled
|
||||
from rest_framework import viewsets
|
||||
@@ -65,7 +64,6 @@ class DiscountViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
'limit_sales_channels',
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -80,7 +78,6 @@ class DiscountViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
ctx['event'] = self.request.event
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -90,7 +87,6 @@ class DiscountViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
if not instance.allow_delete():
|
||||
raise PermissionDenied('You cannot delete this discount because it already has '
|
||||
|
||||
@@ -45,7 +45,6 @@ from rest_framework.exceptions import (
|
||||
NotFound, PermissionDenied, ValidationError,
|
||||
)
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from rest_framework.mixins import UpdateModelMixin
|
||||
from rest_framework.response import Response
|
||||
|
||||
from pretix.api.auth.permission import EventCRUDPermission
|
||||
@@ -257,7 +256,6 @@ class EventViewSet(viewsets.ModelViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
copy_from = None
|
||||
if 'clone_from' in self.request.GET:
|
||||
@@ -321,7 +319,6 @@ class EventViewSet(viewsets.ModelViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
if not instance.allow_delete():
|
||||
raise PermissionDenied('The event can not be deleted as it already contains orders. Please set \'live\''
|
||||
@@ -357,7 +354,6 @@ class CloneEventViewSet(viewsets.ModelViewSet):
|
||||
ctx['organizer'] = self.request.organizer
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
# Weird edge case: Requires settings permission on the event (to read) but also on the organizer (two write)
|
||||
perm_holder = (self.request.auth if isinstance(self.request.auth, (Device, TeamAPIToken))
|
||||
@@ -516,7 +512,6 @@ class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
resp['X-Page-Generated'] = date
|
||||
return resp
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
original_data = self.get_serializer(instance=serializer.instance).data
|
||||
super().perform_update(serializer)
|
||||
@@ -533,7 +528,6 @@ class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -543,7 +537,6 @@ class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
if not instance.allow_delete():
|
||||
raise PermissionDenied('The sub-event can not be deleted as it has already been used in orders. Please set'
|
||||
@@ -572,7 +565,6 @@ class TaxRuleViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
def get_queryset(self):
|
||||
return self.request.event.tax_rules.all()
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
super().perform_update(serializer)
|
||||
serializer.instance.log_action(
|
||||
@@ -582,7 +574,6 @@ class TaxRuleViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -592,7 +583,6 @@ class TaxRuleViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
if not instance.allow_delete():
|
||||
raise PermissionDenied('This tax rule can not be deleted as it is currently in use.')
|
||||
@@ -721,7 +711,7 @@ class SeatFilter(FilterSet):
|
||||
fields = ('zone_name', 'row_name', 'row_label', 'seat_number', 'seat_label', 'seat_guid', 'blocked',)
|
||||
|
||||
|
||||
class SeatViewSet(ConditionalListView, UpdateModelMixin, viewsets.ReadOnlyModelViewSet):
|
||||
class SeatViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
serializer_class = SeatSerializer
|
||||
queryset = Seat.objects.none()
|
||||
write_permission = 'event.settings.general:write'
|
||||
@@ -766,7 +756,6 @@ class SeatViewSet(ConditionalListView, UpdateModelMixin, viewsets.ReadOnlyModelV
|
||||
}
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
super().perform_update(serializer)
|
||||
serializer.instance.event.log_action(
|
||||
@@ -776,7 +765,6 @@ class SeatViewSet(ConditionalListView, UpdateModelMixin, viewsets.ReadOnlyModelV
|
||||
data={"seats": [serializer.instance.pk]},
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def bulk_change_blocked(self, blocked):
|
||||
s = SeatBulkBlockInputSerializer(
|
||||
data=self.request.data,
|
||||
|
||||
@@ -23,7 +23,6 @@ from datetime import timedelta
|
||||
|
||||
from celery.result import AsyncResult
|
||||
from django.conf import settings
|
||||
from django.db import transaction
|
||||
from django.http import Http404
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.functional import cached_property
|
||||
@@ -46,8 +45,7 @@ from pretix.base.models import (
|
||||
)
|
||||
from pretix.base.models.organizer import TeamQuerySet
|
||||
from pretix.base.services.export import (
|
||||
ExportError, export, init_event_exporters, init_organizer_exporters,
|
||||
multiexport,
|
||||
export, init_event_exporters, init_organizer_exporters, multiexport,
|
||||
)
|
||||
from pretix.helpers.http import ChunkBasedFileResponse
|
||||
|
||||
@@ -151,11 +149,8 @@ class EventExportersViewSet(ExportersMixin, viewsets.ViewSet):
|
||||
))
|
||||
exporters = []
|
||||
for ex in sorted(raw_exporters, key=lambda ex: str(ex.verbose_name)):
|
||||
try:
|
||||
ex._serializer = JobRunSerializer(exporter=ex)
|
||||
exporters.append(ex)
|
||||
except ExportError:
|
||||
pass
|
||||
ex._serializer = JobRunSerializer(exporter=ex)
|
||||
exporters.append(ex)
|
||||
return exporters
|
||||
|
||||
def do_export(self, cf, instance, data):
|
||||
@@ -185,11 +180,8 @@ class OrganizerExportersViewSet(ExportersMixin, viewsets.ViewSet):
|
||||
))
|
||||
exporters = []
|
||||
for ex in sorted(raw_exporters, key=lambda ex: str(ex.verbose_name)):
|
||||
try:
|
||||
ex._serializer = JobRunSerializer(exporter=ex)
|
||||
exporters.append(ex)
|
||||
except ExportError:
|
||||
pass
|
||||
ex._serializer = JobRunSerializer(exporter=ex)
|
||||
exporters.append(ex)
|
||||
return exporters
|
||||
|
||||
def do_export(self, cf, instance, data):
|
||||
@@ -228,7 +220,6 @@ class ScheduledEventExportViewSet(ScheduledExportersViewSet):
|
||||
qs = self.request.event.scheduled_exports
|
||||
return qs.select_related("owner")
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
if not self.request.user.is_authenticated:
|
||||
raise PermissionDenied('Creation of exports requires user-specific API access.')
|
||||
@@ -259,7 +250,6 @@ class ScheduledEventExportViewSet(ScheduledExportersViewSet):
|
||||
))
|
||||
return {e.identifier: e for e in exporters}
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
if not self.request.user.is_authenticated or self.request.user != serializer.instance.owner:
|
||||
# This is to prevent a possible privilege escalation where user A creates a scheduled export and
|
||||
@@ -285,7 +275,6 @@ class ScheduledEventExportViewSet(ScheduledExportersViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
self.request.event.log_action(
|
||||
'pretix.event.export.schedule.deleted',
|
||||
@@ -313,7 +302,6 @@ class ScheduledOrganizerExportViewSet(ScheduledExportersViewSet):
|
||||
qs = self.request.organizer.scheduled_exports
|
||||
return qs.select_related("owner")
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
if not self.request.user.is_authenticated:
|
||||
raise PermissionDenied('Creation of exports requires user-specific API access.')
|
||||
@@ -344,7 +332,6 @@ class ScheduledOrganizerExportViewSet(ScheduledExportersViewSet):
|
||||
))
|
||||
return {e.identifier: e for e in exporters}
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
if not self.request.user.is_authenticated or self.request.user != serializer.instance.owner:
|
||||
# This is to prevent a possible privilege escalation where user A creates a scheduled export and
|
||||
@@ -395,7 +382,6 @@ class ScheduledOrganizerExportViewSet(ScheduledExportersViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
self.request.organizer.log_action(
|
||||
'pretix.organizer.export.schedule.deleted',
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
import django_filters
|
||||
from django.db import transaction
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.functional import cached_property
|
||||
@@ -110,7 +109,6 @@ class ItemViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
'limit_sales_channels', 'variations__limit_sales_channels', 'program_times'
|
||||
).all()
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -125,7 +123,6 @@ class ItemViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
ctx['event'] = self.request.event
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
original_data = self.get_serializer(instance=serializer.instance).data
|
||||
|
||||
@@ -142,7 +139,6 @@ class ItemViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
if not instance.allow_delete():
|
||||
raise PermissionDenied('This item cannot be deleted because it has already been ordered '
|
||||
@@ -187,7 +183,6 @@ class ItemVariationViewSet(viewsets.ModelViewSet):
|
||||
ctx['event'] = self.request.event
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
item = self.item
|
||||
if not item.has_variations:
|
||||
@@ -202,7 +197,6 @@ class ItemVariationViewSet(viewsets.ModelViewSet):
|
||||
{'value': serializer.instance.value})
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.item.log_action(
|
||||
@@ -213,7 +207,6 @@ class ItemVariationViewSet(viewsets.ModelViewSet):
|
||||
{'value': serializer.instance.value})
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
if not instance.allow_delete():
|
||||
raise PermissionDenied('This variation cannot be deleted because it has already been ordered '
|
||||
@@ -256,7 +249,6 @@ class ItemBundleViewSet(viewsets.ModelViewSet):
|
||||
ctx['item'] = self.item
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
item = get_object_or_404(Item, pk=self.kwargs['item'], event=self.request.event)
|
||||
serializer.save(base_item=item)
|
||||
@@ -267,7 +259,6 @@ class ItemBundleViewSet(viewsets.ModelViewSet):
|
||||
data=merge_dicts(self.request.data, {'id': serializer.instance.pk})
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.base_item.log_action(
|
||||
@@ -277,7 +268,6 @@ class ItemBundleViewSet(viewsets.ModelViewSet):
|
||||
data=merge_dicts(self.request.data, {'id': serializer.instance.pk})
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
super().perform_destroy(instance)
|
||||
instance.base_item.log_action(
|
||||
@@ -313,7 +303,6 @@ class ItemProgramTimeViewSet(viewsets.ModelViewSet):
|
||||
ctx['item'] = self.item
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
item = get_object_or_404(Item, pk=self.kwargs['item'], event=self.request.event)
|
||||
serializer.save(item=item)
|
||||
@@ -324,7 +313,6 @@ class ItemProgramTimeViewSet(viewsets.ModelViewSet):
|
||||
data=merge_dicts(self.request.data, {'id': serializer.instance.pk})
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.item.log_action(
|
||||
@@ -334,7 +322,6 @@ class ItemProgramTimeViewSet(viewsets.ModelViewSet):
|
||||
data=merge_dicts(self.request.data, {'id': serializer.instance.pk})
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
super().perform_destroy(instance)
|
||||
instance.item.log_action(
|
||||
@@ -367,7 +354,6 @@ class ItemAddOnViewSet(viewsets.ModelViewSet):
|
||||
ctx['item'] = self.item
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
item = self.item
|
||||
category = get_object_or_404(ItemCategory, pk=self.request.data['addon_category'])
|
||||
@@ -379,7 +365,6 @@ class ItemAddOnViewSet(viewsets.ModelViewSet):
|
||||
data=merge_dicts(self.request.data, {'ORDER': serializer.instance.position}, {'id': serializer.instance.pk})
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.base_item.log_action(
|
||||
@@ -389,7 +374,6 @@ class ItemAddOnViewSet(viewsets.ModelViewSet):
|
||||
data=merge_dicts(self.request.data, {'ORDER': serializer.instance.position}, {'id': serializer.instance.pk})
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
super().perform_destroy(instance)
|
||||
instance.base_item.log_action(
|
||||
@@ -419,7 +403,6 @@ class ItemCategoryViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
def get_queryset(self):
|
||||
return self.request.event.categories.all()
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -434,7 +417,6 @@ class ItemCategoryViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
ctx['event'] = self.request.event
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -444,7 +426,6 @@ class ItemCategoryViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
for item in instance.items.all():
|
||||
item.category = None
|
||||
@@ -475,12 +456,8 @@ class QuestionViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
write_permission = 'event.items:write'
|
||||
|
||||
def get_queryset(self):
|
||||
return self.request.event.questions.filter(
|
||||
# the container_type parameter is undocumented, this API is going to change in a later release
|
||||
container_type=self.request.GET.get('container_type', Question.ContainerType.ORDERPOSITION),
|
||||
).prefetch_related('options').all()
|
||||
return self.request.event.questions.prefetch_related('options').all()
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -495,7 +472,6 @@ class QuestionViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
ctx['event'] = self.request.event
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -505,7 +481,6 @@ class QuestionViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
data=self.request.data
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
instance.log_action(
|
||||
'pretix.event.question.deleted',
|
||||
@@ -534,7 +509,6 @@ class QuestionOptionViewSet(viewsets.ModelViewSet):
|
||||
ctx['question'] = get_object_or_404(Question, pk=self.kwargs['question'], event=self.request.event)
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
q = get_object_or_404(Question, pk=self.kwargs['question'], event=self.request.event)
|
||||
serializer.save(question=q)
|
||||
@@ -545,7 +519,6 @@ class QuestionOptionViewSet(viewsets.ModelViewSet):
|
||||
data=merge_dicts(self.request.data, {'ORDER': serializer.instance.position}, {'id': serializer.instance.pk})
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.question.log_action(
|
||||
@@ -555,7 +528,6 @@ class QuestionOptionViewSet(viewsets.ModelViewSet):
|
||||
data=merge_dicts(self.request.data, {'ORDER': serializer.instance.position}, {'id': serializer.instance.pk})
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
instance.question.log_action(
|
||||
'pretix.event.question.option.deleted',
|
||||
@@ -614,7 +586,6 @@ class QuotaViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
serializer = self.get_serializer(page, many=True)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -637,7 +608,6 @@ class QuotaViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
ctx['request'] = self.request
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
original_data = self.get_serializer(instance=serializer.instance).data
|
||||
|
||||
@@ -693,7 +663,6 @@ class QuotaViewSet(ConditionalListView, viewsets.ModelViewSet):
|
||||
)
|
||||
serializer.instance.rebuild_cache()
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
instance.log_action(
|
||||
'pretix.event.quota.deleted',
|
||||
|
||||
@@ -394,7 +394,6 @@ class TeamViewSet(viewsets.ModelViewSet):
|
||||
)
|
||||
return inst
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
instance.log_action('pretix.team.deleted', user=self.request.user, auth=self.request.auth)
|
||||
instance.delete()
|
||||
@@ -694,7 +693,6 @@ class MembershipTypeViewSet(viewsets.ModelViewSet):
|
||||
ctx['organizer'] = self.request.organizer
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
if not instance.allow_delete():
|
||||
raise PermissionDenied("Can only be deleted if unused.")
|
||||
@@ -835,7 +833,6 @@ class SalesChannelViewSet(viewsets.ModelViewSet):
|
||||
)
|
||||
return inst
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
if not instance.allow_delete():
|
||||
raise PermissionDenied("Can only be deleted if unused.")
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import django_filters
|
||||
from django.db import transaction
|
||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||
from django_scopes import scopes_disabled
|
||||
from rest_framework import viewsets
|
||||
@@ -63,7 +62,6 @@ class WaitingListViewSet(viewsets.ModelViewSet):
|
||||
ctx['event'] = self.request.event
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
serializer.save(event=self.request.event)
|
||||
serializer.instance.log_action(
|
||||
@@ -72,7 +70,6 @@ class WaitingListViewSet(viewsets.ModelViewSet):
|
||||
auth=self.request.auth,
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
if serializer.instance.voucher:
|
||||
raise PermissionDenied('This entry can not be changed as it has already been assigned a voucher.')
|
||||
@@ -83,7 +80,6 @@ class WaitingListViewSet(viewsets.ModelViewSet):
|
||||
auth=self.request.auth,
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
if instance.voucher:
|
||||
raise PermissionDenied('This entry can not be deleted as it has already been assigned a voucher.')
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import django_filters
|
||||
from django.db import transaction
|
||||
from django_filters.rest_framework import DjangoFilterBackend, FilterSet
|
||||
from rest_framework import viewsets
|
||||
|
||||
@@ -49,7 +48,6 @@ class WebHookViewSet(viewsets.ModelViewSet):
|
||||
ctx['organizer'] = self.request.organizer
|
||||
return ctx
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_create(self, serializer):
|
||||
inst = serializer.save(organizer=self.request.organizer)
|
||||
self.request.organizer.log_action(
|
||||
@@ -59,7 +57,6 @@ class WebHookViewSet(viewsets.ModelViewSet):
|
||||
data=merge_dicts(self.request.data, {'id': inst.pk})
|
||||
)
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_update(self, serializer):
|
||||
inst = serializer.save(organizer=self.request.organizer)
|
||||
self.request.organizer.log_action(
|
||||
@@ -70,7 +67,6 @@ class WebHookViewSet(viewsets.ModelViewSet):
|
||||
)
|
||||
return inst
|
||||
|
||||
@transaction.atomic()
|
||||
def perform_destroy(self, instance):
|
||||
self.request.organizer.log_action(
|
||||
'pretix.webhook.changed',
|
||||
|
||||
@@ -40,12 +40,11 @@ from django.utils.translation import gettext as _, gettext_lazy, pgettext_lazy
|
||||
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES
|
||||
|
||||
from ..exporter import MultiSheetListExporter, OrganizerLevelExportMixin
|
||||
from ..models import Membership
|
||||
from ..exporter import ListExporter, OrganizerLevelExportMixin
|
||||
from ..signals import register_multievent_data_exporters
|
||||
|
||||
|
||||
class CustomerListExporter(OrganizerLevelExportMixin, MultiSheetListExporter):
|
||||
class CustomerListExporter(OrganizerLevelExportMixin, ListExporter):
|
||||
identifier = 'customerlist'
|
||||
verbose_name = gettext_lazy('Customer accounts')
|
||||
category = pgettext_lazy('export_category', 'Customer accounts')
|
||||
@@ -55,20 +54,13 @@ class CustomerListExporter(OrganizerLevelExportMixin, MultiSheetListExporter):
|
||||
def get_required_organizer_permission(cls) -> str:
|
||||
return 'organizer.customers:write'
|
||||
|
||||
@property
|
||||
def sheets(self):
|
||||
return (
|
||||
('customers', _('Customers')),
|
||||
('memberships', _('Memberships')),
|
||||
)
|
||||
|
||||
@property
|
||||
def additional_form_fields(self):
|
||||
return OrderedDict(
|
||||
[]
|
||||
)
|
||||
|
||||
def iterate_customers(self, form_data):
|
||||
def iterate_list(self, form_data):
|
||||
qs = self.organizer.customers.prefetch_related('provider')
|
||||
|
||||
headers = [
|
||||
@@ -117,52 +109,6 @@ class CustomerListExporter(OrganizerLevelExportMixin, MultiSheetListExporter):
|
||||
]
|
||||
yield row
|
||||
|
||||
def iterate_memberships(self, form_data):
|
||||
qs = Membership.objects.filter(
|
||||
customer__organizer=self.organizer
|
||||
).prefetch_related('membership_type').select_related('customer', 'granted_in', 'granted_in__order')
|
||||
|
||||
headers = [
|
||||
_('Customer ID'),
|
||||
_('External identifier'),
|
||||
_('Email'),
|
||||
_('Test mode'),
|
||||
_('Canceled'),
|
||||
_('Membership type'),
|
||||
_('Purchase ticket'),
|
||||
_('Start date'),
|
||||
_('Start time'),
|
||||
_('End date'),
|
||||
_('End time'),
|
||||
_('Name'),
|
||||
]
|
||||
name_scheme = PERSON_NAME_SCHEMES[self.organizer.settings.name_scheme]
|
||||
if name_scheme and len(name_scheme['fields']) > 1:
|
||||
for k, label, w in name_scheme['fields']:
|
||||
headers.append(_('Name') + ': ' + str(label))
|
||||
yield headers
|
||||
|
||||
tz = get_current_timezone()
|
||||
for obj in qs:
|
||||
row = [
|
||||
obj.customer.identifier,
|
||||
obj.customer.external_identifier,
|
||||
obj.customer.email or '',
|
||||
_('Yes') if obj.testmode else _('No'),
|
||||
_('Yes') if obj.canceled else _('No'),
|
||||
str(obj.membership_type.name),
|
||||
f'{obj.granted_in.order.code}-{obj.granted_in.positionid}' if obj.granted_in else None,
|
||||
obj.date_start.astimezone(tz).strftime('%Y-%m-%d'),
|
||||
obj.date_start.astimezone(tz).strftime('%H:%M'),
|
||||
obj.date_end.astimezone(tz).strftime('%Y-%m-%d'),
|
||||
obj.date_end.astimezone(tz).strftime('%H:%M'),
|
||||
obj.attendee_name or '',
|
||||
]
|
||||
if name_scheme and len(name_scheme['fields']) > 1:
|
||||
for k, label, w in name_scheme['fields']:
|
||||
row.append(obj.attendee_name_parts.get(k, ''))
|
||||
yield row
|
||||
|
||||
def get_filename(self):
|
||||
return '{}_customers'.format(self.organizer.slug)
|
||||
|
||||
|
||||
+425
-510
@@ -36,7 +36,6 @@ import copy
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from collections import namedtuple
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
from io import BytesIO
|
||||
@@ -637,271 +636,449 @@ class PortraitImageField(SizeValidationMixin, ExtValidationMixin, forms.FileFiel
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
FakeQuestion = namedtuple(
|
||||
'FakeQuestion', 'id question position required help_text container_type', defaults=('', Question.ContainerType.ORDERPOSITION)
|
||||
)
|
||||
|
||||
|
||||
def get_fake_attendee_questions(settings):
|
||||
fq = []
|
||||
sqo = settings.system_question_order
|
||||
|
||||
if settings.attendee_names_asked:
|
||||
fq.append(FakeQuestion('attendee_name_parts', _('Attendee name'), sqo.get('attendee_name_parts', 0), settings.attendee_names_required))
|
||||
|
||||
if settings.attendee_emails_asked:
|
||||
fq.append(FakeQuestion('attendee_email', _('Attendee email'), sqo.get('attendee_email', 0), settings.attendee_emails_required))
|
||||
|
||||
if settings.attendee_company_asked:
|
||||
fq.append(FakeQuestion('company', _('Company'), sqo.get('company', 0), settings.attendee_company_required))
|
||||
|
||||
if settings.attendee_addresses_asked:
|
||||
fq.append(FakeQuestion('street', _('Street'), sqo.get('street', 0), settings.attendee_addresses_required))
|
||||
fq.append(FakeQuestion('zipcode', _('ZIP code'), sqo.get('zipcode', 0), settings.attendee_addresses_required))
|
||||
fq.append(FakeQuestion('city', _('City'), sqo.get('city', 0), settings.attendee_addresses_required))
|
||||
fq.append(FakeQuestion('state', _('State'), sqo.get('country', 0), settings.attendee_addresses_required))
|
||||
fq.append(FakeQuestion('country', _('Country'), sqo.get('country', 0), settings.attendee_addresses_required))
|
||||
return fq
|
||||
|
||||
|
||||
class BaseQuestionsForm(forms.Form):
|
||||
"""
|
||||
This is the base form class responsible for asking order- or ticket-related questions.
|
||||
This form class is responsible for asking order-related questions. This includes
|
||||
the attendee name for admission tickets, if the corresponding setting is enabled,
|
||||
as well as additional questions defined by the organizer.
|
||||
"""
|
||||
address_validation = False
|
||||
|
||||
def build_user_question_field(self, request, event, answerlist, q):
|
||||
# Do we already have an answer? Provide it as the initial value
|
||||
answers = [a for a in answerlist if a.question_id == q.id]
|
||||
if answers:
|
||||
initial = answers[0]
|
||||
else:
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Takes two additional keyword arguments:
|
||||
|
||||
:param cartpos: The cart position the form should be for
|
||||
:param event: The event this belongs to
|
||||
"""
|
||||
request = kwargs.pop('request', None)
|
||||
cartpos = self.cartpos = kwargs.pop('cartpos', None)
|
||||
orderpos = self.orderpos = kwargs.pop('orderpos', None)
|
||||
pos = cartpos or orderpos
|
||||
item = pos.item
|
||||
questions = pos.item.questions_to_ask
|
||||
event = kwargs.pop('event')
|
||||
self.all_optional = kwargs.pop('all_optional', False)
|
||||
self.attendee_addresses_required = event.settings.attendee_addresses_required and not self.all_optional
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if cartpos and item.validity_mode == Item.VALIDITY_MODE_DYNAMIC and item.validity_dynamic_start_choice:
|
||||
if item.validity_dynamic_start_choice_day_limit:
|
||||
max_date = time_machine_now().astimezone(event.timezone) + timedelta(days=item.validity_dynamic_start_choice_day_limit)
|
||||
else:
|
||||
max_date = None
|
||||
min_date = time_machine_now()
|
||||
initial = None
|
||||
tz = ZoneInfo(event.settings.timezone)
|
||||
required = q.required and not self.all_optional
|
||||
if q.type == Question.TYPE_BOOLEAN:
|
||||
if required:
|
||||
# For some reason, django-bootstrap3 does not set the required attribute
|
||||
# itself.
|
||||
widget = forms.CheckboxInput(attrs={'required': 'required'})
|
||||
if (item.require_membership or (pos.variation and pos.variation.require_membership)) and pos.used_membership:
|
||||
if pos.used_membership.date_start >= time_machine_now():
|
||||
initial = min_date = pos.used_membership.date_start
|
||||
max_date = min(max_date, pos.used_membership.date_end) if max_date else pos.used_membership.date_end
|
||||
if item.validity_dynamic_duration_months or item.validity_dynamic_duration_days:
|
||||
attrs = {}
|
||||
if max_date:
|
||||
attrs['data-max'] = max_date.date().isoformat()
|
||||
if min_date:
|
||||
attrs['data-min'] = min_date.date().isoformat()
|
||||
self.fields['requested_valid_from'] = forms.DateField(
|
||||
label=_('Start date'),
|
||||
help_text='' if initial else _('If you keep this empty, the ticket will be valid starting at the time of purchase.'),
|
||||
required=bool(initial),
|
||||
initial=pos.requested_valid_from or initial,
|
||||
widget=DatePickerWidget(attrs),
|
||||
validators=([MaxDateValidator(max_date.date())] if max_date else []) + [MinDateValidator(min_date.date())]
|
||||
)
|
||||
else:
|
||||
widget = forms.CheckboxInput()
|
||||
self.fields['requested_valid_from'] = forms.SplitDateTimeField(
|
||||
label=_('Start date'),
|
||||
help_text='' if initial else _('If you keep this empty, the ticket will be valid starting at the time of purchase.'),
|
||||
required=bool(initial),
|
||||
initial=pos.requested_valid_from or initial,
|
||||
widget=SplitDateTimePickerWidget(
|
||||
time_format=get_format_without_seconds('TIME_INPUT_FORMATS'),
|
||||
min_date=min_date,
|
||||
max_date=max_date
|
||||
),
|
||||
validators=([MaxDateTimeValidator(max_date)] if max_date else []) + [MinDateTimeValidator(min_date)]
|
||||
)
|
||||
|
||||
if initial:
|
||||
initialbool = (initial.answer == "True")
|
||||
else:
|
||||
initialbool = False
|
||||
add_fields = {}
|
||||
|
||||
field = forms.BooleanField(
|
||||
label=escape(q.question), required=required,
|
||||
help_text=rich_text(q.help_text),
|
||||
initial=initialbool, widget=widget,
|
||||
if item.ask_attendee_data and event.settings.attendee_names_asked:
|
||||
add_fields['attendee_name_parts'] = NamePartsFormField(
|
||||
max_length=255,
|
||||
required=event.settings.attendee_names_required and not self.all_optional,
|
||||
scheme=event.settings.name_scheme,
|
||||
titles=event.settings.name_scheme_titles,
|
||||
label=_('Attendee name'),
|
||||
initial=(cartpos.attendee_name_parts if cartpos else orderpos.attendee_name_parts),
|
||||
)
|
||||
elif q.type == Question.TYPE_NUMBER:
|
||||
field = forms.DecimalField(
|
||||
label=escape(q.question), required=required,
|
||||
min_value=q.valid_number_min or Decimal('0.00'),
|
||||
max_value=q.valid_number_max,
|
||||
help_text=rich_text(q.help_text),
|
||||
initial=initial.answer if initial else None,
|
||||
if item.ask_attendee_data and event.settings.attendee_emails_asked:
|
||||
add_fields['attendee_email'] = forms.EmailField(
|
||||
required=event.settings.attendee_emails_required and not self.all_optional,
|
||||
label=_('Attendee email'),
|
||||
initial=(cartpos.attendee_email if cartpos else orderpos.attendee_email),
|
||||
widget=forms.EmailInput(
|
||||
attrs={
|
||||
'autocomplete': 'email'
|
||||
}
|
||||
)
|
||||
)
|
||||
elif q.type == Question.TYPE_STRING:
|
||||
field = forms.CharField(
|
||||
label=escape(q.question), required=required,
|
||||
max_length=q.valid_string_length_max,
|
||||
help_text=rich_text(q.help_text),
|
||||
initial=initial.answer if initial else None,
|
||||
if item.ask_attendee_data and event.settings.attendee_company_asked:
|
||||
add_fields['company'] = forms.CharField(
|
||||
required=event.settings.attendee_company_required and not self.all_optional,
|
||||
label=_('Company'),
|
||||
max_length=255,
|
||||
initial=(cartpos.company if cartpos else orderpos.company),
|
||||
)
|
||||
elif q.type == Question.TYPE_TEXT:
|
||||
field = forms.CharField(
|
||||
label=escape(q.question), required=required,
|
||||
max_length=q.valid_string_length_max,
|
||||
help_text=rich_text(q.help_text),
|
||||
widget=forms.Textarea,
|
||||
initial=initial.answer if initial else None,
|
||||
|
||||
if item.ask_attendee_data and event.settings.attendee_addresses_asked:
|
||||
add_fields['street'] = forms.CharField(
|
||||
required=self.attendee_addresses_required,
|
||||
label=_('Address'),
|
||||
widget=forms.Textarea(attrs={
|
||||
'rows': 2,
|
||||
'placeholder': _('Street and Number'),
|
||||
'autocomplete': 'street-address'
|
||||
}),
|
||||
initial=(cartpos.street if cartpos else orderpos.street),
|
||||
)
|
||||
elif q.type == Question.TYPE_COUNTRYCODE:
|
||||
field = CountryField(
|
||||
countries=CachedCountries,
|
||||
blank=True, null=True, blank_label=' ',
|
||||
add_fields['zipcode'] = forms.CharField(
|
||||
required=False,
|
||||
max_length=30,
|
||||
label=_('ZIP code'),
|
||||
initial=(cartpos.zipcode if cartpos else orderpos.zipcode),
|
||||
widget=forms.TextInput(attrs={
|
||||
'autocomplete': 'postal-code',
|
||||
}),
|
||||
)
|
||||
add_fields['city'] = forms.CharField(
|
||||
required=False,
|
||||
label=_('City'),
|
||||
max_length=255,
|
||||
initial=(cartpos.city if cartpos else orderpos.city),
|
||||
widget=forms.TextInput(attrs={
|
||||
'autocomplete': 'address-level2',
|
||||
}),
|
||||
)
|
||||
country = (cartpos.country if cartpos else orderpos.country) or guess_country_from_request(request, event)
|
||||
add_fields['country'] = CountryField(
|
||||
countries=CachedCountries
|
||||
).formfield(
|
||||
label=escape(q.question), required=required,
|
||||
help_text=rich_text(q.help_text),
|
||||
widget=forms.Select,
|
||||
empty_label=' ',
|
||||
initial=initial.answer if initial else (
|
||||
guess_country_from_request(request, event) if required else None),
|
||||
required=self.attendee_addresses_required,
|
||||
label=_('Country'),
|
||||
initial=country,
|
||||
widget=forms.Select(attrs={
|
||||
'autocomplete': 'country',
|
||||
'data-trigger-address-info': 'on',
|
||||
}),
|
||||
)
|
||||
elif q.type == Question.TYPE_CHOICE:
|
||||
field = forms.ModelChoiceField(
|
||||
queryset=q.options,
|
||||
label=escape(q.question), required=required,
|
||||
help_text=rich_text(q.help_text),
|
||||
widget=forms.Select,
|
||||
to_field_name='identifier',
|
||||
empty_label='',
|
||||
initial=initial.options.first() if initial else None,
|
||||
c = [('', '---')]
|
||||
fprefix = str(self.prefix) + '-' if self.prefix is not None and self.prefix != '-' else ''
|
||||
cc = None
|
||||
state = None
|
||||
if fprefix + 'country' in self.data:
|
||||
cc = str(self.data[fprefix + 'country'])
|
||||
elif country:
|
||||
cc = str(country)
|
||||
if cc and cc in COUNTRIES_WITH_STATE_IN_ADDRESS:
|
||||
types, form = COUNTRIES_WITH_STATE_IN_ADDRESS[cc]
|
||||
statelist = [s for s in pycountry.subdivisions.get(country_code=cc) if s.type in types]
|
||||
c += sorted([(s.code[3:], s.name) for s in statelist], key=lambda s: s[1])
|
||||
state = (cartpos.state if cartpos else orderpos.state)
|
||||
elif fprefix + 'state' in self.data:
|
||||
self.data = self.data.copy()
|
||||
del self.data[fprefix + 'state']
|
||||
|
||||
add_fields['state'] = forms.ChoiceField(
|
||||
label=pgettext_lazy('address', 'State'),
|
||||
required=False,
|
||||
choices=c,
|
||||
initial=state,
|
||||
widget=forms.Select(attrs={
|
||||
'autocomplete': 'address-level1',
|
||||
}),
|
||||
)
|
||||
elif q.type == Question.TYPE_CHOICE_MULTIPLE:
|
||||
field = forms.ModelMultipleChoiceField(
|
||||
queryset=q.options,
|
||||
label=escape(q.question), required=required,
|
||||
help_text=rich_text(q.help_text),
|
||||
to_field_name='identifier',
|
||||
widget=QuestionCheckboxSelectMultiple,
|
||||
initial=initial.options.all() if initial else None,
|
||||
)
|
||||
elif q.type == Question.TYPE_FILE:
|
||||
if q.valid_file_portrait:
|
||||
field = PortraitImageField(
|
||||
label=escape(q.question), required=required,
|
||||
help_text=rich_text(q.help_text),
|
||||
initial=initial.file if initial else None,
|
||||
widget=PortraitImageWidget(answer=initial, request=request,
|
||||
attrs={'data-portrait-photo': 'true'}),
|
||||
add_fields['state'].widget.is_required = True
|
||||
|
||||
field_positions = list(
|
||||
[
|
||||
(n, event.settings.system_question_order.get(n if n != 'state' else 'country', 0))
|
||||
for n in add_fields.keys()
|
||||
]
|
||||
)
|
||||
|
||||
for q in questions:
|
||||
# Do we already have an answer? Provide it as the initial value
|
||||
answers = [a for a in pos.answerlist if a.question_id == q.id]
|
||||
if answers:
|
||||
initial = answers[0]
|
||||
else:
|
||||
initial = None
|
||||
tz = ZoneInfo(event.settings.timezone)
|
||||
help_text = rich_text(q.help_text)
|
||||
label = escape(q.question) # django-bootstrap3 calls mark_safe
|
||||
required = q.required and not self.all_optional
|
||||
if q.type == Question.TYPE_BOOLEAN:
|
||||
if required:
|
||||
# For some reason, django-bootstrap3 does not set the required attribute
|
||||
# itself.
|
||||
widget = forms.CheckboxInput(attrs={'required': 'required'})
|
||||
else:
|
||||
widget = forms.CheckboxInput()
|
||||
|
||||
if initial:
|
||||
initialbool = (initial.answer == "True")
|
||||
else:
|
||||
initialbool = False
|
||||
|
||||
field = forms.BooleanField(
|
||||
label=label, required=required,
|
||||
help_text=help_text,
|
||||
initial=initialbool, widget=widget,
|
||||
)
|
||||
else:
|
||||
field = ExtFileField(
|
||||
label=escape(q.question), required=required,
|
||||
help_text=rich_text(q.help_text),
|
||||
initial=initial.file if initial else None,
|
||||
widget=UploadedFileWidget(answer=initial, request=request),
|
||||
ext_whitelist=settings.FILE_UPLOAD_EXTENSIONS_OTHER,
|
||||
max_size=settings.FILE_UPLOAD_MAX_SIZE_OTHER,
|
||||
elif q.type == Question.TYPE_NUMBER:
|
||||
field = forms.DecimalField(
|
||||
label=label, required=required,
|
||||
min_value=q.valid_number_min or Decimal('0.00'),
|
||||
max_value=q.valid_number_max,
|
||||
help_text=help_text,
|
||||
initial=initial.answer if initial else None,
|
||||
)
|
||||
elif q.type == Question.TYPE_DATE:
|
||||
attrs = {}
|
||||
if q.valid_date_min:
|
||||
attrs['data-min'] = q.valid_date_min.isoformat()
|
||||
if q.valid_date_max:
|
||||
attrs['data-max'] = q.valid_date_max.isoformat()
|
||||
help_text = q.help_text
|
||||
if not help_text:
|
||||
if q.valid_date_min and q.valid_date_max:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date between {min} and {max}.'),
|
||||
min=date_format(q.valid_date_min, "SHORT_DATE_FORMAT"),
|
||||
max=date_format(q.valid_date_max, "SHORT_DATE_FORMAT"),
|
||||
elif q.type == Question.TYPE_STRING:
|
||||
field = forms.CharField(
|
||||
label=label, required=required,
|
||||
max_length=q.valid_string_length_max,
|
||||
help_text=help_text,
|
||||
initial=initial.answer if initial else None,
|
||||
)
|
||||
elif q.type == Question.TYPE_TEXT:
|
||||
field = forms.CharField(
|
||||
label=label, required=required,
|
||||
max_length=q.valid_string_length_max,
|
||||
help_text=help_text,
|
||||
widget=forms.Textarea,
|
||||
initial=initial.answer if initial else None,
|
||||
)
|
||||
elif q.type == Question.TYPE_COUNTRYCODE:
|
||||
field = CountryField(
|
||||
countries=CachedCountries,
|
||||
blank=True, null=True, blank_label=' ',
|
||||
).formfield(
|
||||
label=label, required=required,
|
||||
help_text=help_text,
|
||||
widget=forms.Select,
|
||||
empty_label=' ',
|
||||
initial=initial.answer if initial else (guess_country_from_request(request, event) if required else None),
|
||||
)
|
||||
elif q.type == Question.TYPE_CHOICE:
|
||||
field = forms.ModelChoiceField(
|
||||
queryset=q.options,
|
||||
label=label, required=required,
|
||||
help_text=help_text,
|
||||
widget=forms.Select,
|
||||
to_field_name='identifier',
|
||||
empty_label='',
|
||||
initial=initial.options.first() if initial else None,
|
||||
)
|
||||
elif q.type == Question.TYPE_CHOICE_MULTIPLE:
|
||||
field = forms.ModelMultipleChoiceField(
|
||||
queryset=q.options,
|
||||
label=label, required=required,
|
||||
help_text=help_text,
|
||||
to_field_name='identifier',
|
||||
widget=QuestionCheckboxSelectMultiple,
|
||||
initial=initial.options.all() if initial else None,
|
||||
)
|
||||
elif q.type == Question.TYPE_FILE:
|
||||
if q.valid_file_portrait:
|
||||
field = PortraitImageField(
|
||||
label=label, required=required,
|
||||
help_text=help_text,
|
||||
initial=initial.file if initial else None,
|
||||
widget=PortraitImageWidget(position=pos, event=event, answer=initial, attrs={'data-portrait-photo': 'true'}),
|
||||
)
|
||||
elif q.valid_date_min:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date no earlier than {min}.'),
|
||||
min=date_format(q.valid_date_min, "SHORT_DATE_FORMAT"),
|
||||
else:
|
||||
field = ExtFileField(
|
||||
label=label, required=required,
|
||||
help_text=help_text,
|
||||
initial=initial.file if initial else None,
|
||||
widget=UploadedFileWidget(position=pos, event=event, answer=initial),
|
||||
ext_whitelist=settings.FILE_UPLOAD_EXTENSIONS_OTHER,
|
||||
max_size=settings.FILE_UPLOAD_MAX_SIZE_OTHER,
|
||||
)
|
||||
elif q.valid_date_max:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date no later than {max}.'),
|
||||
max=date_format(q.valid_date_max, "SHORT_DATE_FORMAT"),
|
||||
)
|
||||
if initial and initial.answer:
|
||||
try:
|
||||
_initial = dateutil.parser.parse(initial.answer).date()
|
||||
except dateutil.parser.ParserError:
|
||||
elif q.type == Question.TYPE_DATE:
|
||||
attrs = {}
|
||||
if q.valid_date_min:
|
||||
attrs['data-min'] = q.valid_date_min.isoformat()
|
||||
if q.valid_date_max:
|
||||
attrs['data-max'] = q.valid_date_max.isoformat()
|
||||
if not help_text:
|
||||
if q.valid_date_min and q.valid_date_max:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date between {min} and {max}.'),
|
||||
min=date_format(q.valid_date_min, "SHORT_DATE_FORMAT"),
|
||||
max=date_format(q.valid_date_max, "SHORT_DATE_FORMAT"),
|
||||
)
|
||||
elif q.valid_date_min:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date no earlier than {min}.'),
|
||||
min=date_format(q.valid_date_min, "SHORT_DATE_FORMAT"),
|
||||
)
|
||||
elif q.valid_date_max:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date no later than {max}.'),
|
||||
max=date_format(q.valid_date_max, "SHORT_DATE_FORMAT"),
|
||||
)
|
||||
if initial and initial.answer:
|
||||
try:
|
||||
_initial = dateutil.parser.parse(initial.answer).date()
|
||||
except dateutil.parser.ParserError:
|
||||
_initial = None
|
||||
else:
|
||||
_initial = None
|
||||
else:
|
||||
_initial = None
|
||||
field = forms.DateField(
|
||||
label=escape(q.question), required=required,
|
||||
help_text=rich_text(help_text),
|
||||
initial=_initial,
|
||||
widget=DatePickerWidget(attrs),
|
||||
)
|
||||
if q.valid_date_min:
|
||||
field.validators.append(MinDateValidator(q.valid_date_min))
|
||||
if q.valid_date_max:
|
||||
field.validators.append(MaxDateValidator(q.valid_date_max))
|
||||
elif q.type == Question.TYPE_TIME:
|
||||
if initial and initial.answer:
|
||||
try:
|
||||
_initial = dateutil.parser.parse(initial.answer).time()
|
||||
except dateutil.parser.ParserError:
|
||||
field = forms.DateField(
|
||||
label=label, required=required,
|
||||
help_text=help_text,
|
||||
initial=_initial,
|
||||
widget=DatePickerWidget(attrs),
|
||||
)
|
||||
if q.valid_date_min:
|
||||
field.validators.append(MinDateValidator(q.valid_date_min))
|
||||
if q.valid_date_max:
|
||||
field.validators.append(MaxDateValidator(q.valid_date_max))
|
||||
elif q.type == Question.TYPE_TIME:
|
||||
if initial and initial.answer:
|
||||
try:
|
||||
_initial = dateutil.parser.parse(initial.answer).time()
|
||||
except dateutil.parser.ParserError:
|
||||
_initial = None
|
||||
else:
|
||||
_initial = None
|
||||
else:
|
||||
_initial = None
|
||||
field = forms.TimeField(
|
||||
label=escape(q.question), required=required,
|
||||
help_text=rich_text(q.help_text),
|
||||
initial=_initial,
|
||||
widget=TimePickerWidget(without_seconds=True),
|
||||
)
|
||||
elif q.type == Question.TYPE_DATETIME:
|
||||
help_text = q.help_text
|
||||
if not help_text:
|
||||
if q.valid_datetime_min and q.valid_datetime_max:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date and time between {min} and {max}.'),
|
||||
min=date_format(q.valid_datetime_min, "SHORT_DATETIME_FORMAT"),
|
||||
max=date_format(q.valid_datetime_max, "SHORT_DATETIME_FORMAT"),
|
||||
)
|
||||
elif q.valid_datetime_min:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date and time no earlier than {min}.'),
|
||||
min=date_format(q.valid_datetime_min, "SHORT_DATETIME_FORMAT"),
|
||||
)
|
||||
elif q.valid_datetime_max:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date and time no later than {max}.'),
|
||||
max=date_format(q.valid_datetime_max, "SHORT_DATETIME_FORMAT"),
|
||||
)
|
||||
field = forms.TimeField(
|
||||
label=label, required=required,
|
||||
help_text=help_text,
|
||||
initial=_initial,
|
||||
widget=TimePickerWidget(without_seconds=True),
|
||||
)
|
||||
elif q.type == Question.TYPE_DATETIME:
|
||||
if not help_text:
|
||||
if q.valid_datetime_min and q.valid_datetime_max:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date and time between {min} and {max}.'),
|
||||
min=date_format(q.valid_datetime_min, "SHORT_DATETIME_FORMAT"),
|
||||
max=date_format(q.valid_datetime_max, "SHORT_DATETIME_FORMAT"),
|
||||
)
|
||||
elif q.valid_datetime_min:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date and time no earlier than {min}.'),
|
||||
min=date_format(q.valid_datetime_min, "SHORT_DATETIME_FORMAT"),
|
||||
)
|
||||
elif q.valid_datetime_max:
|
||||
help_text = format_lazy(
|
||||
_('Please enter a date and time no later than {max}.'),
|
||||
max=date_format(q.valid_datetime_max, "SHORT_DATETIME_FORMAT"),
|
||||
)
|
||||
|
||||
if initial and initial.answer:
|
||||
try:
|
||||
_initial = dateutil.parser.parse(initial.answer).astimezone(tz)
|
||||
except dateutil.parser.ParserError:
|
||||
if initial and initial.answer:
|
||||
try:
|
||||
_initial = dateutil.parser.parse(initial.answer).astimezone(tz)
|
||||
except dateutil.parser.ParserError:
|
||||
_initial = None
|
||||
else:
|
||||
_initial = None
|
||||
else:
|
||||
_initial = None
|
||||
|
||||
field = SplitDateTimeField(
|
||||
label=escape(q.question), required=required,
|
||||
help_text=rich_text(help_text),
|
||||
initial=_initial,
|
||||
widget=SplitDateTimePickerWidget(
|
||||
time_format=get_format_without_seconds('TIME_INPUT_FORMATS'),
|
||||
min_date=q.valid_datetime_min,
|
||||
max_date=q.valid_datetime_max
|
||||
),
|
||||
)
|
||||
if q.valid_datetime_min:
|
||||
field.validators.append(MinDateTimeValidator(q.valid_datetime_min))
|
||||
if q.valid_datetime_max:
|
||||
field.validators.append(MaxDateTimeValidator(q.valid_datetime_max))
|
||||
elif q.type == Question.TYPE_PHONENUMBER:
|
||||
if initial:
|
||||
try:
|
||||
initial = PhoneNumber().from_string(initial.answer)
|
||||
except NumberParseException:
|
||||
initial = None
|
||||
field = SplitDateTimeField(
|
||||
label=label, required=required,
|
||||
help_text=help_text,
|
||||
initial=_initial,
|
||||
widget=SplitDateTimePickerWidget(
|
||||
time_format=get_format_without_seconds('TIME_INPUT_FORMATS'),
|
||||
min_date=q.valid_datetime_min,
|
||||
max_date=q.valid_datetime_max
|
||||
),
|
||||
)
|
||||
if q.valid_datetime_min:
|
||||
field.validators.append(MinDateTimeValidator(q.valid_datetime_min))
|
||||
if q.valid_datetime_max:
|
||||
field.validators.append(MaxDateTimeValidator(q.valid_datetime_max))
|
||||
elif q.type == Question.TYPE_PHONENUMBER:
|
||||
if initial:
|
||||
try:
|
||||
initial = PhoneNumber().from_string(initial.answer)
|
||||
except NumberParseException:
|
||||
initial = None
|
||||
|
||||
if not initial:
|
||||
phone_prefix = guess_phone_prefix_from_request(request, event)
|
||||
if phone_prefix:
|
||||
initial = "+{}.".format(phone_prefix)
|
||||
if not initial:
|
||||
phone_prefix = guess_phone_prefix_from_request(request, event)
|
||||
if phone_prefix:
|
||||
initial = "+{}.".format(phone_prefix)
|
||||
|
||||
field = PhoneNumberField(
|
||||
label=escape(q.question), required=required,
|
||||
help_text=rich_text(q.help_text),
|
||||
# We now exploit an implementation detail in PhoneNumberPrefixWidget to allow us to pass just
|
||||
# a country code but no number as an initial value. It's a bit hacky, but should be stable for
|
||||
# the future.
|
||||
initial=initial,
|
||||
widget=WrappedPhoneNumberPrefixWidget()
|
||||
)
|
||||
field.question = q
|
||||
if answers:
|
||||
# Cache the answer object for later use
|
||||
field.answer = answers[0]
|
||||
field = PhoneNumberField(
|
||||
label=label, required=required,
|
||||
help_text=help_text,
|
||||
# We now exploit an implementation detail in PhoneNumberPrefixWidget to allow us to pass just
|
||||
# a country code but no number as an initial value. It's a bit hacky, but should be stable for
|
||||
# the future.
|
||||
initial=initial,
|
||||
widget=WrappedPhoneNumberPrefixWidget()
|
||||
)
|
||||
field.question = q
|
||||
if answers:
|
||||
# Cache the answer object for later use
|
||||
field.answer = answers[0]
|
||||
|
||||
if q.dependency_question_id:
|
||||
field.widget.attrs['data-question-dependency'] = q.dependency_question_id
|
||||
field.widget.attrs['data-question-dependency-values'] = escapejson_attr(json.dumps(q.dependency_values))
|
||||
if q.type != 'M':
|
||||
field.widget.attrs['required'] = q.required and not self.all_optional
|
||||
field._required = q.required and not self.all_optional
|
||||
field.required = False
|
||||
return field
|
||||
if q.dependency_question_id:
|
||||
field.widget.attrs['data-question-dependency'] = q.dependency_question_id
|
||||
field.widget.attrs['data-question-dependency-values'] = escapejson_attr(json.dumps(q.dependency_values))
|
||||
if q.type != 'M':
|
||||
field.widget.attrs['required'] = q.required and not self.all_optional
|
||||
field._required = q.required and not self.all_optional
|
||||
field.required = False
|
||||
|
||||
add_fields['question_%s' % q.id] = field
|
||||
field_positions.append(('question_%s' % q.id, q.position))
|
||||
|
||||
field_positions.sort(key=lambda e: e[1])
|
||||
for fname, p in field_positions:
|
||||
self.fields[fname] = add_fields[fname]
|
||||
|
||||
responses = question_form_fields.send(sender=event, position=pos)
|
||||
data = pos.meta_info_data
|
||||
for r, response in sorted(responses, key=lambda r: str(r[0])):
|
||||
for key, value in response.items():
|
||||
# We need to be this explicit, since OrderedDict.update does not retain ordering
|
||||
self.fields[key] = value
|
||||
value.initial = data.get('question_form_data', {}).get(key)
|
||||
|
||||
for k, v in self.fields.items():
|
||||
if isinstance(v.widget, forms.MultiWidget):
|
||||
for w in v.widget.widgets:
|
||||
autocomplete = w.attrs.get('autocomplete', '')
|
||||
if autocomplete.strip() == "off":
|
||||
w.attrs['autocomplete'] = 'off'
|
||||
else:
|
||||
w.attrs['autocomplete'] = 'section-{} '.format(self.prefix) + autocomplete
|
||||
if v.widget.attrs.get('autocomplete') or k == 'attendee_name_parts':
|
||||
autocomplete = v.widget.attrs.get('autocomplete', '')
|
||||
if autocomplete.strip() == "off":
|
||||
v.widget.attrs['autocomplete'] = 'off'
|
||||
else:
|
||||
v.widget.attrs['autocomplete'] = 'section-{} '.format(self.prefix) + autocomplete
|
||||
|
||||
def clean(self):
|
||||
from pretix.base.addressvalidation import \
|
||||
validate_address # local import to prevent impact on startup time
|
||||
|
||||
d = super().clean()
|
||||
|
||||
if self.address_validation:
|
||||
self.cleaned_data = d = validate_address(d, all_optional=not self.attendee_addresses_required)
|
||||
|
||||
if d.get('street') and d.get('country') and str(d['country']) in COUNTRIES_WITH_STATE_IN_ADDRESS:
|
||||
if not d.get('state'):
|
||||
self.add_error('state', _('This field is required.'))
|
||||
|
||||
def check_user_questions(self, d):
|
||||
question_cache = {f.question.pk: f.question for f in self.fields.values() if getattr(f, 'question', None)}
|
||||
|
||||
def question_is_visible(parentid, qvals):
|
||||
@@ -944,269 +1121,7 @@ class BaseQuestionsForm(forms.Form):
|
||||
for q in question_cache.values():
|
||||
if q.required and q.type == Question.TYPE_BOOLEAN:
|
||||
if 'question_%d' % q.pk in d and d['question_%d' % q.pk] is False:
|
||||
d['question_%d' % q.pk] = None
|
||||
|
||||
|
||||
class OrderLevelQuestionsForm(BaseQuestionsForm):
|
||||
def __init__(self, container, *args, **kwargs):
|
||||
"""
|
||||
Takes two additional keyword arguments:
|
||||
|
||||
:param checkoutsession: The checkout session the form should be for
|
||||
:param order: The order the form should be for
|
||||
:param event: The event this belongs to
|
||||
"""
|
||||
request = kwargs.pop('request', None)
|
||||
event = kwargs.pop('event')
|
||||
self.all_optional = kwargs.pop('all_optional', False)
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
questions = Question.objects.filter(
|
||||
event=event, container_type=Question.ContainerType.ORDER,
|
||||
ask_during_checkin=False, hidden=False,
|
||||
).order_by('position')
|
||||
answerlist = container.answers.prefetch_related('options')
|
||||
|
||||
for q in questions:
|
||||
self.fields['question_%s' % q.id] = self.build_user_question_field(request, event, answerlist, q)
|
||||
|
||||
def clean(self):
|
||||
d = super().clean()
|
||||
self.check_user_questions(d)
|
||||
return d
|
||||
|
||||
|
||||
class TicketLevelQuestionsForm(BaseQuestionsForm):
|
||||
"""
|
||||
This form class is responsible for asking ticket-related questions. This includes
|
||||
the attendee name for admission tickets, if the corresponding setting is enabled,
|
||||
as well as additional questions defined by the organizer.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
"""
|
||||
Takes two additional keyword arguments:
|
||||
|
||||
:param cartpos: The cart position the form should be for
|
||||
:param event: The event this belongs to
|
||||
"""
|
||||
request = kwargs.pop('request', None)
|
||||
cartpos = self.cartpos = kwargs.pop('cartpos', None)
|
||||
orderpos = self.orderpos = kwargs.pop('orderpos', None)
|
||||
pos = cartpos or orderpos
|
||||
item = pos.item
|
||||
event = kwargs.pop('event')
|
||||
self.all_optional = kwargs.pop('all_optional', False)
|
||||
self.attendee_addresses_required = event.settings.attendee_addresses_required and not self.all_optional
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
if cartpos and item.validity_mode == Item.VALIDITY_MODE_DYNAMIC and item.validity_dynamic_start_choice:
|
||||
self.fields['requested_valid_from'] = self.build_requested_valid_from_field(event, pos, item)
|
||||
|
||||
questions = []
|
||||
if item.ask_attendee_data:
|
||||
questions += get_fake_attendee_questions(event.settings)
|
||||
questions += pos.item.questions_to_ask
|
||||
|
||||
questions.sort(key=lambda q: q.position)
|
||||
|
||||
for q in questions:
|
||||
if isinstance(q, FakeQuestion):
|
||||
self.fields[q.id] = self.build_system_question_field(request, event, pos, q)
|
||||
else:
|
||||
self.fields['question_%s' % q.id] = self.build_user_question_field(request, event, pos.answerlist, q)
|
||||
|
||||
responses = question_form_fields.send(sender=event, position=pos)
|
||||
data = pos.meta_info_data
|
||||
for r, response in sorted(responses, key=lambda r: str(r[0])):
|
||||
for key, value in response.items():
|
||||
# We need to be this explicit, since OrderedDict.update does not retain ordering
|
||||
self.fields[key] = value
|
||||
value.initial = data.get('question_form_data', {}).get(key)
|
||||
|
||||
for k, v in self.fields.items():
|
||||
if isinstance(v.widget, forms.MultiWidget):
|
||||
for w in v.widget.widgets:
|
||||
autocomplete = w.attrs.get('autocomplete', '')
|
||||
if autocomplete.strip() == "off":
|
||||
w.attrs['autocomplete'] = 'off'
|
||||
else:
|
||||
w.attrs['autocomplete'] = 'section-{} '.format(self.prefix) + autocomplete
|
||||
if v.widget.attrs.get('autocomplete') or k == 'attendee_name_parts':
|
||||
autocomplete = v.widget.attrs.get('autocomplete', '')
|
||||
if autocomplete.strip() == "off":
|
||||
v.widget.attrs['autocomplete'] = 'off'
|
||||
else:
|
||||
v.widget.attrs['autocomplete'] = 'section-{} '.format(self.prefix) + autocomplete
|
||||
|
||||
def build_requested_valid_from_field(self, event, pos, item):
|
||||
if item.validity_dynamic_start_choice_day_limit:
|
||||
max_date = time_machine_now().astimezone(event.timezone) + timedelta(days=item.validity_dynamic_start_choice_day_limit)
|
||||
else:
|
||||
max_date = None
|
||||
min_date = time_machine_now()
|
||||
initial = None
|
||||
if (item.require_membership or (pos.variation and pos.variation.require_membership)) and pos.used_membership:
|
||||
if pos.used_membership.date_start >= time_machine_now():
|
||||
initial = min_date = pos.used_membership.date_start
|
||||
max_date = min(max_date, pos.used_membership.date_end) if max_date else pos.used_membership.date_end
|
||||
if item.validity_dynamic_duration_months or item.validity_dynamic_duration_days:
|
||||
attrs = {}
|
||||
if max_date:
|
||||
attrs['data-max'] = max_date.date().isoformat()
|
||||
if min_date:
|
||||
attrs['data-min'] = min_date.date().isoformat()
|
||||
return forms.DateField(
|
||||
label=_('Start date'),
|
||||
help_text='' if initial else _('If you keep this empty, the ticket will be valid starting at the time of purchase.'),
|
||||
required=bool(initial),
|
||||
initial=pos.requested_valid_from or initial,
|
||||
widget=DatePickerWidget(attrs),
|
||||
validators=([MaxDateValidator(max_date.date())] if max_date else []) + [MinDateValidator(min_date.date())]
|
||||
)
|
||||
else:
|
||||
return forms.SplitDateTimeField(
|
||||
label=_('Start date'),
|
||||
help_text='' if initial else _('If you keep this empty, the ticket will be valid starting at the time of purchase.'),
|
||||
required=bool(initial),
|
||||
initial=pos.requested_valid_from or initial,
|
||||
widget=SplitDateTimePickerWidget(
|
||||
time_format=get_format_without_seconds('TIME_INPUT_FORMATS'),
|
||||
min_date=min_date,
|
||||
max_date=max_date
|
||||
),
|
||||
validators=([MaxDateTimeValidator(max_date)] if max_date else []) + [MinDateTimeValidator(min_date)]
|
||||
)
|
||||
|
||||
def build_system_question_field(self, request, event, pos, qc):
|
||||
field_name = qc.id
|
||||
if field_name == 'attendee_name_parts':
|
||||
return NamePartsFormField(
|
||||
max_length=255,
|
||||
required=qc.required and not self.all_optional,
|
||||
scheme=event.settings.name_scheme,
|
||||
titles=event.settings.name_scheme_titles,
|
||||
label=escape(qc.question),
|
||||
help_text=rich_text(qc.help_text),
|
||||
initial=pos.attendee_name_parts,
|
||||
)
|
||||
if field_name == 'attendee_email':
|
||||
return forms.EmailField(
|
||||
required=qc.required and not self.all_optional,
|
||||
label=escape(qc.question),
|
||||
help_text=rich_text(qc.help_text),
|
||||
initial=pos.attendee_email,
|
||||
widget=forms.EmailInput(
|
||||
attrs={
|
||||
'autocomplete': 'email'
|
||||
}
|
||||
)
|
||||
)
|
||||
if field_name == 'company':
|
||||
return forms.CharField(
|
||||
required=qc.required and not self.all_optional,
|
||||
label=escape(qc.question),
|
||||
help_text=rich_text(qc.help_text),
|
||||
max_length=255,
|
||||
initial=pos.company,
|
||||
)
|
||||
|
||||
if field_name == 'street':
|
||||
return forms.CharField(
|
||||
required=qc.required and not self.all_optional,
|
||||
label=escape(qc.question),
|
||||
help_text=rich_text(qc.help_text),
|
||||
widget=forms.Textarea(attrs={
|
||||
'rows': 2,
|
||||
'placeholder': _('Street and Number'),
|
||||
'autocomplete': 'street-address'
|
||||
}),
|
||||
initial=pos.street,
|
||||
)
|
||||
if field_name == 'zipcode':
|
||||
return forms.CharField(
|
||||
required=False,
|
||||
max_length=30,
|
||||
label=escape(qc.question),
|
||||
help_text=rich_text(qc.help_text),
|
||||
initial=pos.zipcode,
|
||||
widget=forms.TextInput(attrs={
|
||||
'autocomplete': 'postal-code',
|
||||
}),
|
||||
)
|
||||
if field_name == 'city':
|
||||
return forms.CharField(
|
||||
required=False,
|
||||
label=escape(qc.question),
|
||||
help_text=rich_text(qc.help_text),
|
||||
max_length=255,
|
||||
initial=pos.city,
|
||||
widget=forms.TextInput(attrs={
|
||||
'autocomplete': 'address-level2',
|
||||
}),
|
||||
)
|
||||
if field_name == 'country':
|
||||
country = pos.country or guess_country_from_request(request, event)
|
||||
return CountryField(
|
||||
countries=CachedCountries
|
||||
).formfield(
|
||||
required=qc.required and not self.all_optional,
|
||||
label=escape(qc.question),
|
||||
help_text=rich_text(qc.help_text),
|
||||
initial=country,
|
||||
widget=forms.Select(attrs={
|
||||
'autocomplete': 'country',
|
||||
'data-trigger-address-info': 'on',
|
||||
}),
|
||||
)
|
||||
if field_name == 'state':
|
||||
country = pos.country or guess_country_from_request(request, event)
|
||||
c = [('', '---')]
|
||||
fprefix = str(self.prefix) + '-' if self.prefix is not None and self.prefix != '-' else ''
|
||||
cc = None
|
||||
state = None
|
||||
if fprefix + 'country' in self.data:
|
||||
cc = str(self.data[fprefix + 'country'])
|
||||
elif country:
|
||||
cc = str(country)
|
||||
if cc and cc in COUNTRIES_WITH_STATE_IN_ADDRESS:
|
||||
types, form = COUNTRIES_WITH_STATE_IN_ADDRESS[cc]
|
||||
statelist = [s for s in pycountry.subdivisions.get(country_code=cc) if s.type in types]
|
||||
c += sorted([(s.code[3:], s.name) for s in statelist], key=lambda s: s[1])
|
||||
state = (pos.state)
|
||||
elif fprefix + 'state' in self.data:
|
||||
self.data = self.data.copy()
|
||||
del self.data[fprefix + 'state']
|
||||
|
||||
field = forms.ChoiceField(
|
||||
label=escape(qc.question),
|
||||
help_text=rich_text(qc.help_text),
|
||||
required=False,
|
||||
choices=c,
|
||||
initial=state,
|
||||
widget=forms.Select(attrs={
|
||||
'autocomplete': 'address-level1',
|
||||
}),
|
||||
)
|
||||
field.widget.is_required = True
|
||||
return field
|
||||
|
||||
def clean(self):
|
||||
from pretix.base.addressvalidation import \
|
||||
validate_address # local import to prevent impact on startup time
|
||||
|
||||
d = super().clean()
|
||||
|
||||
if self.address_validation:
|
||||
self.cleaned_data = d = validate_address(d, all_optional=not self.attendee_addresses_required)
|
||||
|
||||
if d.get('street') and d.get('country') and str(d['country']) in COUNTRIES_WITH_STATE_IN_ADDRESS:
|
||||
if not d.get('state'):
|
||||
self.add_error('state', _('This field is required.'))
|
||||
|
||||
self.check_user_questions(d)
|
||||
del d['question_%d' % q.pk]
|
||||
|
||||
return d
|
||||
|
||||
@@ -1286,15 +1201,15 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
if not self.ask_vat_id:
|
||||
del self.fields['vat_id']
|
||||
elif self.validate_vat_id:
|
||||
self.fields['vat_id'].help_text = _(
|
||||
'Optional, but depending on the country you reside in we might need to charge you '
|
||||
'additional taxes if you do not enter it.'
|
||||
)
|
||||
self.fields['vat_id'].help_text = '<br/>'.join([
|
||||
str(_('Optional, but depending on the country you reside in we might need to charge you '
|
||||
'additional taxes if you do not enter it.')),
|
||||
])
|
||||
else:
|
||||
self.fields['vat_id'].help_text = _(
|
||||
'Optional, but it might be required for you to claim tax benefits on your invoice '
|
||||
'depending on your and the seller’s country of residence.'
|
||||
)
|
||||
self.fields['vat_id'].help_text = '<br/>'.join([
|
||||
str(_('Optional, but it might be required for you to claim tax benefits on your invoice '
|
||||
'depending on your and the seller’s country of residence.')),
|
||||
])
|
||||
|
||||
transmission_type_choices = [
|
||||
(t.identifier, t.public_name) for t in get_transmission_types()
|
||||
@@ -1380,8 +1295,8 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
||||
del self.fields['beneficiary']
|
||||
|
||||
if event.settings.invoice_address_custom_field:
|
||||
self.fields['custom_field'].label = escape(event.settings.invoice_address_custom_field)
|
||||
self.fields['custom_field'].help_text = rich_text(event.settings.invoice_address_custom_field_helptext)
|
||||
self.fields['custom_field'].label = event.settings.invoice_address_custom_field
|
||||
self.fields['custom_field'].help_text = event.settings.invoice_address_custom_field_helptext
|
||||
else:
|
||||
del self.fields['custom_field']
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ from pretix.helpers.i18n import (
|
||||
get_format_without_seconds, get_javascript_format,
|
||||
get_javascript_format_without_seconds,
|
||||
)
|
||||
from pretix.helpers.safedownload import get_token
|
||||
|
||||
|
||||
def replace_arabic_numbers(inp):
|
||||
@@ -158,26 +157,36 @@ class TimePickerWidget(forms.TimeInput):
|
||||
|
||||
class UploadedFileWidget(forms.ClearableFileInput):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.position = kwargs.pop('position')
|
||||
self.event = kwargs.pop('event')
|
||||
self.answer = kwargs.pop('answer')
|
||||
self.request = kwargs.pop('request')
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
class FakeFile:
|
||||
def __init__(self, file, answer, request):
|
||||
def __init__(self, file, position, event, answer):
|
||||
self.file = file
|
||||
self.position = position
|
||||
self.event = event
|
||||
self.answer = answer
|
||||
self.request = request
|
||||
|
||||
def __str__(self):
|
||||
return os.path.basename(self.file.name).split('.', 1)[-1]
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
token = get_token(self.request, self.answer)
|
||||
if self.request.resolver_match.namespace == 'control':
|
||||
return self.answer.backend_file_url + '?token=' + token
|
||||
from pretix.base.models import OrderPosition
|
||||
from pretix.multidomain.urlreverse import eventreverse
|
||||
|
||||
if isinstance(self.position, OrderPosition):
|
||||
return eventreverse(self.event, 'presale:event.order.download.answer', kwargs={
|
||||
'order': self.position.order.code,
|
||||
'secret': self.position.order.secret,
|
||||
'answer': self.answer.pk,
|
||||
})
|
||||
else:
|
||||
return self.answer.frontend_file_url + '?token=' + token
|
||||
return eventreverse(self.event, 'presale:event.cart.download.answer', kwargs={
|
||||
'answer': self.answer.pk,
|
||||
})
|
||||
|
||||
def get_context(self, name, value, attrs):
|
||||
# Browsers can't recognize that the server already has a file uploaded
|
||||
@@ -190,7 +199,7 @@ class UploadedFileWidget(forms.ClearableFileInput):
|
||||
|
||||
def format_value(self, value):
|
||||
if self.is_initial(value):
|
||||
return self.FakeFile(value, self.answer, self.request)
|
||||
return self.FakeFile(value, self.position, self.event, self.answer)
|
||||
|
||||
|
||||
class SplitDateTimePickerWidget(forms.SplitDateTimeWidget):
|
||||
@@ -305,18 +314,3 @@ class BusinessBooleanRadio(forms.RadioSelect):
|
||||
'False': False,
|
||||
False: False,
|
||||
}.get(value)
|
||||
|
||||
|
||||
class OptionAttrsSelect(forms.Select):
|
||||
def __init__(self, *args, option_attrs=None, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.option_attrs = option_attrs or {}
|
||||
|
||||
def create_option(self, name, value, label, selected, index, subindex=None, attrs=None):
|
||||
option = super().create_option(
|
||||
name, value, label, selected, index, subindex=subindex, attrs=attrs
|
||||
)
|
||||
extra = self.option_attrs.get(str(value))
|
||||
if extra:
|
||||
option["attrs"].update(extra)
|
||||
return option
|
||||
|
||||
@@ -497,16 +497,8 @@ class RejectInvalidInputMiddleware(MiddlewareMixin):
|
||||
if "\x00" in request.META['QUERY_STRING'] or "%00" in request.META['QUERY_STRING']:
|
||||
raise BadRequest("Invalid characters in input.")
|
||||
if request.method in ('POST', 'PUT', 'PATCH') and request.content_type == "application/x-www-form-urlencoded":
|
||||
try:
|
||||
post_data = request.POST.lists()
|
||||
except BadRequest:
|
||||
# Reading request.POST wasn't possible, probably an invalid charset. Django will crash once we actually
|
||||
# use request.POST, but if we don't, let's not crash it (required for some weird payment provider
|
||||
# webhooks, e.g. computop).
|
||||
pass
|
||||
else:
|
||||
if any("\x00" in value for key, value_list in post_data for value in value_list):
|
||||
raise BadRequest("Invalid characters in input.")
|
||||
if any("\x00" in value for key, value_list in request.POST.lists() for value in value_list):
|
||||
raise BadRequest("Invalid characters in input.")
|
||||
|
||||
|
||||
class CustomCommonMiddleware(CommonMiddleware):
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
# Generated by Django 5.2.16 on 2026-08-05 08:00
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
import pretix.helpers.database
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("pretixbase", "0306_alter_eventmetaproperty_unique_together"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="DeviceLastSeen",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("last_seen", models.DateTimeField(auto_now=True)),
|
||||
(
|
||||
"device",
|
||||
models.OneToOneField(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="pretixbase.device",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="devicelastseen",
|
||||
index=pretix.helpers.database.BrinIndexIgnoredOnSQLite(
|
||||
models.F("last_seen"),
|
||||
autosummarize=True,
|
||||
name="pretixbase_device_last_seen",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -1,63 +0,0 @@
|
||||
# Generated by Django 4.2.17 on 2025-01-01 20:25
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("pretixbase", "0307_devicelastseen"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="CheckoutSession",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True, primary_key=True, serialize=False
|
||||
),
|
||||
),
|
||||
("cart_id", models.CharField(max_length=255, unique=True)),
|
||||
("created", models.DateTimeField(auto_now_add=True)),
|
||||
("testmode", models.BooleanField(default=False)),
|
||||
("session_data", models.JSONField(default=dict)),
|
||||
(
|
||||
"customer",
|
||||
models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="checkout_sessions",
|
||||
to="pretixbase.customer",
|
||||
),
|
||||
),
|
||||
(
|
||||
"event",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="checkout_sessions",
|
||||
to="pretixbase.event",
|
||||
),
|
||||
),
|
||||
(
|
||||
"sales_channel",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="pretixbase.saleschannel",
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="invoiceaddress",
|
||||
name="checkout_session",
|
||||
field=models.OneToOneField(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="invoice_address",
|
||||
to="pretixbase.checkoutsession",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -1,33 +0,0 @@
|
||||
# Generated by Django 5.2.15 on 2026-08-07 20:01
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0308_checkoutsession_invoiceaddress_checkout_session'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='question',
|
||||
name='container_type',
|
||||
field=models.CharField(default='P', max_length=5),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='questionanswer',
|
||||
name='checkoutsession',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='answers', to='pretixbase.checkoutsession'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='questionanswer',
|
||||
name='order',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='answers', to='pretixbase.order'),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='questionanswer',
|
||||
unique_together={('cartposition', 'question'), ('checkoutsession', 'question'), ('order', 'question'), ('orderposition', 'question')},
|
||||
),
|
||||
]
|
||||
@@ -33,7 +33,6 @@ from django.db.models.aggregates import Sum
|
||||
from django.db.models.expressions import OuterRef, Subquery
|
||||
from django.db.models.functions.comparison import Coalesce
|
||||
from django.utils.crypto import get_random_string, salted_hmac
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
||||
from django_scopes import ScopedManager, scopes_disabled
|
||||
@@ -410,17 +409,6 @@ class AttendeeProfile(models.Model):
|
||||
|
||||
return '\n'.join([str(p).strip() for p in parts if p and str(p).strip()])
|
||||
|
||||
@cached_property
|
||||
def answers_key_to_index(self):
|
||||
return {a.get('field_name'): i for i, a in enumerate(self.answers)}
|
||||
|
||||
def store_answer(self, answer_dict):
|
||||
k = answer_dict['field_name']
|
||||
if k in self.answers_key_to_index:
|
||||
self.answers[self.answers_key_to_index[k]] = answer_dict
|
||||
else:
|
||||
self.answers.append(answer_dict)
|
||||
|
||||
|
||||
def generate_client_id():
|
||||
return get_random_string(40)
|
||||
|
||||
@@ -20,13 +20,11 @@
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import string
|
||||
from datetime import timedelta
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.db.models import Max
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_scopes import ScopedManager, scopes_disabled
|
||||
|
||||
@@ -34,7 +32,6 @@ from pretix.base.models import LoggedModel
|
||||
from pretix.base.permissions import (
|
||||
AnyPermissionOf, assert_valid_event_permission,
|
||||
)
|
||||
from pretix.helpers import BrinIndexIgnoredOnSQLite
|
||||
|
||||
|
||||
@scopes_disabled()
|
||||
@@ -290,27 +287,3 @@ class Device(LoggedModel):
|
||||
return self.get_events_with_any_permission()
|
||||
else:
|
||||
return self.organizer.events.none()
|
||||
|
||||
|
||||
class DeviceLastSeen(models.Model):
|
||||
# This is a separate model since we expect it to get A LOT of writes and PostgreSQL always
|
||||
# writes full rows and then needs to update all indexes on the row, so this is going to save a
|
||||
# lot of write traffic on the databse
|
||||
device = models.OneToOneField("Device", on_delete=models.CASCADE, related_name="last_seen")
|
||||
last_seen = models.DateTimeField(auto_now=True)
|
||||
|
||||
class Meta:
|
||||
indexes = [
|
||||
BrinIndexIgnoredOnSQLite(
|
||||
# BRIN indexes are highly efficient on lots of updates, especially of chronological data
|
||||
# and especially if we later want to query them by range, as we likely want to.
|
||||
"last_seen",
|
||||
name="pretixbase_device_last_seen",
|
||||
autosummarize=True
|
||||
)
|
||||
]
|
||||
|
||||
@property
|
||||
def is_recent(self):
|
||||
# pretixSCAN/pretixPOS sync every 5 minutes, so 7 minutes can be considered "offline"
|
||||
return now() - self.last_seen < timedelta(minutes=7)
|
||||
|
||||
@@ -736,7 +736,7 @@ class Event(EventMixin, LoggedModel):
|
||||
self.settings.mail_send_order_paid_attendee = True
|
||||
self.settings.mail_send_order_approved_attendee = True
|
||||
self.settings.mail_send_order_approved_free_attendee = True
|
||||
self.settings.mail_send_download_reminder_attendee = True
|
||||
self.settings.mail_text_download_reminder_attendee = True
|
||||
|
||||
@property
|
||||
def social_image(self):
|
||||
|
||||
@@ -1606,9 +1606,6 @@ class Question(LoggedModel):
|
||||
:param dependency_values: The values that `dependency_question` needs to be set to for this question to be applicable.
|
||||
:type dependency_values: list[str]
|
||||
"""
|
||||
class ContainerType(models.TextChoices):
|
||||
ORDER = "O", _("Order")
|
||||
ORDERPOSITION = "P", _("Order position")
|
||||
TYPE_NUMBER = "N"
|
||||
TYPE_STRING = "S"
|
||||
TYPE_TEXT = "T"
|
||||
@@ -1644,12 +1641,6 @@ class Question(LoggedModel):
|
||||
related_name="questions",
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
container_type = models.CharField(
|
||||
max_length=5,
|
||||
choices=ContainerType.choices,
|
||||
verbose_name=_("Asked on"),
|
||||
default=ContainerType.ORDERPOSITION,
|
||||
)
|
||||
question = I18nTextField(
|
||||
verbose_name=_("Question")
|
||||
)
|
||||
|
||||
@@ -1304,9 +1304,10 @@ class Order(LockModel, LoggedModel):
|
||||
|
||||
def answerfile_name(instance, filename: str) -> str:
|
||||
secret = get_random_string(length=32, allowed_chars=string.ascii_letters + string.digits)
|
||||
event = (instance.cartposition if instance.cartposition else instance.orderposition.order).event
|
||||
return 'cachedfiles/answers/{org}/{ev}/{secret}.{filename}'.format(
|
||||
org=instance.event.organizer.slug,
|
||||
ev=instance.event.slug,
|
||||
org=event.organizer.slug,
|
||||
ev=event.slug,
|
||||
secret=secret,
|
||||
filename=escape_uri_path(filename),
|
||||
)
|
||||
@@ -1335,14 +1336,6 @@ class QuestionAnswer(models.Model):
|
||||
'CartPosition', null=True, blank=True,
|
||||
related_name='answers', on_delete=models.CASCADE
|
||||
)
|
||||
order = models.ForeignKey(
|
||||
'Order', null=True, blank=True,
|
||||
related_name='answers', on_delete=models.CASCADE
|
||||
)
|
||||
checkoutsession = models.ForeignKey(
|
||||
'CheckoutSession', null=True, blank=True,
|
||||
related_name='answers', on_delete=models.CASCADE
|
||||
)
|
||||
question = models.ForeignKey(
|
||||
Question, related_name='answers', on_delete=models.CASCADE
|
||||
)
|
||||
@@ -1358,21 +1351,16 @@ class QuestionAnswer(models.Model):
|
||||
objects = ScopedManager(organizer='question__event__organizer')
|
||||
|
||||
class Meta:
|
||||
unique_together = [
|
||||
['orderposition', 'question'],
|
||||
['cartposition', 'question'],
|
||||
['order', 'question'],
|
||||
['checkoutsession', 'question'],
|
||||
]
|
||||
unique_together = [['orderposition', 'question'], ['cartposition', 'question']]
|
||||
|
||||
@property
|
||||
def backend_file_url(self):
|
||||
if self.file:
|
||||
if self.associated_order:
|
||||
if self.orderposition:
|
||||
return reverse('control:event.order.download.answer', kwargs={
|
||||
'code': self.associated_order.code,
|
||||
'event': self.associated_order.event.slug,
|
||||
'organizer': self.associated_order.event.organizer.slug,
|
||||
'code': self.orderposition.order.code,
|
||||
'event': self.orderposition.order.event.slug,
|
||||
'organizer': self.orderposition.order.event.organizer.slug,
|
||||
'answer': self.pk,
|
||||
})
|
||||
return ""
|
||||
@@ -1382,14 +1370,14 @@ class QuestionAnswer(models.Model):
|
||||
from pretix.multidomain.urlreverse import eventreverse
|
||||
|
||||
if self.file:
|
||||
if self.associated_order:
|
||||
url = eventreverse(self.associated_order.event, 'presale:event.order.download.answer', kwargs={
|
||||
'order': self.associated_order.code,
|
||||
'secret': self.associated_order.secret,
|
||||
if self.orderposition:
|
||||
url = eventreverse(self.orderposition.order.event, 'presale:event.order.download.answer', kwargs={
|
||||
'order': self.orderposition.order.code,
|
||||
'secret': self.orderposition.order.secret,
|
||||
'answer': self.pk,
|
||||
})
|
||||
else:
|
||||
url = eventreverse(self.event, 'presale:event.cart.download.answer', kwargs={
|
||||
url = eventreverse(self.cartposition.event, 'presale:event.cart.download.answer', kwargs={
|
||||
'answer': self.pk,
|
||||
})
|
||||
|
||||
@@ -1404,24 +1392,6 @@ class QuestionAnswer(models.Model):
|
||||
def file_name(self):
|
||||
return self.file.name.split('.', 1)[-1]
|
||||
|
||||
@property
|
||||
def associated_order(self):
|
||||
if self.orderposition:
|
||||
return self.orderposition.order
|
||||
elif self.order:
|
||||
return self.order
|
||||
|
||||
@property
|
||||
def event(self):
|
||||
if self.orderposition:
|
||||
return self.orderposition.order.event
|
||||
elif self.cartposition:
|
||||
return self.cartposition.event
|
||||
elif self.order:
|
||||
return self.order.event
|
||||
elif self.checkoutsession:
|
||||
return self.checkoutsession.event
|
||||
|
||||
def __str__(self):
|
||||
return self.to_string(use_cached=True)
|
||||
|
||||
@@ -3207,39 +3177,6 @@ class Transaction(models.Model):
|
||||
return self.tax_value_includes_rounding_correction * self.count
|
||||
|
||||
|
||||
class CheckoutSession(models.Model):
|
||||
"""
|
||||
A checkout session optionally bundles cart positions with additional information. This is historically
|
||||
not required in pretix and currently only used in the Storefront API.
|
||||
"""
|
||||
event = models.ForeignKey(
|
||||
Event,
|
||||
verbose_name=_("Event"),
|
||||
related_name="checkout_sessions",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
cart_id = models.CharField(
|
||||
max_length=255, unique=True,
|
||||
verbose_name=_("Cart ID (e.g. session key)"),
|
||||
)
|
||||
created = models.DateTimeField(
|
||||
verbose_name=_("Date"),
|
||||
auto_now_add=True,
|
||||
)
|
||||
customer = models.ForeignKey(
|
||||
Customer,
|
||||
related_name='checkout_sessions',
|
||||
null=True, blank=True,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
sales_channel = models.ForeignKey(
|
||||
"SalesChannel",
|
||||
on_delete=models.CASCADE,
|
||||
)
|
||||
testmode = models.BooleanField(default=False)
|
||||
session_data = models.JSONField(default=dict)
|
||||
|
||||
|
||||
class CartPosition(AbstractPosition):
|
||||
"""
|
||||
A cart position is similar to an order line, except that it is not
|
||||
@@ -3444,13 +3381,6 @@ class CartPosition(AbstractPosition):
|
||||
|
||||
class InvoiceAddress(models.Model):
|
||||
last_modified = models.DateTimeField(auto_now=True)
|
||||
checkout_session = models.OneToOneField(
|
||||
CheckoutSession,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='invoice_address',
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
order = models.OneToOneField(Order, null=True, blank=True, related_name='invoice_address', on_delete=models.CASCADE)
|
||||
customer = models.ForeignKey(
|
||||
Customer,
|
||||
|
||||
@@ -330,24 +330,9 @@ class BasePaymentProvider:
|
||||
payment method. This returns ``False`` by default which is no guarantee that
|
||||
aborting a pending payment can never happen, it just hides the frontend button
|
||||
to avoid users accidentally committing double payments.
|
||||
If the decision doesn't depend on the specific payment, then only implementing
|
||||
``abort_pending_allowed`` is enough, ``payment_abort_pending_allowed(payment: OrderPayment)``
|
||||
is expected to take this into account.
|
||||
As a consumer only evaluate ``payment_abort_pending_allowed(payment: OrderPayment)``
|
||||
to check if aborting this pending payment is possible.
|
||||
"""
|
||||
return False
|
||||
|
||||
def _payment_abort_pending_allowed(self, payment: OrderPayment) -> bool:
|
||||
"""
|
||||
Experimental: This might change during upcomming releases.
|
||||
Whether or not a user can abort a payment in pending state to switch to another
|
||||
payment method. This returns ``self.abort_pending_allowed`` by default which is
|
||||
no guarantee that aborting a pending payment can never happen, it just hides the
|
||||
frontend button to avoid users accidentally committing double payments.
|
||||
"""
|
||||
return self.abort_pending_allowed
|
||||
|
||||
@property
|
||||
def requires_invoice_immediately(self):
|
||||
"""
|
||||
@@ -1034,12 +1019,10 @@ class BasePaymentProvider:
|
||||
On success, you should set ``payment.state = OrderPayment.PAYMENT_STATE_CANCELED`` (or call the super method).
|
||||
On failure, you should raise a PaymentException.
|
||||
"""
|
||||
|
||||
if payment.state == OrderPayment.PAYMENT_STATE_PENDING:
|
||||
if not self._payment_abort_pending_allowed(payment):
|
||||
raise PaymentException(_(
|
||||
"This payment is already being processed and cannot be canceled any more."
|
||||
))
|
||||
if payment.state == OrderPayment.PAYMENT_STATE_PENDING and not self.abort_pending_allowed:
|
||||
raise PaymentException(_(
|
||||
"This payment is already being processed and can not be canceled any more."
|
||||
))
|
||||
|
||||
payment.state = OrderPayment.PAYMENT_STATE_CANCELED
|
||||
payment.save(update_fields=['state'])
|
||||
|
||||
+155
-373
@@ -19,245 +19,30 @@
|
||||
# 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/>.
|
||||
#
|
||||
import copy
|
||||
import datetime
|
||||
import os
|
||||
import warnings
|
||||
from collections import namedtuple
|
||||
from dataclasses import dataclass
|
||||
from typing import (
|
||||
TYPE_CHECKING, Iterable, List, Literal, Optional, Tuple, Union, cast,
|
||||
)
|
||||
from typing import Union
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from dateutil import parser
|
||||
from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.forms.widgets import Widget
|
||||
from django.utils.formats import get_format
|
||||
from django.utils.functional import Promise, lazy
|
||||
from django.utils.functional import lazy
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from pretix.base.forms.widgets import OptionAttrsSelect
|
||||
BASE_CHOICES = (
|
||||
('date_from', _('Event start')),
|
||||
('date_to', _('Event end')),
|
||||
('date_admission', _('Event admission')),
|
||||
('presale_start', _('Presale start')),
|
||||
('presale_end', _('Presale end')),
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .models import Event, Order, SubEvent
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BaseChoice:
|
||||
base: Literal["event", "order"]
|
||||
attribute: str
|
||||
text: Promise
|
||||
supports_before: bool
|
||||
supports_after: bool
|
||||
|
||||
@property
|
||||
def key(self) -> str:
|
||||
key = f"{self.base}__{self.attribute}"
|
||||
return key
|
||||
|
||||
@staticmethod
|
||||
def find(objects: Iterable["BaseChoice"], key: str) -> "BaseChoice":
|
||||
if "__" in key:
|
||||
choice = next((obj for obj in objects if obj.key == key), None)
|
||||
else:
|
||||
# fallback for RelativeDateFields stored, before support for bases other than event was added
|
||||
choice = next((obj for obj in objects if obj.attribute == key and obj.base == "event"), None)
|
||||
|
||||
if choice is None:
|
||||
raise TypeError(f"key {key} must be a valid key in BASE_CHOICES")
|
||||
|
||||
return choice
|
||||
|
||||
|
||||
BASE_CHOICES: List[BaseChoice] = [
|
||||
BaseChoice('event', 'date_from', _('Event start'), True, True),
|
||||
BaseChoice('event', 'date_to', _('Event end'), True, True),
|
||||
BaseChoice('event', 'date_admission', _('Event admission'), True, True),
|
||||
BaseChoice('event', 'presale_start', _('Presale start'), True, True),
|
||||
BaseChoice('event', 'presale_end', _('Presale end'), True, True),
|
||||
BaseChoice('order', 'datetime', _('Order creation'), False, True),
|
||||
BaseChoice('order', 'expires', _('Order expiry'), True, True),
|
||||
]
|
||||
|
||||
EVENT_BASE_CHOICES = [
|
||||
x for x in BASE_CHOICES if x.base == 'event'
|
||||
]
|
||||
|
||||
ORDER_BASE_CHOICES = [
|
||||
x for x in BASE_CHOICES if x.base == 'order'
|
||||
]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RelativeDate:
|
||||
"""
|
||||
This contains information on a date that is defined in relation to a fixed base point.
|
||||
This means that the underlying data is a fixed date as the base point and a number of days or a time interval
|
||||
to calculate the date.
|
||||
|
||||
The list of valid base date choices is defined in BASE_CHOICES.
|
||||
If the base_date_name is not set, the date_from attribute of Event is used.
|
||||
"""
|
||||
|
||||
days: int = 0
|
||||
minutes: Optional[int] = None
|
||||
time: Optional[datetime.time] = None
|
||||
is_after: bool = False
|
||||
base_date_name: str = 'event__date_from__'
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.is_after and not self._choice.supports_after:
|
||||
raise ValueError(
|
||||
"The selected base date and attribute combination does not support relative dates placed after the base date"
|
||||
)
|
||||
if not self.is_after and not self._choice.supports_before:
|
||||
raise ValueError(
|
||||
"The selected base date and attribute combination does not support relative dates placed before the base date")
|
||||
|
||||
@property
|
||||
def _choice(self):
|
||||
return BaseChoice.find(BASE_CHOICES, self.base_date_name)
|
||||
|
||||
@property
|
||||
def key(self):
|
||||
return self._choice.key
|
||||
|
||||
def __eq__(self, o: object) -> bool:
|
||||
if not isinstance(o, RelativeDate):
|
||||
return False
|
||||
return self.to_string() == o.to_string()
|
||||
|
||||
def _resolve_date(self, base: "Event | Order | SubEvent") -> Tuple[datetime.datetime, ZoneInfo]:
|
||||
"""
|
||||
Resolves the datetime and timezone information of this RelativeDate object in relation to the provided reference.
|
||||
|
||||
:param base: the reference which should be used to resolve the relative date
|
||||
:return:
|
||||
"""
|
||||
from .models import Event, Order, SubEvent
|
||||
|
||||
choice = self._choice
|
||||
|
||||
if choice.base == "order" and isinstance(base, Order):
|
||||
event = base.event
|
||||
base_date = getattr(base, choice.attribute)
|
||||
elif choice.base == "event" and isinstance(base, SubEvent):
|
||||
event = base.event
|
||||
base_date = (getattr(base, choice.attribute) or
|
||||
getattr(base.event, choice.attribute) or
|
||||
base.date_from)
|
||||
elif choice.base == "event" and isinstance(base, Event):
|
||||
event = base
|
||||
base_date = getattr(base, choice.attribute) or event.date_from
|
||||
else:
|
||||
raise TypeError("The base defined by data does not match the passed in base")
|
||||
|
||||
tz = ZoneInfo(event.settings.timezone)
|
||||
return base_date, tz
|
||||
|
||||
def date(self, base: "Event | Order | SubEvent") -> datetime.date:
|
||||
"""
|
||||
Resolves the effective date of this RelativeDate object in relation to the provided reference.
|
||||
|
||||
:param base: the reference which should be used to resolve the date
|
||||
:return: datetime.date
|
||||
"""
|
||||
if self.minutes is not None:
|
||||
raise ValueError('A minute-based relative datetime can not be used as a date')
|
||||
|
||||
base_date, tz = self._resolve_date(base)
|
||||
|
||||
if self.is_after:
|
||||
new_date = base_date.astimezone(tz) + datetime.timedelta(days=self.days)
|
||||
else:
|
||||
new_date = base_date.astimezone(tz) - datetime.timedelta(days=self.days)
|
||||
return new_date.date()
|
||||
|
||||
def datetime(self, base: "Event | Order | SubEvent") -> datetime.datetime:
|
||||
"""
|
||||
Resolves the effective datetime of this RelativeDate object in relation to the provided reference.
|
||||
|
||||
:param base: the reference which should be used to resolve the datetime
|
||||
:return: datetime.datetime
|
||||
"""
|
||||
base_date, tz = self._resolve_date(base)
|
||||
|
||||
if self.minutes is not None:
|
||||
if self.is_after:
|
||||
return base_date.astimezone(tz) + datetime.timedelta(minutes=self.minutes)
|
||||
else:
|
||||
return base_date.astimezone(tz) - datetime.timedelta(minutes=self.minutes)
|
||||
else:
|
||||
if self.is_after:
|
||||
new_date = (base_date.astimezone(tz) + datetime.timedelta(days=self.days)).astimezone(tz)
|
||||
else:
|
||||
new_date = (base_date.astimezone(tz) - datetime.timedelta(days=self.days)).astimezone(tz)
|
||||
if self.time:
|
||||
new_date = new_date.replace(
|
||||
hour=self.time.hour,
|
||||
minute=self.time.minute,
|
||||
second=self.time.second
|
||||
)
|
||||
new_date = new_date.astimezone(tz)
|
||||
return new_date
|
||||
|
||||
def to_string(self) -> str:
|
||||
if self.minutes is not None:
|
||||
return 'RELDATE/minutes/{}/{}/{}'.format( #
|
||||
self.minutes,
|
||||
self._choice.key,
|
||||
'after' if self.is_after else '',
|
||||
)
|
||||
return 'RELDATE/{}/{}/{}/{}'.format( #
|
||||
self.days,
|
||||
self.time.strftime('%H:%M:%S') if self.time else '-',
|
||||
self._choice.key,
|
||||
'after' if self.is_after else '',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_string(cls, input: str):
|
||||
if not input.startswith('RELDATE/'):
|
||||
raise TypeError("Invalid input for RelativeDate.from_string()")
|
||||
|
||||
parts = input.split('/')
|
||||
if parts[1] == 'minutes':
|
||||
data = RelativeDate(
|
||||
days=0,
|
||||
minutes=int(parts[2]),
|
||||
base_date_name=parts[3],
|
||||
time=None,
|
||||
is_after=len(parts) > 4 and parts[4] == "after",
|
||||
)
|
||||
else:
|
||||
if parts[2] == '-':
|
||||
time = None
|
||||
else:
|
||||
timeparts = parts[2].split(':')
|
||||
time = datetime.time(hour=int(timeparts[0]), minute=int(timeparts[1]), second=int(timeparts[2]))
|
||||
try:
|
||||
data = RelativeDate(
|
||||
days=int(parts[1] or 0),
|
||||
base_date_name=parts[3],
|
||||
time=time,
|
||||
minutes=None,
|
||||
is_after=len(parts) > 4 and parts[4] == "after",
|
||||
)
|
||||
except ValueError:
|
||||
data = RelativeDate(
|
||||
days=0,
|
||||
base_date_name=parts[3],
|
||||
time=time,
|
||||
minutes=None,
|
||||
is_after=len(parts) > 4 and parts[4] == "after",
|
||||
)
|
||||
|
||||
return data
|
||||
RelativeDate = namedtuple('RelativeDate', ['days', 'minutes', 'time', 'is_after', 'base_date_name'], defaults=(0, None, None, False, 'date_from'))
|
||||
|
||||
|
||||
class RelativeDateWrapper:
|
||||
@@ -265,53 +50,130 @@ class RelativeDateWrapper:
|
||||
This contains information on a date that might be relative to an event. This means
|
||||
that the underlying data is either a fixed date or a number of days and a wall clock
|
||||
time to calculate the date based on a base point.
|
||||
|
||||
The base point can be the date_from, date_to, date_admission, presale_start or presale_end
|
||||
attribute of an event or subevent. If the respective attribute is not set, ``date_from``
|
||||
will be used.
|
||||
"""
|
||||
|
||||
def __init__(self, data: Union[datetime.datetime, RelativeDate]):
|
||||
self.data = data
|
||||
|
||||
def date(self, base: "Event | Order | SubEvent") -> datetime.date:
|
||||
"""
|
||||
If the RelativeDateWrapper wraps a RelativeDate object:
|
||||
Resolves the effective date of this object in relation to the provided reference.
|
||||
If the RelativeDateWrapper wraps an absolute date or datetime:
|
||||
Returns the wrapped absolute date.
|
||||
def date(self, event) -> datetime.date:
|
||||
from .models import SubEvent
|
||||
|
||||
:param base: the reference which should be used to resolve the date in case it is a relative date.
|
||||
:return: datetime.date
|
||||
"""
|
||||
if isinstance(self.data, datetime.datetime):
|
||||
return self.data.date()
|
||||
elif isinstance(self.data, datetime.date):
|
||||
return self.data
|
||||
else:
|
||||
return self.data.date(base)
|
||||
if self.data.minutes is not None:
|
||||
raise ValueError('A minute-based relative datetime can not be used as a date')
|
||||
|
||||
def datetime(self, base: "Event | Order | SubEvent") -> datetime.datetime:
|
||||
"""
|
||||
If the RelativeDateWrapper wraps a RelativeDate object:
|
||||
Resolves the effective datetime of this object in relation to the provided reference.
|
||||
If the RelativeDateWrapper wraps an absolute date or datetime:
|
||||
Returns the wrapped absolute datetime.
|
||||
tz = ZoneInfo(event.settings.timezone)
|
||||
if isinstance(event, SubEvent):
|
||||
base_date = (
|
||||
getattr(event, self.data.base_date_name)
|
||||
or getattr(event.event, self.data.base_date_name)
|
||||
or event.date_from
|
||||
)
|
||||
else:
|
||||
base_date = getattr(event, self.data.base_date_name) or event.date_from
|
||||
|
||||
if self.data.is_after:
|
||||
new_date = base_date.astimezone(tz) + datetime.timedelta(days=self.data.days)
|
||||
else:
|
||||
new_date = base_date.astimezone(tz) - datetime.timedelta(days=self.data.days)
|
||||
return new_date.date()
|
||||
|
||||
def datetime(self, event) -> datetime.datetime:
|
||||
from .models import SubEvent
|
||||
|
||||
:param base: the reference which should be used to resolve the datetime in case it is a relative datetime.
|
||||
:return: datetime.datetime
|
||||
"""
|
||||
if isinstance(self.data, (datetime.datetime, datetime.date)):
|
||||
return self.data
|
||||
else:
|
||||
return self.data.datetime(base)
|
||||
tz = ZoneInfo(event.settings.timezone)
|
||||
if isinstance(event, SubEvent):
|
||||
base_date = (
|
||||
getattr(event, self.data.base_date_name)
|
||||
or getattr(event.event, self.data.base_date_name)
|
||||
or event.date_from
|
||||
)
|
||||
else:
|
||||
base_date = getattr(event, self.data.base_date_name) or event.date_from
|
||||
|
||||
if self.data.minutes is not None:
|
||||
if self.data.is_after:
|
||||
return base_date.astimezone(tz) + datetime.timedelta(minutes=self.data.minutes)
|
||||
else:
|
||||
return base_date.astimezone(tz) - datetime.timedelta(minutes=self.data.minutes)
|
||||
else:
|
||||
if self.data.is_after:
|
||||
new_date = (base_date.astimezone(tz) + datetime.timedelta(days=self.data.days)).astimezone(tz)
|
||||
else:
|
||||
new_date = (base_date.astimezone(tz) - datetime.timedelta(days=self.data.days)).astimezone(tz)
|
||||
if self.data.time:
|
||||
new_date = new_date.replace(
|
||||
hour=self.data.time.hour,
|
||||
minute=self.data.time.minute,
|
||||
second=self.data.time.second
|
||||
)
|
||||
new_date = new_date.astimezone(tz)
|
||||
return new_date
|
||||
|
||||
def to_string(self) -> str:
|
||||
if isinstance(self.data, (datetime.datetime, datetime.date)):
|
||||
return self.data.isoformat()
|
||||
else:
|
||||
return self.data.to_string()
|
||||
if self.data.minutes is not None:
|
||||
return 'RELDATE/minutes/{}/{}/{}'.format( #
|
||||
self.data.minutes,
|
||||
self.data.base_date_name,
|
||||
'after' if self.data.is_after else '',
|
||||
)
|
||||
return 'RELDATE/{}/{}/{}/{}'.format( #
|
||||
self.data.days,
|
||||
self.data.time.strftime('%H:%M:%S') if self.data.time else '-',
|
||||
self.data.base_date_name,
|
||||
'after' if self.data.is_after else '',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_string(cls, input: str):
|
||||
if input.startswith('RELDATE/'):
|
||||
data = RelativeDate.from_string(input)
|
||||
parts = input.split('/')
|
||||
if parts[1] == 'minutes':
|
||||
data = RelativeDate(
|
||||
days=0,
|
||||
minutes=int(parts[2]),
|
||||
base_date_name=parts[3],
|
||||
time=None,
|
||||
is_after=len(parts) > 4 and parts[4] == "after",
|
||||
)
|
||||
else:
|
||||
if parts[2] == '-':
|
||||
time = None
|
||||
else:
|
||||
timeparts = parts[2].split(':')
|
||||
time = datetime.time(hour=int(timeparts[0]), minute=int(timeparts[1]), second=int(timeparts[2]))
|
||||
try:
|
||||
data = RelativeDate(
|
||||
days=int(parts[1] or 0),
|
||||
base_date_name=parts[3],
|
||||
time=time,
|
||||
minutes=None,
|
||||
is_after=len(parts) > 4 and parts[4] == "after",
|
||||
)
|
||||
except ValueError:
|
||||
data = RelativeDate(
|
||||
days=0,
|
||||
base_date_name=parts[3],
|
||||
time=time,
|
||||
minutes=None,
|
||||
is_after=len(parts) > 4 and parts[4] == "after",
|
||||
)
|
||||
if data.base_date_name not in [k[0] for k in BASE_CHOICES]:
|
||||
raise ValueError('{} is not a valid base date'.format(data.base_date_name))
|
||||
else:
|
||||
data = parser.parse(input)
|
||||
return RelativeDateWrapper(data)
|
||||
@@ -325,6 +187,7 @@ BEFORE_AFTER_CHOICE = (
|
||||
('after', _('after')),
|
||||
)
|
||||
|
||||
|
||||
reldatetimeparts = namedtuple('reldatetimeparts', (
|
||||
"status", # 0
|
||||
"absolute", # 1
|
||||
@@ -339,14 +202,6 @@ reldatetimeparts = namedtuple('reldatetimeparts', (
|
||||
reldatetimeparts.indizes = reldatetimeparts(*range(9))
|
||||
|
||||
|
||||
def _get_choices(base_choices: List[BaseChoice]) -> List[Tuple[str, Promise]]:
|
||||
return [(c.key, c.text) for c in base_choices]
|
||||
|
||||
|
||||
def _get_choice_validation_obj(choices: List[BaseChoice]):
|
||||
return {c.key: {"data-supports-before": c.supports_before, "data-supports-after": c.supports_after} for c in choices}
|
||||
|
||||
|
||||
class RelativeDateTimeWidget(forms.MultiWidget):
|
||||
template_name = 'pretixbase/forms/widgets/reldatetime.html'
|
||||
parts = reldatetimeparts
|
||||
@@ -354,7 +209,6 @@ class RelativeDateTimeWidget(forms.MultiWidget):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.status_choices = kwargs.pop('status_choices')
|
||||
base_choices = kwargs.pop('base_choices')
|
||||
choices = _get_choices(base_choices)
|
||||
|
||||
def placeholder_datetime_format():
|
||||
df = get_format('DATETIME_INPUT_FORMATS')[0]
|
||||
@@ -366,29 +220,21 @@ class RelativeDateTimeWidget(forms.MultiWidget):
|
||||
tf = get_format('TIME_INPUT_FORMATS')[0]
|
||||
return datetime.time(8, 30, 0).strftime(tf)
|
||||
|
||||
widgets = cast(dict[str, Widget | type[Widget]], cast(object, reldatetimeparts(
|
||||
widgets = reldatetimeparts(
|
||||
status=forms.RadioSelect(choices=self.status_choices),
|
||||
absolute=forms.DateTimeInput(
|
||||
attrs={'placeholder': lazy(placeholder_datetime_format, str), 'class': 'datetimepicker'}
|
||||
),
|
||||
rel_days_number=forms.NumberInput(),
|
||||
rel_mins_relationto=OptionAttrsSelect(
|
||||
attrs={'data-relative-choice': True},
|
||||
choices=choices,
|
||||
option_attrs=_get_choice_validation_obj(base_choices)
|
||||
),
|
||||
rel_mins_relationto=forms.Select(choices=base_choices),
|
||||
rel_days_timeofday=forms.TimeInput(
|
||||
attrs={'placeholder': lazy(placeholder_time_format, str), 'class': 'timepickerfield'}
|
||||
),
|
||||
rel_mins_number=forms.NumberInput(),
|
||||
rel_days_relationto=OptionAttrsSelect(
|
||||
attrs={'data-relative-choice': True},
|
||||
choices=choices,
|
||||
option_attrs=_get_choice_validation_obj(base_choices)
|
||||
),
|
||||
rel_mins_relation=forms.Select(attrs={'data-relation-choice': True}, choices=BEFORE_AFTER_CHOICE),
|
||||
rel_days_relation=forms.Select(attrs={'data-relation-choice': True}, choices=BEFORE_AFTER_CHOICE),
|
||||
)))
|
||||
rel_days_relationto=forms.Select(choices=base_choices),
|
||||
rel_mins_relation=forms.Select(choices=BEFORE_AFTER_CHOICE),
|
||||
rel_days_relation=forms.Select(choices=BEFORE_AFTER_CHOICE),
|
||||
)
|
||||
super().__init__(widgets=widgets, *args, **kwargs)
|
||||
|
||||
def decompress(self, value):
|
||||
@@ -401,10 +247,10 @@ class RelativeDateTimeWidget(forms.MultiWidget):
|
||||
status="unset",
|
||||
absolute=None,
|
||||
rel_days_number=1,
|
||||
rel_mins_relationto="event__date_from",
|
||||
rel_mins_relationto="date_from",
|
||||
rel_days_timeofday=None,
|
||||
rel_mins_number=0,
|
||||
rel_days_relationto="event__date_from",
|
||||
rel_days_relationto="date_from",
|
||||
rel_mins_relation="before",
|
||||
rel_days_relation="before"
|
||||
)
|
||||
@@ -413,10 +259,10 @@ class RelativeDateTimeWidget(forms.MultiWidget):
|
||||
status="absolute",
|
||||
absolute=value.data,
|
||||
rel_days_number=1,
|
||||
rel_mins_relationto="event__date_from",
|
||||
rel_mins_relationto="date_from",
|
||||
rel_days_timeofday=None,
|
||||
rel_mins_number=0,
|
||||
rel_days_relationto="event__date_from",
|
||||
rel_days_relationto="date_from",
|
||||
rel_mins_relation="before",
|
||||
rel_days_relation="before"
|
||||
)
|
||||
@@ -425,10 +271,10 @@ class RelativeDateTimeWidget(forms.MultiWidget):
|
||||
status="relative_minutes",
|
||||
absolute=None,
|
||||
rel_days_number=None,
|
||||
rel_mins_relationto=value.data.key,
|
||||
rel_mins_relationto=value.data.base_date_name,
|
||||
rel_days_timeofday=None,
|
||||
rel_mins_number=value.data.minutes,
|
||||
rel_days_relationto=value.data.key,
|
||||
rel_days_relationto=value.data.base_date_name,
|
||||
rel_mins_relation="after" if value.data.is_after else "before",
|
||||
rel_days_relation="after" if value.data.is_after else "before"
|
||||
)
|
||||
@@ -436,10 +282,10 @@ class RelativeDateTimeWidget(forms.MultiWidget):
|
||||
status="relative",
|
||||
absolute=None,
|
||||
rel_days_number=value.data.days,
|
||||
rel_mins_relationto=value.data.key,
|
||||
rel_mins_relationto=value.data.base_date_name,
|
||||
rel_days_timeofday=value.data.time,
|
||||
rel_mins_number=0,
|
||||
rel_days_relationto=value.data.key,
|
||||
rel_days_relationto=value.data.base_date_name,
|
||||
rel_mins_relation="after" if value.data.is_after else "before",
|
||||
rel_days_relation="after" if value.data.is_after else "before"
|
||||
)
|
||||
@@ -463,41 +309,17 @@ class RelativeDateTimeField(forms.MultiValueField):
|
||||
('relative', _('Relative date:')),
|
||||
('relative_minutes', _('Relative time:')),
|
||||
]
|
||||
self.relative_to_order = kwargs.pop('relative_to_order', False)
|
||||
|
||||
possible_choices = copy.deepcopy(EVENT_BASE_CHOICES)
|
||||
if self.relative_to_order:
|
||||
possible_choices.extend(ORDER_BASE_CHOICES)
|
||||
|
||||
if kwargs.get('limit_choices'):
|
||||
limit = kwargs.pop('limit_choices')
|
||||
if any(["__" not in l for l in limit]):
|
||||
_warn_skips = (str(os.path.dirname(__file__)),)
|
||||
|
||||
warnings.warn(
|
||||
message="Please prefix limit_choices with the base the attributes refer to, for example event__date_from",
|
||||
category=DeprecationWarning,
|
||||
skip_file_prefixes=_warn_skips
|
||||
)
|
||||
|
||||
possible_choices = [
|
||||
c for c in possible_choices if
|
||||
# new base case as we want limit_choices to be expressed as base__attribute
|
||||
(c.key in limit) or
|
||||
# fallback for old event based entries
|
||||
# if the base is an event, then using only attribute is fine
|
||||
(c.base == "event" and c.attribute in limit)
|
||||
]
|
||||
|
||||
choices = [(k, v) for k, v in BASE_CHOICES if k in limit]
|
||||
else:
|
||||
choices = BASE_CHOICES
|
||||
if not kwargs.get('required', True):
|
||||
status_choices.insert(0, ('unset', _('Not set')))
|
||||
|
||||
choices = _get_choices(possible_choices)
|
||||
|
||||
fields = reldatetimeparts(
|
||||
status=forms.ChoiceField(
|
||||
choices=status_choices,
|
||||
required=True,
|
||||
required=True
|
||||
),
|
||||
absolute=forms.DateTimeField(
|
||||
required=False
|
||||
@@ -507,7 +329,7 @@ class RelativeDateTimeField(forms.MultiValueField):
|
||||
),
|
||||
rel_mins_relationto=forms.ChoiceField(
|
||||
choices=choices,
|
||||
required=False,
|
||||
required=False
|
||||
),
|
||||
rel_days_timeofday=forms.TimeField(
|
||||
required=False,
|
||||
@@ -517,7 +339,7 @@ class RelativeDateTimeField(forms.MultiValueField):
|
||||
),
|
||||
rel_days_relationto=forms.ChoiceField(
|
||||
choices=choices,
|
||||
required=False,
|
||||
required=False
|
||||
),
|
||||
rel_mins_relation=forms.ChoiceField(
|
||||
choices=BEFORE_AFTER_CHOICE,
|
||||
@@ -528,9 +350,8 @@ class RelativeDateTimeField(forms.MultiValueField):
|
||||
required=False
|
||||
),
|
||||
)
|
||||
|
||||
if 'widget' not in kwargs:
|
||||
kwargs['widget'] = RelativeDateTimeWidget(status_choices=status_choices, base_choices=possible_choices)
|
||||
kwargs['widget'] = RelativeDateTimeWidget(status_choices=status_choices, base_choices=choices)
|
||||
kwargs.pop('max_length', 0)
|
||||
kwargs.pop('empty_value', 0)
|
||||
super().__init__(
|
||||
@@ -538,24 +359,21 @@ class RelativeDateTimeField(forms.MultiValueField):
|
||||
)
|
||||
|
||||
def set_event(self, event):
|
||||
possible_choices = copy.deepcopy(EVENT_BASE_CHOICES)
|
||||
if self.relative_to_order:
|
||||
possible_choices.extend(ORDER_BASE_CHOICES)
|
||||
|
||||
possible_choices = possible_choices
|
||||
choices = _get_choices(possible_choices)
|
||||
|
||||
self.widget.widgets[reldatetimeparts.indizes.rel_days_relationto].choices = choices
|
||||
self.widget.widgets[reldatetimeparts.indizes.rel_mins_relationto].choices = choices
|
||||
self.widget.widgets[reldatetimeparts.indizes.rel_days_relationto].choices = [
|
||||
(k, v) for k, v in BASE_CHOICES if getattr(event, k, None)
|
||||
]
|
||||
self.widget.widgets[reldatetimeparts.indizes.rel_mins_relationto].choices = [
|
||||
(k, v) for k, v in BASE_CHOICES if getattr(event, k, None)
|
||||
]
|
||||
|
||||
def compress(self, data_list):
|
||||
if not data_list:
|
||||
return None
|
||||
data = reldatetimeparts(*data_list)
|
||||
if data.status == 'unset':
|
||||
return None
|
||||
elif data.status == 'absolute':
|
||||
if data.status == 'absolute':
|
||||
return RelativeDateWrapper(data.absolute)
|
||||
elif data.status == 'unset':
|
||||
return None
|
||||
elif data.status == 'relative_minutes':
|
||||
return RelativeDateWrapper(RelativeDate(
|
||||
days=0,
|
||||
@@ -586,18 +404,6 @@ class RelativeDateTimeField(forms.MultiValueField):
|
||||
raise ValidationError(self.error_messages['incomplete'])
|
||||
elif data.status == 'relative_minutes' and (data.rel_mins_number is None or not data.rel_mins_relationto):
|
||||
raise ValidationError(self.error_messages['incomplete'])
|
||||
elif data.status == 'relative':
|
||||
choice = BaseChoice.find(BASE_CHOICES, data.rel_days_relationto)
|
||||
if data.rel_days_relation == "before" and not choice.supports_before:
|
||||
raise ValidationError(_('A relative date cannot be expressed as "before" for "{}"'.format(choice.text)))
|
||||
elif data.status == 'relative' and data.rel_days_relation == "after" and not choice.supports_after:
|
||||
raise ValidationError(_('A relative date cannot be expressed as "after" for "{}"'.format(choice.text)))
|
||||
elif data.status == 'relative_minutes':
|
||||
choice = BaseChoice.find(BASE_CHOICES, data.rel_days_relationto)
|
||||
if data.rel_days_relation == "before" and not choice.supports_before:
|
||||
raise ValidationError(_('A relative time cannot be expressed as "before" for "{}"'.format(choice.text)))
|
||||
elif data.rel_days_relation == "after" and not choice.supports_after:
|
||||
raise ValidationError(_('A relative time cannot be expressed as "after" for "{}"'.format(choice.text)))
|
||||
|
||||
return super().clean(value)
|
||||
|
||||
@@ -618,20 +424,15 @@ class RelativeDateWidget(RelativeDateTimeWidget):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.status_choices = kwargs.pop('status_choices')
|
||||
self.base_choices = kwargs.pop('base_choices')
|
||||
widgets = cast(dict[str, Widget | type[Widget]], cast(object, reldateparts(
|
||||
widgets = reldateparts(
|
||||
status=forms.RadioSelect(choices=self.status_choices),
|
||||
absolute=forms.DateInput(
|
||||
attrs={'class': 'datepickerfield'}
|
||||
),
|
||||
rel_days_number=forms.NumberInput(),
|
||||
rel_days_relationto=OptionAttrsSelect(
|
||||
choices=self.base_choices,
|
||||
option_attrs=_get_choice_validation_obj(self.base_choices),
|
||||
attrs={'data-relative-choice': True},
|
||||
),
|
||||
rel_days_relation=forms.Select(choices=BEFORE_AFTER_CHOICE, attrs={'data-relation-choice': True},),
|
||||
)))
|
||||
rel_days_relationto=forms.Select(choices=kwargs.pop('base_choices')),
|
||||
rel_days_relation=forms.Select(choices=BEFORE_AFTER_CHOICE),
|
||||
)
|
||||
forms.MultiWidget.__init__(self, widgets=widgets, *args, **kwargs)
|
||||
|
||||
def decompress(self, value):
|
||||
@@ -659,7 +460,7 @@ class RelativeDateWidget(RelativeDateTimeWidget):
|
||||
status="relative",
|
||||
absolute=None,
|
||||
rel_days_number=value.data.days,
|
||||
rel_days_relationto=value.data.key,
|
||||
rel_days_relationto=value.data.base_date_name,
|
||||
rel_days_relation="after" if value.data.is_after else "before"
|
||||
)
|
||||
|
||||
@@ -673,15 +474,6 @@ class RelativeDateField(RelativeDateTimeField):
|
||||
]
|
||||
if not kwargs.get('required', True):
|
||||
status_choices.insert(0, ('unset', _('Not set')))
|
||||
|
||||
self.relative_to_order = kwargs.pop('relative_to_order', False)
|
||||
|
||||
possible_choices = copy.deepcopy(EVENT_BASE_CHOICES)
|
||||
if self.relative_to_order:
|
||||
possible_choices.extend(ORDER_BASE_CHOICES)
|
||||
|
||||
choices = _get_choices(possible_choices)
|
||||
|
||||
fields = reldateparts(
|
||||
status=forms.ChoiceField(
|
||||
choices=status_choices,
|
||||
@@ -694,37 +486,33 @@ class RelativeDateField(RelativeDateTimeField):
|
||||
required=False
|
||||
),
|
||||
rel_days_relationto=forms.ChoiceField(
|
||||
choices=choices,
|
||||
required=False,
|
||||
choices=BASE_CHOICES,
|
||||
required=False
|
||||
),
|
||||
rel_days_relation=forms.ChoiceField(
|
||||
choices=BEFORE_AFTER_CHOICE,
|
||||
required=False
|
||||
),
|
||||
)
|
||||
|
||||
if 'widget' not in kwargs:
|
||||
kwargs['widget'] = RelativeDateWidget(status_choices=status_choices, base_choices=possible_choices)
|
||||
kwargs['widget'] = RelativeDateWidget(status_choices=status_choices, base_choices=BASE_CHOICES)
|
||||
forms.MultiValueField.__init__(
|
||||
self, fields=fields, require_all_fields=False, *args, **kwargs
|
||||
)
|
||||
|
||||
def set_event(self, event):
|
||||
choices = [
|
||||
(c.key, c.text) for c in EVENT_BASE_CHOICES if getattr(event, c.attribute, None)
|
||||
self.widget.widgets[reldateparts.indizes.rel_days_relationto].choices = [
|
||||
(k, v) for k, v in BASE_CHOICES if getattr(event, k, None)
|
||||
]
|
||||
if self.relative_to_order:
|
||||
choices += [(c.key, c.text) for c in ORDER_BASE_CHOICES]
|
||||
self.widget.widgets[reldateparts.indizes.rel_days_relationto].choices = choices
|
||||
|
||||
def compress(self, data_list):
|
||||
if not data_list:
|
||||
return None
|
||||
data = reldateparts(*data_list)
|
||||
if data.status == 'unset':
|
||||
return None
|
||||
elif data.status == 'absolute':
|
||||
if data.status == 'absolute':
|
||||
return RelativeDateWrapper(data.absolute)
|
||||
elif data.status == 'unset':
|
||||
return None
|
||||
else:
|
||||
return RelativeDateWrapper(RelativeDate(
|
||||
days=data.rel_days_number,
|
||||
@@ -737,14 +525,8 @@ class RelativeDateField(RelativeDateTimeField):
|
||||
data = reldateparts(*value)
|
||||
if data.status == 'absolute' and not data.absolute:
|
||||
raise ValidationError(self.error_messages['incomplete'])
|
||||
if data.status == 'relative':
|
||||
choice = BaseChoice.find(BASE_CHOICES, data.rel_days_relationto)
|
||||
if data.rel_days_number is None or not data.rel_days_relationto:
|
||||
raise ValidationError(self.error_messages['incomplete'])
|
||||
elif data.rel_days_relation == "before" and not choice.supports_before:
|
||||
raise ValidationError(_("A relative date cannot be expressed as 'before' for '{}'".format(choice.text)))
|
||||
elif data.rel_days_relation == "after" and not choice.supports_after:
|
||||
raise ValidationError(_("A relative date cannot be expressed as 'after' for '{}'".format(choice.text)))
|
||||
elif data.status == 'relative' and (data.rel_days_number is None or not data.rel_days_relationto):
|
||||
raise ValidationError(self.error_messages['incomplete'])
|
||||
|
||||
return forms.MultiValueField.clean(self, value)
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ from django.utils.translation import (
|
||||
)
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.media import MEDIA_TYPES
|
||||
from pretix.base.models import (
|
||||
@@ -61,7 +60,7 @@ from pretix.base.models import (
|
||||
Seat, SeatCategoryMapping, Voucher,
|
||||
)
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.models.orders import CheckoutSession, OrderFee
|
||||
from pretix.base.models.orders import OrderFee
|
||||
from pretix.base.models.tax import TaxRule
|
||||
from pretix.base.reldate import RelativeDateWrapper
|
||||
from pretix.base.services.checkin import _save_answers
|
||||
@@ -472,16 +471,6 @@ class CartManager:
|
||||
if term_last < time_machine_now(self.real_now_dt):
|
||||
raise CartError(error_messages['payment_ended'])
|
||||
|
||||
def _ensure_checkout_session(self):
|
||||
CheckoutSession.objects.get_or_create(
|
||||
event=self.event,
|
||||
cart_id=self.cart_id,
|
||||
defaults={
|
||||
"sales_channel": self._sales_channel,
|
||||
"testmode": self.event.testmode,
|
||||
},
|
||||
)
|
||||
|
||||
def _extend_expiry_of_valid_existing_positions(self):
|
||||
# real_now_dt is initialized at CartManager instantiation, so it's slightly in the past. Add a small
|
||||
# delta to reduce risk of extending already expired CartPositions.
|
||||
@@ -927,8 +916,6 @@ class CartManager:
|
||||
if custom_price > 99_999_999_999:
|
||||
raise CartError(error_messages['price_too_high'])
|
||||
|
||||
custom_price = round_decimal(custom_price, currency=self.event.currency)
|
||||
|
||||
op = self.AddOperation(
|
||||
count=i['count'],
|
||||
item=item,
|
||||
@@ -1051,8 +1038,6 @@ class CartManager:
|
||||
if custom_price > 99_999_999_999:
|
||||
raise CartError(error_messages['price_too_high'])
|
||||
|
||||
custom_price = round_decimal(custom_price, currency=self.event.currency)
|
||||
|
||||
# Fix positions with wrong price (TODO: happens out-of-cartmanager-transaction and therefore a little hacky)
|
||||
for ca in current_addons[cp][a['item'], a['variation']]:
|
||||
if ca.listed_price != listed_price:
|
||||
@@ -1569,7 +1554,6 @@ class CartManager:
|
||||
|
||||
def commit(self):
|
||||
self._check_presale_dates()
|
||||
self._ensure_checkout_session()
|
||||
self._check_max_cart_size()
|
||||
|
||||
err = self._delete_out_of_timeframe()
|
||||
|
||||
@@ -40,7 +40,7 @@ import dateutil
|
||||
import dateutil.parser
|
||||
from dateutil.tz import datetime_exists
|
||||
from django.core.files import File
|
||||
from django.db import IntegrityError
|
||||
from django.db import IntegrityError, transaction
|
||||
from django.db.models import (
|
||||
BooleanField, Case, Count, ExpressionWrapper, F, IntegerField, Max, Min,
|
||||
OuterRef, Q, Subquery, TextField, Value, When,
|
||||
@@ -59,7 +59,6 @@ from pretix.base.models import (
|
||||
)
|
||||
from pretix.base.signals import checkin_created, periodic_task
|
||||
from pretix.helpers import OF_SELF
|
||||
from pretix.helpers.database import conditional_atomic
|
||||
from pretix.helpers.jsonlogic import Logic
|
||||
from pretix.helpers.jsonlogic_boolalg import convert_to_dnf
|
||||
from pretix.helpers.jsonlogic_query import (
|
||||
@@ -892,7 +891,6 @@ def _save_answers(op, answers, given_answers):
|
||||
qa.answer = answer
|
||||
qa.save(update_fields=['answer'])
|
||||
qa.options.clear()
|
||||
return qa
|
||||
|
||||
written = False
|
||||
for q, a in given_answers.items():
|
||||
@@ -1045,10 +1043,10 @@ def perform_checkin(op: OrderPosition, clist: CheckinList, given_answers: dict,
|
||||
if not simulate:
|
||||
_save_answers(op, answers, given_answers)
|
||||
|
||||
with conditional_atomic(not simulate):
|
||||
with transaction.atomic():
|
||||
# Lock order positions, if it is an entry. We don't need it for exits, as a race condition wouldn't be problematic
|
||||
opqs = OrderPosition.all.select_related("order", "item")
|
||||
if type != Checkin.TYPE_EXIT and not simulate:
|
||||
if type != Checkin.TYPE_EXIT:
|
||||
opqs = opqs.select_for_update(of=OF_SELF)
|
||||
op = opqs.get(pk=op.pk)
|
||||
|
||||
|
||||
@@ -33,7 +33,6 @@ from pretix.base.models.customers import CustomerSSOGrant
|
||||
|
||||
from ..models import CachedFile, CartPosition, InvoiceAddress
|
||||
from ..models.auth import UserKnownLoginSource
|
||||
from ..models.orders import CheckoutSession
|
||||
from ..signals import periodic_task
|
||||
|
||||
|
||||
@@ -44,10 +43,6 @@ def clean_cart_positions(sender, **kwargs):
|
||||
cp.delete()
|
||||
for cp in CartPosition.objects.filter(expires__lt=now() - timedelta(days=14), addon_to__isnull=True):
|
||||
cp.delete()
|
||||
for cs in CheckoutSession.objects.filter(created__lt=now() - timedelta(days=14)).exclude(
|
||||
Exists(CartPosition.objects.filter(cart_id=OuterRef("cart_id")))
|
||||
):
|
||||
cs.delete()
|
||||
for ia in InvoiceAddress.objects.filter(order__isnull=True, customer__isnull=True, last_modified__lt=now() - timedelta(days=14)):
|
||||
ia.delete()
|
||||
|
||||
|
||||
@@ -48,12 +48,12 @@ from celery.exceptions import MaxRetriesExceededError
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models, transaction
|
||||
from django.db import transaction
|
||||
from django.db.models import (
|
||||
Count, Exists, F, IntegerField, Max, Min, OuterRef, Q, QuerySet, Subquery,
|
||||
Sum, Value,
|
||||
Count, Exists, F, IntegerField, Max, Min, OuterRef, Q, QuerySet, Sum,
|
||||
Value,
|
||||
)
|
||||
from django.db.models.functions import Cast, Greatest
|
||||
from django.db.models.functions import Coalesce, Greatest
|
||||
from django.db.transaction import get_connection
|
||||
from django.dispatch import receiver
|
||||
from django.utils.functional import cached_property
|
||||
@@ -71,10 +71,10 @@ from pretix.base.models import (
|
||||
Membership, Order, OrderPayment, OrderPosition, Quota, Seat,
|
||||
SeatCategoryMapping, User, Voucher,
|
||||
)
|
||||
from pretix.base.models.event import Event_SettingsStore, SubEvent
|
||||
from pretix.base.models.event import SubEvent
|
||||
from pretix.base.models.orders import (
|
||||
BlockedTicketSecret, CheckoutSession, InvoiceAddress, OrderFee,
|
||||
OrderRefund, generate_secret,
|
||||
BlockedTicketSecret, InvoiceAddress, OrderFee, OrderRefund,
|
||||
generate_secret,
|
||||
)
|
||||
from pretix.base.models.organizer import SalesChannel, TeamAPIToken
|
||||
from pretix.base.models.tax import TAXED_ZERO, TaxedPrice, TaxRule
|
||||
@@ -1030,8 +1030,7 @@ def _apply_rounding_and_fees(positions: List[CartPosition], payment_requests: Li
|
||||
def _create_order(event: Event, *, email: str, positions: List[CartPosition], now_dt: datetime,
|
||||
payment_requests: List[dict], sales_channel: SalesChannel, locale: str=None,
|
||||
address: InvoiceAddress=None, meta_info: dict=None, shown_total=None,
|
||||
customer=None, valid_if_pending=False, api_meta: dict=None, tax_rounding_mode=None,
|
||||
cart_id: str=None):
|
||||
customer=None, valid_if_pending=False, api_meta: dict=None, tax_rounding_mode=None):
|
||||
payments = []
|
||||
|
||||
try:
|
||||
@@ -1114,14 +1113,6 @@ def _create_order(event: Event, *, email: str, positions: List[CartPosition], no
|
||||
if meta_info:
|
||||
for msg in meta_info.get('confirm_messages', []):
|
||||
order.log_action('pretix.event.order.consent', data={'msg': msg})
|
||||
if cart_id:
|
||||
try:
|
||||
session = CheckoutSession.objects.get(event=event, cart_id=cart_id)
|
||||
except CheckoutSession.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
session.answers.update(order=order, checkoutsession=None)
|
||||
session.delete()
|
||||
|
||||
order_placed.send(event, order=order, bulk=False)
|
||||
return order, payments
|
||||
@@ -1169,7 +1160,7 @@ def _order_placed_email_attendee(event: Event, order: Order, position: OrderPosi
|
||||
|
||||
def _perform_order(event: Event, payment_requests: List[dict], position_ids: List[str],
|
||||
email: str, locale: str, address: int, meta_info: dict=None, sales_channel: str='web',
|
||||
shown_total=None, customer=None, api_meta: dict=None, tax_rounding_mode=None, cart_id: str=None):
|
||||
shown_total=None, customer=None, api_meta: dict=None, tax_rounding_mode=None):
|
||||
for p in payment_requests:
|
||||
p['pprov'] = event.get_payment_providers(cached=True)[p['provider']]
|
||||
if not p['pprov']:
|
||||
@@ -1276,7 +1267,6 @@ def _perform_order(event: Event, payment_requests: List[dict], position_ids: Lis
|
||||
valid_if_pending=valid_if_pending,
|
||||
api_meta=api_meta,
|
||||
tax_rounding_mode=tax_rounding_mode,
|
||||
cart_id=cart_id,
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -1504,104 +1494,83 @@ def send_expiry_warnings(sender, **kwargs):
|
||||
@scopes_disabled()
|
||||
def send_download_reminders(sender, **kwargs):
|
||||
today = now().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
|
||||
events = Event.objects.filter(
|
||||
Q(has_subevents=False, date_from__gte=now()) |
|
||||
(Q(has_subevents=True) & Q(Exists(
|
||||
SubEvent.objects.filter(event_id=OuterRef('id'), date_from__gte=now())
|
||||
)))
|
||||
).annotate(
|
||||
reminder_days=Subquery(
|
||||
Event_SettingsStore.objects.filter(
|
||||
object=OuterRef('id'),
|
||||
key='mail_days_download_reminder'
|
||||
).exclude(
|
||||
value="None"
|
||||
).annotate(
|
||||
val=Cast(F("value"), output_field=models.IntegerField()),
|
||||
).values("val")
|
||||
qs = Order.objects.annotate(
|
||||
first_date=Coalesce(
|
||||
Min('all_positions__subevent__date_from'),
|
||||
F('event__date_from')
|
||||
)
|
||||
).filter(
|
||||
reminder_days__isnull=False,
|
||||
).order_by()
|
||||
download_reminder_sent=False,
|
||||
datetime__lte=now() - timedelta(hours=2),
|
||||
first_date__gte=today,
|
||||
).only(
|
||||
'pk', 'event_id', 'sales_channel', 'datetime',
|
||||
).order_by('event_id')
|
||||
event_id = None
|
||||
days = None
|
||||
event = None
|
||||
|
||||
for event in events.iterator(chunk_size=10_000):
|
||||
qs = event.orders.filter(
|
||||
download_reminder_sent=False,
|
||||
datetime__lte=now() - timedelta(hours=2),
|
||||
)
|
||||
for o in qs:
|
||||
if o.event_id != event_id:
|
||||
days = o.event.settings.get('mail_days_download_reminder', as_type=int)
|
||||
event = o.event
|
||||
event_id = o.event_id
|
||||
|
||||
if event.has_subevents:
|
||||
qs = qs.annotate(
|
||||
first_date=Min('all_positions__subevent__date_from')
|
||||
).filter(
|
||||
Q(first_date__gte=today)
|
||||
)
|
||||
else:
|
||||
event_reminder_date = (event.date_from - timedelta(days=event.reminder_days)).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
if now() < event_reminder_date:
|
||||
if days is None:
|
||||
continue
|
||||
|
||||
if o.sales_channel.identifier not in event.settings.mail_sales_channel_download_reminder:
|
||||
continue
|
||||
|
||||
reminder_date = (o.first_date - timedelta(days=days)).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
if now() < reminder_date or o.datetime > reminder_date:
|
||||
continue
|
||||
|
||||
with transaction.atomic():
|
||||
o = Order.objects.select_for_update(of=OF_SELF).get(pk=o.pk)
|
||||
if o.download_reminder_sent:
|
||||
# Race condition
|
||||
continue
|
||||
positions = list(o.positions_with_tickets)
|
||||
if not positions:
|
||||
continue
|
||||
|
||||
qs = qs.only(
|
||||
'pk', 'event_id', 'sales_channel', 'datetime',
|
||||
).order_by()
|
||||
|
||||
for o in qs:
|
||||
if o.sales_channel.identifier not in event.settings.mail_sales_channel_download_reminder:
|
||||
if not o.ticket_download_available:
|
||||
continue
|
||||
|
||||
if event.has_subevents:
|
||||
reminder_date = ((o.first_date or event.date_from) - timedelta(days=event.reminder_days)).replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
else:
|
||||
reminder_date = event_reminder_date
|
||||
if now() < reminder_date or o.datetime > reminder_date:
|
||||
continue
|
||||
|
||||
with transaction.atomic():
|
||||
o = Order.objects.select_for_update(of=OF_SELF).get(pk=o.pk)
|
||||
if o.download_reminder_sent:
|
||||
# Race condition
|
||||
continue
|
||||
positions = list(o.positions_with_tickets)
|
||||
if not positions:
|
||||
if o.status != Order.STATUS_PAID:
|
||||
if o.status != Order.STATUS_PENDING or o.require_approval or (not o.valid_if_pending and not o.event.settings.ticket_download_pending):
|
||||
continue
|
||||
|
||||
if not o.ticket_download_available:
|
||||
continue
|
||||
with language(o.locale, o.event.settings.region):
|
||||
o.download_reminder_sent = True
|
||||
o.save(update_fields=['download_reminder_sent'])
|
||||
email_template = event.settings.mail_text_download_reminder
|
||||
email_subject = event.settings.mail_subject_download_reminder
|
||||
email_context = get_email_context(event=event, order=o)
|
||||
o.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.download_reminder_sent',
|
||||
attach_tickets=True
|
||||
)
|
||||
|
||||
if o.status != Order.STATUS_PAID:
|
||||
if o.status != Order.STATUS_PENDING or o.require_approval or (not o.valid_if_pending and not o.event.settings.ticket_download_pending):
|
||||
continue
|
||||
|
||||
with language(o.locale, o.event.settings.region):
|
||||
o.download_reminder_sent = True
|
||||
o.save(update_fields=['download_reminder_sent'])
|
||||
email_template = event.settings.mail_text_download_reminder
|
||||
email_subject = event.settings.mail_subject_download_reminder
|
||||
email_context = get_email_context(event=event, order=o)
|
||||
o.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.download_reminder_sent',
|
||||
attach_tickets=True
|
||||
)
|
||||
|
||||
if event.settings.mail_send_download_reminder_attendee:
|
||||
for p in positions:
|
||||
if p.subevent_id:
|
||||
reminder_date = (p.subevent.date_from - timedelta(days=event.reminder_days)).replace(
|
||||
hour=0, minute=0, second=0, microsecond=0
|
||||
)
|
||||
if now() < reminder_date:
|
||||
continue
|
||||
if p.addon_to_id is None and p.attendee_email and p.attendee_email != o.email:
|
||||
email_template = event.settings.mail_text_download_reminder_attendee
|
||||
email_subject = event.settings.mail_subject_download_reminder_attendee
|
||||
email_context = get_email_context(event=event, order=o, position=p)
|
||||
o.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.download_reminder_sent',
|
||||
attach_tickets=True, position=p
|
||||
)
|
||||
if event.settings.mail_send_download_reminder_attendee:
|
||||
for p in positions:
|
||||
if p.subevent_id:
|
||||
reminder_date = (p.subevent.date_from - timedelta(days=days)).replace(
|
||||
hour=0, minute=0, second=0, microsecond=0
|
||||
)
|
||||
if now() < reminder_date:
|
||||
continue
|
||||
if p.addon_to_id is None and p.attendee_email and p.attendee_email != o.email:
|
||||
email_template = event.settings.mail_text_download_reminder_attendee
|
||||
email_subject = event.settings.mail_subject_download_reminder_attendee
|
||||
email_context = get_email_context(event=event, order=o, position=p)
|
||||
o.send_mail(
|
||||
email_subject, email_template, email_context,
|
||||
'pretix.event.order.email.download_reminder_sent',
|
||||
attach_tickets=True, position=p
|
||||
)
|
||||
|
||||
|
||||
def notify_user_changed_order(order, user=None, auth=None, invoices=[]):
|
||||
@@ -3200,12 +3169,12 @@ class OrderChangeManager:
|
||||
def perform_order(self, event: Event, payments: List[dict], positions: List[str],
|
||||
email: str=None, locale: str=None, address: int=None, meta_info: dict=None,
|
||||
sales_channel: str='web', shown_total=None, customer=None, override_now_dt: datetime=None,
|
||||
api_meta: dict=None, cart_id: str=None):
|
||||
api_meta: dict=None):
|
||||
with language(locale), time_machine_now_assigned(override_now_dt):
|
||||
try:
|
||||
try:
|
||||
return _perform_order(event, payments, positions, email, locale, address, meta_info,
|
||||
sales_channel, shown_total, customer, api_meta, cart_id=cart_id)
|
||||
sales_channel, shown_total, customer, api_meta)
|
||||
except LockTimeoutException:
|
||||
self.retry()
|
||||
except (MaxRetriesExceededError, LockTimeoutException):
|
||||
|
||||
@@ -801,10 +801,11 @@ def get_available_placeholders(event, base_parameters, rich=False):
|
||||
return params
|
||||
|
||||
|
||||
def prepare_sample_context_for_preview(placeholder_to_sample):
|
||||
def get_sample_context(event, context_parameters, rich=True):
|
||||
context_dict = {}
|
||||
lbl = _('This value will be replaced based on dynamic parameters.')
|
||||
for k, sample in placeholder_to_sample.items():
|
||||
for k, v in get_available_placeholders(event, context_parameters, rich=rich).items():
|
||||
sample = v.render_sample(event)
|
||||
if isinstance(sample, PlainHtmlAlternativeString):
|
||||
context_dict[k] = PlainHtmlAlternativeString(
|
||||
'<{el} class="placeholder" title="{title}">{plain}</{el}>'.format(
|
||||
@@ -829,12 +830,3 @@ def prepare_sample_context_for_preview(placeholder_to_sample):
|
||||
escape(sample)
|
||||
))
|
||||
return context_dict
|
||||
|
||||
|
||||
def get_sample_context(event, context_parameters, rich=True):
|
||||
return prepare_sample_context_for_preview(
|
||||
{
|
||||
k: v.render_sample(event)
|
||||
for k, v in get_available_placeholders(event, context_parameters, rich=rich).items()
|
||||
}
|
||||
)
|
||||
|
||||
@@ -193,7 +193,7 @@ class QuotaAvailability:
|
||||
lock_name = '_'.join([str(p) for p in sorted([q.pk for q in quotas])])
|
||||
if rc.exists(f'quotas:availabilitycachewrite:{lock_name}{self._cache_key_suffix}'):
|
||||
return
|
||||
rc.set(f'quotas:availabilitycachewrite:{lock_name}{self._cache_key_suffix}', '1', ex=10)
|
||||
rc.setex(f'quotas:availabilitycachewrite:{lock_name}{self._cache_key_suffix}', '1', 10)
|
||||
|
||||
update = defaultdict(list)
|
||||
for q in quotas:
|
||||
|
||||
@@ -2930,7 +2930,7 @@ Your {event} team""")) # noqa: W291
|
||||
},
|
||||
'mail_days_download_reminder': {
|
||||
'type': int,
|
||||
'default': None # when this default is changed, send_download_reminders needs to change
|
||||
'default': None
|
||||
},
|
||||
'mail_send_download_reminder_attendee': {
|
||||
'type': bool,
|
||||
|
||||
@@ -44,7 +44,7 @@ def timeline_for_event(event, subevent=None):
|
||||
ev = subevent or event
|
||||
if subevent:
|
||||
ev_edit_url = reverse(
|
||||
'control:event.subevent', kwargs={
|
||||
'control:event.subevent.edit', kwargs={
|
||||
'event': event.slug,
|
||||
'organizer': event.organizer.slug,
|
||||
'subevent': subevent.pk
|
||||
|
||||
+72
-112
@@ -32,21 +32,18 @@ from django.utils.functional import cached_property
|
||||
from django.utils.timezone import make_aware
|
||||
|
||||
from pretix.base.forms.questions import (
|
||||
BaseInvoiceAddressForm, BaseInvoiceNameForm, OrderLevelQuestionsForm,
|
||||
TicketLevelQuestionsForm,
|
||||
BaseInvoiceAddressForm, BaseInvoiceNameForm, BaseQuestionsForm,
|
||||
)
|
||||
from pretix.base.models import (
|
||||
CartPosition, InvoiceAddress, OrderPosition, Question, QuestionAnswer,
|
||||
QuestionOption,
|
||||
)
|
||||
from pretix.base.models.customers import AttendeeProfile
|
||||
from pretix.base.models.orders import CheckoutSession, Order
|
||||
from pretix.presale.signals import contact_form_fields_overrides
|
||||
|
||||
|
||||
class BaseQuestionsViewMixin:
|
||||
order_form_class = OrderLevelQuestionsForm
|
||||
orderposition_form_class = TicketLevelQuestionsForm
|
||||
form_class = BaseQuestionsForm
|
||||
all_optional = False
|
||||
|
||||
@cached_property
|
||||
@@ -59,28 +56,6 @@ class BaseQuestionsViewMixin:
|
||||
def question_form_kwargs(self, cr):
|
||||
return {}
|
||||
|
||||
@property
|
||||
def order_question_container(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
@cached_property
|
||||
def order_questions_form(self):
|
||||
container = self.order_question_container
|
||||
if container is None:
|
||||
return None
|
||||
kwargs = {} # self.question_form_kwargs(cr)
|
||||
form = self.order_form_class(
|
||||
event=self.request.event,
|
||||
prefix='order',
|
||||
request=self.request,
|
||||
container=container,
|
||||
all_optional=self.all_optional,
|
||||
data=(self.request.POST if self.request.method == 'POST' else None),
|
||||
files=(self.request.FILES if self.request.method == 'POST' else None),
|
||||
**kwargs
|
||||
)
|
||||
return form
|
||||
|
||||
@cached_property
|
||||
def forms(self):
|
||||
"""
|
||||
@@ -94,17 +69,15 @@ class BaseQuestionsViewMixin:
|
||||
orderpos = cr if isinstance(cr, OrderPosition) else None
|
||||
|
||||
kwargs = self.question_form_kwargs(cr)
|
||||
form = self.orderposition_form_class(
|
||||
event=self.request.event,
|
||||
prefix=cr.id,
|
||||
request=self.request,
|
||||
cartpos=cartpos,
|
||||
orderpos=orderpos,
|
||||
all_optional=self.all_optional,
|
||||
data=(self.request.POST if self.request.method == 'POST' else None),
|
||||
files=(self.request.FILES if self.request.method == 'POST' else None),
|
||||
**kwargs
|
||||
)
|
||||
form = self.form_class(event=self.request.event,
|
||||
prefix=cr.id,
|
||||
request=self.request,
|
||||
cartpos=cartpos,
|
||||
orderpos=orderpos,
|
||||
all_optional=self.all_optional,
|
||||
data=(self.request.POST if self.request.method == 'POST' else None),
|
||||
files=(self.request.FILES if self.request.method == 'POST' else None),
|
||||
**kwargs)
|
||||
form.pos = cartpos or orderpos
|
||||
form.show_copy_answers_to_addon_button = form.pos.addon_to and (
|
||||
set(form.pos.addon_to.item.questions.all()) & set(form.pos.item.questions.all()) or
|
||||
@@ -157,38 +130,8 @@ class BaseQuestionsViewMixin:
|
||||
|
||||
def save(self):
|
||||
failed = False
|
||||
if self.order_questions_form:
|
||||
if not self.order_questions_form.is_valid():
|
||||
failed = True
|
||||
else:
|
||||
checkoutsession = self.order_question_container if isinstance(self.order_question_container, CheckoutSession) else None
|
||||
order = self.order_question_container if isinstance(self.order_question_container, Order) else None
|
||||
for k, v in self.order_questions_form.cleaned_data.items():
|
||||
if k.startswith('question_'):
|
||||
field = self.order_questions_form.fields[k]
|
||||
if hasattr(field, 'answer'):
|
||||
# We already have a cached answer object, so we don't
|
||||
# have to create a new one
|
||||
if v == '' or v is None or (isinstance(field, forms.FileField) and v is False) \
|
||||
or (isinstance(v, QuerySet) and not v.exists()):
|
||||
if field.answer.file:
|
||||
field.answer.file.delete()
|
||||
field.answer.delete()
|
||||
else:
|
||||
self._save_to_answer(field, field.answer, v)
|
||||
field.answer.save()
|
||||
elif v != '' and v is not None:
|
||||
self._upsert_answer(
|
||||
field, v,
|
||||
checkoutsession=checkoutsession,
|
||||
order=order,
|
||||
question=field.question,
|
||||
)
|
||||
|
||||
for form in self.forms:
|
||||
meta_info = form.pos.meta_info_data
|
||||
cartposition = form.pos if isinstance(form.pos, CartPosition) else None
|
||||
orderposition = form.pos if isinstance(form.pos, OrderPosition) else None
|
||||
# Every form represents a CartPosition or OrderPosition with questions attached
|
||||
if not form.is_valid():
|
||||
failed = True
|
||||
@@ -197,8 +140,10 @@ class BaseQuestionsViewMixin:
|
||||
prof = AttendeeProfile.objects.filter(
|
||||
customer=self.cart_customer, pk=form.cleaned_data.get('saved_id')
|
||||
).first() or AttendeeProfile(customer=getattr(self, 'cart_customer', None))
|
||||
answers_key_to_index = {a.get('field_name'): i for i, a in enumerate(prof.answers)}
|
||||
else:
|
||||
prof = AttendeeProfile(customer=getattr(self, 'cart_customer', None))
|
||||
answers_key_to_index = {}
|
||||
|
||||
# This form was correctly filled, so we store the data as
|
||||
# answers to the questions / in the CartPosition object
|
||||
@@ -236,19 +181,64 @@ class BaseQuestionsViewMixin:
|
||||
else:
|
||||
self._save_to_answer(field, field.answer, v)
|
||||
field.answer.save()
|
||||
|
||||
answer_dict = self._build_answer_dict(field, field.answer, k)
|
||||
prof.store_answer(answer_dict)
|
||||
if isinstance(field, forms.ModelMultipleChoiceField) or isinstance(field, forms.ModelChoiceField):
|
||||
answer_value = {o.identifier: str(o) for o in field.answer.options.all()}
|
||||
elif isinstance(field, forms.BooleanField):
|
||||
answer_value = bool(field.answer.answer)
|
||||
else:
|
||||
answer_value = str(field.answer.answer)
|
||||
answer_dict = {
|
||||
'field_name': k,
|
||||
'field_label': str(field.label),
|
||||
'value': answer_value,
|
||||
'question_type': field.question.type,
|
||||
'question_identifier': field.question.identifier,
|
||||
}
|
||||
if k in answers_key_to_index:
|
||||
prof.answers[answers_key_to_index[k]] = answer_dict
|
||||
else:
|
||||
prof.answers.append(answer_dict)
|
||||
elif v != '' and v is not None:
|
||||
answer = self._upsert_answer(
|
||||
field, v,
|
||||
cartposition=cartposition,
|
||||
orderposition=orderposition,
|
||||
answer = QuestionAnswer(
|
||||
cartposition=(form.pos if isinstance(form.pos, CartPosition) else None),
|
||||
orderposition=(form.pos if isinstance(form.pos, OrderPosition) else None),
|
||||
question=field.question,
|
||||
)
|
||||
try:
|
||||
self._save_to_answer(field, answer, v)
|
||||
answer.save()
|
||||
except IntegrityError:
|
||||
# Since we prefill ``field.answer`` at form creation time, there's a possible race condition
|
||||
# here if the users submits their save request a second time while the first one is still running,
|
||||
# thus leading to duplicate QuestionAnswer objects. Since Django doesn't support UPSERT, the "proper"
|
||||
# fix would be a transaction with select_for_update(), or at least fetching using get_or_create here
|
||||
# again. However, both of these approaches have a significant performance overhead for *all* requests,
|
||||
# while the issue happens very very rarely. So we opt for just catching the error and retrying properly.
|
||||
answer = QuestionAnswer.objects.get(
|
||||
cartposition=(form.pos if isinstance(form.pos, CartPosition) else None),
|
||||
orderposition=(form.pos if isinstance(form.pos, OrderPosition) else None),
|
||||
question=field.question,
|
||||
)
|
||||
self._save_to_answer(field, answer, v)
|
||||
answer.save()
|
||||
|
||||
answer_dict = self._build_answer_dict(field, answer, k)
|
||||
prof.store_answer(answer_dict)
|
||||
if isinstance(field, forms.ModelMultipleChoiceField) or isinstance(field, forms.ModelChoiceField):
|
||||
answer_value = {o.identifier: str(o) for o in answer.options.all()}
|
||||
elif isinstance(field, forms.BooleanField):
|
||||
answer_value = bool(answer.answer)
|
||||
else:
|
||||
answer_value = str(answer.answer)
|
||||
answer_dict = {
|
||||
'field_name': k,
|
||||
'field_label': str(field.label),
|
||||
'value': answer_value,
|
||||
'question_type': field.question.type,
|
||||
'question_identifier': field.question.identifier,
|
||||
}
|
||||
if k in answers_key_to_index:
|
||||
prof.answers[answers_key_to_index[k]] = answer_dict
|
||||
else:
|
||||
prof.answers.append(answer_dict)
|
||||
|
||||
else:
|
||||
field = form.fields[k]
|
||||
@@ -267,7 +257,10 @@ class BaseQuestionsViewMixin:
|
||||
'question_type': None,
|
||||
'question_identifier': None,
|
||||
}
|
||||
prof.store_answer(answer_dict)
|
||||
if k in answers_key_to_index:
|
||||
prof.answers[answers_key_to_index[k]] = answer_dict
|
||||
else:
|
||||
prof.answers.append(answer_dict)
|
||||
|
||||
form.pos.meta_info = json.dumps(meta_info)
|
||||
form.pos.save()
|
||||
@@ -278,23 +271,6 @@ class BaseQuestionsViewMixin:
|
||||
|
||||
return not failed
|
||||
|
||||
def _upsert_answer(self, field, v, **answer_kwargs):
|
||||
answer = QuestionAnswer(**answer_kwargs)
|
||||
try:
|
||||
self._save_to_answer(field, answer, v)
|
||||
answer.save()
|
||||
except IntegrityError:
|
||||
# Since we prefill ``field.answer`` at form creation time, there's a possible race condition
|
||||
# here if the users submits their save request a second time while the first one is still running,
|
||||
# thus leading to duplicate QuestionAnswer objects. Since Django doesn't support UPSERT, the "proper"
|
||||
# fix would be a transaction with select_for_update(), or at least fetching using get_or_create here
|
||||
# again. However, both of these approaches have a significant performance overhead for *all* requests,
|
||||
# while the issue happens very very rarely. So we opt for just catching the error and retrying properly.
|
||||
answer = QuestionAnswer.objects.get(**answer_kwargs)
|
||||
self._save_to_answer(field, answer, v)
|
||||
answer.save()
|
||||
return answer
|
||||
|
||||
def _save_to_answer(self, field, answer, value):
|
||||
if isinstance(field, forms.ModelMultipleChoiceField):
|
||||
answstr = ", ".join([str(o) for o in value])
|
||||
@@ -318,21 +294,6 @@ class BaseQuestionsViewMixin:
|
||||
else:
|
||||
answer.answer = value
|
||||
|
||||
def _build_answer_dict(self, field, answer, k):
|
||||
if isinstance(field, forms.ModelMultipleChoiceField) or isinstance(field, forms.ModelChoiceField):
|
||||
answer_value = {o.identifier: str(o) for o in answer.options.all()}
|
||||
elif isinstance(field, forms.BooleanField):
|
||||
answer_value = bool(answer.answer)
|
||||
else:
|
||||
answer_value = str(answer.answer)
|
||||
return {
|
||||
'field_name': k,
|
||||
'field_label': str(field.label),
|
||||
'value': answer_value,
|
||||
'question_type': field.question.type,
|
||||
'question_identifier': field.question.identifier,
|
||||
}
|
||||
|
||||
|
||||
class OrderQuestionsViewMixin(BaseQuestionsViewMixin):
|
||||
invoice_form_class = BaseInvoiceAddressForm
|
||||
@@ -348,7 +309,7 @@ class OrderQuestionsViewMixin(BaseQuestionsViewMixin):
|
||||
def positions(self):
|
||||
qqs = self.request.event.questions.all()
|
||||
if self.only_user_visible:
|
||||
qqs = qqs.filter(ask_during_checkin=False, hidden=False, container_type=Question.ContainerType.ORDERPOSITION)
|
||||
qqs = qqs.filter(ask_during_checkin=False, hidden=False)
|
||||
return list(self.order.positions.select_related(
|
||||
'item', 'variation'
|
||||
).prefetch_related(
|
||||
@@ -436,7 +397,6 @@ class OrderQuestionsViewMixin(BaseQuestionsViewMixin):
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['order'] = self.order
|
||||
ctx['order_questions_form'] = self.order_questions_form
|
||||
ctx['formgroups'] = self.formdict.items()
|
||||
ctx['invoice_form'] = self.invoice_form
|
||||
ctx['invoice_address_asked'] = self.address_asked
|
||||
|
||||
@@ -153,19 +153,11 @@ class QuestionForm(I18nModelForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
if self.instance.container_type == Question.ContainerType.ORDERPOSITION:
|
||||
self.fields['items'].queryset = self.instance.event.items.all()
|
||||
self.fields['items'].required = True
|
||||
else:
|
||||
del self.fields['items']
|
||||
del self.fields['ask_during_checkin']
|
||||
del self.fields['show_during_checkin']
|
||||
del self.fields['print_on_invoice']
|
||||
self.fields['dependency_question'].widget.attrs['data-container-type'] = self.instance.container_type
|
||||
self.fields['items'].queryset = self.instance.event.items.all()
|
||||
self.fields['items'].required = True
|
||||
self.fields['dependency_question'].queryset = self.instance.event.questions.filter(
|
||||
type__in=(Question.TYPE_BOOLEAN, Question.TYPE_CHOICE, Question.TYPE_CHOICE_MULTIPLE),
|
||||
ask_during_checkin=False,
|
||||
container_type=self.instance.container_type,
|
||||
ask_during_checkin=False
|
||||
)
|
||||
if self.instance.pk:
|
||||
self.fields['dependency_question'].queryset = self.fields['dependency_question'].queryset.exclude(
|
||||
|
||||
@@ -562,7 +562,9 @@ class OrderPositionChangeForm(forms.Form):
|
||||
if instance.addon_to_id:
|
||||
del self.fields['operation_split']
|
||||
|
||||
if not instance.seat and not instance._seat_allowed:
|
||||
if not instance.seat and not (
|
||||
instance.item.seat_category_mappings.filter(subevent=instance.subevent).exists()
|
||||
):
|
||||
del self.fields['seat']
|
||||
|
||||
choices = [
|
||||
|
||||
@@ -94,14 +94,14 @@ class SubEventBulkForm(SubEventForm):
|
||||
label=_('Start of presale'),
|
||||
help_text=_('Optional. No products will be sold before this date.'),
|
||||
required=False,
|
||||
limit_choices=('event__date_from', 'event__date_to'),
|
||||
limit_choices=('date_from', 'date_to'),
|
||||
)
|
||||
rel_presale_end = RelativeDateTimeField(
|
||||
label=_('End of presale'),
|
||||
help_text=_('Optional. No products will be sold after this date. If you do not set this value, the presale '
|
||||
'will end after the end date of your event.'),
|
||||
required=False,
|
||||
limit_choices=('event__date_from', 'event__date_to'),
|
||||
limit_choices=('date_from', 'date_to'),
|
||||
)
|
||||
skip_if_overlap = forms.BooleanField(
|
||||
label=pgettext_lazy('subevent', 'Skip dates that overlap with any existing date'),
|
||||
@@ -333,12 +333,12 @@ class BulkSubEventItemForm(SubEventItemForm):
|
||||
rel_available_from = RelativeDateTimeField(
|
||||
label=_('Available from'),
|
||||
required=False,
|
||||
limit_choices=('event__date_from', 'event__date_to'),
|
||||
limit_choices=('date_from', 'date_to'),
|
||||
)
|
||||
rel_available_until = RelativeDateTimeField(
|
||||
label=_('Available until'),
|
||||
required=False,
|
||||
limit_choices=('event__date_from', 'event__date_to'),
|
||||
limit_choices=('date_from', 'date_to'),
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -355,12 +355,12 @@ class BulkSubEventItemVariationForm(SubEventItemVariationForm):
|
||||
rel_available_from = RelativeDateTimeField(
|
||||
label=_('Available from'),
|
||||
required=False,
|
||||
limit_choices=('event__date_from', 'event__date_to'),
|
||||
limit_choices=('date_from', 'date_to'),
|
||||
)
|
||||
rel_available_until = RelativeDateTimeField(
|
||||
label=_('Available_until'),
|
||||
required=False,
|
||||
limit_choices=('event__date_from', 'event__date_to'),
|
||||
limit_choices=('date_from', 'date_to'),
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
# 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.
|
||||
|
||||
import functools
|
||||
from collections import defaultdict
|
||||
from datetime import datetime
|
||||
from decimal import Decimal
|
||||
@@ -70,15 +69,6 @@ OVERVIEW_BANLIST = [
|
||||
]
|
||||
|
||||
|
||||
@functools.lru_cache(maxsize=32)
|
||||
def object_id_to_string(model_class, **kwargs):
|
||||
# The cache is thread-local and persists requests, but it's small enough that we can accept that
|
||||
try:
|
||||
return str(model_class.objects.get(**kwargs))
|
||||
except model_class.DoesNotExist:
|
||||
return "?"
|
||||
|
||||
|
||||
class OrderChangeLogEntryType(OrderLogEntryType):
|
||||
prefix = _('The order has been changed:')
|
||||
|
||||
@@ -103,10 +93,10 @@ class OrderItemChanged(OrderChangeLogEntryType):
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
old_item = str(event.items.get(pk=data['old_item']))
|
||||
if data['old_variation']:
|
||||
old_item += ' - ' + str(object_id_to_string(ItemVariation, item__event_id=event.pk, pk=data['old_variation']))
|
||||
old_item += ' - ' + str(ItemVariation.objects.get(item__event=event, pk=data['old_variation']))
|
||||
new_item = str(event.items.get(pk=data['new_item']))
|
||||
if data['new_variation']:
|
||||
new_item += ' - ' + str(object_id_to_string(ItemVariation, item__event_id=event.pk, pk=data['new_variation']))
|
||||
new_item += ' - ' + str(ItemVariation.objects.get(item__event=event, pk=data['new_variation']))
|
||||
return _('Position #{posid}: {old_item} ({old_price}) changed to {new_item} ({new_price}).').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
old_item=old_item, new_item=new_item,
|
||||
@@ -163,14 +153,14 @@ class OrderTaxRuleChanged(OrderChangeLogEntryType):
|
||||
if 'positionid' in data:
|
||||
return _('Tax rule of position #{posid} changed from {old_rule} to {new_rule}.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
old_rule=object_id_to_string(TaxRule, pk=data['old_taxrule']) if data['old_taxrule'] else '–',
|
||||
new_rule=object_id_to_string(TaxRule, pk=data['new_taxrule']),
|
||||
old_rule=TaxRule.objects.get(pk=data['old_taxrule']) if data['old_taxrule'] else '–',
|
||||
new_rule=TaxRule.objects.get(pk=data['new_taxrule']),
|
||||
)
|
||||
elif 'fee' in data:
|
||||
return _('Tax rule of fee #{fee} changed from {old_rule} to {new_rule}.').format(
|
||||
fee=data.get('fee', '?'),
|
||||
old_rule=object_id_to_string(TaxRule, pk=data['old_taxrule']) if data['old_taxrule'] else '–',
|
||||
new_rule=object_id_to_string(TaxRule, pk=data['new_taxrule']),
|
||||
old_rule=TaxRule.objects.get(pk=data['old_taxrule']) if data['old_taxrule'] else '–',
|
||||
new_rule=TaxRule.objects.get(pk=data['new_taxrule']),
|
||||
)
|
||||
|
||||
|
||||
@@ -214,7 +204,7 @@ class OrderCanceled(OrderChangeLogEntryType):
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
old_item = str(event.items.get(pk=data['old_item']))
|
||||
if data['old_variation']:
|
||||
old_item += ' - ' + object_id_to_string(ItemVariation, pk=data['old_variation'])
|
||||
old_item += ' - ' + str(ItemVariation.objects.get(pk=data['old_variation']))
|
||||
return _('Position #{posid} ({old_item}, {old_price}) canceled.').format(
|
||||
posid=data.get('positionid', '?'),
|
||||
old_item=old_item,
|
||||
@@ -229,7 +219,7 @@ class OrderPositionAdded(OrderChangeLogEntryType):
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
item = str(event.items.get(pk=data['item']))
|
||||
if data['variation']:
|
||||
item += ' - ' + object_id_to_string(ItemVariation, item__event_id=event.pk, pk=data['variation'])
|
||||
item += ' - ' + str(ItemVariation.objects.get(item__event=event, pk=data['variation']))
|
||||
if data['addon_to']:
|
||||
addon_to = OrderPosition.objects.get(order__event=event, pk=data['addon_to'])
|
||||
return _('Position #{posid} created: {item} ({price}) as an add-on to position #{addon_to}.').format(
|
||||
@@ -293,7 +283,7 @@ class OrderChangedSplit(OrderChangeLogEntryType):
|
||||
def display_prefixed(self, event: Event, logentry: LogEntry, data):
|
||||
old_item = str(event.items.get(pk=data['old_item']))
|
||||
if data['old_variation']:
|
||||
old_item += ' - ' + object_id_to_string(ItemVariation, pk=data['old_variation'])
|
||||
old_item += ' - ' + str(ItemVariation.objects.get(pk=data['old_variation']))
|
||||
url = reverse('control:event.order', kwargs={
|
||||
'event': event.slug,
|
||||
'organizer': event.organizer.slug,
|
||||
@@ -349,7 +339,6 @@ class OrderChangedSplitFrom(OrderLogEntryType):
|
||||
'pretix.event.checkin.reverted': _('The check-in of position #{posid} on list "{list}" has been reverted.'),
|
||||
})
|
||||
class CheckinErrorLogEntryType(OrderLogEntryType):
|
||||
|
||||
def display(self, logentry: LogEntry, data):
|
||||
return self.display_plain(self.plain, logentry, data)
|
||||
|
||||
@@ -364,7 +353,10 @@ class CheckinErrorLogEntryType(OrderLogEntryType):
|
||||
event = logentry.event
|
||||
|
||||
if 'list' in data and event:
|
||||
data['list'] = object_id_to_string(CheckinList, event_id=event.id, pk=data['list'])
|
||||
try:
|
||||
data['list'] = event.checkin_lists.get(pk=data.get('list')).name
|
||||
except CheckinList.DoesNotExist:
|
||||
data['list'] = _("(unknown)")
|
||||
else:
|
||||
data['list'] = _("(unknown)")
|
||||
|
||||
|
||||
@@ -133,22 +133,14 @@ This signal is sent out to include custom HTML in the top part of the the event
|
||||
Receivers should return a SafeString containing HTML, or a string that will be HTML-escaped.
|
||||
|
||||
As with all event plugin signals, the ``sender`` keyword argument will contain the event.
|
||||
An additional keyword argument ``subevent`` *can* contain a sub-event.
|
||||
"""
|
||||
|
||||
event_dashboard_widgets = EventPluginSignal()
|
||||
event_dashboard_statistics = EventPluginSignal()
|
||||
"""
|
||||
This signal is sent out to include widgets in the event dashboard. Receivers
|
||||
should return a list of dictionaries, where each dictionary can have the keys:
|
||||
|
||||
* content (SafeString, containing HTML)
|
||||
* display_size (str, one of "full" (whole row), "big" (half a row) or "small"
|
||||
(quarter of a row). May be ignored on small displays, default is "small")
|
||||
* priority (int, used for ordering, higher comes first, default is 1)
|
||||
* url (str, optional, if the full widget should be a link)
|
||||
This signal is sent out to include statistical content on the event dashboard.
|
||||
Receivers should return a SafeString containing HTML, or a string that will be HTML-escaped.
|
||||
|
||||
As with all event plugin signals, the ``sender`` keyword argument will contain the event.
|
||||
An additional keyword argument ``subevent`` *can* contain a sub-event.
|
||||
"""
|
||||
|
||||
user_dashboard_widgets = GlobalSignal()
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
{% endif %}
|
||||
{% compress js %}
|
||||
<script type="text/javascript" src="{% static "jquery/js/jquery-3.6.4.min.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "htmx/htmx-2.0.10.min.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "js/jquery.formset.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "typeahead/typeahead.bundle.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "bootstrap/js/bootstrap.js" %}"></script>
|
||||
@@ -58,7 +59,6 @@
|
||||
<script type="text/javascript" src="{% static "leaflet/leaflet.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixcontrol/js/ui/geo.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixbase/js/details.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixbase/js/reldate.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "pretixbase/js/asynctask.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "sortable/Sortable.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "colorpicker/bootstrap-colorpicker.js" %}"></script>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{% load i18n %}
|
||||
{% load icon %}
|
||||
{% load humanize %}
|
||||
{% for cl in lists %}
|
||||
<a class="quotabox quotabox-full availability"
|
||||
href="{% url "control:event.orders.checkinlists.show" organizer=request.event.organizer.slug event=request.event.slug list=cl.id %}">
|
||||
<strong>{{ cl.name }}</strong>
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success progress-bar-{{ cl.percent }}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="numbers">
|
||||
{% icon "sign-in" %}
|
||||
{{ cl.checkin_count|default_if_none:0|intcomma }} /
|
||||
{{ cl.position_count|default_if_none:0|intcomma }}
|
||||
<br>
|
||||
{% icon "user" %}
|
||||
{% blocktrans trimmed with n=cl.inside_count|intcomma %}
|
||||
{{ n }} present
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,17 @@
|
||||
{% load i18n %}
|
||||
{% load icon %}
|
||||
<div id="comment-form">
|
||||
<strong>{% trans "Comment" %}:</strong>
|
||||
{% if "event.settings.general:write" in request.eventpermset %}
|
||||
<button type="button" class="btn btn-default btn-xs"
|
||||
hx-get="{% url "control:event.index.comment" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
hx-target="#comment-form">
|
||||
{% icon "edit" %}
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if request.event.comment %}
|
||||
<p>
|
||||
{{ request.event.comment|linebreaksbr }}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -0,0 +1,16 @@
|
||||
{% load i18n %}
|
||||
{% load bootstrap3 %}
|
||||
<form class="form" method="post"
|
||||
hx-post="{% url "control:event.index.comment" event=request.event.slug organizer=request.event.organizer.slug %}">
|
||||
{% csrf_token %}
|
||||
<div>
|
||||
<p>
|
||||
{% bootstrap_field form.comment layout="inline" show_help=True show_label=False horizontal_field_class="col-md-12" %}
|
||||
</p>
|
||||
<p class="text-right flip">
|
||||
<button class="btn btn-default">
|
||||
{% trans "Update comment" %}
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% for q in quotas %}
|
||||
{% include "pretixcontrol/fragment_quota_box.html" with quota=q full=1 %}
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,11 @@
|
||||
{% load i18n %}
|
||||
{% load humanize %}
|
||||
{% if count %}
|
||||
<a href="{% url "control:event.orders.waitinglist" event=request.event.slug organizer=request.organizer.slug %}">
|
||||
{% blocktrans trimmed with number=count|intcomma count count=count %}
|
||||
{{ number }} person waiting
|
||||
{% plural %}
|
||||
{{ number }} persons waiting
|
||||
{% endblocktrans %}
|
||||
</a>
|
||||
{% endif %}
|
||||
@@ -1,4 +1,5 @@
|
||||
{% load i18n %}
|
||||
{% load eventsignal %}
|
||||
{% if has_overpaid_orders %}
|
||||
<div class="alert alert-warning">
|
||||
{% blocktrans trimmed %}
|
||||
@@ -56,3 +57,4 @@
|
||||
class="btn btn-primary">{% trans "Show sync problems" %}</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% eventsignal request.event "pretix.control.signals.event_dashboard_top" request=request %}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{% load i18n %}
|
||||
<div class="panel panel-primary">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">{% trans "Welcome to pretix!" %}</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="attentionline">{% trans "Get started with our setup tool" %}</div>
|
||||
<p>
|
||||
{% blocktrans trimmed %}
|
||||
To start selling tickets, you need to create products or quotas. The fastest way to create
|
||||
this is to use our setup tool.
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
<a href="{% url "control:event.quick" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
class="btn btn-primary btn-lg">
|
||||
{% trans "Set up event" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,12 +0,0 @@
|
||||
<div class="welcome-wizard">
|
||||
<h3>{{ title }}</h3>
|
||||
{% if subtitle %}
|
||||
<div class="attentionline">{{ subtitle }}</div>
|
||||
{% endif %}
|
||||
{% if text %}
|
||||
<p>{{ text }}</p>
|
||||
{% endif %}
|
||||
{% if button_text %}
|
||||
<p><a href="{{ button_url }}" class="btn btn-primary btn-lg">{{ button_text }}</a></p>
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -1,10 +1,10 @@
|
||||
{% load i18n %}
|
||||
<div class="panel panel-default items">
|
||||
<div class="panel-heading">
|
||||
<details class="panel panel-default items" open>
|
||||
<summary class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Your timeline" %}
|
||||
{% trans "Timeline" %}
|
||||
</h3>
|
||||
</div>
|
||||
</summary>
|
||||
<div class="panel-body timeline">
|
||||
{% regroup timeline by date as tl_list %}
|
||||
{% for day in tl_list %}
|
||||
@@ -33,4 +33,4 @@
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
{% load eventurl %}
|
||||
{% load bootstrap3 %}
|
||||
{% load static %}
|
||||
{% load eventsignal %}
|
||||
{% load icon %}
|
||||
{% block title %}{{ request.event.name }}{% endblock %}
|
||||
{% block content %}
|
||||
<h1>
|
||||
<h1 class="event-dashboard-header">
|
||||
{{ request.event.name }}
|
||||
<small>
|
||||
{% if request.event.has_subevents %}
|
||||
@@ -14,11 +14,43 @@
|
||||
{% else %}
|
||||
{{ request.event.get_date_range_display }}
|
||||
{% endif %}
|
||||
<span id="warnings_loading" class="fa fa-cog fa-spin"></span>
|
||||
<span id="warnings_indicator" class="htmx-indicator">{% icon "cog fa-spin" %}</span>
|
||||
</small>
|
||||
<div class="pull-right flip">
|
||||
<a href="{% url "control:event.live" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
data-toggle="tooltip"
|
||||
title="{% trans "Click to change shop status" %}">
|
||||
{% icon "pencil" %}</a>
|
||||
<a href="{% url "control:event.live" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
data-toggle="tooltip"
|
||||
title="{% trans "Click to change shop status" %}">
|
||||
{% if request.event.live and request.event.testmode %}
|
||||
<span class="label label-warning">
|
||||
<span class="fa fa-warning"></span>
|
||||
{% trans "public test mode" %}
|
||||
</span>
|
||||
{% elif request.event.live %}
|
||||
<span class="label label-success">
|
||||
<span class="fa fa-check"></span>
|
||||
{% trans "live" %}
|
||||
</span>
|
||||
{% elif request.event.testmode %}
|
||||
<span class="label label-warning">
|
||||
<span class="fa fa-power-off"></span>
|
||||
{% trans "private test mode" %}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="label label-danger">
|
||||
<span class="fa fa-power-off"></span>
|
||||
{% trans "offline" %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</h1>
|
||||
<div class="helper-space-below">
|
||||
{% trans "Shop URL:" %}
|
||||
<strong>{% trans "Shop URL:" %}</strong>
|
||||
<span id="shop_url" class="text-muted">{% abseventurl request.event "presale:event.index" %}</span>
|
||||
<button type="button" class="btn btn-default btn-xs btn-clipboard js-only" data-clipboard-target="#shop_url">
|
||||
<i class="fa fa-clipboard" aria-hidden="true"></i>
|
||||
@@ -31,75 +63,76 @@
|
||||
{% include "pretixcontrol/event/fragment_qr_dropdown.html" with url=0 %}
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
<div id="warnings_target"></div>
|
||||
{% eventsignal request.event "pretix.control.signals.event_dashboard_top" request=request %}
|
||||
|
||||
{% if request.event.has_subevents %}
|
||||
<form class="form-inline helper-display-inline" action="" method="get">
|
||||
{% include "pretixcontrol/event/fragment_subevent_choice_simple.html" %}
|
||||
</form>
|
||||
{% endif %}
|
||||
{% if not request.event.has_subevents or subevent %}
|
||||
{% include "pretixcontrol/event/fragment_timeline.html" %}
|
||||
{% endif %}
|
||||
<div class="dashboard">
|
||||
{% for w in widgets %}
|
||||
<div class="widget-container widget-{{ w.display_size|default:"small" }} {% if w.lazy %}widget-lazy-loading{% endif %}" data-lazy-id="{{ w.lazy }}">
|
||||
{% if w.url %}{# backwards compatibility #}
|
||||
<a href="{{ w.url }}" class="widget">
|
||||
{% if w.lazy %}
|
||||
<span class="fa fa-cog fa-4x"></span>
|
||||
{% else %}
|
||||
{{ w.content }}
|
||||
{% endif %}
|
||||
</a>
|
||||
{% elif w.link %}
|
||||
<a href="{{ w.link }}" class="widget">
|
||||
{% if w.lazy %}
|
||||
<span class="fa fa-cog fa-4x´"></span>
|
||||
{% else %}
|
||||
{{ w.content }}
|
||||
{% endif %}
|
||||
</a>
|
||||
{% else %}
|
||||
<div class="widget">
|
||||
{% if w.lazy %}
|
||||
<span class="fa fa-cog fa-4x"></span>
|
||||
{% else %}
|
||||
{{ w.content }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% include "pretixcontrol/event/dashboard_partial_comment.html" with url=0 %}
|
||||
</div>
|
||||
|
||||
<div hx-get="{% url "control:event.index.warnings" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
{# loading indicator is somewhere else because the happy case is "no warnings" and shouldn't make the page jump #}
|
||||
hx-indicator="#warnings_indicator"
|
||||
hx-trigger="load"></div>
|
||||
|
||||
{% if stats %}
|
||||
{{ stats }}
|
||||
{% endif %}
|
||||
<p> </p>
|
||||
<div class="panel panel-default items">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">
|
||||
{% trans "Internal comment" %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<form class="form" method="post"
|
||||
action="{% url "control:event.comment" event=request.event.slug organizer=request.event.organizer.slug %}">
|
||||
{% csrf_token %}
|
||||
<div class="row">
|
||||
{% bootstrap_field comment_form.comment layout="horizontal" show_help=True show_label=False horizontal_field_class="col-md-12" %}
|
||||
|
||||
{% if not request.event.items.exists %}
|
||||
{% include "pretixcontrol/event/dashboard_partial_welcome.html" %}
|
||||
{% elif not request.event.has_subevents %}
|
||||
{% include "pretixcontrol/event/fragment_timeline.html" %}
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right">
|
||||
<div hx-get="{% url "control:event.index.waiting" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
hx-trigger="load">
|
||||
<span class="loading-mock loading-mock-text-short"></span>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="panel-title">{% trans "Quotas" %}</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div hx-get="{% url "control:event.index.quotas" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
hx-trigger="load">
|
||||
{% for i in "12" %}
|
||||
{% include "pretixcontrol/fragment_quota_box_mock.html" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if not comment_form.readonly %}
|
||||
<p class="text-right flip">
|
||||
<br>
|
||||
<button class="btn btn-default">
|
||||
{% trans "Update comment" %}
|
||||
</button>
|
||||
</p>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">{% trans "Check-in lists" %}</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div hx-get="{% url "control:event.index.checkin" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
hx-trigger="load">
|
||||
{% for i in "12" %}
|
||||
{% include "pretixcontrol/fragment_quota_box_mock.html" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% elif has_checkin_widgets %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h2 class="panel-title">{% trans "Check-in lists" %}</h2>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div hx-get="{% url "control:event.index.checkin" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
hx-trigger="load">
|
||||
{% for i in "12" %}
|
||||
{% include "pretixcontrol/fragment_quota_box_mock.html" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if "event.orders:read" in request.eventpermset or "event.orders:write" in request.eventpermset or "event.settings.general:write" in request.eventpermset or "event.items:write" in request.eventpermset %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
@@ -107,10 +140,27 @@
|
||||
{% trans "Event logs" %}
|
||||
</h3>
|
||||
</div>
|
||||
<ul class="list-group" id="logs_target">
|
||||
<div class="logs-lazy-loading">
|
||||
<span class="fa fa-cog fa-4x"></span>
|
||||
</div>
|
||||
<ul class="list-group"
|
||||
hx-get="{% url "control:event.index.logs" organizer=request.organizer.slug event=request.event.slug %}"
|
||||
hx-trigger="load">
|
||||
{% for i in "12345" %}
|
||||
<li class="list-group-item logentry">
|
||||
<div class="row">
|
||||
<div class="col-lg-2 col-sm-6 col-xs-12">
|
||||
<span class="loading-mock loading-mock-text-medium"></span>
|
||||
</div>
|
||||
<div class="col-lg-2 col-sm-6 col-xs-12">
|
||||
<span class="loading-mock loading-mock-text-short"></span>
|
||||
</div>
|
||||
<div class="col-lg-2 col-sm-12 col-xs-12">
|
||||
<span class="loading-mock loading-mock-text-medium"></span>
|
||||
</div>
|
||||
<div class="col-lg-6 col-sm-12 col-xs-12">
|
||||
<span class="loading-mock loading-mock-text-long"></span>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<div class="panel-footer">
|
||||
<a href="{% url "control:event.log" event=request.event.slug organizer=request.event.organizer.slug %}">
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
<a href="?{% url_replace request 'ordering' 'date_to' %}"><i class="fa fa-caret-up"></i></a>
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Paid tickets per quota" %}
|
||||
{% trans "Quota utilization" %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Status" %}
|
||||
@@ -151,7 +151,7 @@
|
||||
</td>
|
||||
<td>
|
||||
{% for q in e.first_quotas|slice:":3" %}
|
||||
{% include "pretixcontrol/fragment_quota_box_paid.html" with quota=q %}
|
||||
{% include "pretixcontrol/fragment_quota_box.html" with quota=q %}
|
||||
{% endfor %}
|
||||
{% if e.first_quotas|length > 3 %}
|
||||
<a href="{% url "control:event.items.quotas" organizer=e.organizer.slug event=e.slug %}"
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
{% load i18n %}
|
||||
<div class="quotabox availability" data-toggle="tooltip_html" data-placement="top"
|
||||
title="{% trans "Quota:" %} {{ q.name|force_escape|force_escape }}<br>{% blocktrans with date=q.cached_availability_time|date:"SHORT_DATETIME_FORMAT" %}Numbers as of {{ date }}{% endblocktrans %}">
|
||||
{% load humanize %}
|
||||
<a class="quotabox {% if full %}quotabox-full{% endif %}" data-toggle="tooltip_html" data-placement="top"
|
||||
title="{% trans "Quota:" %} {{ q.name|force_escape|force_escape }}{% if q.cached_avail.1 is not None %}<br>{% blocktrans with num=q.cached_avail.1 %}Currently available: {{ num }}{% endblocktrans %}{% endif %}"
|
||||
href="{% url "control:event.items.quotas.show" event=q.event.slug organizer=q.event.organizer.slug quota=q.pk %}">
|
||||
{% if full %}
|
||||
<strong>{{ q.name }}</strong>
|
||||
{% endif %}
|
||||
{% if q.size|default_if_none:"NONE" == "NONE" %}
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-success progress-bar-100">
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-{% if q.cached_avail.0 <= 10 or q.cached_avail.0 >= 100 %}danger{% else %}warning{% endif %} progress-bar-{{ q.inv_percent }}">
|
||||
<div class="progress-bar progress-bar-{% if q.cached_avail.0 < 10 %}danger{% elif q.cached_avail.0 < 100 %}warning{% else %}success{% endif %} progress-bar-{{ q.percent_paid }}">
|
||||
</div>
|
||||
<div class="progress-bar progress-bar-{% if q.cached_avail.0 < 10 %}danger{% elif q.cached_avail.0 < 100 %}warning{% else %}success{% endif %} progress-bar-unconfirmed progress-bar-{{ q.percent_other }}">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="numbers">
|
||||
{{ q.cached_avail.1|default_if_none:"∞" }} / {{ q.size|default_if_none:"∞" }}
|
||||
{{ q.used|default_if_none:"∞" }} / {{ q.size|default_if_none:"∞" }}<br>
|
||||
{% blocktrans trimmed with n=q.cached_availability_paid_orders %}
|
||||
{{ n }} paid
|
||||
{% endblocktrans %}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<a class="quotabox quotabox-full">
|
||||
<strong>
|
||||
<span class="loading-mock loading-mock-text-short"></span>
|
||||
</strong>
|
||||
<div class="progress loading-mock"></div>
|
||||
<div class="numbers">
|
||||
<span class="loading-mock loading-mock-text-short"></span>
|
||||
<br><span class="loading-mock loading-mock-text-short"></span>
|
||||
</div>
|
||||
</a>
|
||||
@@ -1,17 +0,0 @@
|
||||
{% load i18n %}
|
||||
<a class="quotabox" data-toggle="tooltip_html" data-placement="top"
|
||||
title="{% trans "Quota:" %} {{ q.name|force_escape|force_escape }}{% if q.cached_avail.1 is not None %}<br>{% blocktrans with num=q.cached_avail.1 %}Currently available: {{ num }}{% endblocktrans %}{% endif %}"
|
||||
href="{% url "control:event.items.quotas.show" event=q.event.slug organizer=q.event.organizer.slug quota=q.pk %}">
|
||||
{% if q.size|default_if_none:"NONE" == "NONE" %}
|
||||
<div class="progress">
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="progress">
|
||||
<div class="progress-bar progress-bar-{% if q.cached_avail.0 < 10 %}danger{% elif q.cached_avail.0 < 100 %}warning{% else %}success{% endif %} progress-bar-{{ q.percent_paid }}">
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="numbers">
|
||||
{{ q.cached_availability_paid_orders|default_if_none:"?" }} / {{ q.size|default_if_none:"∞" }}
|
||||
</div>
|
||||
</a>
|
||||
@@ -13,11 +13,9 @@
|
||||
{% blocktrans with url=edit_url|add:"#tab-0-1-open" %}If you want to keep the answers, <a href="{{url}}">edit the question</a> and set it to hidden.{% endblocktrans %}
|
||||
</p>
|
||||
</div>
|
||||
<ul>
|
||||
{% for item in dependent %}
|
||||
<li><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.pk %}">{{ item }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% for item in dependent %}
|
||||
<li><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.pk %}">{{ item }}</a></li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<div class="form-group submit-group">
|
||||
<a href="{% url "control:event.items.questions" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default btn-cancel">
|
||||
|
||||
@@ -24,9 +24,7 @@
|
||||
<legend>{% trans "General" %}</legend>
|
||||
{% bootstrap_field form.question layout="control" %}
|
||||
{% bootstrap_field form.type layout="control" %}
|
||||
{% if form.items %}
|
||||
{% bootstrap_field form.items layout="control" %}
|
||||
{% endif %}
|
||||
{% bootstrap_field form.items layout="control" %}
|
||||
{% bootstrap_field form.required layout="control" %}
|
||||
<div class="alert alert-info alert-required-boolean">
|
||||
{% blocktrans trimmed %}
|
||||
@@ -130,16 +128,10 @@
|
||||
<legend>{% trans "Advanced" %}</legend>
|
||||
{% bootstrap_field form.help_text layout="control" %}
|
||||
{% bootstrap_field form.identifier layout="control" %}
|
||||
{% if form.ask_during_checkin %}
|
||||
{% bootstrap_field form.ask_during_checkin layout="control" %}
|
||||
{% endif %}
|
||||
{% if form.show_during_checkin %}
|
||||
{% bootstrap_field form.show_during_checkin layout="control" %}
|
||||
{% endif %}
|
||||
{% bootstrap_field form.ask_during_checkin layout="control" %}
|
||||
{% bootstrap_field form.show_during_checkin layout="control" %}
|
||||
{% bootstrap_field form.hidden layout="control" %}
|
||||
{% if form.print_on_invoice %}
|
||||
{% bootstrap_field form.print_on_invoice layout="control" %}
|
||||
{% endif %}
|
||||
{% bootstrap_field form.print_on_invoice layout="control" %}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-md-3 control-label" for="id_dependency_question">
|
||||
|
||||
@@ -10,26 +10,11 @@
|
||||
{% endblocktrans %}
|
||||
</p>
|
||||
{% csrf_token %}
|
||||
|
||||
{% if request.event.settings.feature_flag_order_level_questions %}
|
||||
{% if 'event.items:write' in request.eventpermset %}
|
||||
<p>
|
||||
<a href="{% url "control:event.items.questions.add" organizer=request.event.organizer.slug event=request.event.slug %}?container_type=P" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new per-ticket question" %}
|
||||
</a>
|
||||
<a href="{% url "control:event.items.questions.add" organizer=request.event.organizer.slug event=request.event.slug %}?container_type=O" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new order-level question" %}
|
||||
</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<h2>{% trans "Per-ticket questions" %}</h2>
|
||||
<p>{% trans "These questions are asked for every ticket, so possibly multiple times in the same order." %}</p>
|
||||
{% else %}
|
||||
{% if 'event.items:write' in request.eventpermset %}
|
||||
<p>
|
||||
<a href="{% url "control:event.items.questions.add" organizer=request.event.organizer.slug event=request.event.slug %}?container_type=P" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new question" %}
|
||||
</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% if 'event.items:write' in request.eventpermset %}
|
||||
<p>
|
||||
<a href="{% url "control:event.items.questions.add" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default"><i class="fa fa-plus"></i> {% trans "Create a new question" %}
|
||||
</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-quotas">
|
||||
@@ -47,8 +32,8 @@
|
||||
<th class="action-col-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-dnd-url="{% url "control:event.items.questions.reorder" organizer=request.event.organizer.slug event=request.event.slug %}?container_type=P">
|
||||
{% for q in questions %}{% if q.container_type == "P" %}
|
||||
<tbody data-dnd-url="{% url "control:event.items.questions.reorder" organizer=request.event.organizer.slug event=request.event.slug %}">
|
||||
{% for q in questions %}
|
||||
<tr data-dnd-id="{{ q.id }}">
|
||||
<td>
|
||||
<strong>
|
||||
@@ -78,6 +63,7 @@
|
||||
{% if q.pk and q.ask_during_checkin %}
|
||||
<span class="fa fa-check-square text-muted" data-toggle="tooltip" title="{% trans "Ask during check-in" %}"></span>
|
||||
{% endif %}
|
||||
|
||||
</td>
|
||||
<td>
|
||||
{% if q.pk and q.hidden %}
|
||||
@@ -116,90 +102,8 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{% if request.event.settings.feature_flag_order_level_questions %}
|
||||
<h2>
|
||||
{% trans "Per-order questions" %}
|
||||
<small><span class="label label-info" title="
|
||||
{% trans "This functionality is in active development and expected to change significantly over the coming months." %}
|
||||
{% trans "Per-order questions are currently not supported and will not be displayed in pretixPOS." %}
|
||||
" data-toggle="tooltip">
|
||||
<span class="fa fa-flask" aria-hidden="true"></span>
|
||||
{% trans "Experimental feature" %}
|
||||
</span></small>
|
||||
</h2>
|
||||
<p>{% trans "These questions are asked once per order." %}</p>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-quotas">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Question" %}</th>
|
||||
<th>{% trans "Type" %}</th>
|
||||
<th class="iconcol"></th>
|
||||
<th class="iconcol"></th>
|
||||
<th class="iconcol"></th>
|
||||
{% if 'event.items:write' in request.eventpermset %}
|
||||
<th class="action-col-2"></th>
|
||||
{% endif %}
|
||||
<th class="action-col-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-dnd-url="{% url "control:event.items.questions.reorder" organizer=request.event.organizer.slug event=request.event.slug %}?container_type=O">
|
||||
{% for q in questions %}{% if q.container_type == "O" %}
|
||||
<tr data-dnd-id="{{ q.id }}">
|
||||
<td>
|
||||
<strong>
|
||||
{{ q.question }}
|
||||
</strong><br>
|
||||
<small class="text-muted">{{ q.identifier }}</small>
|
||||
</td>
|
||||
<td>
|
||||
{% if q.pk %}
|
||||
{{ q.get_type_display }}
|
||||
{% else %}
|
||||
{% trans "System question" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if q.required %}
|
||||
<span class="fa fa-exclamation-circle text-muted" data-toggle="tooltip" title="{% trans "Required question" %}"></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if q.pk and q.ask_during_checkin %}
|
||||
<span class="fa fa-check-square text-muted" data-toggle="tooltip" title="{% trans "Ask during check-in" %}"></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if q.pk and q.hidden %}
|
||||
<span class="fa fa-eye-slash text-muted" data-toggle="tooltip" title="{% trans "Hidden question" %}"></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
{% if 'event.items:write' in request.eventpermset %}
|
||||
<td class="dnd-container">
|
||||
</td>
|
||||
{% endif %}
|
||||
<td class="text-right flip">
|
||||
{% if q.pk %}
|
||||
{% if 'event.items:write' in request.eventpermset %}
|
||||
<a href="{% url "control:event.items.questions.edit" organizer=request.event.organizer.slug event=request.event.slug question=q.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
|
||||
<a href="{% url "control:event.items.questions.delete" organizer=request.event.organizer.slug event=request.event.slug question=q.id %}" class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if 'event.settings.general:write' in request.eventpermset %}
|
||||
<a href="{% url "control:event.settings" organizer=request.event.organizer.slug event=request.event.slug %}#tab-0-2-open"
|
||||
class="btn btn-default btn-sm"><i class="fa fa-wrench"></i></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -35,18 +35,6 @@
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% if order_questions_form.fields %}
|
||||
<details class="panel panel-default" open>
|
||||
<summary class="panel-heading">
|
||||
<h4 class="panel-title">
|
||||
<strong>{% trans "Additional order information" %}</strong>
|
||||
</h4>
|
||||
</summary>
|
||||
<div class="panel-body">
|
||||
{% bootstrap_form order_questions_form layout="horizontal" %}
|
||||
</div>
|
||||
</details>
|
||||
{% endif %}
|
||||
{% for pos, forms in formgroups %}
|
||||
<details class="panel panel-default" open>
|
||||
<summary class="panel-heading">
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
{% load safelink %}
|
||||
{% load i18n %}
|
||||
{% load rich_text %}
|
||||
{% if answer %}
|
||||
{% if answer.file %}
|
||||
<span class="fa fa-file"></span>
|
||||
<a href="{{ answer.backend_file_url }}?token={% answer_token request answer %}">
|
||||
{{ answer.file_name }}
|
||||
</a>
|
||||
<span class="label label-danger" data-toggle="tooltip"
|
||||
title="{% trans "This file has been uploaded by a user and could contain viruses or other malicious content." %}">
|
||||
{% trans "UNSAFE" %}
|
||||
</span>
|
||||
{% if answer.is_image %}
|
||||
<br>
|
||||
<a href="{{ answer.backend_file_url }}?token={% answer_token request answer %}" data-lightbox="order"
|
||||
class="answer-thumb">
|
||||
<img src="{{ answer.backend_file_url }}?token={% answer_token request answer %}">
|
||||
</a>
|
||||
{% endif %}
|
||||
{% elif question.type == "M" %}
|
||||
{{ answer.to_string_i18n|rich_text_snippet }}
|
||||
{% else %}
|
||||
{{ answer.to_string_i18n|linebreaksbr }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<em>{% trans "not answered" %}</em>
|
||||
{% endif %}
|
||||
@@ -427,14 +427,6 @@
|
||||
</form>
|
||||
</dd>
|
||||
{% endif %}
|
||||
|
||||
{% if order.answers.all %}
|
||||
<hr>
|
||||
{% endif %}
|
||||
{% for ans in order.answers.all %}
|
||||
<dt>{{ ans.question.internal_name|default:ans.question.question }}</dt>
|
||||
<dd>{% include "pretixcontrol/order/fragment_question_answer.html" with request=request question=ans.question answer=ans %}</dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
@@ -672,7 +664,31 @@
|
||||
{% endif %}
|
||||
</dt>
|
||||
<dd>
|
||||
{% include "pretixcontrol/order/fragment_question_answer.html" with request=request question=q answer=q.answer %}
|
||||
{% if q.answer %}
|
||||
{% if q.answer.file %}
|
||||
<span class="fa fa-file"></span>
|
||||
<a href="{{ q.answer.backend_file_url }}?token={% answer_token request q.answer %}">
|
||||
{{ q.answer.file_name }}
|
||||
</a>
|
||||
<span class="label label-danger" data-toggle="tooltip"
|
||||
title="{% trans "This file has been uploaded by a user and could contain viruses or other malicious content." %}">
|
||||
{% trans "UNSAFE" %}
|
||||
</span>
|
||||
{% if q.answer.is_image %}
|
||||
<br>
|
||||
<a href="{{ q.answer.backend_file_url }}?token={% answer_token request q.answer %}" data-lightbox="order"
|
||||
class="answer-thumb">
|
||||
<img src="{{ q.answer.backend_file_url }}?token={% answer_token request q.answer %}">
|
||||
</a>
|
||||
{% endif %}
|
||||
{% elif q.type == "M" %}
|
||||
{{ q.answer.to_string_i18n|rich_text_snippet }}
|
||||
{% else %}
|
||||
{{ q.answer.to_string_i18n|linebreaksbr }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<em>{% trans "not answered" %}</em>
|
||||
{% endif %}
|
||||
</dd>
|
||||
{% endfor %}
|
||||
{% for q in line.additional_fields %}
|
||||
@@ -817,7 +833,7 @@
|
||||
<strong>{% trans "Pending total" %}</strong>
|
||||
</div>
|
||||
<div class="col-md-3 col-xs-6 col-md-offset-5 price">
|
||||
<strong>{{ pending_sum|money:event.currency }}</strong>
|
||||
<strong>{{ order.pending_sum|money:event.currency }}</strong>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
|
||||
@@ -118,10 +118,6 @@
|
||||
</td>
|
||||
{% endif %}
|
||||
<td>
|
||||
<span class="fa fa-fw {% if d.last_seen and d.last_seen.is_recent %}fa-check-circle text-success{% else %}fa-circle text-danger{% endif %}"
|
||||
data-toggle="tooltip"
|
||||
title="{% if d.last_seen %}{% blocktrans with time=d.last_seen.last_seen|date:"SHORT_DATETIME_FORMAT" %}Last seen: {{ time }}{% endblocktrans %}{% else %}{% trans "No recent contact" %}{% endif %}"
|
||||
></span>
|
||||
{{ d.device_id }}
|
||||
</td>
|
||||
<td>
|
||||
@@ -129,7 +125,6 @@
|
||||
<del>{% endif %}
|
||||
{{ d.name }}
|
||||
{% if d.revoked %}</del>{% endif %}
|
||||
|
||||
{% if d.gate %}
|
||||
<br>
|
||||
<small class="text-muted">{{ d.gate.name }}</small>
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
{% endif %}
|
||||
</dl>
|
||||
</fieldset>
|
||||
{% include "pretixcontrol/event/fragment_timeline.html" %}
|
||||
<fieldset>
|
||||
<legend>{% trans "Quotas" %}</legend>
|
||||
<div class="table-responsive">
|
||||
|
||||
@@ -102,7 +102,7 @@
|
||||
<a href="?{% url_replace request 'filter-ordering' 'date_from' %}"><i class="fa fa-caret-up"></i></a>
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Paid tickets per quota" %}
|
||||
{% trans "Quota utilization" %}
|
||||
</th>
|
||||
<th>
|
||||
{% trans "Status" %}
|
||||
@@ -155,7 +155,7 @@
|
||||
</td>
|
||||
<td>
|
||||
{% for q in s.first_quotas|slice:":3" %}
|
||||
{% include "pretixcontrol/fragment_quota_box_paid.html" with quota=q %}
|
||||
{% include "pretixcontrol/fragment_quota_box.html" with quota=q %}
|
||||
{% endfor %}
|
||||
{% if s.first_quotas|length > 3 %}
|
||||
<a href="{% url "control:event.items.quotas" organizer=request.event.organizer.slug event=request.event.slug %}?subevent={{ s.id }}"
|
||||
|
||||
@@ -251,7 +251,7 @@
|
||||
</td>
|
||||
<td>
|
||||
{% if e.voucher %}
|
||||
<a href="{% url "control:event.voucher" organizer=request.event.organizer.slug event=request.event.slug voucher=e.voucher.pk %}?next={{ request.get_full_path|urlencode }}">
|
||||
<a href="{% url "control:event.voucher" organizer=request.event.organizer.slug event=request.event.slug voucher=e.voucher.pk %}">
|
||||
{{ e.voucher }}
|
||||
</a>
|
||||
{% elif not e.voucher and e.availability.0 == 100 and e.availability.1|default_if_none:"none" != "none" %}
|
||||
|
||||
@@ -272,15 +272,16 @@ urlpatterns = [
|
||||
re_path(r'^event/(?P<organizer>[^/]+)/(?P<event>[^/]+)/', include([
|
||||
re_path(r'^$', dashboards.event_index, name='event.index'),
|
||||
re_path(r'^qrcode.(?P<filetype>(png|jpeg|gif|svg))$', event.EventQRCode.as_view(), name='event.qrcode'),
|
||||
re_path(r'^widgets.json$', dashboards.event_index_widgets_lazy, name='event.index.widgets'),
|
||||
re_path(r'^dashboard/partials/logs$', dashboards.event_index_log_lazy, name='event.index.logs'),
|
||||
re_path(r'^dashboard/partials/warnings$', dashboards.event_index_warnings_lazy, name='event.index.warnings'),
|
||||
re_path(r'^dashboard/partials/quotas$', dashboards.event_index_quotas_lazy, name='event.index.quotas'),
|
||||
re_path(r'^dashboard/partials/waiting$', dashboards.event_index_waiting_lazy, name='event.index.waiting'),
|
||||
re_path(r'^dashboard/partials/checkin$', dashboards.event_index_checkin_lazy, name='event.index.checkin'),
|
||||
re_path(r'^dashboard/partials/comment$', event.EventComment.as_view(), name='event.index.comment'),
|
||||
re_path(r'^live/$', event.EventLive.as_view(), name='event.live'),
|
||||
re_path(r'^transfer_session/$', event.EventTransferSession.as_view(), name='event.transfer_session'),
|
||||
re_path(r'^logs/$', event.EventLog.as_view(), name='event.log'),
|
||||
re_path(r'^delete/$', event.EventDelete.as_view(), name='event.delete'),
|
||||
re_path(r'^comment/$', event.EventComment.as_view(),
|
||||
name='event.comment'),
|
||||
re_path(r'^quickstart/$', event.QuickSetupView.as_view(), name='event.quick'),
|
||||
re_path(r'^settings/$', event.EventUpdate.as_view(), name='event.settings'),
|
||||
re_path(r'^settings/plugins$', event.EventPlugins.as_view(), name='event.settings.plugins'),
|
||||
|
||||
@@ -33,317 +33,48 @@
|
||||
# License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
from zoneinfo import ZoneInfo
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.humanize.templatetags.humanize import intcomma
|
||||
from django.db.models import (
|
||||
Count, IntegerField, Max, Min, OuterRef, Prefetch, Q, Subquery, Sum,
|
||||
Count, IntegerField, Max, Min, OuterRef, Q, Subquery,
|
||||
)
|
||||
from django.db.models.functions import Coalesce, Greatest
|
||||
from django.dispatch import receiver
|
||||
from django.http import JsonResponse
|
||||
from django.http import Http404, JsonResponse
|
||||
from django.shortcuts import render
|
||||
from django.template.loader import get_template
|
||||
from django.urls import reverse
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.html import conditional_escape, escape, format_html
|
||||
from django.utils.html import (
|
||||
conditional_escape, escape, format_html, format_html_join,
|
||||
)
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _, ngettext, pgettext
|
||||
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.models import (
|
||||
Item, ItemCategory, ItemVariation, Order, OrderPosition, OrderRefund,
|
||||
Question, Quota, SubEvent, Voucher, WaitingListEntry,
|
||||
Item, ItemCategory, Order, OrderRefund, Question, Quota, Voucher,
|
||||
WaitingListEntry,
|
||||
)
|
||||
from pretix.base.services.quotas import QuotaAvailability
|
||||
from pretix.base.timeline import timeline_for_event
|
||||
from pretix.control.signals import (
|
||||
event_dashboard_widgets, user_dashboard_widgets,
|
||||
event_dashboard_statistics, user_dashboard_widgets,
|
||||
)
|
||||
from pretix.helpers.daterange import daterange
|
||||
|
||||
from ...base.models.orders import CancellationRequest
|
||||
from ...base.models.organizer import TeamQuerySet
|
||||
from ...base.templatetags.money import money_filter
|
||||
from ..logdisplay import OVERVIEW_BANLIST
|
||||
|
||||
NUM_WIDGET = '<div class="numwidget"><span class="num">{num}</span><span class="text">{text}</span></div>'
|
||||
from .utils import prepare_quotas_for_boxes
|
||||
|
||||
|
||||
@receiver(signal=event_dashboard_widgets)
|
||||
def base_widgets(sender, subevent=None, lazy=False, **kwargs):
|
||||
if not lazy:
|
||||
prodc = Item.objects.filter(
|
||||
event=sender, active=True,
|
||||
).filter(
|
||||
(Q(available_until__isnull=True) | Q(available_until__gte=now())) &
|
||||
(Q(available_from__isnull=True) | Q(available_from__lte=now()))
|
||||
).count()
|
||||
|
||||
if subevent:
|
||||
opqs = OrderPosition.objects.filter(subevent=subevent)
|
||||
else:
|
||||
opqs = OrderPosition.objects
|
||||
|
||||
tickc = opqs.filter(
|
||||
order__event=sender, item__admission=True,
|
||||
order__status__in=(Order.STATUS_PAID, Order.STATUS_PENDING),
|
||||
).count()
|
||||
|
||||
paidc = opqs.filter(
|
||||
order__event=sender, item__admission=True,
|
||||
order__status=Order.STATUS_PAID,
|
||||
).count()
|
||||
|
||||
if subevent:
|
||||
rev = opqs.filter(
|
||||
order__event=sender, order__status=Order.STATUS_PAID
|
||||
).aggregate(
|
||||
sum=Sum('price')
|
||||
)['sum'] or Decimal('0.00')
|
||||
else:
|
||||
rev = Order.objects.filter(
|
||||
event=sender,
|
||||
status=Order.STATUS_PAID
|
||||
).aggregate(sum=Sum('total'))['sum'] or Decimal('0.00')
|
||||
|
||||
return [
|
||||
def event_index_waiting_lazy(request, organizer, event):
|
||||
wles = WaitingListEntry.objects.filter(event=request.event, voucher__isnull=True)
|
||||
return render(
|
||||
request,
|
||||
'pretixcontrol/event/dashboard_partial_waiting.html',
|
||||
{
|
||||
'content': None if lazy else format_html(NUM_WIDGET, num=intcomma(tickc), text=_('Attendees (ordered)')),
|
||||
'lazy': 'attendees-ordered',
|
||||
'display_size': 'small',
|
||||
'priority': 100,
|
||||
'url': reverse('control:event.orders', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug
|
||||
}) + ('?subevent={}'.format(subevent.pk) if subevent else '')
|
||||
},
|
||||
{
|
||||
'content': None if lazy else format_html(NUM_WIDGET, num=intcomma(paidc), text=_('Attendees (paid)')),
|
||||
'lazy': 'attendees-paid',
|
||||
'display_size': 'small',
|
||||
'priority': 100,
|
||||
'url': reverse('control:event.orders.overview', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug
|
||||
}) + ('?subevent={}'.format(subevent.pk) if subevent else '')
|
||||
},
|
||||
{
|
||||
'content': None if lazy else format_html(
|
||||
NUM_WIDGET,
|
||||
num=money_filter(round_decimal(rev, sender.currency), sender.currency, hide_currency=True),
|
||||
text=_('Total revenue ({currency})').format(currency=sender.currency)
|
||||
),
|
||||
'lazy': 'total-revenue',
|
||||
'display_size': 'small',
|
||||
'priority': 100,
|
||||
'url': reverse('control:event.orders.overview', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug
|
||||
}) + ('?subevent={}'.format(subevent.pk) if subevent else '')
|
||||
},
|
||||
{
|
||||
'content': None if lazy else format_html(NUM_WIDGET, num=prodc, text=_('Active products')),
|
||||
'lazy': 'active-products',
|
||||
'display_size': 'small',
|
||||
'priority': 100,
|
||||
'url': reverse('control:event.items', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug
|
||||
})
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
@receiver(signal=event_dashboard_widgets)
|
||||
def waitinglist_widgets(sender, subevent=None, lazy=False, **kwargs):
|
||||
widgets = []
|
||||
|
||||
wles = WaitingListEntry.objects.filter(event=sender, subevent=subevent, voucher__isnull=True)
|
||||
if wles.exists():
|
||||
if not lazy:
|
||||
quota_cache = {}
|
||||
happy = 0
|
||||
tuples = wles.values('item', 'variation').order_by().annotate(cnt=Count('id'))
|
||||
|
||||
items = {
|
||||
i.pk: i for i in sender.items.filter(id__in=[t['item'] for t in tuples]).prefetch_related(
|
||||
Prefetch('quotas',
|
||||
to_attr='_subevent_quotas',
|
||||
queryset=sender.quotas.using(settings.DATABASE_REPLICA).filter(subevent=subevent)),
|
||||
)
|
||||
}
|
||||
vars = {
|
||||
i.pk: i for i in ItemVariation.objects.filter(
|
||||
item__event=sender, id__in=[t['variation'] for t in tuples if t['variation']]
|
||||
).prefetch_related(
|
||||
Prefetch('quotas',
|
||||
to_attr='_subevent_quotas',
|
||||
queryset=sender.quotas.using(settings.DATABASE_REPLICA).filter(subevent=subevent)),
|
||||
)
|
||||
}
|
||||
|
||||
for wlt in tuples:
|
||||
item = items.get(wlt['item'])
|
||||
variation = vars.get(wlt['variation'])
|
||||
if not item:
|
||||
continue
|
||||
quotas = (
|
||||
variation._get_quotas(subevent=subevent)
|
||||
if variation
|
||||
else item._get_quotas(subevent=subevent)
|
||||
)
|
||||
row = (
|
||||
variation.check_quotas(subevent=subevent, count_waitinglist=False, _cache=quota_cache)
|
||||
if variation
|
||||
else item.check_quotas(subevent=subevent, count_waitinglist=False, _cache=quota_cache)
|
||||
)
|
||||
if row[1] is None:
|
||||
happy += wlt['cnt']
|
||||
elif row[1] > 0:
|
||||
happy += min(wlt['cnt'], row[1])
|
||||
for q in quotas:
|
||||
if q.size is not None:
|
||||
quota_cache[q.pk] = (quota_cache[q.pk][0], quota_cache[q.pk][1] - min(wlt['cnt'], row[1]))
|
||||
|
||||
widgets.append({
|
||||
'content': None if lazy else format_html(
|
||||
NUM_WIDGET, num=intcomma(happy), text=_('available to give to people on waiting list')
|
||||
),
|
||||
'lazy': 'waitinglist-avail',
|
||||
'priority': 50,
|
||||
'url': reverse('control:event.orders.waitinglist', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug,
|
||||
})
|
||||
})
|
||||
widgets.append({
|
||||
'content': None if lazy else format_html(
|
||||
NUM_WIDGET, num=intcomma(wles.count()), text=_('total waiting list length')
|
||||
),
|
||||
'lazy': 'waitinglist-length',
|
||||
'display_size': 'small',
|
||||
'priority': 50,
|
||||
'url': reverse('control:event.orders.waitinglist', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug,
|
||||
})
|
||||
})
|
||||
|
||||
return widgets
|
||||
|
||||
|
||||
@receiver(signal=event_dashboard_widgets)
|
||||
def quota_widgets(sender, subevent=None, lazy=False, **kwargs):
|
||||
widgets = []
|
||||
quotas = sender.quotas.filter(subevent=subevent)
|
||||
|
||||
qa = QuotaAvailability()
|
||||
if quotas:
|
||||
qa.queue(*quotas)
|
||||
qa.compute(allow_cache=True)
|
||||
|
||||
for q in quotas:
|
||||
if not lazy:
|
||||
status, left = qa.results[q] if q in qa.results else q.availability(allow_cache=True)
|
||||
widgets.append({
|
||||
'content': None if lazy else format_html(
|
||||
NUM_WIDGET,
|
||||
num='{}/{}'.format(intcomma(left), intcomma(q.size)) if q.size is not None else '\u221e',
|
||||
text=format_html(_('{quota} left'), quota=q.name)
|
||||
),
|
||||
'lazy': 'quota-{}'.format(q.pk),
|
||||
'display_size': 'small',
|
||||
'priority': 50,
|
||||
'url': reverse('control:event.items.quotas.show', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug,
|
||||
'quota': q.id
|
||||
})
|
||||
})
|
||||
return widgets
|
||||
|
||||
|
||||
@receiver(signal=event_dashboard_widgets)
|
||||
def shop_state_widget(sender, **kwargs):
|
||||
return [{
|
||||
'display_size': 'small',
|
||||
'priority': 1000,
|
||||
'content': format_html(
|
||||
'<div class="shopstate">{t1}<br><span class="{cls}"><span class="fa {icon}"></span> {state}</span>{t2}</div>',
|
||||
t1=_('Your ticket shop is'), t2=_('Click here to change'),
|
||||
state=_('live') if sender.live and not sender.testmode else (
|
||||
_('live and in test mode') if sender.live else (
|
||||
_('not yet public') if not sender.testmode else (
|
||||
_('in private test mode')
|
||||
)
|
||||
)
|
||||
),
|
||||
icon='fa-check-circle' if sender.live and not sender.testmode else (
|
||||
'fa-warning' if sender.live else (
|
||||
'fa-times-circle' if not sender.testmode else (
|
||||
'fa-times-circle'
|
||||
)
|
||||
)
|
||||
),
|
||||
cls='live' if sender.live else 'off'
|
||||
),
|
||||
'url': reverse('control:event.live', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug
|
||||
})
|
||||
}]
|
||||
|
||||
|
||||
@receiver(signal=event_dashboard_widgets)
|
||||
def checkin_widget(sender, subevent=None, lazy=False, **kwargs):
|
||||
widgets = []
|
||||
qs = sender.checkin_lists.filter(subevent=subevent)
|
||||
for cl in qs:
|
||||
widgets.append({
|
||||
'content': None if lazy else format_html(
|
||||
NUM_WIDGET,
|
||||
num='{}/{}'.format(intcomma(cl.inside_count), intcomma(cl.position_count)),
|
||||
text=format_html(_('Present – {list}'), list=cl.name)
|
||||
),
|
||||
'lazy': 'checkin-{}'.format(cl.pk),
|
||||
'display_size': 'small',
|
||||
'priority': 50,
|
||||
'url': reverse('control:event.orders.checkinlists.show', kwargs={
|
||||
'event': sender.slug,
|
||||
'organizer': sender.organizer.slug,
|
||||
'list': cl.pk
|
||||
})
|
||||
})
|
||||
return widgets
|
||||
|
||||
|
||||
@receiver(signal=event_dashboard_widgets)
|
||||
def welcome_wizard_widget(sender, **kwargs):
|
||||
template = get_template('pretixcontrol/event/dashboard_widget_welcome.html')
|
||||
ctx = {
|
||||
'title': _('Welcome to pretix!')
|
||||
}
|
||||
kwargs = {'event': sender.slug, 'organizer': sender.organizer.slug}
|
||||
|
||||
if not sender.items.exists():
|
||||
ctx.update({
|
||||
'subtitle': _('Get started with our setup tool'),
|
||||
'text': _('To start selling tickets, you need to create products or quotas. The fastest way to create '
|
||||
'this is to use our setup tool.'),
|
||||
'button_text': _('Set up event'),
|
||||
'button_url': reverse('control:event.quick', kwargs=kwargs)
|
||||
})
|
||||
else:
|
||||
return []
|
||||
return [{
|
||||
'display_size': 'full',
|
||||
'priority': 2000,
|
||||
'content': template.render(ctx)
|
||||
}]
|
||||
'count': wles.count,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def build_json_response(widgets):
|
||||
@@ -353,62 +84,38 @@ def build_json_response(widgets):
|
||||
|
||||
|
||||
def event_index(request, organizer, event):
|
||||
from pretix.control.forms.event import CommentForm
|
||||
can_view_orders = request.user.has_event_permission(
|
||||
request.organizer,
|
||||
request.event,
|
||||
'event.orders:read',
|
||||
request=request
|
||||
)
|
||||
|
||||
subevent = None
|
||||
if request.GET.get("subevent", "") != "" and request.event.has_subevents:
|
||||
i = request.GET.get("subevent", "")
|
||||
try:
|
||||
subevent = request.event.subevents.get(pk=i)
|
||||
except SubEvent.DoesNotExist:
|
||||
pass
|
||||
|
||||
can_view_orders = request.user.has_event_permission(request.organizer, request.event, 'event.orders:read',
|
||||
request=request)
|
||||
can_change_event_settings = request.user.has_event_permission(request.organizer, request.event,
|
||||
'event.settings.general:write', request=request)
|
||||
|
||||
widgets = []
|
||||
stats = []
|
||||
if can_view_orders:
|
||||
for r, result in event_dashboard_widgets.send(sender=request.event, subevent=subevent, lazy=True):
|
||||
widgets.extend(result)
|
||||
for r, result in event_dashboard_statistics.send(sender=request.event, request=request):
|
||||
stats.append(result)
|
||||
|
||||
ctx = {
|
||||
'widgets': rearrange(widgets),
|
||||
'subevent': subevent,
|
||||
'comment_form': CommentForm(initial={'comment': request.event.comment}, readonly=not can_change_event_settings),
|
||||
'stats': format_html_join("", "{}", [(s,) for s in stats]),
|
||||
}
|
||||
|
||||
ctx['timeline'] = [
|
||||
{
|
||||
'date': t.datetime.astimezone(request.event.timezone).date(),
|
||||
'entry': t,
|
||||
'time': t.datetime.astimezone(request.event.timezone)
|
||||
}
|
||||
for t in timeline_for_event(request.event, subevent)
|
||||
]
|
||||
if not request.event.has_subevents:
|
||||
ctx['timeline'] = [
|
||||
{
|
||||
'date': t.datetime.astimezone(request.event.timezone).date(),
|
||||
'entry': t,
|
||||
'time': t.datetime.astimezone(request.event.timezone)
|
||||
}
|
||||
for t in timeline_for_event(request.event, None)
|
||||
]
|
||||
ctx['today'] = now().astimezone(request.event.timezone).date()
|
||||
ctx['nearly_now'] = now().astimezone(request.event.timezone) - timedelta(seconds=20)
|
||||
ctx['has_checkin_widgets'] = not request.event.has_subevents or request.event.checkin_lists.filter(subevent=None).exists()
|
||||
resp = render(request, 'pretixcontrol/event/index.html', ctx)
|
||||
return resp
|
||||
|
||||
|
||||
def event_index_widgets_lazy(request, organizer, event):
|
||||
subevent = None
|
||||
if request.GET.get("subevent", "") != "" and request.event.has_subevents:
|
||||
i = request.GET.get("subevent", "")
|
||||
try:
|
||||
subevent = request.event.subevents.get(pk=i)
|
||||
except SubEvent.DoesNotExist:
|
||||
pass
|
||||
|
||||
widgets = []
|
||||
for r, result in event_dashboard_widgets.send(sender=request.event, subevent=subevent, lazy=False):
|
||||
widgets.extend(result)
|
||||
|
||||
return build_json_response(widgets)
|
||||
|
||||
|
||||
def event_index_warnings_lazy(request, organizer, event):
|
||||
can_view_orders = request.user.has_event_permission(request.organizer, request.event, 'event.orders:read',
|
||||
request=request)
|
||||
@@ -445,6 +152,32 @@ def event_index_warnings_lazy(request, organizer, event):
|
||||
)
|
||||
|
||||
|
||||
def event_index_quotas_lazy(request, organizer, event):
|
||||
if request.event.has_subevents:
|
||||
raise Http404()
|
||||
|
||||
quotas = request.event.quotas.filter(subevent=None)[:10]
|
||||
prepare_quotas_for_boxes(quotas)
|
||||
return render(
|
||||
request,
|
||||
'pretixcontrol/event/dashboard_partial_quotas.html',
|
||||
{
|
||||
'quotas': quotas,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def event_index_checkin_lazy(request, organizer, event):
|
||||
lists = request.event.checkin_lists.filter(subevent=None)[:10]
|
||||
return render(
|
||||
request,
|
||||
'pretixcontrol/event/dashboard_partial_checkin.html',
|
||||
{
|
||||
'lists': lists,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def event_index_log_lazy(request, organizer, event):
|
||||
qs = request.event.logentry_set.all().select_related('user', 'content_type', 'api_token', 'oauth_application',
|
||||
'device').order_by('-datetime')
|
||||
|
||||
@@ -57,10 +57,9 @@ from django.db import transaction
|
||||
from django.db.models import Count, ProtectedError
|
||||
from django.forms import inlineformset_factory
|
||||
from django.http import (
|
||||
Http404, HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed,
|
||||
JsonResponse,
|
||||
Http404, HttpResponse, HttpResponseBadRequest, JsonResponse,
|
||||
)
|
||||
from django.shortcuts import redirect
|
||||
from django.shortcuts import redirect, render
|
||||
from django.urls import NoReverseMatch, reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import conditional_escape, format_html
|
||||
@@ -1299,24 +1298,23 @@ class EventLog(EventPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
return LogFilterForm(data=self.request.GET, organizer=self.request.organizer)
|
||||
|
||||
|
||||
class EventComment(EventPermissionRequiredMixin, View):
|
||||
class EventComment(EventPermissionRequiredMixin, UpdateView):
|
||||
permission = 'event.settings.general:write'
|
||||
form_class = CommentForm
|
||||
template_name = 'pretixcontrol/event/dashboard_partial_comment_form.html'
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
form = CommentForm(self.request.POST)
|
||||
if form.is_valid():
|
||||
self.request.event.comment = form.cleaned_data.get('comment')
|
||||
self.request.event.save()
|
||||
self.request.event.log_action('pretix.event.comment', user=self.request.user, data={
|
||||
'new_comment': form.cleaned_data.get('comment')
|
||||
})
|
||||
messages.success(self.request, _('The comment has been updated.'))
|
||||
else:
|
||||
messages.error(self.request, _('Could not update the comment.'))
|
||||
return redirect(self.get_success_url())
|
||||
def get_object(self, queryset=None):
|
||||
return self.request.event
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
return HttpResponseNotAllowed(['POST'])
|
||||
def form_valid(self, form):
|
||||
form.save()
|
||||
self.request.event.log_action('pretix.event.comment', user=self.request.user, data={
|
||||
'new_comment': form.cleaned_data.get('comment')
|
||||
})
|
||||
return render(
|
||||
self.request,
|
||||
'pretixcontrol/event/dashboard_partial_comment.html',
|
||||
)
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
return reverse('control:event.index', kwargs={
|
||||
@@ -1568,7 +1566,7 @@ class WidgetSettings(EventSettingsViewMixin, EventPermissionRequiredMixin, FormV
|
||||
return ctx
|
||||
|
||||
|
||||
class QuickSetupView(EventPermissionRequiredMixin, FormView):
|
||||
class QuickSetupView(FormView):
|
||||
template_name = 'pretixcontrol/event/quick_setup.html'
|
||||
permission = 'event.settings.general:write'
|
||||
form_class = QuickSetupForm
|
||||
|
||||
@@ -65,7 +65,6 @@ from pretix.api.serializers.item import (
|
||||
ItemVariationSerializer,
|
||||
)
|
||||
from pretix.base.forms import I18nFormSet
|
||||
from pretix.base.forms.questions import get_fake_attendee_questions
|
||||
from pretix.base.models import (
|
||||
CartPosition, Item, ItemCategory, ItemProgramTime, ItemVariation, LogEntry,
|
||||
OrderPosition, Question, QuestionAnswer, QuestionOption, Quota,
|
||||
@@ -427,7 +426,7 @@ def reorder_categories(request, organizer, event):
|
||||
|
||||
|
||||
FakeQuestion = namedtuple(
|
||||
'FakeQuestion', 'id question position required container_type'
|
||||
'FakeQuestion', 'id question position required'
|
||||
)
|
||||
|
||||
|
||||
@@ -441,8 +440,85 @@ class QuestionList(ListView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
questions = []
|
||||
|
||||
questions = get_fake_attendee_questions(self.request.event.settings)
|
||||
if self.request.event.settings.attendee_names_asked:
|
||||
questions.append(
|
||||
FakeQuestion(
|
||||
id='attendee_name_parts',
|
||||
question=_('Attendee name'),
|
||||
position=self.request.event.settings.system_question_order.get(
|
||||
'attendee_name_parts', 0
|
||||
),
|
||||
required=self.request.event.settings.attendee_names_required,
|
||||
)
|
||||
)
|
||||
|
||||
if self.request.event.settings.attendee_emails_asked:
|
||||
questions.append(
|
||||
FakeQuestion(
|
||||
id='attendee_email',
|
||||
question=_('Attendee email'),
|
||||
position=self.request.event.settings.system_question_order.get(
|
||||
'attendee_email', 0
|
||||
),
|
||||
required=self.request.event.settings.attendee_emails_required,
|
||||
)
|
||||
)
|
||||
|
||||
if self.request.event.settings.attendee_company_asked:
|
||||
questions.append(
|
||||
FakeQuestion(
|
||||
id='company',
|
||||
question=_('Company'),
|
||||
position=self.request.event.settings.system_question_order.get(
|
||||
'company', 0
|
||||
),
|
||||
required=self.request.event.settings.attendee_company_required,
|
||||
)
|
||||
)
|
||||
|
||||
if self.request.event.settings.attendee_addresses_asked:
|
||||
questions.append(
|
||||
FakeQuestion(
|
||||
id='street',
|
||||
question=_('Street'),
|
||||
position=self.request.event.settings.system_question_order.get(
|
||||
'street', 0
|
||||
),
|
||||
required=self.request.event.settings.attendee_addresses_required,
|
||||
)
|
||||
)
|
||||
questions.append(
|
||||
FakeQuestion(
|
||||
id='zipcode',
|
||||
question=_('ZIP code'),
|
||||
position=self.request.event.settings.system_question_order.get(
|
||||
'zipcode', 0
|
||||
),
|
||||
required=self.request.event.settings.attendee_addresses_required,
|
||||
)
|
||||
)
|
||||
questions.append(
|
||||
FakeQuestion(
|
||||
id='city',
|
||||
question=_('City'),
|
||||
position=self.request.event.settings.system_question_order.get(
|
||||
'city', 0
|
||||
),
|
||||
required=self.request.event.settings.attendee_addresses_required,
|
||||
)
|
||||
)
|
||||
questions.append(
|
||||
FakeQuestion(
|
||||
id='country',
|
||||
question=_('Country'),
|
||||
position=self.request.event.settings.system_question_order.get(
|
||||
'country', 0
|
||||
),
|
||||
required=self.request.event.settings.attendee_addresses_required,
|
||||
)
|
||||
)
|
||||
|
||||
questions += list(ctx['questions'])
|
||||
questions.sort(key=lambda q: q.position)
|
||||
@@ -459,16 +535,14 @@ def reorder_questions(request, organizer, event):
|
||||
except (JSONDecodeError, KeyError, ValueError):
|
||||
return HttpResponseBadRequest("expected JSON: {ids:[]}")
|
||||
|
||||
qs = request.event.questions.filter(container_type=request.GET['container_type'])
|
||||
|
||||
# filter system_questions - normal questions are int/digit, system_questions strings
|
||||
custom_question_ids = [i for i in ids if i.isdigit()]
|
||||
input_questions = list(qs.filter(id__in=custom_question_ids))
|
||||
input_questions = list(request.event.questions.filter(id__in=custom_question_ids))
|
||||
|
||||
if len(input_questions) != len(custom_question_ids):
|
||||
raise Http404(_("Some of the provided object ids are invalid."))
|
||||
|
||||
if len(input_questions) != qs.count():
|
||||
if len(input_questions) != request.event.questions.count():
|
||||
raise Http404(_("Not all objects have been selected."))
|
||||
|
||||
for q in input_questions:
|
||||
@@ -482,19 +556,18 @@ def reorder_questions(request, organizer, event):
|
||||
}
|
||||
)
|
||||
|
||||
if request.GET['container_type'] == Question.ContainerType.ORDERPOSITION:
|
||||
system_question_order = {}
|
||||
for s in ('attendee_name_parts', 'attendee_email', 'company', 'street', 'zipcode', 'city', 'country'):
|
||||
if s in ids:
|
||||
system_question_order[s] = ids.index(s)
|
||||
else:
|
||||
system_question_order[s] = -1
|
||||
request.event.settings.system_question_order = system_question_order
|
||||
request.event.log_action(
|
||||
'pretix.event.settings', user=request.user, data={
|
||||
'system_question_order': system_question_order,
|
||||
}
|
||||
)
|
||||
system_question_order = {}
|
||||
for s in ('attendee_name_parts', 'attendee_email', 'company', 'street', 'zipcode', 'city', 'country'):
|
||||
if s in ids:
|
||||
system_question_order[s] = ids.index(s)
|
||||
else:
|
||||
system_question_order[s] = -1
|
||||
request.event.settings.system_question_order = system_question_order
|
||||
request.event.log_action(
|
||||
'pretix.event.settings', user=request.user, data={
|
||||
'system_question_order': system_question_order,
|
||||
}
|
||||
)
|
||||
|
||||
return HttpResponse()
|
||||
|
||||
@@ -732,9 +805,6 @@ class QuestionCreate(EventPermissionRequiredMixin, QuestionMixin, CreateView):
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super().get_form_kwargs()
|
||||
kwargs['instance'] = Question(event=self.request.event)
|
||||
kwargs['instance'].container_type = self.request.GET.get('container_type', Question.ContainerType.ORDERPOSITION)
|
||||
if kwargs['instance'].container_type not in Question.ContainerType.values:
|
||||
raise PermissionDenied
|
||||
return kwargs
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
|
||||
@@ -269,8 +269,8 @@ class MailSettingsSetupView(TemplateView):
|
||||
if settings.MAIL_CUSTOM_SENDER_DMARC_REQUIRED:
|
||||
dmarc_record = get_dmarc_record(hostname)
|
||||
if not dmarc_record:
|
||||
dmarc_warning = _(
|
||||
'We did not find a DMARC record for your domain. This means that there is a very high chance '
|
||||
spf_warning = _(
|
||||
'We did not find DMARC record for your domain. This means that there is a very high chance '
|
||||
'most of the emails will be rejected or marked as spam. You should update the DNS settings '
|
||||
'of your domain.'
|
||||
)
|
||||
|
||||
@@ -52,13 +52,13 @@ from pretix.base.forms import SafeSessionWizardView
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.models import Event, EventMetaValue, Organizer, Quota, Team
|
||||
from pretix.base.models.organizer import TeamQuerySet
|
||||
from pretix.base.services.quotas import QuotaAvailability
|
||||
from pretix.control.forms.event import (
|
||||
EventWizardBasicsForm, EventWizardCopyForm, EventWizardFoundationForm,
|
||||
)
|
||||
from pretix.control.forms.filter import EventFilterForm
|
||||
from pretix.control.permissions import OrganizerPermissionRequiredMixin
|
||||
from pretix.control.views import PaginationMixin
|
||||
from pretix.control.views.utils import prepare_quotas_for_boxes
|
||||
|
||||
|
||||
class EventList(PaginationMixin, ListView):
|
||||
@@ -117,19 +117,7 @@ class EventList(PaginationMixin, ListView):
|
||||
s.first_quotas = s.first_quotas[:4]
|
||||
quotas += list(s.first_quotas)
|
||||
|
||||
qa = QuotaAvailability(early_out=False)
|
||||
for q in quotas:
|
||||
qa.queue(q)
|
||||
qa.compute()
|
||||
|
||||
for q in quotas:
|
||||
q.cached_avail = qa.results[q]
|
||||
q.cached_availability_paid_orders = qa.count_paid_orders.get(q, 0)
|
||||
if q.size is not None:
|
||||
q.percent_paid = min(
|
||||
100,
|
||||
round(q.cached_availability_paid_orders / q.size * 100) if q.size > 0 else 100
|
||||
)
|
||||
prepare_quotas_for_boxes(quotas)
|
||||
return ctx
|
||||
|
||||
@cached_property
|
||||
|
||||
@@ -81,7 +81,7 @@ from pretix.base.i18n import language
|
||||
from pretix.base.models import (
|
||||
CachedFile, CachedTicket, Checkin, GiftCard, Invoice, InvoiceAddress, Item,
|
||||
ItemVariation, LogEntry, Order, QuestionAnswer, Quota,
|
||||
ScheduledEventExport, SeatCategoryMapping, generate_secret,
|
||||
ScheduledEventExport, generate_secret,
|
||||
)
|
||||
from pretix.base.models.orders import (
|
||||
CancellationRequest, OrderFee, OrderPayment, OrderPosition, OrderRefund,
|
||||
@@ -382,7 +382,7 @@ class OrderOverpaidRefundBulkActionView(BaseOrderBulkActionView):
|
||||
'provider': refund.provider,
|
||||
}, user=self.request.user)
|
||||
payment.payment_provider.execute_refund(refund)
|
||||
return bool(proposals)
|
||||
return True
|
||||
except (ValueError, PaymentException):
|
||||
return False
|
||||
|
||||
@@ -564,11 +564,10 @@ class OrderDetail(OrderView):
|
||||
})
|
||||
ctx['display_locale'] = dict(settings.LANGUAGES)[self.object.locale or self.request.event.settings.locale]
|
||||
|
||||
pending_sum = self.order.pending_sum
|
||||
ctx['overpaid'] = pending_sum * -1
|
||||
ctx['overpaid'] = self.order.pending_sum * -1
|
||||
ctx['download_buttons'] = self.download_buttons
|
||||
ctx['payment_refund_sum'] = self.order.payment_refund_sum
|
||||
ctx['pending_sum'] = pending_sum
|
||||
ctx['pending_sum'] = self.order.pending_sum
|
||||
ctx['uncancelled_invoice'] = self.order.invoices.exclude(
|
||||
Exists(self.order.invoices.filter(refers=OuterRef('pk'), is_cancellation=True))
|
||||
).exclude(is_cancellation=True).first()
|
||||
@@ -602,9 +601,8 @@ class OrderDetail(OrderView):
|
||||
).prefetch_related(
|
||||
'item__questions', 'issued_gift_cards', 'owned_gift_cards', 'linked_media',
|
||||
Prefetch('answers', queryset=QuestionAnswer.objects.prefetch_related('options').select_related('question')),
|
||||
Prefetch('all_checkins', queryset=Checkin.all.select_related('list', 'gate').order_by('datetime')),
|
||||
Prefetch('all_checkins', queryset=Checkin.all.select_related('list').order_by('datetime')),
|
||||
Prefetch('print_logs', queryset=PrintLog.objects.select_related('device').order_by('datetime')),
|
||||
Prefetch('subevent', queryset=self.request.event.subevents.all()),
|
||||
).order_by('positionid')
|
||||
|
||||
positions = []
|
||||
@@ -1987,37 +1985,20 @@ class OrderChange(OrderView):
|
||||
def fees(self):
|
||||
fees = list(self.order.fees.all())
|
||||
for f in fees:
|
||||
f.form = OrderFeeChangeForm(
|
||||
prefix='of-{}'.format(f.pk),
|
||||
instance=f,
|
||||
data=self.request.POST if self.request.method == "POST" else None
|
||||
)
|
||||
f.form = OrderFeeChangeForm(prefix='of-{}'.format(f.pk), instance=f,
|
||||
data=self.request.POST if self.request.method == "POST" else None)
|
||||
return fees
|
||||
|
||||
@cached_property
|
||||
def positions(self):
|
||||
positions = list(self.order.positions.select_related(
|
||||
'item', 'item__tax_rule', 'used_membership', 'used_membership__membership_type', 'tax_rule',
|
||||
'seat',
|
||||
).prefetch_related(
|
||||
Prefetch(
|
||||
'subevent',
|
||||
queryset=self.request.event.subevents.all(),
|
||||
),
|
||||
'granted_memberships',
|
||||
'issued_gift_cards',
|
||||
'addons',
|
||||
).annotate(
|
||||
_seat_allowed=Exists(SeatCategoryMapping.objects.filter(subevent=OuterRef("subevent"), product=OuterRef("item")))
|
||||
))
|
||||
'seat', 'subevent',
|
||||
).prefetch_related('granted_memberships', 'issued_gift_cards'))
|
||||
for p in positions:
|
||||
p.form = OrderPositionChangeForm(
|
||||
prefix='op-{}'.format(p.pk),
|
||||
instance=p,
|
||||
items=self.items,
|
||||
initial={'seat': p.seat.seat_guid if p.seat else None},
|
||||
data=self.request.POST if self.request.method == "POST" else None
|
||||
)
|
||||
p.form = OrderPositionChangeForm(prefix='op-{}'.format(p.pk), instance=p, items=self.items,
|
||||
initial={'seat': p.seat.seat_guid if p.seat else None},
|
||||
data=self.request.POST if self.request.method == "POST" else None)
|
||||
return positions
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -2226,10 +2207,6 @@ class OrderModifyInformation(OrderQuestionsViewMixin, OrderView):
|
||||
only_user_visible = False
|
||||
all_optional = True
|
||||
|
||||
@property
|
||||
def order_question_container(self):
|
||||
return self.order
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['other_form'] = self.other_form
|
||||
@@ -2591,11 +2568,7 @@ class AnswerDownload(EventPermissionRequiredMixin, OrderViewMixin, ListView):
|
||||
answid = kwargs.get('answer')
|
||||
token = request.GET.get('token', '')
|
||||
|
||||
answer = get_object_or_404(
|
||||
QuestionAnswer,
|
||||
Q(orderposition__order=self.order) | Q(order=self.order),
|
||||
id=answid
|
||||
)
|
||||
answer = get_object_or_404(QuestionAnswer, orderposition__order=self.order, id=answid)
|
||||
if not answer.file:
|
||||
raise Http404()
|
||||
if not check_token(request, answer, token):
|
||||
@@ -2605,7 +2578,7 @@ class AnswerDownload(EventPermissionRequiredMixin, OrderViewMixin, ListView):
|
||||
resp = FileResponse(answer.file, content_type=ftype or 'application/binary')
|
||||
resp['Content-Disposition'] = 'attachment; filename="{}-{}-{}-{}"'.format(
|
||||
self.request.event.slug.upper(), self.order.code,
|
||||
answer.orderposition.positionid if answer.orderposition else '',
|
||||
answer.orderposition.positionid,
|
||||
os.path.basename(answer.file.name).split('.', 1)[1]
|
||||
)
|
||||
return resp
|
||||
|
||||
@@ -108,9 +108,6 @@ from pretix.base.services.export import (
|
||||
init_organizer_exporters, multiexport, scheduled_organizer_export,
|
||||
)
|
||||
from pretix.base.services.mail import mail, prefix_subject
|
||||
from pretix.base.services.placeholders import (
|
||||
prepare_sample_context_for_preview,
|
||||
)
|
||||
from pretix.base.templatetags.rich_text import markdown_compile_email
|
||||
from pretix.base.views.tasks import AsyncAction
|
||||
from pretix.control.forms.exports import ScheduledOrganizerExportForm
|
||||
@@ -348,11 +345,16 @@ class MailSettingsPreview(OrganizerPermissionRequiredMixin, View):
|
||||
|
||||
# get all supported placeholders with dummy values
|
||||
def placeholders(self, item):
|
||||
ctx = prepare_sample_context_for_preview(
|
||||
MailSettingsForm(obj=self.request.organizer)._get_sample_context(
|
||||
MailSettingsForm.base_context[item]
|
||||
)
|
||||
)
|
||||
ctx = {}
|
||||
for p, s in MailSettingsForm(obj=self.request.organizer)._get_sample_context(
|
||||
MailSettingsForm.base_context[item]).items():
|
||||
if s.strip().startswith('*'):
|
||||
ctx[p] = s
|
||||
else:
|
||||
ctx[p] = '<span class="placeholder" title="{}">{}</span>'.format(
|
||||
_('This value will be replaced based on dynamic parameters.'),
|
||||
s
|
||||
)
|
||||
return self.SafeDict(ctx)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
@@ -1208,7 +1210,7 @@ class DeviceQueryMixin:
|
||||
def get_queryset(self):
|
||||
qs = self.request.organizer.devices.prefetch_related(
|
||||
'limit_events', 'gate',
|
||||
).select_related('last_seen').order_by('revoked', '-device_id')
|
||||
).order_by('revoked', '-device_id')
|
||||
|
||||
if 'device' in self.request_data and '__ALL' not in self.request_data:
|
||||
qs = qs.filter(
|
||||
|
||||
@@ -69,6 +69,7 @@ from pretix.base.models.orders import CancellationRequest
|
||||
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
||||
from pretix.base.services import tickets
|
||||
from pretix.base.services.quotas import QuotaAvailability
|
||||
from pretix.base.timeline import timeline_for_event
|
||||
from pretix.base.views.tasks import AsyncFormView
|
||||
from pretix.control.forms.checkin import SimpleCheckinListForm
|
||||
from pretix.control.forms.filter import SubEventFilterForm
|
||||
@@ -83,6 +84,7 @@ from pretix.control.permissions import EventPermissionRequiredMixin
|
||||
from pretix.control.signals import subevent_forms
|
||||
from pretix.control.views import PaginationMixin
|
||||
from pretix.control.views.event import MetaDataEditorMixin
|
||||
from pretix.control.views.utils import prepare_quotas_for_boxes
|
||||
from pretix.helpers import GroupConcat
|
||||
from pretix.helpers.compat import CompatDeleteView
|
||||
from pretix.helpers.i18n import get_format_without_seconds
|
||||
@@ -144,19 +146,7 @@ class SubEventList(EventPermissionRequiredMixin, PaginationMixin, SubEventQueryM
|
||||
s.first_quotas = s.first_quotas[:4]
|
||||
quotas += list(s.first_quotas)
|
||||
|
||||
qa = QuotaAvailability(early_out=False)
|
||||
for q in quotas:
|
||||
qa.queue(q)
|
||||
qa.compute()
|
||||
|
||||
for q in quotas:
|
||||
q.cached_avail = qa.results[q]
|
||||
q.cached_availability_paid_orders = qa.count_paid_orders.get(q, 0)
|
||||
if q.size is not None:
|
||||
q.percent_paid = min(
|
||||
100,
|
||||
round(q.cached_availability_paid_orders / q.size * 100) if q.size > 0 else 100
|
||||
)
|
||||
prepare_quotas_for_boxes(quotas)
|
||||
return ctx
|
||||
|
||||
|
||||
@@ -431,7 +421,7 @@ class SubEventEditorMixin(MetaDataEditorMixin):
|
||||
days = (self.copy_from.date_from.astimezone(tz).date() - value.astimezone(tz).date()).days
|
||||
return RelativeDateWrapper(RelativeDate(
|
||||
days=abs(days),
|
||||
base_date_name='event__date_from',
|
||||
base_date_name='date_from',
|
||||
time=value.astimezone(tz).time(),
|
||||
minutes=None,
|
||||
is_after=days < 0,
|
||||
@@ -566,6 +556,17 @@ class SubEventDetail(EventPermissionRequiredMixin, DetailView):
|
||||
for quota in ctx["quotas"]:
|
||||
quota.cached_avail = qa.results[quota]
|
||||
|
||||
ctx['timeline'] = [
|
||||
{
|
||||
'date': t.datetime.astimezone(self.request.event.timezone).date(),
|
||||
'entry': t,
|
||||
'time': t.datetime.astimezone(self.request.event.timezone)
|
||||
}
|
||||
for t in timeline_for_event(self.request.event, self.object)
|
||||
]
|
||||
ctx['today'] = now().astimezone(self.request.event.timezone).date()
|
||||
ctx['nearly_now'] = now().astimezone(self.request.event.timezone) - timedelta(seconds=20)
|
||||
|
||||
return super().get_context_data(
|
||||
**kwargs,
|
||||
**ctx,
|
||||
|
||||
@@ -46,7 +46,6 @@ from django.contrib.auth import update_session_auth_hash
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import BadRequest, PermissionDenied
|
||||
from django.db import transaction
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse
|
||||
from django.utils.crypto import get_random_string
|
||||
@@ -96,20 +95,6 @@ class RecentAuthenticationRequiredMixin:
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
tdelta = time.time() - request.session.get('pretix_auth_login_time', 0)
|
||||
if tdelta > self.max_time:
|
||||
|
||||
if request.headers.get("X-Requested-With") == "XMLHttpRequest":
|
||||
# It's not useful to return a 302 redirect on a XMLHttpRequest request, because
|
||||
# the XMLHttpRequest is unable to detect redirects.
|
||||
return HttpResponse(
|
||||
"Authentication required",
|
||||
status=401,
|
||||
headers={
|
||||
# Appending ?next= is handled by client, because it should be the top-level context url,
|
||||
# not the URL called in the background
|
||||
"X-Login-Url": reverse('control:user.reauth')
|
||||
}
|
||||
)
|
||||
|
||||
return redirect(reverse('control:user.reauth') + '?next=' + quote(request.get_full_path()))
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
from pretix.base.services.quotas import QuotaAvailability
|
||||
|
||||
|
||||
def prepare_quotas_for_boxes(quotas):
|
||||
qa = QuotaAvailability(early_out=False)
|
||||
for q in quotas:
|
||||
qa.queue(q)
|
||||
qa.compute()
|
||||
|
||||
for q in quotas:
|
||||
q.cached_avail = qa.results[q]
|
||||
q.cached_availability_paid_orders = qa.count_paid_orders.get(q, 0)
|
||||
q.used = (
|
||||
qa.count_paid_orders.get(q, 0) +
|
||||
qa.count_pending_orders.get(q, 0) +
|
||||
qa.count_exited_orders.get(q, 0) +
|
||||
qa.count_vouchers.get(q, 0) +
|
||||
qa.count_waitinglist.get(q, 0) +
|
||||
qa.count_cart.get(q, 0)
|
||||
)
|
||||
if q.size is not None:
|
||||
other_blocked = q.size - q.cached_availability_paid_orders - q.cached_avail[1]
|
||||
q.percent_paid = min(
|
||||
100,
|
||||
round(q.cached_availability_paid_orders / q.size * 100) if q.size > 0 else 100
|
||||
)
|
||||
q.percent_other = min(
|
||||
100,
|
||||
round(other_blocked / q.size * 100) if q.size > 0 else 100
|
||||
)
|
||||
@@ -53,7 +53,6 @@ from django.shortcuts import redirect, render
|
||||
from django.urls import resolve, reverse
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.html import format_html
|
||||
from django.utils.http import url_has_allowed_host_and_scheme
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@@ -351,8 +350,6 @@ class VoucherUpdate(EventPermissionRequiredMixin, UpdateView):
|
||||
return super().post(request, *args, **kwargs)
|
||||
|
||||
def get_success_url(self) -> str:
|
||||
if "next" in self.request.GET and url_has_allowed_host_and_scheme(self.request.GET.get("next"), allowed_hosts=None):
|
||||
return self.request.GET.get("next")
|
||||
return reverse('control:event.vouchers', kwargs={
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'event': self.request.event.slug,
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
import contextlib
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.postgres.indexes import BrinIndex
|
||||
from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured
|
||||
from django.db import connection, transaction
|
||||
from django.db.models import (
|
||||
@@ -286,30 +285,3 @@ def get_deterministic_ordering(model, ordering):
|
||||
# on the primary key to provide total ordering.
|
||||
ordering.append("-pk")
|
||||
return ordering
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def conditional_atomic(do_atomic, **kwargs):
|
||||
if do_atomic:
|
||||
with transaction.atomic(**kwargs):
|
||||
yield
|
||||
else:
|
||||
yield
|
||||
|
||||
|
||||
class IgnoreOnSQLiteMixin:
|
||||
# Mixin to allow defining PostgreSQL-specific indexes that will just not be created
|
||||
# on SQLite. SQLite is supported for testing only anyways!
|
||||
def create_sql(self, model, schema_editor, *args, **kwargs):
|
||||
if "sqlite" in settings.DATABASES["default"]["ENGINE"]:
|
||||
return ""
|
||||
return super().create_sql(model, schema_editor, *args, **kwargs)
|
||||
|
||||
def remove_sql(self, model, schema_editor, **kwargs):
|
||||
if "sqlite" in settings.DATABASES["default"]["ENGINE"]:
|
||||
return ""
|
||||
return super().remove_sql(model, schema_editor, **kwargs)
|
||||
|
||||
|
||||
class BrinIndexIgnoredOnSQLite(IgnoreOnSQLiteMixin, BrinIndex):
|
||||
pass
|
||||
|
||||
@@ -24,21 +24,17 @@ import hashlib
|
||||
from django.core.signing import BadSignature, TimestampSigner
|
||||
|
||||
|
||||
class SafeDownloadSigner(TimestampSigner):
|
||||
pass
|
||||
|
||||
|
||||
def get_token(request, answer):
|
||||
if not request.session.session_key:
|
||||
request.session.create()
|
||||
payload = '{}:{}'.format(request.session.session_key, answer.pk)
|
||||
signer = SafeDownloadSigner()
|
||||
signer = TimestampSigner()
|
||||
return signer.sign(hashlib.sha1(payload.encode()).hexdigest())
|
||||
|
||||
|
||||
def check_token(request, answer, token):
|
||||
payload = hashlib.sha1('{}:{}'.format(request.session.session_key, answer.pk).encode()).hexdigest()
|
||||
signer = SafeDownloadSigner()
|
||||
signer = TimestampSigner()
|
||||
try:
|
||||
return payload == signer.unsign(token, max_age=3600 * 24)
|
||||
except BadSignature:
|
||||
|
||||
@@ -28,7 +28,7 @@ from django.contrib.auth import login as auth_login
|
||||
from django.contrib.gis import geoip2
|
||||
from django.core.cache import cache
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.timezone import localtime, now, override
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_countries.fields import Country
|
||||
from geoip2.errors import AddressNotFoundError
|
||||
@@ -167,13 +167,13 @@ def handle_login_source(user, request):
|
||||
})
|
||||
if user.known_login_sources.count() > 1:
|
||||
# Do not send on first login or first login after introduction of this feature:
|
||||
with language(user.locale), override(user.timezone):
|
||||
with language(user.locale):
|
||||
mail(
|
||||
user.email,
|
||||
_('New sign-in to your account'),
|
||||
'pretixcontrol/email/login_notice.txt',
|
||||
{
|
||||
'when': date_format(localtime(src.last_seen), 'DATETIME_FORMAT'),
|
||||
'when': date_format(src.last_seen, 'DATETIME_FORMAT'),
|
||||
'agent': src.agent_type,
|
||||
'os': src.os_type,
|
||||
# ua-parser returns "Other" for unidentified desktop devices.
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-30 13:52+0000\n"
|
||||
"POT-Creation-Date: 2026-07-07 09:30+0000\n"
|
||||
"PO-Revision-Date: 2026-07-15 14:20+0000\n"
|
||||
"Last-Translator: Llewelyn Barkhuizen <llewelyn@akademia.ac.za>\n"
|
||||
"Language-Team: Afrikaans <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
@@ -19,6 +19,38 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 2026.7.1\n"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "English"
|
||||
msgstr "Engels"
|
||||
@@ -1169,19 +1201,6 @@ msgstr ""
|
||||
msgid "Download a spreadsheet of all currently registered customer accounts."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/permissions.py
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
msgid "Customers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
msgid "Memberships"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/customers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
@@ -1314,66 +1333,6 @@ msgstr ""
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
msgid "Membership type"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "Purchase ticket"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/forms/questions.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "Start time"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "End time"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/dekodi.py pretix/base/exporters/invoices.py
|
||||
msgctxt "export_category"
|
||||
msgid "Invoices"
|
||||
@@ -2201,6 +2160,30 @@ msgstr ""
|
||||
msgid "Position ID"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/forms/questions.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/modelimport_orders.py pretix/base/modelimport_vouchers.py
|
||||
#: pretix/base/models/items.py pretix/base/models/vouchers.py
|
||||
@@ -2592,6 +2575,12 @@ msgstr ""
|
||||
msgid "Gift card code"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/organizer.py
|
||||
#: pretix/control/forms/event.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/email_setup.html
|
||||
@@ -2705,7 +2694,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/plugins/reports/exporters.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html
|
||||
msgid "Expired"
|
||||
@@ -2871,7 +2860,7 @@ msgid "This combination of credentials is not known to our system."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/forms/auth.py pretix/base/forms/user.py
|
||||
#: pretix/control/views/user.py pretix/presale/forms/customer.py
|
||||
#: pretix/presale/forms/customer.py
|
||||
msgid "For security reasons, please wait 5 minutes before you try again."
|
||||
msgstr ""
|
||||
|
||||
@@ -3794,7 +3783,6 @@ msgstr ""
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py pretix/base/models/vouchers.py
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/views/vouchers.py
|
||||
msgid "Price effect"
|
||||
@@ -4412,8 +4400,8 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py
|
||||
msgid ""
|
||||
"This will be used to let users know if the event is in a different timezone, "
|
||||
"and to let us calculate the local time of a user."
|
||||
"This will be used to let users know if the event is in a different timezone "
|
||||
"and let’s us calculate users’ local times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py pretix/base/models/organizer.py
|
||||
@@ -5708,6 +5696,23 @@ msgstr ""
|
||||
msgid "Number of times this membership can be used in a purchase."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
msgid "Membership type"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/orders.py
|
||||
msgid "pending"
|
||||
msgstr ""
|
||||
@@ -6486,7 +6491,7 @@ msgstr ""
|
||||
msgid "It is currently not possible to create vouchers for add-on products."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"You need to select a specific product or quota if this voucher should "
|
||||
"reserve tickets."
|
||||
@@ -6505,7 +6510,7 @@ msgid ""
|
||||
"usages."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"If you want this voucher to block quota, you need to select a specific date."
|
||||
msgstr ""
|
||||
@@ -6974,12 +6979,6 @@ msgstr ""
|
||||
msgid "This gift card was used in the meantime. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/payment.py
|
||||
msgid ""
|
||||
"This payment provider exists for historical purposes only and is no longer "
|
||||
"usable."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/pdf.py
|
||||
msgid "Ticket code (barcode content)"
|
||||
msgstr ""
|
||||
@@ -7536,6 +7535,11 @@ msgid ""
|
||||
"permissions."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
msgid "Customers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
msgid "Devices"
|
||||
msgstr ""
|
||||
@@ -8661,12 +8665,6 @@ msgid ""
|
||||
"card."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
msgid ""
|
||||
"You cannot change the ticket secret of a position that has been used to "
|
||||
"issue a gift card."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
@@ -10199,11 +10197,11 @@ msgstr ""
|
||||
msgid "We'll show this publicly to allow attendees to contact you."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
msgid "Contact URL"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
msgid ""
|
||||
"If you set this, the footer contact link will point here instead of using "
|
||||
"the email address above. Please note that you still need to add a contact "
|
||||
@@ -11684,7 +11682,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcard.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
@@ -12880,7 +12877,7 @@ msgstr ""
|
||||
msgid "Valid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Paid (or canceled with paid fee)"
|
||||
msgstr ""
|
||||
|
||||
@@ -12904,7 +12901,7 @@ msgstr ""
|
||||
msgid "Cancellations"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Canceled (fully)"
|
||||
msgstr ""
|
||||
|
||||
@@ -13079,22 +13076,6 @@ msgstr ""
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_form.html
|
||||
msgid "Date from"
|
||||
@@ -13132,6 +13113,13 @@ msgstr ""
|
||||
msgid "not yet activated"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
msgid "Memberships"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Has no memberships"
|
||||
msgstr ""
|
||||
@@ -13359,36 +13347,6 @@ msgstr ""
|
||||
msgid "Search email address or subject"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "All sources"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Team actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Customer actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Device actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "User email"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/global_settings.py
|
||||
msgid "Additional footer text"
|
||||
msgstr ""
|
||||
@@ -14566,7 +14524,6 @@ msgstr ""
|
||||
#: pretix/control/forms/renderers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
msgctxt "form_bulk"
|
||||
msgid "change"
|
||||
msgstr ""
|
||||
@@ -14680,53 +14637,6 @@ msgid ""
|
||||
"should show them."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot reduce the maximum number of redemptions to %(max_usages)s, "
|
||||
"because at least one of the selected vouchers has already been redeemed "
|
||||
"%(max_redeemed)s times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"You cannot create a voucher that allows selection of a quota but has no date "
|
||||
"selected."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "The selected quota does not match the selected subevent."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "There is no sufficient quota available to perform this change."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the maximum number of usages in bulk is not supported if any of the "
|
||||
"selected vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgctxt "subevent"
|
||||
msgid ""
|
||||
"Changing the date in bulk is not supported if any of the selected vouchers "
|
||||
"is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the product to a quota is not supported if any of the selected "
|
||||
"vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"This change cannot be completed because not all assigned seats of the "
|
||||
"vouchers are still available"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "Codes"
|
||||
msgstr ""
|
||||
@@ -16432,6 +16342,10 @@ msgstr ""
|
||||
msgid "Account history"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
msgid "Admin sessions"
|
||||
@@ -16700,7 +16614,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/users/create.html
|
||||
#: pretix/control/templates/pretixcontrol/users/form.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html
|
||||
#: pretix/plugins/autocheckin/templates/pretixplugins/autocheckin/add.html
|
||||
@@ -17118,8 +17031,8 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/checkin/checkins.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/index.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/lists.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
#: pretix/control/templates/pretixcontrol/items/question.html
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/index.html
|
||||
@@ -17130,6 +17043,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/teams.html
|
||||
@@ -17264,7 +17178,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html
|
||||
msgid "Select all results on other pages as well"
|
||||
msgstr ""
|
||||
@@ -17820,22 +17733,6 @@ msgstr ""
|
||||
msgid "We found an SPF record on your domain that includes this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Your new DKIM record should be set up as a CNAME record like this:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "We found a DKIM record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Your new DMARC record could look like this:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "We found a DMARC record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Verification"
|
||||
msgstr ""
|
||||
@@ -17996,94 +17893,6 @@ msgid ""
|
||||
"undeletable data, such as orders not performed in test mode."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/delete.html
|
||||
msgid ""
|
||||
"This operation will destroy your event including all configuration, "
|
||||
@@ -18198,6 +18007,69 @@ msgstr ""
|
||||
msgid "Create QR code"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Update comment"
|
||||
@@ -18372,6 +18244,44 @@ msgstr ""
|
||||
msgid "Enable test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "All actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Team actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Customer actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
@@ -19270,20 +19180,6 @@ msgstr ""
|
||||
msgid "More quotas"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
msgid "Open event dashboard"
|
||||
@@ -19294,10 +19190,6 @@ msgctxt "typography"
|
||||
msgid "The quick brown fox jumps over the lazy dog."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
msgid "Specific object selected"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box_paid.html
|
||||
msgid "Quota:"
|
||||
@@ -20312,7 +20204,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/items/quota_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#, python-format
|
||||
msgid "%(number)s selected"
|
||||
msgstr ""
|
||||
@@ -20399,7 +20290,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
msgid "Edit selected"
|
||||
msgstr ""
|
||||
|
||||
@@ -20696,13 +20586,6 @@ msgid ""
|
||||
"the customer account."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
#: pretix/control/views/orders.py
|
||||
msgid ""
|
||||
"Ticket secrets of order positions that have been used to issue a gift card "
|
||||
"can not be changed. Only the link will be changed in this case."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
msgid ""
|
||||
"Removing or splitting this position will also remove or split all add-ons to "
|
||||
@@ -21115,6 +20998,11 @@ msgstr ""
|
||||
msgid "Create a refund"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Cancel transfer"
|
||||
msgstr ""
|
||||
@@ -22191,7 +22079,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Advanced settings"
|
||||
msgstr ""
|
||||
@@ -24348,13 +24235,11 @@ msgid "Copy codes"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Voucher details"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid ""
|
||||
"If you choose \"any product\" for a specific quota and choose to reserve "
|
||||
@@ -24362,10 +24247,6 @@ msgid ""
|
||||
"voucher holder if another quota associated with the product is sold out!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
msgid "Change multiple vouchers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/delete.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Delete voucher"
|
||||
@@ -24705,8 +24586,7 @@ msgstr ""
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"You cannot accept the invitation for \"{}\" as you already are part of this "
|
||||
"team. If you want to add a different user or create a new account, log out "
|
||||
"and click the invitation link again."
|
||||
"team."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/auth.py
|
||||
@@ -25309,30 +25189,6 @@ msgid ""
|
||||
"record."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We could not find a CNAME record pointing to our DKIM key for domain you are "
|
||||
"trying to use. This means that there is a very high change most of the "
|
||||
"emails will be rejected or marked as spam. We strongly recommend setting up "
|
||||
"DKIM through a CNAME record. You can do so through the DNS settings at the "
|
||||
"provider you registered your domain with."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We found a CNAME record for a DKIM key, but it is not pointing to the right "
|
||||
"location. This means that there is a very high chance most of the emails "
|
||||
"will be rejected or marked as spam. You should update the DNS settings of "
|
||||
"your domain."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We did not find DMARC record for your domain. This means that there is a "
|
||||
"very high chance most of the emails will be rejected or marked as spam. You "
|
||||
"should update the DNS settings of your domain."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid "The verification code was incorrect, please try again."
|
||||
msgstr ""
|
||||
@@ -26390,7 +26246,6 @@ msgid "Macao"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/helpers/daterange.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_list.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_week_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/index.html
|
||||
@@ -27578,6 +27433,11 @@ msgstr ""
|
||||
msgid "PayPal account"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
#, python-brace-format
|
||||
msgid "<a target=\"_blank\" rel=\"noopener\" href=\"{docs_url}\">{text}</a>"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
msgid "Click here for a tutorial on how to obtain the required keys"
|
||||
msgstr ""
|
||||
@@ -28212,13 +28072,8 @@ msgstr ""
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"Redirection will only be allowed to URLs that start with one of these "
|
||||
"prefixes. Enter one allowed URL prefix per line. URL prefixes must include a "
|
||||
"slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"All values must be URLs that include at last one slash after the hostname."
|
||||
"prefixes. Enter one or more allowed URL prefix per line. URL prefixes must "
|
||||
"include a slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/sendmail/apps.py
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-30 13:52+0000\n"
|
||||
"POT-Creation-Date: 2026-07-07 09:30+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Automatically generated\n"
|
||||
"Language-Team: none\n"
|
||||
@@ -17,6 +17,38 @@ msgstr ""
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "English"
|
||||
msgstr ""
|
||||
@@ -1167,19 +1199,6 @@ msgstr ""
|
||||
msgid "Download a spreadsheet of all currently registered customer accounts."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/permissions.py
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
msgid "Customers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
msgid "Memberships"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/customers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
@@ -1312,66 +1331,6 @@ msgstr ""
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
msgid "Membership type"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "Purchase ticket"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/forms/questions.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "Start time"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "End time"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/dekodi.py pretix/base/exporters/invoices.py
|
||||
msgctxt "export_category"
|
||||
msgid "Invoices"
|
||||
@@ -2199,6 +2158,30 @@ msgstr ""
|
||||
msgid "Position ID"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/forms/questions.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/modelimport_orders.py pretix/base/modelimport_vouchers.py
|
||||
#: pretix/base/models/items.py pretix/base/models/vouchers.py
|
||||
@@ -2590,6 +2573,12 @@ msgstr ""
|
||||
msgid "Gift card code"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/organizer.py
|
||||
#: pretix/control/forms/event.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/email_setup.html
|
||||
@@ -2703,7 +2692,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/plugins/reports/exporters.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html
|
||||
msgid "Expired"
|
||||
@@ -2869,7 +2858,7 @@ msgid "This combination of credentials is not known to our system."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/forms/auth.py pretix/base/forms/user.py
|
||||
#: pretix/control/views/user.py pretix/presale/forms/customer.py
|
||||
#: pretix/presale/forms/customer.py
|
||||
msgid "For security reasons, please wait 5 minutes before you try again."
|
||||
msgstr ""
|
||||
|
||||
@@ -3792,7 +3781,6 @@ msgstr ""
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py pretix/base/models/vouchers.py
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/views/vouchers.py
|
||||
msgid "Price effect"
|
||||
@@ -4410,8 +4398,8 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py
|
||||
msgid ""
|
||||
"This will be used to let users know if the event is in a different timezone, "
|
||||
"and to let us calculate the local time of a user."
|
||||
"This will be used to let users know if the event is in a different timezone "
|
||||
"and let’s us calculate users’ local times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py pretix/base/models/organizer.py
|
||||
@@ -5706,6 +5694,23 @@ msgstr ""
|
||||
msgid "Number of times this membership can be used in a purchase."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
msgid "Membership type"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/orders.py
|
||||
msgid "pending"
|
||||
msgstr ""
|
||||
@@ -6484,7 +6489,7 @@ msgstr ""
|
||||
msgid "It is currently not possible to create vouchers for add-on products."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"You need to select a specific product or quota if this voucher should "
|
||||
"reserve tickets."
|
||||
@@ -6503,7 +6508,7 @@ msgid ""
|
||||
"usages."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"If you want this voucher to block quota, you need to select a specific date."
|
||||
msgstr ""
|
||||
@@ -6972,12 +6977,6 @@ msgstr ""
|
||||
msgid "This gift card was used in the meantime. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/payment.py
|
||||
msgid ""
|
||||
"This payment provider exists for historical purposes only and is no longer "
|
||||
"usable."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/pdf.py
|
||||
msgid "Ticket code (barcode content)"
|
||||
msgstr ""
|
||||
@@ -7534,6 +7533,11 @@ msgid ""
|
||||
"permissions."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
msgid "Customers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
msgid "Devices"
|
||||
msgstr ""
|
||||
@@ -8659,12 +8663,6 @@ msgid ""
|
||||
"card."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
msgid ""
|
||||
"You cannot change the ticket secret of a position that has been used to "
|
||||
"issue a gift card."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
@@ -10197,11 +10195,11 @@ msgstr ""
|
||||
msgid "We'll show this publicly to allow attendees to contact you."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
msgid "Contact URL"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
msgid ""
|
||||
"If you set this, the footer contact link will point here instead of using "
|
||||
"the email address above. Please note that you still need to add a contact "
|
||||
@@ -11682,7 +11680,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcard.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
@@ -12878,7 +12875,7 @@ msgstr ""
|
||||
msgid "Valid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Paid (or canceled with paid fee)"
|
||||
msgstr ""
|
||||
|
||||
@@ -12902,7 +12899,7 @@ msgstr ""
|
||||
msgid "Cancellations"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Canceled (fully)"
|
||||
msgstr ""
|
||||
|
||||
@@ -13077,22 +13074,6 @@ msgstr ""
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_form.html
|
||||
msgid "Date from"
|
||||
@@ -13130,6 +13111,13 @@ msgstr ""
|
||||
msgid "not yet activated"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
msgid "Memberships"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Has no memberships"
|
||||
msgstr ""
|
||||
@@ -13357,36 +13345,6 @@ msgstr ""
|
||||
msgid "Search email address or subject"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "All sources"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Team actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Customer actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Device actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "User email"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/global_settings.py
|
||||
msgid "Additional footer text"
|
||||
msgstr ""
|
||||
@@ -14564,7 +14522,6 @@ msgstr ""
|
||||
#: pretix/control/forms/renderers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
msgctxt "form_bulk"
|
||||
msgid "change"
|
||||
msgstr ""
|
||||
@@ -14678,53 +14635,6 @@ msgid ""
|
||||
"should show them."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot reduce the maximum number of redemptions to %(max_usages)s, "
|
||||
"because at least one of the selected vouchers has already been redeemed "
|
||||
"%(max_redeemed)s times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"You cannot create a voucher that allows selection of a quota but has no date "
|
||||
"selected."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "The selected quota does not match the selected subevent."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "There is no sufficient quota available to perform this change."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the maximum number of usages in bulk is not supported if any of the "
|
||||
"selected vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgctxt "subevent"
|
||||
msgid ""
|
||||
"Changing the date in bulk is not supported if any of the selected vouchers "
|
||||
"is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the product to a quota is not supported if any of the selected "
|
||||
"vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"This change cannot be completed because not all assigned seats of the "
|
||||
"vouchers are still available"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "Codes"
|
||||
msgstr ""
|
||||
@@ -16430,6 +16340,10 @@ msgstr ""
|
||||
msgid "Account history"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
msgid "Admin sessions"
|
||||
@@ -16698,7 +16612,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/users/create.html
|
||||
#: pretix/control/templates/pretixcontrol/users/form.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html
|
||||
#: pretix/plugins/autocheckin/templates/pretixplugins/autocheckin/add.html
|
||||
@@ -17116,8 +17029,8 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/checkin/checkins.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/index.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/lists.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
#: pretix/control/templates/pretixcontrol/items/question.html
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/index.html
|
||||
@@ -17128,6 +17041,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/teams.html
|
||||
@@ -17262,7 +17176,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html
|
||||
msgid "Select all results on other pages as well"
|
||||
msgstr ""
|
||||
@@ -17818,22 +17731,6 @@ msgstr ""
|
||||
msgid "We found an SPF record on your domain that includes this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Your new DKIM record should be set up as a CNAME record like this:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "We found a DKIM record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Your new DMARC record could look like this:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "We found a DMARC record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Verification"
|
||||
msgstr ""
|
||||
@@ -17994,94 +17891,6 @@ msgid ""
|
||||
"undeletable data, such as orders not performed in test mode."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/delete.html
|
||||
msgid ""
|
||||
"This operation will destroy your event including all configuration, "
|
||||
@@ -18196,6 +18005,69 @@ msgstr ""
|
||||
msgid "Create QR code"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Update comment"
|
||||
@@ -18370,6 +18242,44 @@ msgstr ""
|
||||
msgid "Enable test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "All actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Team actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Customer actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
@@ -19268,20 +19178,6 @@ msgstr ""
|
||||
msgid "More quotas"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
msgid "Open event dashboard"
|
||||
@@ -19292,10 +19188,6 @@ msgctxt "typography"
|
||||
msgid "The quick brown fox jumps over the lazy dog."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
msgid "Specific object selected"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box_paid.html
|
||||
msgid "Quota:"
|
||||
@@ -20310,7 +20202,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/items/quota_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#, python-format
|
||||
msgid "%(number)s selected"
|
||||
msgstr ""
|
||||
@@ -20397,7 +20288,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
msgid "Edit selected"
|
||||
msgstr ""
|
||||
|
||||
@@ -20694,13 +20584,6 @@ msgid ""
|
||||
"the customer account."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
#: pretix/control/views/orders.py
|
||||
msgid ""
|
||||
"Ticket secrets of order positions that have been used to issue a gift card "
|
||||
"can not be changed. Only the link will be changed in this case."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
msgid ""
|
||||
"Removing or splitting this position will also remove or split all add-ons to "
|
||||
@@ -21113,6 +20996,11 @@ msgstr ""
|
||||
msgid "Create a refund"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Cancel transfer"
|
||||
msgstr ""
|
||||
@@ -22189,7 +22077,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Advanced settings"
|
||||
msgstr ""
|
||||
@@ -24346,13 +24233,11 @@ msgid "Copy codes"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Voucher details"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid ""
|
||||
"If you choose \"any product\" for a specific quota and choose to reserve "
|
||||
@@ -24360,10 +24245,6 @@ msgid ""
|
||||
"voucher holder if another quota associated with the product is sold out!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
msgid "Change multiple vouchers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/delete.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Delete voucher"
|
||||
@@ -24703,8 +24584,7 @@ msgstr ""
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"You cannot accept the invitation for \"{}\" as you already are part of this "
|
||||
"team. If you want to add a different user or create a new account, log out "
|
||||
"and click the invitation link again."
|
||||
"team."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/auth.py
|
||||
@@ -25307,30 +25187,6 @@ msgid ""
|
||||
"record."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We could not find a CNAME record pointing to our DKIM key for domain you are "
|
||||
"trying to use. This means that there is a very high change most of the "
|
||||
"emails will be rejected or marked as spam. We strongly recommend setting up "
|
||||
"DKIM through a CNAME record. You can do so through the DNS settings at the "
|
||||
"provider you registered your domain with."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We found a CNAME record for a DKIM key, but it is not pointing to the right "
|
||||
"location. This means that there is a very high chance most of the emails "
|
||||
"will be rejected or marked as spam. You should update the DNS settings of "
|
||||
"your domain."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We did not find DMARC record for your domain. This means that there is a "
|
||||
"very high chance most of the emails will be rejected or marked as spam. You "
|
||||
"should update the DNS settings of your domain."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid "The verification code was incorrect, please try again."
|
||||
msgstr ""
|
||||
@@ -26388,7 +26244,6 @@ msgid "Macao"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/helpers/daterange.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_list.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_week_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/index.html
|
||||
@@ -27576,6 +27431,11 @@ msgstr ""
|
||||
msgid "PayPal account"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
#, python-brace-format
|
||||
msgid "<a target=\"_blank\" rel=\"noopener\" href=\"{docs_url}\">{text}</a>"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
msgid "Click here for a tutorial on how to obtain the required keys"
|
||||
msgstr ""
|
||||
@@ -28210,13 +28070,8 @@ msgstr ""
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"Redirection will only be allowed to URLs that start with one of these "
|
||||
"prefixes. Enter one allowed URL prefix per line. URL prefixes must include a "
|
||||
"slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"All values must be URLs that include at last one slash after the hostname."
|
||||
"prefixes. Enter one or more allowed URL prefix per line. URL prefixes must "
|
||||
"include a slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/sendmail/apps.py
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-30 13:52+0000\n"
|
||||
"POT-Creation-Date: 2026-07-07 09:30+0000\n"
|
||||
"PO-Revision-Date: 2024-12-11 01:00+0000\n"
|
||||
"Last-Translator: Neriman Memmedli <nerim4n@pm.me>\n"
|
||||
"Language-Team: Azerbaijani <https://translate.pretix.eu/projects/pretix/"
|
||||
@@ -19,6 +19,38 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.8.4\n"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "English"
|
||||
msgstr "İngiliscə"
|
||||
@@ -1169,19 +1201,6 @@ msgstr ""
|
||||
msgid "Download a spreadsheet of all currently registered customer accounts."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/permissions.py
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
msgid "Customers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
msgid "Memberships"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/customers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
@@ -1314,66 +1333,6 @@ msgstr ""
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
msgid "Membership type"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "Purchase ticket"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/forms/questions.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "Start time"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "End time"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/dekodi.py pretix/base/exporters/invoices.py
|
||||
msgctxt "export_category"
|
||||
msgid "Invoices"
|
||||
@@ -2201,6 +2160,30 @@ msgstr ""
|
||||
msgid "Position ID"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/forms/questions.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/modelimport_orders.py pretix/base/modelimport_vouchers.py
|
||||
#: pretix/base/models/items.py pretix/base/models/vouchers.py
|
||||
@@ -2592,6 +2575,12 @@ msgstr ""
|
||||
msgid "Gift card code"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/organizer.py
|
||||
#: pretix/control/forms/event.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/email_setup.html
|
||||
@@ -2705,7 +2694,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/plugins/reports/exporters.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html
|
||||
msgid "Expired"
|
||||
@@ -2871,7 +2860,7 @@ msgid "This combination of credentials is not known to our system."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/forms/auth.py pretix/base/forms/user.py
|
||||
#: pretix/control/views/user.py pretix/presale/forms/customer.py
|
||||
#: pretix/presale/forms/customer.py
|
||||
msgid "For security reasons, please wait 5 minutes before you try again."
|
||||
msgstr ""
|
||||
|
||||
@@ -3794,7 +3783,6 @@ msgstr ""
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py pretix/base/models/vouchers.py
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/views/vouchers.py
|
||||
msgid "Price effect"
|
||||
@@ -4412,8 +4400,8 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py
|
||||
msgid ""
|
||||
"This will be used to let users know if the event is in a different timezone, "
|
||||
"and to let us calculate the local time of a user."
|
||||
"This will be used to let users know if the event is in a different timezone "
|
||||
"and let’s us calculate users’ local times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py pretix/base/models/organizer.py
|
||||
@@ -5708,6 +5696,23 @@ msgstr ""
|
||||
msgid "Number of times this membership can be used in a purchase."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
msgid "Membership type"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/orders.py
|
||||
msgid "pending"
|
||||
msgstr ""
|
||||
@@ -6486,7 +6491,7 @@ msgstr ""
|
||||
msgid "It is currently not possible to create vouchers for add-on products."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"You need to select a specific product or quota if this voucher should "
|
||||
"reserve tickets."
|
||||
@@ -6505,7 +6510,7 @@ msgid ""
|
||||
"usages."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"If you want this voucher to block quota, you need to select a specific date."
|
||||
msgstr ""
|
||||
@@ -6974,12 +6979,6 @@ msgstr ""
|
||||
msgid "This gift card was used in the meantime. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/payment.py
|
||||
msgid ""
|
||||
"This payment provider exists for historical purposes only and is no longer "
|
||||
"usable."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/pdf.py
|
||||
msgid "Ticket code (barcode content)"
|
||||
msgstr ""
|
||||
@@ -7536,6 +7535,11 @@ msgid ""
|
||||
"permissions."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
msgid "Customers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
msgid "Devices"
|
||||
msgstr ""
|
||||
@@ -8661,12 +8665,6 @@ msgid ""
|
||||
"card."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
msgid ""
|
||||
"You cannot change the ticket secret of a position that has been used to "
|
||||
"issue a gift card."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
@@ -10199,11 +10197,11 @@ msgstr ""
|
||||
msgid "We'll show this publicly to allow attendees to contact you."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
msgid "Contact URL"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
msgid ""
|
||||
"If you set this, the footer contact link will point here instead of using "
|
||||
"the email address above. Please note that you still need to add a contact "
|
||||
@@ -11684,7 +11682,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcard.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
@@ -12880,7 +12877,7 @@ msgstr ""
|
||||
msgid "Valid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Paid (or canceled with paid fee)"
|
||||
msgstr ""
|
||||
|
||||
@@ -12904,7 +12901,7 @@ msgstr ""
|
||||
msgid "Cancellations"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Canceled (fully)"
|
||||
msgstr ""
|
||||
|
||||
@@ -13079,22 +13076,6 @@ msgstr ""
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_form.html
|
||||
msgid "Date from"
|
||||
@@ -13132,6 +13113,13 @@ msgstr ""
|
||||
msgid "not yet activated"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
msgid "Memberships"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Has no memberships"
|
||||
msgstr ""
|
||||
@@ -13359,36 +13347,6 @@ msgstr ""
|
||||
msgid "Search email address or subject"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "All sources"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Team actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Customer actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Device actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "User email"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/global_settings.py
|
||||
msgid "Additional footer text"
|
||||
msgstr ""
|
||||
@@ -14566,7 +14524,6 @@ msgstr ""
|
||||
#: pretix/control/forms/renderers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
msgctxt "form_bulk"
|
||||
msgid "change"
|
||||
msgstr ""
|
||||
@@ -14680,53 +14637,6 @@ msgid ""
|
||||
"should show them."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot reduce the maximum number of redemptions to %(max_usages)s, "
|
||||
"because at least one of the selected vouchers has already been redeemed "
|
||||
"%(max_redeemed)s times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"You cannot create a voucher that allows selection of a quota but has no date "
|
||||
"selected."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "The selected quota does not match the selected subevent."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "There is no sufficient quota available to perform this change."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the maximum number of usages in bulk is not supported if any of the "
|
||||
"selected vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgctxt "subevent"
|
||||
msgid ""
|
||||
"Changing the date in bulk is not supported if any of the selected vouchers "
|
||||
"is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the product to a quota is not supported if any of the selected "
|
||||
"vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"This change cannot be completed because not all assigned seats of the "
|
||||
"vouchers are still available"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "Codes"
|
||||
msgstr ""
|
||||
@@ -16432,6 +16342,10 @@ msgstr ""
|
||||
msgid "Account history"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
msgid "Admin sessions"
|
||||
@@ -16700,7 +16614,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/users/create.html
|
||||
#: pretix/control/templates/pretixcontrol/users/form.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html
|
||||
#: pretix/plugins/autocheckin/templates/pretixplugins/autocheckin/add.html
|
||||
@@ -17118,8 +17031,8 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/checkin/checkins.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/index.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/lists.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
#: pretix/control/templates/pretixcontrol/items/question.html
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/index.html
|
||||
@@ -17130,6 +17043,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/teams.html
|
||||
@@ -17264,7 +17178,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html
|
||||
msgid "Select all results on other pages as well"
|
||||
msgstr ""
|
||||
@@ -17820,22 +17733,6 @@ msgstr ""
|
||||
msgid "We found an SPF record on your domain that includes this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Your new DKIM record should be set up as a CNAME record like this:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "We found a DKIM record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Your new DMARC record could look like this:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "We found a DMARC record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Verification"
|
||||
msgstr ""
|
||||
@@ -17996,94 +17893,6 @@ msgid ""
|
||||
"undeletable data, such as orders not performed in test mode."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/delete.html
|
||||
msgid ""
|
||||
"This operation will destroy your event including all configuration, "
|
||||
@@ -18198,6 +18007,69 @@ msgstr ""
|
||||
msgid "Create QR code"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Update comment"
|
||||
@@ -18372,6 +18244,44 @@ msgstr ""
|
||||
msgid "Enable test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "All actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Team actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Customer actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
@@ -19270,20 +19180,6 @@ msgstr ""
|
||||
msgid "More quotas"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
msgid "Open event dashboard"
|
||||
@@ -19294,10 +19190,6 @@ msgctxt "typography"
|
||||
msgid "The quick brown fox jumps over the lazy dog."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
msgid "Specific object selected"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box_paid.html
|
||||
msgid "Quota:"
|
||||
@@ -20312,7 +20204,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/items/quota_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#, python-format
|
||||
msgid "%(number)s selected"
|
||||
msgstr ""
|
||||
@@ -20399,7 +20290,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
msgid "Edit selected"
|
||||
msgstr ""
|
||||
|
||||
@@ -20696,13 +20586,6 @@ msgid ""
|
||||
"the customer account."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
#: pretix/control/views/orders.py
|
||||
msgid ""
|
||||
"Ticket secrets of order positions that have been used to issue a gift card "
|
||||
"can not be changed. Only the link will be changed in this case."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
msgid ""
|
||||
"Removing or splitting this position will also remove or split all add-ons to "
|
||||
@@ -21115,6 +20998,11 @@ msgstr ""
|
||||
msgid "Create a refund"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Cancel transfer"
|
||||
msgstr ""
|
||||
@@ -22191,7 +22079,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Advanced settings"
|
||||
msgstr ""
|
||||
@@ -24348,13 +24235,11 @@ msgid "Copy codes"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Voucher details"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid ""
|
||||
"If you choose \"any product\" for a specific quota and choose to reserve "
|
||||
@@ -24362,10 +24247,6 @@ msgid ""
|
||||
"voucher holder if another quota associated with the product is sold out!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
msgid "Change multiple vouchers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/delete.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Delete voucher"
|
||||
@@ -24705,8 +24586,7 @@ msgstr ""
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"You cannot accept the invitation for \"{}\" as you already are part of this "
|
||||
"team. If you want to add a different user or create a new account, log out "
|
||||
"and click the invitation link again."
|
||||
"team."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/auth.py
|
||||
@@ -25309,30 +25189,6 @@ msgid ""
|
||||
"record."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We could not find a CNAME record pointing to our DKIM key for domain you are "
|
||||
"trying to use. This means that there is a very high change most of the "
|
||||
"emails will be rejected or marked as spam. We strongly recommend setting up "
|
||||
"DKIM through a CNAME record. You can do so through the DNS settings at the "
|
||||
"provider you registered your domain with."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We found a CNAME record for a DKIM key, but it is not pointing to the right "
|
||||
"location. This means that there is a very high chance most of the emails "
|
||||
"will be rejected or marked as spam. You should update the DNS settings of "
|
||||
"your domain."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We did not find DMARC record for your domain. This means that there is a "
|
||||
"very high chance most of the emails will be rejected or marked as spam. You "
|
||||
"should update the DNS settings of your domain."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid "The verification code was incorrect, please try again."
|
||||
msgstr ""
|
||||
@@ -26392,7 +26248,6 @@ msgid "Macao"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/helpers/daterange.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_list.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_week_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/index.html
|
||||
@@ -27580,6 +27435,11 @@ msgstr ""
|
||||
msgid "PayPal account"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
#, python-brace-format
|
||||
msgid "<a target=\"_blank\" rel=\"noopener\" href=\"{docs_url}\">{text}</a>"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
msgid "Click here for a tutorial on how to obtain the required keys"
|
||||
msgstr ""
|
||||
@@ -28214,13 +28074,8 @@ msgstr ""
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"Redirection will only be allowed to URLs that start with one of these "
|
||||
"prefixes. Enter one allowed URL prefix per line. URL prefixes must include a "
|
||||
"slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"All values must be URLs that include at last one slash after the hostname."
|
||||
"prefixes. Enter one or more allowed URL prefix per line. URL prefixes must "
|
||||
"include a slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/sendmail/apps.py
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-30 13:52+0000\n"
|
||||
"POT-Creation-Date: 2026-07-07 09:30+0000\n"
|
||||
"PO-Revision-Date: 2026-06-25 14:00+0000\n"
|
||||
"Last-Translator: Kim Lozano <joaquim.lozano@upc.edu>\n"
|
||||
"Language-Team: Catalan <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
@@ -19,6 +19,38 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 2026.6.1\n"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr "Botiga desactivada"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr "S'ha acabat la prevenda"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr "No ha començat la prevenda"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr "En venda"
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "English"
|
||||
msgstr "Anglès"
|
||||
@@ -1342,24 +1374,6 @@ msgstr "Compte de Stripe"
|
||||
msgid "Download a spreadsheet of all currently registered customer accounts."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/permissions.py
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
#, fuzzy
|
||||
#| msgctxt "refund_source"
|
||||
#| msgid "Customer"
|
||||
msgid "Customers"
|
||||
msgstr "Client"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
#, fuzzy
|
||||
#| msgid "Members"
|
||||
msgid "Memberships"
|
||||
msgstr "Membres"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/customers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
@@ -1499,74 +1513,6 @@ msgstr "Si"
|
||||
msgid "No"
|
||||
msgstr "No"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr "Mode de prova"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr "Cancel·lat"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#, fuzzy
|
||||
#| msgid "Members"
|
||||
msgid "Membership type"
|
||||
msgstr "Membres"
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
#, fuzzy
|
||||
#| msgid "Purchased"
|
||||
msgid "Purchase ticket"
|
||||
msgstr "Comprat"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/forms/questions.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr "Data d'inici"
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
#, fuzzy
|
||||
#| msgid "Date"
|
||||
msgid "Start time"
|
||||
msgstr "Data"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr "Data de finalització"
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
#, fuzzy
|
||||
#| msgid "End: %(time)s"
|
||||
msgid "End time"
|
||||
msgstr "Final: %(time)s"
|
||||
|
||||
#: pretix/base/exporters/dekodi.py pretix/base/exporters/invoices.py
|
||||
#, fuzzy
|
||||
#| msgid "Invoices"
|
||||
@@ -2444,6 +2390,30 @@ msgstr "cancel·lat"
|
||||
msgid "Position ID"
|
||||
msgstr "Identificador de la posició"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/forms/questions.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr "Data d'inici"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr "Data de finalització"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/modelimport_orders.py pretix/base/modelimport_vouchers.py
|
||||
#: pretix/base/models/items.py pretix/base/models/vouchers.py
|
||||
@@ -2884,6 +2854,12 @@ msgstr ""
|
||||
msgid "Gift card code"
|
||||
msgstr "Codi del val regal"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr "Mode de prova"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/organizer.py
|
||||
#: pretix/control/forms/event.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/email_setup.html
|
||||
@@ -2997,7 +2973,7 @@ msgstr "Expirat i amb valor"
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/plugins/reports/exporters.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html
|
||||
msgid "Expired"
|
||||
@@ -3183,7 +3159,7 @@ msgid "This combination of credentials is not known to our system."
|
||||
msgstr "El sistema no reconeix aquesta combinació de credencials."
|
||||
|
||||
#: pretix/base/forms/auth.py pretix/base/forms/user.py
|
||||
#: pretix/control/views/user.py pretix/presale/forms/customer.py
|
||||
#: pretix/presale/forms/customer.py
|
||||
msgid "For security reasons, please wait 5 minutes before you try again."
|
||||
msgstr ""
|
||||
"Per raons de seguretat, si us plau espereu 5 minuts abans de tornar-ho a "
|
||||
@@ -4210,7 +4186,6 @@ msgstr "Permet traspassar la quota"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py pretix/base/models/vouchers.py
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/views/vouchers.py
|
||||
msgid "Price effect"
|
||||
@@ -4934,8 +4909,8 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py
|
||||
msgid ""
|
||||
"This will be used to let users know if the event is in a different timezone, "
|
||||
"and to let us calculate the local time of a user."
|
||||
"This will be used to let users know if the event is in a different timezone "
|
||||
"and let’s us calculate users’ local times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py pretix/base/models/organizer.py
|
||||
@@ -6473,6 +6448,25 @@ msgstr ""
|
||||
msgid "Number of times this membership can be used in a purchase."
|
||||
msgstr "Número de vegades que es pot utilitzar aquest val."
|
||||
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr "Cancel·lat"
|
||||
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#, fuzzy
|
||||
#| msgid "Members"
|
||||
msgid "Membership type"
|
||||
msgstr "Membres"
|
||||
|
||||
#: pretix/base/models/orders.py
|
||||
msgid "pending"
|
||||
msgstr "pendent"
|
||||
@@ -7333,7 +7327,7 @@ msgstr "Aquesta variació no pertany a aquest producte."
|
||||
msgid "It is currently not possible to create vouchers for add-on products."
|
||||
msgstr "Actualment no es poden crear vals per a complements de productes."
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"You need to select a specific product or quota if this voucher should "
|
||||
"reserve tickets."
|
||||
@@ -7361,7 +7355,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"El número màxim per comanda no pot ser menor que el número mínim per comanda."
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"If you want this voucher to block quota, you need to select a specific date."
|
||||
msgstr ""
|
||||
@@ -7905,12 +7899,6 @@ msgstr ""
|
||||
msgid "This gift card was used in the meantime. Please try again."
|
||||
msgstr "Aquesta targeta regal ja s'ha fet servir. Si us plau torneu a provar."
|
||||
|
||||
#: pretix/base/payment.py
|
||||
msgid ""
|
||||
"This payment provider exists for historical purposes only and is no longer "
|
||||
"usable."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/pdf.py
|
||||
msgid "Ticket code (barcode content)"
|
||||
msgstr "Codi de tiquet (contingut del codi de barres)"
|
||||
@@ -8561,6 +8549,14 @@ msgid ""
|
||||
"permissions."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
#, fuzzy
|
||||
#| msgctxt "refund_source"
|
||||
#| msgid "Customer"
|
||||
msgid "Customers"
|
||||
msgstr "Client"
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
msgid "Devices"
|
||||
msgstr ""
|
||||
@@ -9953,14 +9949,6 @@ msgid ""
|
||||
"card."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
#, fuzzy
|
||||
#| msgid "You cannot select a quota that belongs to a different event."
|
||||
msgid ""
|
||||
"You cannot change the ticket secret of a position that has been used to "
|
||||
"issue a gift card."
|
||||
msgstr "No podeu seleccionar una quota que pertany a un esdeveniment diferent."
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
@@ -11834,13 +11822,13 @@ msgid "We'll show this publicly to allow attendees to contact you."
|
||||
msgstr ""
|
||||
"Això es mostrarà públicament per permetre que els assistents us contactin."
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
#, fuzzy
|
||||
#| msgid "Contact address"
|
||||
msgid "Contact URL"
|
||||
msgstr "Adreça de contacte"
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
msgid ""
|
||||
"If you set this, the footer contact link will point here instead of using "
|
||||
"the email address above. Please note that you still need to add a contact "
|
||||
@@ -13876,7 +13864,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcard.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
@@ -15316,7 +15303,7 @@ msgstr "Totes les comandes"
|
||||
msgid "Valid orders"
|
||||
msgstr "Comandes pagades"
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Paid (or canceled with paid fee)"
|
||||
msgstr "Paga (o cancel·lat amb tarifa de pagament)"
|
||||
|
||||
@@ -15345,7 +15332,7 @@ msgstr "Pendent o pagat"
|
||||
msgid "Cancellations"
|
||||
msgstr "Cancel·lació"
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#, fuzzy
|
||||
#| msgid "Canceled (paid fee)"
|
||||
msgid "Canceled (fully)"
|
||||
@@ -15559,22 +15546,6 @@ msgstr "La tenda està activa i la pre-venda en marxa"
|
||||
msgid "Inactive"
|
||||
msgstr "Inactiu"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr "No ha començat la prevenda"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr "S'ha acabat la prevenda"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_form.html
|
||||
#, fuzzy
|
||||
@@ -15624,6 +15595,15 @@ msgstr "Inactiu"
|
||||
msgid "not yet activated"
|
||||
msgstr "Inactiu"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
#, fuzzy
|
||||
#| msgid "Members"
|
||||
msgid "Memberships"
|
||||
msgstr "Membres"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#, fuzzy
|
||||
#| msgid "Event end"
|
||||
@@ -15897,42 +15877,6 @@ msgstr "Revocar l'accés"
|
||||
msgid "Search email address or subject"
|
||||
msgstr "Requereix adreces de correu per tiquet"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#, fuzzy
|
||||
#| msgid "All orders"
|
||||
msgid "All sources"
|
||||
msgstr "Totes les comandes"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Team actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Customer actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#, fuzzy
|
||||
#| msgid "Device name"
|
||||
msgid "Device actions"
|
||||
msgstr "Nom del dispositiu"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#, fuzzy
|
||||
#| msgid "Order details"
|
||||
msgid "User email"
|
||||
msgstr "Detalls de la comanda"
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/global_settings.py
|
||||
msgid "Additional footer text"
|
||||
msgstr ""
|
||||
@@ -17262,7 +17206,6 @@ msgstr "Opcional"
|
||||
#: pretix/control/forms/renderers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#, fuzzy
|
||||
#| msgid "Save changes"
|
||||
msgctxt "form_bulk"
|
||||
@@ -17384,65 +17327,6 @@ msgid ""
|
||||
"should show them."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot reduce the maximum number of redemptions to %(max_usages)s, "
|
||||
"because at least one of the selected vouchers has already been redeemed "
|
||||
"%(max_redeemed)s times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "You cannot create a voucher that blocks quota as the selected product or "
|
||||
#| "quota is currently sold out or completely reserved."
|
||||
msgid ""
|
||||
"You cannot create a voucher that allows selection of a quota but has no date "
|
||||
"selected."
|
||||
msgstr ""
|
||||
"No podeu crear un val que bloca la quota ja que el producte o quota "
|
||||
"seleccionats s'han venut o reservat completament."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, fuzzy
|
||||
#| msgid "The selected product does not allow to select a seat."
|
||||
msgid "The selected quota does not match the selected subevent."
|
||||
msgstr "El producte seleccionat no permet triar un seient."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "There is not enough quota available on quota \"{}\" to perform the "
|
||||
#| "operation."
|
||||
msgid "There is no sufficient quota available to perform this change."
|
||||
msgstr "No hi ha prou quota disponible a \"{}\" per realitzar l'operació."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the maximum number of usages in bulk is not supported if any of the "
|
||||
"selected vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgctxt "subevent"
|
||||
msgid ""
|
||||
"Changing the date in bulk is not supported if any of the selected vouchers "
|
||||
"is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the product to a quota is not supported if any of the selected "
|
||||
"vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"This change cannot be completed because not all assigned seats of the "
|
||||
"vouchers are still available"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "Codes"
|
||||
msgstr ""
|
||||
@@ -19390,6 +19274,10 @@ msgstr ""
|
||||
msgid "Account history"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
msgid "Admin sessions"
|
||||
@@ -19675,7 +19563,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/users/create.html
|
||||
#: pretix/control/templates/pretixcontrol/users/form.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html
|
||||
#: pretix/plugins/autocheckin/templates/pretixplugins/autocheckin/add.html
|
||||
@@ -20129,8 +20016,8 @@ msgstr "Esborrar"
|
||||
#: pretix/control/templates/pretixcontrol/checkin/checkins.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/index.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/lists.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
#: pretix/control/templates/pretixcontrol/items/question.html
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/index.html
|
||||
@@ -20141,6 +20028,7 @@ msgstr "Esborrar"
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/teams.html
|
||||
@@ -20292,7 +20180,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html
|
||||
msgid "Select all results on other pages as well"
|
||||
msgstr ""
|
||||
@@ -20936,22 +20823,6 @@ msgstr ""
|
||||
msgid "We found an SPF record on your domain that includes this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Your new DKIM record should be set up as a CNAME record like this:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "We found a DKIM record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Your new DMARC record could look like this:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "We found a DMARC record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
#, fuzzy
|
||||
#| msgid "Verification failed"
|
||||
@@ -21126,94 +20997,6 @@ msgid ""
|
||||
"undeletable data, such as orders not performed in test mode."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/delete.html
|
||||
msgid ""
|
||||
"This operation will destroy your event including all configuration, "
|
||||
@@ -21332,6 +21115,69 @@ msgstr "URL de sistema:"
|
||||
msgid "Create QR code"
|
||||
msgstr "Codi de comanda"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Update comment"
|
||||
@@ -21523,6 +21369,44 @@ msgstr ""
|
||||
msgid "Enable test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "All actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Team actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Customer actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
@@ -22535,20 +22419,6 @@ msgstr ""
|
||||
msgid "More quotas"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr "Botiga desactivada"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr "En venda"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
msgid "Open event dashboard"
|
||||
@@ -22559,12 +22429,6 @@ msgctxt "typography"
|
||||
msgid "The quick brown fox jumps over the lazy dog."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
#, fuzzy
|
||||
#| msgid "Specific seat"
|
||||
msgid "Specific object selected"
|
||||
msgstr "Seient específic"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box_paid.html
|
||||
msgid "Quota:"
|
||||
@@ -23682,7 +23546,6 @@ msgstr "Pot canviar les comandes"
|
||||
#: pretix/control/templates/pretixcontrol/items/quota_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#, python-format
|
||||
msgid "%(number)s selected"
|
||||
msgstr ""
|
||||
@@ -23773,7 +23636,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
msgid "Edit selected"
|
||||
msgstr ""
|
||||
|
||||
@@ -24079,13 +23941,6 @@ msgid ""
|
||||
"the customer account."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
#: pretix/control/views/orders.py
|
||||
msgid ""
|
||||
"Ticket secrets of order positions that have been used to issue a gift card "
|
||||
"can not be changed. Only the link will be changed in this case."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
@@ -24546,6 +24401,11 @@ msgstr ""
|
||||
msgid "Create a refund"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Cancel transfer"
|
||||
msgstr ""
|
||||
@@ -25770,7 +25630,6 @@ msgstr "Pot canviar les comandes"
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Advanced settings"
|
||||
msgstr "Configuració avançada"
|
||||
@@ -28139,13 +27998,11 @@ msgid "Copy codes"
|
||||
msgstr "Copiar codis"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Voucher details"
|
||||
msgstr "Detalls del val"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid ""
|
||||
"If you choose \"any product\" for a specific quota and choose to reserve "
|
||||
@@ -28153,12 +28010,6 @@ msgid ""
|
||||
"voucher holder if another quota associated with the product is sold out!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#, fuzzy
|
||||
#| msgid "Create multiple vouchers"
|
||||
msgid "Change multiple vouchers"
|
||||
msgstr "Crear múltiples vals"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/delete.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Delete voucher"
|
||||
@@ -28522,8 +28373,7 @@ msgstr ""
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"You cannot accept the invitation for \"{}\" as you already are part of this "
|
||||
"team. If you want to add a different user or create a new account, log out "
|
||||
"and click the invitation link again."
|
||||
"team."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/auth.py
|
||||
@@ -29163,30 +29013,6 @@ msgid ""
|
||||
"record."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We could not find a CNAME record pointing to our DKIM key for domain you are "
|
||||
"trying to use. This means that there is a very high change most of the "
|
||||
"emails will be rejected or marked as spam. We strongly recommend setting up "
|
||||
"DKIM through a CNAME record. You can do so through the DNS settings at the "
|
||||
"provider you registered your domain with."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We found a CNAME record for a DKIM key, but it is not pointing to the right "
|
||||
"location. This means that there is a very high chance most of the emails "
|
||||
"will be rejected or marked as spam. You should update the DNS settings of "
|
||||
"your domain."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We did not find DMARC record for your domain. This means that there is a "
|
||||
"very high chance most of the emails will be rejected or marked as spam. You "
|
||||
"should update the DNS settings of your domain."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
#, fuzzy
|
||||
#| msgid "This gift card was used in the meantime. Please try again."
|
||||
@@ -30374,7 +30200,6 @@ msgid "Macao"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/helpers/daterange.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_list.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_week_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/index.html
|
||||
@@ -31714,6 +31539,11 @@ msgstr ""
|
||||
msgid "PayPal account"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
#, python-brace-format
|
||||
msgid "<a target=\"_blank\" rel=\"noopener\" href=\"{docs_url}\">{text}</a>"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
msgid "Click here for a tutorial on how to obtain the required keys"
|
||||
msgstr ""
|
||||
@@ -32439,13 +32269,8 @@ msgstr "URL base de la redirecció"
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"Redirection will only be allowed to URLs that start with one of these "
|
||||
"prefixes. Enter one allowed URL prefix per line. URL prefixes must include a "
|
||||
"slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"All values must be URLs that include at last one slash after the hostname."
|
||||
"prefixes. Enter one or more allowed URL prefix per line. URL prefixes must "
|
||||
"include a slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/sendmail/apps.py
|
||||
@@ -38462,6 +38287,13 @@ msgstr "Kosovo"
|
||||
#~ msgid "Full access"
|
||||
#~ msgstr "Nom complet"
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "You cannot select a quota that belongs to a different event."
|
||||
#~ msgid ""
|
||||
#~ "You cannot cancel a position that has been used to issue a gift card."
|
||||
#~ msgstr ""
|
||||
#~ "No podeu seleccionar una quota que pertany a un esdeveniment diferent."
|
||||
|
||||
#~ msgid "Automatically on payment"
|
||||
#~ msgstr "Automàticament durant el pagament"
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-30 13:52+0000\n"
|
||||
"POT-Creation-Date: 2026-07-07 09:30+0000\n"
|
||||
"PO-Revision-Date: 2026-01-29 19:42+0000\n"
|
||||
"Last-Translator: Jiří Pastrňák <jiri@pastrnak.email>\n"
|
||||
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix/cs/"
|
||||
@@ -19,6 +19,38 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.15.2\n"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr "Obchod vypnut"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr "Předprodej ukončen"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr "Předprodej zatím nezačal"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr "V prodeji"
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "English"
|
||||
msgstr "Angličtina"
|
||||
@@ -1270,19 +1302,6 @@ msgstr "Zákaznické účty"
|
||||
msgid "Download a spreadsheet of all currently registered customer accounts."
|
||||
msgstr "Stažení tabulky všech aktuálně registrovaných zákaznických účtů."
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/permissions.py
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
msgid "Customers"
|
||||
msgstr "Zákazníci"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
msgid "Memberships"
|
||||
msgstr "Členství"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/customers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
@@ -1415,71 +1434,6 @@ msgstr "Ano"
|
||||
msgid "No"
|
||||
msgstr "Ne"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr "Testovací režím"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr "Zrušeno"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
msgid "Membership type"
|
||||
msgstr "Druh členství"
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
#, fuzzy
|
||||
msgid "Purchase ticket"
|
||||
msgstr "Zakoupeno"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/forms/questions.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr "Datum začátku"
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
#, fuzzy
|
||||
#| msgid "Start time from"
|
||||
msgid "Start time"
|
||||
msgstr "Čas začátku od"
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr "Datum konce"
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
#, fuzzy
|
||||
#| msgid "End: %(time)s"
|
||||
msgid "End time"
|
||||
msgstr "Konec: %(time)s"
|
||||
|
||||
#: pretix/base/exporters/dekodi.py pretix/base/exporters/invoices.py
|
||||
msgctxt "export_category"
|
||||
msgid "Invoices"
|
||||
@@ -2335,6 +2289,30 @@ msgstr "zrušeno"
|
||||
msgid "Position ID"
|
||||
msgstr "ID pozice"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/forms/questions.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr "Datum začátku"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr "Datum konce"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/modelimport_orders.py pretix/base/modelimport_vouchers.py
|
||||
#: pretix/base/models/items.py pretix/base/models/vouchers.py
|
||||
@@ -2739,6 +2717,12 @@ msgstr "Stáhněte si tabulku všech transakcí s dárkovými poukazy."
|
||||
msgid "Gift card code"
|
||||
msgstr "kód dárkové poukázky"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr "Testovací režím"
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/organizer.py
|
||||
#: pretix/control/forms/event.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/email_setup.html
|
||||
@@ -2855,7 +2839,7 @@ msgstr "Expirované a s hodnotou"
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/plugins/reports/exporters.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html
|
||||
msgid "Expired"
|
||||
@@ -3023,7 +3007,7 @@ msgid "This combination of credentials is not known to our system."
|
||||
msgstr "Zadané přihlašovací údaje nejsou platné."
|
||||
|
||||
#: pretix/base/forms/auth.py pretix/base/forms/user.py
|
||||
#: pretix/control/views/user.py pretix/presale/forms/customer.py
|
||||
#: pretix/presale/forms/customer.py
|
||||
msgid "For security reasons, please wait 5 minutes before you try again."
|
||||
msgstr ""
|
||||
"Z bezpečnostních důvodů, prosím, počkejte pět minut a potom to zkuste znovu."
|
||||
@@ -3995,7 +3979,6 @@ msgstr "Ignorování kvóty"
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py pretix/base/models/vouchers.py
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/views/vouchers.py
|
||||
msgid "Price effect"
|
||||
@@ -4687,8 +4670,8 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py
|
||||
msgid ""
|
||||
"This will be used to let users know if the event is in a different timezone, "
|
||||
"and to let us calculate the local time of a user."
|
||||
"This will be used to let users know if the event is in a different timezone "
|
||||
"and let’s us calculate users’ local times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py pretix/base/models/organizer.py
|
||||
@@ -6155,6 +6138,23 @@ msgstr ""
|
||||
msgid "Number of times this membership can be used in a purchase."
|
||||
msgstr "Maximální počet využití."
|
||||
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr "Zrušeno"
|
||||
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
msgid "Membership type"
|
||||
msgstr "Druh členství"
|
||||
|
||||
#: pretix/base/models/orders.py
|
||||
msgid "pending"
|
||||
msgstr "chybějící"
|
||||
@@ -6990,7 +6990,7 @@ msgstr "Tato varianta nepatří k tomuto produktu."
|
||||
msgid "It is currently not possible to create vouchers for add-on products."
|
||||
msgstr "V současné době není možné vytvářet poukazy na doplňkové produkty."
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"You need to select a specific product or quota if this voucher should "
|
||||
"reserve tickets."
|
||||
@@ -7013,7 +7013,7 @@ msgid ""
|
||||
"usages."
|
||||
msgstr "Maximální počet použití nesmí být nižší než minimální počet použití."
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"If you want this voucher to block quota, you need to select a specific date."
|
||||
msgstr ""
|
||||
@@ -7536,15 +7536,6 @@ msgstr "Tato dárková karta není organizátorem akce akceptována."
|
||||
msgid "This gift card was used in the meantime. Please try again."
|
||||
msgstr "Tato dárková karta byla mezitím použita. Zkuste to prosím znovu."
|
||||
|
||||
#: pretix/base/payment.py
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "This payment provider does not exist or the respective plugin is disabled."
|
||||
msgid ""
|
||||
"This payment provider exists for historical purposes only and is no longer "
|
||||
"usable."
|
||||
msgstr "Tento poskytovatel plateb neexistuje nebo příslušný plugin je vypnutý."
|
||||
|
||||
#: pretix/base/pdf.py
|
||||
msgid "Ticket code (barcode content)"
|
||||
msgstr "Kód vstupenky (obsah čárkového kódu)"
|
||||
@@ -8150,6 +8141,11 @@ msgid ""
|
||||
"permissions."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
msgid "Customers"
|
||||
msgstr "Zákazníci"
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
msgid "Devices"
|
||||
msgstr "Zařízení"
|
||||
@@ -9477,16 +9473,6 @@ msgid ""
|
||||
"card."
|
||||
msgstr "Cenu pozice, která byla použita k vydání dárkové karty, nelze změnit."
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "You cannot change the price of a position that has been used to issue a "
|
||||
#| "gift card."
|
||||
msgid ""
|
||||
"You cannot change the ticket secret of a position that has been used to "
|
||||
"issue a gift card."
|
||||
msgstr "Cenu pozice, která byla použita k vydání dárkové karty, nelze změnit."
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
@@ -11302,13 +11288,13 @@ msgstr "Kontaktní e-mail"
|
||||
msgid "We'll show this publicly to allow attendees to contact you."
|
||||
msgstr "Tento údaj zobrazíme veřejně, aby vás účastníci mohli kontaktovat."
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
#, fuzzy
|
||||
#| msgid "Contact"
|
||||
msgid "Contact URL"
|
||||
msgstr "Kontakt"
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
msgid ""
|
||||
"If you set this, the footer contact link will point here instead of using "
|
||||
"the email address above. Please note that you still need to add a contact "
|
||||
@@ -13301,7 +13287,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcard.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
@@ -14611,7 +14596,7 @@ msgstr "Všechny objednávky"
|
||||
msgid "Valid orders"
|
||||
msgstr "Platné objednávky"
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Paid (or canceled with paid fee)"
|
||||
msgstr "Zaplaceno (nebo zrušeno se zaplaceným poplatkem)"
|
||||
|
||||
@@ -14635,7 +14620,7 @@ msgstr "Probíhající nebo zaplacené"
|
||||
msgid "Cancellations"
|
||||
msgstr "Storna"
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Canceled (fully)"
|
||||
msgstr "Zrušeno (kompletní)"
|
||||
|
||||
@@ -14815,22 +14800,6 @@ msgstr "Obchod naživo a předprodej běží"
|
||||
msgid "Inactive"
|
||||
msgstr "Neaktivní"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr "Předprodej zatím nezačal"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr "Předprodej ukončen"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_form.html
|
||||
msgid "Date from"
|
||||
@@ -14868,6 +14837,13 @@ msgstr "aktivní"
|
||||
msgid "not yet activated"
|
||||
msgstr "zatím neaktivováno"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
msgid "Memberships"
|
||||
msgstr "Členství"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Has no memberships"
|
||||
msgstr "Nemá žádné členství"
|
||||
@@ -15097,42 +15073,6 @@ msgstr "Odvolaná zařízení"
|
||||
msgid "Search email address or subject"
|
||||
msgstr "Vyžadovat e-mailové adresy na lístek"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr "Zdroj"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#, fuzzy
|
||||
#| msgid "All vouchers"
|
||||
msgid "All sources"
|
||||
msgstr "Všechny poukázky"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Team actions"
|
||||
msgstr "Týmové akce"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Customer actions"
|
||||
msgstr "Zákaznické akce"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#, fuzzy
|
||||
#| msgid "Device status"
|
||||
msgid "Device actions"
|
||||
msgstr "Stav zařízení"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#, fuzzy
|
||||
#| msgid "Order details"
|
||||
msgid "User email"
|
||||
msgstr "Podrobnosti o objednávce"
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr "Všechny uživatelé"
|
||||
|
||||
#: pretix/control/forms/global_settings.py
|
||||
msgid "Additional footer text"
|
||||
msgstr "Další text v zápatí"
|
||||
@@ -16500,7 +16440,6 @@ msgstr "Volitelné"
|
||||
#: pretix/control/forms/renderers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
msgctxt "form_bulk"
|
||||
msgid "change"
|
||||
msgstr "změnit"
|
||||
@@ -16616,65 +16555,6 @@ msgstr ""
|
||||
"Poukázka odpovídá pouze skrytým produktům, ale nezvolili jste, že je mají "
|
||||
"zobrazit."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot reduce the maximum number of redemptions to %(max_usages)s, "
|
||||
"because at least one of the selected vouchers has already been redeemed "
|
||||
"%(max_redeemed)s times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "You cannot create a voucher that blocks quota as the selected product or "
|
||||
#| "quota is currently sold out or completely reserved."
|
||||
msgid ""
|
||||
"You cannot create a voucher that allows selection of a quota but has no date "
|
||||
"selected."
|
||||
msgstr ""
|
||||
"Nelze vytvořit poukaz, který blokuje kvótu, protože vybraný produkt nebo "
|
||||
"kvóta jsou aktuálně vyprodány nebo zcela rezervovány."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, fuzzy
|
||||
#| msgid "The selected product does not allow to select a seat."
|
||||
msgid "The selected quota does not match the selected subevent."
|
||||
msgstr "Vybraný produkt neumožňuje výběr místa."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "There is not enough quota available on quota \"{}\" to perform the "
|
||||
#| "operation."
|
||||
msgid "There is no sufficient quota available to perform this change."
|
||||
msgstr "Na kvótu „{}“ není k dispozici dostatek kvóty k provedení operace."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the maximum number of usages in bulk is not supported if any of the "
|
||||
"selected vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgctxt "subevent"
|
||||
msgid ""
|
||||
"Changing the date in bulk is not supported if any of the selected vouchers "
|
||||
"is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the product to a quota is not supported if any of the selected "
|
||||
"vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"This change cannot be completed because not all assigned seats of the "
|
||||
"vouchers are still available"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "Codes"
|
||||
msgstr "Kupónové kódy"
|
||||
@@ -18533,6 +18413,10 @@ msgstr "Autorizované aplikace"
|
||||
msgid "Account history"
|
||||
msgstr "Historie účtu"
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr "Všechny uživatelé"
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
msgid "Admin sessions"
|
||||
@@ -18811,7 +18695,6 @@ msgstr "Nastavit nové heslo"
|
||||
#: pretix/control/templates/pretixcontrol/users/create.html
|
||||
#: pretix/control/templates/pretixcontrol/users/form.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html
|
||||
#: pretix/plugins/autocheckin/templates/pretixplugins/autocheckin/add.html
|
||||
@@ -19267,8 +19150,8 @@ msgstr "Smazat"
|
||||
#: pretix/control/templates/pretixcontrol/checkin/checkins.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/index.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/lists.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
#: pretix/control/templates/pretixcontrol/items/question.html
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/index.html
|
||||
@@ -19279,6 +19162,7 @@ msgstr "Smazat"
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/teams.html
|
||||
@@ -19413,7 +19297,6 @@ msgstr "Čas"
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html
|
||||
msgid "Select all results on other pages as well"
|
||||
msgstr "Vybrat všechny výsledky i na dalších stránkách"
|
||||
@@ -20129,34 +20012,6 @@ msgid "We found an SPF record on your domain that includes this system. Great!"
|
||||
msgstr ""
|
||||
"Našli jsme záznam SPF na vaší doméně, který obsahuje tento systém. Skvělé!"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
#, fuzzy
|
||||
#| msgid "Your new SPF record could look like this:"
|
||||
msgid "Your new DKIM record should be set up as a CNAME record like this:"
|
||||
msgstr "Váš nový záznam SPF může vypadat takto:"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "We found an SPF record on your domain that includes this system. Great!"
|
||||
msgid "We found a DKIM record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
"Našli jsme záznam SPF na vaší doméně, který obsahuje tento systém. Skvělé!"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
#, fuzzy
|
||||
#| msgid "Your new SPF record could look like this:"
|
||||
msgid "Your new DMARC record could look like this:"
|
||||
msgstr "Váš nový záznam SPF může vypadat takto:"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "We found an SPF record on your domain that includes this system. Great!"
|
||||
msgid "We found a DMARC record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
"Našli jsme záznam SPF na vaší doméně, který obsahuje tento systém. Skvělé!"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Verification"
|
||||
msgstr "Ověřování"
|
||||
@@ -20356,103 +20211,6 @@ msgstr ""
|
||||
"nesmazatelná data, například objednávky, které nebyly provedeny v testovacím "
|
||||
"režimu."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr "Kontrola"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
"Tato akce obsahuje <strong>přeplacené objednávky</strong>, například z "
|
||||
"důvodu duplicitních pokusů o platbu. Měli byste tyto případy zkontrolovat a "
|
||||
"uvažovat možnost vrácení přeplacené částky uživateli."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr "Zobrazit přeplacené objednávky"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
"Tato akce obsahuje <strong>nevyřízené náhrady</strong>, o které byste se "
|
||||
"měli postarat."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr "Zobrazit čekající náhrady"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
"Tato akce obsahuje <strong>vyžádaná zrušení</strong>, o které byste se měli "
|
||||
"postarat."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr "Zobrazit objednávky s požadavkem na zrušení"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
"Tato akce obsahuje <strong>nevyřízená schválení</strong>, o která byste se "
|
||||
"měli postarat."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr "Zobrazit objednávky čekající na schválení"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/delete.html
|
||||
msgid ""
|
||||
"This operation will destroy your event including all configuration, "
|
||||
@@ -20577,6 +20335,78 @@ msgstr "Adresa obchodu:"
|
||||
msgid "Create QR code"
|
||||
msgstr "Vytvořit kód QR"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
"Tato akce obsahuje <strong>přeplacené objednávky</strong>, například z "
|
||||
"důvodu duplicitních pokusů o platbu. Měli byste tyto případy zkontrolovat a "
|
||||
"uvažovat možnost vrácení přeplacené částky uživateli."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr "Zobrazit přeplacené objednávky"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
"Tato akce obsahuje <strong>nevyřízené náhrady</strong>, o které byste se "
|
||||
"měli postarat."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr "Zobrazit čekající náhrady"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
"Tato akce obsahuje <strong>vyžádaná zrušení</strong>, o které byste se měli "
|
||||
"postarat."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr "Zobrazit objednávky s požadavkem na zrušení"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
"Tato akce obsahuje <strong>nevyřízená schválení</strong>, o která byste se "
|
||||
"měli postarat."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr "Zobrazit objednávky čekající na schválení"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Update comment"
|
||||
@@ -20758,6 +20588,44 @@ msgstr ""
|
||||
msgid "Enable test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "All actions"
|
||||
msgstr "Všechny akce"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Team actions"
|
||||
msgstr "Týmové akce"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Customer actions"
|
||||
msgstr "Zákaznické akce"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr "Kontrola"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
@@ -21720,20 +21588,6 @@ msgstr "Žádné termíny"
|
||||
msgid "More quotas"
|
||||
msgstr "Další kvóty"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr "Obchod vypnut"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr "V prodeji"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
msgid "Open event dashboard"
|
||||
@@ -21744,12 +21598,6 @@ msgctxt "typography"
|
||||
msgid "The quick brown fox jumps over the lazy dog."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
#, fuzzy
|
||||
#| msgid "Specific seat"
|
||||
msgid "Specific object selected"
|
||||
msgstr "Přidělené místo"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box_paid.html
|
||||
msgid "Quota:"
|
||||
@@ -22806,7 +22654,6 @@ msgstr "Změnit více zařízení"
|
||||
#: pretix/control/templates/pretixcontrol/items/quota_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#, python-format
|
||||
msgid "%(number)s selected"
|
||||
msgstr "%(number)s vybráno"
|
||||
@@ -22903,7 +22750,6 @@ msgstr "Smazat vybrané"
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
msgid "Edit selected"
|
||||
msgstr "Upravit vybrané"
|
||||
|
||||
@@ -23205,13 +23051,6 @@ msgid ""
|
||||
"the customer account."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
#: pretix/control/views/orders.py
|
||||
msgid ""
|
||||
"Ticket secrets of order positions that have been used to issue a gift card "
|
||||
"can not be changed. Only the link will be changed in this case."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
msgid ""
|
||||
"Removing or splitting this position will also remove or split all add-ons to "
|
||||
@@ -23648,6 +23487,11 @@ msgstr ""
|
||||
msgid "Create a refund"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr "Zdroj"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Cancel transfer"
|
||||
msgstr ""
|
||||
@@ -24795,7 +24639,6 @@ msgstr "Změnit více zařízení"
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Advanced settings"
|
||||
msgstr "Rozšířená nastavení"
|
||||
@@ -27126,13 +26969,11 @@ msgid "Copy codes"
|
||||
msgstr "Kopírovat kódy"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Voucher details"
|
||||
msgstr "Podrobnosti o poukázce"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid ""
|
||||
"If you choose \"any product\" for a specific quota and choose to reserve "
|
||||
@@ -27140,12 +26981,6 @@ msgid ""
|
||||
"voucher holder if another quota associated with the product is sold out!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#, fuzzy
|
||||
#| msgid "Change multiple devices"
|
||||
msgid "Change multiple vouchers"
|
||||
msgstr "Změnit více zařízení"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/delete.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Delete voucher"
|
||||
@@ -27502,8 +27337,7 @@ msgstr ""
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"You cannot accept the invitation for \"{}\" as you already are part of this "
|
||||
"team. If you want to add a different user or create a new account, log out "
|
||||
"and click the invitation link again."
|
||||
"team."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/auth.py
|
||||
@@ -28137,66 +27971,6 @@ msgstr ""
|
||||
"Měli byste aktualizovat nastavení DNS své domény tak, aby zahrnovalo tento "
|
||||
"systém v záznamu SPF."
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "We could not find an SPF record set for the domain you are trying to use. "
|
||||
#| "This means that there is a very high change most of the emails will be "
|
||||
#| "rejected or marked as spam. We strongly recommend setting an SPF record "
|
||||
#| "on the domain. You can do so through the DNS settings at the provider you "
|
||||
#| "registered your domain with."
|
||||
msgid ""
|
||||
"We could not find a CNAME record pointing to our DKIM key for domain you are "
|
||||
"trying to use. This means that there is a very high change most of the "
|
||||
"emails will be rejected or marked as spam. We strongly recommend setting up "
|
||||
"DKIM through a CNAME record. You can do so through the DNS settings at the "
|
||||
"provider you registered your domain with."
|
||||
msgstr ""
|
||||
"Nepodařilo se nám najít záznam SPF nastavený pro doménu, kterou se snažíte "
|
||||
"použít. To znamená, že je velmi vysoká pravděpodobnost, že většina e-mailů "
|
||||
"bude odmítnuta nebo označena jako spam. Důrazně doporučujeme nastavit záznam "
|
||||
"SPF pro danou doménu. Můžete tak učinit prostřednictvím nastavení DNS u "
|
||||
"poskytovatele, u kterého jste doménu zaregistrovali."
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "We found an SPF record set for the domain you are trying to use, but it "
|
||||
#| "does not include this system's email server. This means that there is a "
|
||||
#| "very high chance most of the emails will be rejected or marked as spam. "
|
||||
#| "You should update the DNS settings of your domain to include this system "
|
||||
#| "in the SPF record."
|
||||
msgid ""
|
||||
"We found a CNAME record for a DKIM key, but it is not pointing to the right "
|
||||
"location. This means that there is a very high chance most of the emails "
|
||||
"will be rejected or marked as spam. You should update the DNS settings of "
|
||||
"your domain."
|
||||
msgstr ""
|
||||
"Našli jsme záznam SPF nastavený pro doménu, kterou se snažíte použít, ale "
|
||||
"neobsahuje e-mailový server tohoto systému. To znamená, že je velmi vysoká "
|
||||
"pravděpodobnost, že většina e-mailů bude odmítnuta nebo označena jako spam. "
|
||||
"Měli byste aktualizovat nastavení DNS své domény tak, aby zahrnovalo tento "
|
||||
"systém v záznamu SPF."
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "We found an SPF record set for the domain you are trying to use, but it "
|
||||
#| "does not include this system's email server. This means that there is a "
|
||||
#| "very high chance most of the emails will be rejected or marked as spam. "
|
||||
#| "You should update the DNS settings of your domain to include this system "
|
||||
#| "in the SPF record."
|
||||
msgid ""
|
||||
"We did not find DMARC record for your domain. This means that there is a "
|
||||
"very high chance most of the emails will be rejected or marked as spam. You "
|
||||
"should update the DNS settings of your domain."
|
||||
msgstr ""
|
||||
"Našli jsme záznam SPF nastavený pro doménu, kterou se snažíte použít, ale "
|
||||
"neobsahuje e-mailový server tohoto systému. To znamená, že je velmi vysoká "
|
||||
"pravděpodobnost, že většina e-mailů bude odmítnuta nebo označena jako spam. "
|
||||
"Měli byste aktualizovat nastavení DNS své domény tak, aby zahrnovalo tento "
|
||||
"systém v záznamu SPF."
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid "The verification code was incorrect, please try again."
|
||||
msgstr ""
|
||||
@@ -29299,7 +29073,6 @@ msgid "Macao"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/helpers/daterange.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_list.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_week_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/index.html
|
||||
@@ -30562,6 +30335,11 @@ msgstr ""
|
||||
msgid "PayPal account"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
#, python-brace-format
|
||||
msgid "<a target=\"_blank\" rel=\"noopener\" href=\"{docs_url}\">{text}</a>"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
msgid "Click here for a tutorial on how to obtain the required keys"
|
||||
msgstr ""
|
||||
@@ -31247,13 +31025,8 @@ msgstr "Přesměrování URL"
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"Redirection will only be allowed to URLs that start with one of these "
|
||||
"prefixes. Enter one allowed URL prefix per line. URL prefixes must include a "
|
||||
"slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"All values must be URLs that include at last one slash after the hostname."
|
||||
"prefixes. Enter one or more allowed URL prefix per line. URL prefixes must "
|
||||
"include a slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/sendmail/apps.py
|
||||
@@ -36150,9 +35923,6 @@ msgstr "Přístup k zápisu"
|
||||
msgid "Kosovo"
|
||||
msgstr "Kosovo"
|
||||
|
||||
#~ msgid "All actions"
|
||||
#~ msgstr "Všechny akce"
|
||||
|
||||
#, fuzzy
|
||||
#~| msgid "Account information"
|
||||
#~ msgid "Account invitation"
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-30 13:52+0000\n"
|
||||
"POT-Creation-Date: 2026-07-07 09:30+0000\n"
|
||||
"PO-Revision-Date: 2023-11-14 11:00+0000\n"
|
||||
"Last-Translator: Charliecoleg <DM229135@colegsirgar.ac.uk>\n"
|
||||
"Language-Team: Welsh <https://translate.pretix.eu/projects/pretix/pretix/cy/"
|
||||
@@ -20,6 +20,38 @@ msgstr ""
|
||||
"(n==3) ? 3 :(n==6) ? 4 : 5;\n"
|
||||
"X-Generator: Weblate 5.1.1\n"
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr ""
|
||||
|
||||
#: htmlcov/d_daa1541d0cbf5e2b_dashboards_py.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/_base_settings.py
|
||||
msgid "English"
|
||||
msgstr "Saesneg"
|
||||
@@ -1191,19 +1223,6 @@ msgstr ""
|
||||
msgid "Download a spreadsheet of all currently registered customer accounts."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/permissions.py
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
msgid "Customers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
msgid "Memberships"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/customers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
@@ -1336,66 +1355,6 @@ msgstr ""
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
msgid "Membership type"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "Purchase ticket"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/forms/questions.py
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "Start time"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
|
||||
#: pretix/base/exporters/waitinglist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/customers.py
|
||||
msgid "End time"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/dekodi.py pretix/base/exporters/invoices.py
|
||||
msgctxt "export_category"
|
||||
msgid "Invoices"
|
||||
@@ -2223,6 +2182,30 @@ msgstr ""
|
||||
msgid "Position ID"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/forms/questions.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/rrule.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "Start date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
#: pretix/plugins/checkinlists/exporters.py
|
||||
msgid "End date"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/exporters/waitinglist.py
|
||||
#: pretix/base/modelimport_orders.py pretix/base/modelimport_vouchers.py
|
||||
#: pretix/base/models/items.py pretix/base/models/vouchers.py
|
||||
@@ -2614,6 +2597,12 @@ msgstr ""
|
||||
msgid "Gift card code"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/memberships.py
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/event/live.html
|
||||
msgid "Test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/exporters/orderlist.py pretix/base/models/organizer.py
|
||||
#: pretix/control/forms/event.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/email_setup.html
|
||||
@@ -2727,7 +2716,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/plugins/reports/exporters.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html
|
||||
msgid "Expired"
|
||||
@@ -2893,7 +2882,7 @@ msgid "This combination of credentials is not known to our system."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/forms/auth.py pretix/base/forms/user.py
|
||||
#: pretix/control/views/user.py pretix/presale/forms/customer.py
|
||||
#: pretix/presale/forms/customer.py
|
||||
msgid "For security reasons, please wait 5 minutes before you try again."
|
||||
msgstr ""
|
||||
|
||||
@@ -3822,7 +3811,6 @@ msgstr ""
|
||||
|
||||
#: pretix/base/modelimport_vouchers.py pretix/base/models/vouchers.py
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/views/vouchers.py
|
||||
msgid "Price effect"
|
||||
@@ -4440,8 +4428,8 @@ msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py
|
||||
msgid ""
|
||||
"This will be used to let users know if the event is in a different timezone, "
|
||||
"and to let us calculate the local time of a user."
|
||||
"This will be used to let users know if the event is in a different timezone "
|
||||
"and let’s us calculate users’ local times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/event.py pretix/base/models/organizer.py
|
||||
@@ -5736,6 +5724,23 @@ msgstr ""
|
||||
msgid "Number of times this membership can be used in a purchase."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/memberships.py pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/orders/fragment_order_status.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/overview.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/plugins/reports/exporters.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
msgid "Canceled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/memberships.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html
|
||||
msgid "Membership type"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/orders.py
|
||||
msgid "pending"
|
||||
msgstr ""
|
||||
@@ -6521,7 +6526,7 @@ msgstr ""
|
||||
msgid "It is currently not possible to create vouchers for add-on products."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"You need to select a specific product or quota if this voucher should "
|
||||
"reserve tickets."
|
||||
@@ -6540,7 +6545,7 @@ msgid ""
|
||||
"usages."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/models/vouchers.py pretix/control/forms/vouchers.py
|
||||
#: pretix/base/models/vouchers.py
|
||||
msgid ""
|
||||
"If you want this voucher to block quota, you need to select a specific date."
|
||||
msgstr ""
|
||||
@@ -7009,12 +7014,6 @@ msgstr ""
|
||||
msgid "This gift card was used in the meantime. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/payment.py
|
||||
msgid ""
|
||||
"This payment provider exists for historical purposes only and is no longer "
|
||||
"usable."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/pdf.py
|
||||
msgid "Ticket code (barcode content)"
|
||||
msgstr ""
|
||||
@@ -7578,6 +7577,11 @@ msgid ""
|
||||
"permissions."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
msgid "Customers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/permissions.py pretix/control/navigation.py
|
||||
msgid "Devices"
|
||||
msgstr ""
|
||||
@@ -8717,12 +8721,6 @@ msgid ""
|
||||
"card."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
msgid ""
|
||||
"You cannot change the ticket secret of a position that has been used to "
|
||||
"issue a gift card."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/orders.py
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
@@ -10260,13 +10258,13 @@ msgstr ""
|
||||
msgid "We'll show this publicly to allow attendees to contact you."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
#, fuzzy
|
||||
#| msgid "Content"
|
||||
msgid "Contact URL"
|
||||
msgstr "Cynnwys"
|
||||
|
||||
#: pretix/base/settings.py
|
||||
#: pretix/base/settings.py pretix/control/forms/event.py
|
||||
msgid ""
|
||||
"If you set this, the footer contact link will point here instead of using "
|
||||
"the email address above. Please note that you still need to add a contact "
|
||||
@@ -11753,7 +11751,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_membership.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customers.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcard.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
@@ -12951,7 +12948,7 @@ msgstr ""
|
||||
msgid "Valid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Paid (or canceled with paid fee)"
|
||||
msgstr ""
|
||||
|
||||
@@ -12975,7 +12972,7 @@ msgstr ""
|
||||
msgid "Cancellations"
|
||||
msgstr "Dileadau"
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/plugins/sendmail/forms.py
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Canceled (fully)"
|
||||
msgstr ""
|
||||
|
||||
@@ -13150,22 +13147,6 @@ msgstr ""
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale not started"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
msgid "Presale over"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_form.html
|
||||
msgid "Date from"
|
||||
@@ -13203,6 +13184,13 @@ msgstr ""
|
||||
msgid "not yet activated"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html
|
||||
#: pretix/presale/views/customer.py
|
||||
msgid "Memberships"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Has no memberships"
|
||||
msgstr ""
|
||||
@@ -13430,38 +13418,6 @@ msgstr ""
|
||||
msgid "Search email address or subject"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr "Tarddiad"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "All sources"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Team actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "Customer actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
#, fuzzy
|
||||
#| msgid "Redirection"
|
||||
msgid "Device actions"
|
||||
msgstr "Ailgyfeiriad"
|
||||
|
||||
#: pretix/control/forms/filter.py
|
||||
msgid "User email"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/global_settings.py
|
||||
msgid "Additional footer text"
|
||||
msgstr ""
|
||||
@@ -14649,7 +14605,6 @@ msgstr "Dewisol"
|
||||
#: pretix/control/forms/renderers.py
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
msgctxt "form_bulk"
|
||||
msgid "change"
|
||||
msgstr "newid"
|
||||
@@ -14763,55 +14718,6 @@ msgid ""
|
||||
"should show them."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, python-format
|
||||
msgid ""
|
||||
"You cannot reduce the maximum number of redemptions to %(max_usages)s, "
|
||||
"because at least one of the selected vouchers has already been redeemed "
|
||||
"%(max_redeemed)s times."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"You cannot create a voucher that allows selection of a quota but has no date "
|
||||
"selected."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
#, fuzzy
|
||||
#| msgid "The subevent does not belong to this event."
|
||||
msgid "The selected quota does not match the selected subevent."
|
||||
msgstr "Nid yw'r digwyddiad yn perthyn i'r digwyddiad hwn."
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "There is no sufficient quota available to perform this change."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the maximum number of usages in bulk is not supported if any of the "
|
||||
"selected vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgctxt "subevent"
|
||||
msgid ""
|
||||
"Changing the date in bulk is not supported if any of the selected vouchers "
|
||||
"is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"Changing the product to a quota is not supported if any of the selected "
|
||||
"vouchers is assigned a seat."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid ""
|
||||
"This change cannot be completed because not all assigned seats of the "
|
||||
"vouchers are still available"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/vouchers.py
|
||||
msgid "Codes"
|
||||
msgstr ""
|
||||
@@ -16518,6 +16424,10 @@ msgstr ""
|
||||
msgid "Account history"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
msgid "All users"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/navigation.py
|
||||
#: pretix/control/templates/pretixcontrol/user/staff_session_list.html
|
||||
msgid "Admin sessions"
|
||||
@@ -16786,7 +16696,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/users/create.html
|
||||
#: pretix/control/templates/pretixcontrol/users/form.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html
|
||||
#: pretix/plugins/autocheckin/templates/pretixplugins/autocheckin/add.html
|
||||
@@ -17210,8 +17119,8 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/checkin/checkins.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/index.html
|
||||
#: pretix/control/templates/pretixcontrol/checkin/lists.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
#: pretix/control/templates/pretixcontrol/items/question.html
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/index.html
|
||||
@@ -17222,6 +17131,7 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/giftcards.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/reusable_media.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/teams.html
|
||||
@@ -17356,7 +17266,6 @@ msgstr "Stamp amser"
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html
|
||||
msgid "Select all results on other pages as well"
|
||||
msgstr ""
|
||||
@@ -17927,22 +17836,6 @@ msgstr ""
|
||||
msgid "We found an SPF record on your domain that includes this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Your new DKIM record should be set up as a CNAME record like this:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "We found a DKIM record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Your new DMARC record could look like this:"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "We found a DMARC record on your domain for this system. Great!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
|
||||
msgid "Verification"
|
||||
msgstr ""
|
||||
@@ -18103,94 +17996,6 @@ msgid ""
|
||||
"undeletable data, such as orders not performed in test mode."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/dashboard_partial_warnings.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/delete.html
|
||||
msgid ""
|
||||
"This operation will destroy your event including all configuration, "
|
||||
@@ -18305,6 +18110,69 @@ msgstr ""
|
||||
msgid "Create QR code"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>overpaid orders</strong>, for example due to "
|
||||
"duplicate payment attempts. You should review the cases and consider "
|
||||
"refunding the overpaid amount to the user."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show overpaid orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending refunds</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show pending refunds"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>requested cancellations</strong> that you should "
|
||||
"take care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders requesting cancellation"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>pending approvals</strong> that you should take "
|
||||
"care of."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show orders pending approval"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"This event contains <strong>fully paid orders</strong> that are not marked "
|
||||
"as paid, probably because no quota was left at the time their payment "
|
||||
"arrived. You should review the cases and consider either refunding the "
|
||||
"customer or creating more space."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show affected orders"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid ""
|
||||
"Orders in this event could not be <strong>synced to an external system</"
|
||||
"strong> as configured."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
msgid "Show sync problems"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/index.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Update comment"
|
||||
@@ -18479,6 +18347,44 @@ msgstr ""
|
||||
msgid "Enable test mode"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "All actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Team actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
msgid "Customer actions"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "Personal data was cleared from this log entry."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
msgid "This change was performed by a pretix administrator."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/event/logs_embed.html
|
||||
#: pretix/control/templates/pretixcontrol/includes/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/search/payments.html
|
||||
msgid "Inspect"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html
|
||||
@@ -19396,20 +19302,6 @@ msgstr ""
|
||||
msgid "More quotas"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "Shop disabled"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/views/dashboards.py
|
||||
msgid "On sale"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/events/index.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/detail.html
|
||||
msgid "Open event dashboard"
|
||||
@@ -19420,10 +19312,6 @@ msgctxt "typography"
|
||||
msgid "The quick brown fox jumps over the lazy dog."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
|
||||
msgid "Specific object selected"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box.html
|
||||
#: pretix/control/templates/pretixcontrol/fragment_quota_box_paid.html
|
||||
msgid "Quota:"
|
||||
@@ -20454,7 +20342,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/items/quota_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#, python-format
|
||||
msgid "%(number)s selected"
|
||||
msgstr ""
|
||||
@@ -20545,7 +20432,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/items/quotas.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/devices.html
|
||||
#: pretix/control/templates/pretixcontrol/subevents/index.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/index.html
|
||||
msgid "Edit selected"
|
||||
msgstr ""
|
||||
|
||||
@@ -20842,13 +20728,6 @@ msgid ""
|
||||
"the customer account."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
#: pretix/control/views/orders.py
|
||||
msgid ""
|
||||
"Ticket secrets of order positions that have been used to issue a gift card "
|
||||
"can not be changed. Only the link will be changed in this case."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/change.html
|
||||
msgid ""
|
||||
"Removing or splitting this position will also remove or split all add-ons to "
|
||||
@@ -21263,6 +21142,11 @@ msgstr ""
|
||||
msgid "Create a refund"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
#: pretix/control/templates/pretixcontrol/orders/refunds.html
|
||||
msgid "Source"
|
||||
msgstr "Tarddiad"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/index.html
|
||||
msgid "Cancel transfer"
|
||||
msgstr ""
|
||||
@@ -22353,7 +22237,6 @@ msgstr ""
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Advanced settings"
|
||||
msgstr ""
|
||||
@@ -24534,13 +24417,11 @@ msgid "Copy codes"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Voucher details"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid ""
|
||||
"If you choose \"any product\" for a specific quota and choose to reserve "
|
||||
@@ -24548,10 +24429,6 @@ msgid ""
|
||||
"voucher holder if another quota associated with the product is sold out!"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
|
||||
msgid "Change multiple vouchers"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/delete.html
|
||||
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
|
||||
msgid "Delete voucher"
|
||||
@@ -24893,8 +24770,7 @@ msgstr ""
|
||||
#, python-brace-format
|
||||
msgid ""
|
||||
"You cannot accept the invitation for \"{}\" as you already are part of this "
|
||||
"team. If you want to add a different user or create a new account, log out "
|
||||
"and click the invitation link again."
|
||||
"team."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/auth.py
|
||||
@@ -25505,30 +25381,6 @@ msgid ""
|
||||
"record."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We could not find a CNAME record pointing to our DKIM key for domain you are "
|
||||
"trying to use. This means that there is a very high change most of the "
|
||||
"emails will be rejected or marked as spam. We strongly recommend setting up "
|
||||
"DKIM through a CNAME record. You can do so through the DNS settings at the "
|
||||
"provider you registered your domain with."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We found a CNAME record for a DKIM key, but it is not pointing to the right "
|
||||
"location. This means that there is a very high chance most of the emails "
|
||||
"will be rejected or marked as spam. You should update the DNS settings of "
|
||||
"your domain."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid ""
|
||||
"We did not find DMARC record for your domain. This means that there is a "
|
||||
"very high chance most of the emails will be rejected or marked as spam. You "
|
||||
"should update the DNS settings of your domain."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/views/mailsetup.py
|
||||
msgid "The verification code was incorrect, please try again."
|
||||
msgstr ""
|
||||
@@ -26592,7 +26444,6 @@ msgid "Macao"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/helpers/daterange.py
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_subevent_list.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/fragment_week_calendar.html
|
||||
#: pretix/presale/templates/pretixpresale/organizers/index.html
|
||||
@@ -27789,6 +27640,11 @@ msgstr ""
|
||||
msgid "PayPal account"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
#, python-brace-format
|
||||
msgid "<a target=\"_blank\" rel=\"noopener\" href=\"{docs_url}\">{text}</a>"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/paypal/payment.py pretix/plugins/paypal2/payment.py
|
||||
msgid "Click here for a tutorial on how to obtain the required keys"
|
||||
msgstr ""
|
||||
@@ -28425,13 +28281,8 @@ msgstr "Ailgyfeirio URIs"
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"Redirection will only be allowed to URLs that start with one of these "
|
||||
"prefixes. Enter one allowed URL prefix per line. URL prefixes must include a "
|
||||
"slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/returnurl/views.py
|
||||
msgid ""
|
||||
"All values must be URLs that include at last one slash after the hostname."
|
||||
"prefixes. Enter one or more allowed URL prefix per line. URL prefixes must "
|
||||
"include a slash after the hostname."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/sendmail/apps.py
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-06 15:52+0000\n"
|
||||
"PO-Revision-Date: 2026-07-31 18:00+0000\n"
|
||||
"PO-Revision-Date: 2026-04-22 18:00+0000\n"
|
||||
"Last-Translator: Nikolai <nikolai@lengefeldt.de>\n"
|
||||
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
"da/>\n"
|
||||
@@ -16,7 +16,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 2026.7.1\n"
|
||||
"X-Generator: Weblate 5.17\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js
|
||||
msgid "Marked as paid"
|
||||
@@ -1306,62 +1306,62 @@ msgstr ""
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "January"
|
||||
msgstr "januar"
|
||||
msgstr "Januar"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "February"
|
||||
msgstr "februar"
|
||||
msgstr "Februar"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "March"
|
||||
msgstr "marts"
|
||||
msgstr "Marts"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "April"
|
||||
msgstr "april"
|
||||
msgstr "April"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "May"
|
||||
msgstr "maj"
|
||||
msgstr "Maj"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "June"
|
||||
msgstr "juni"
|
||||
msgstr "Juni"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "July"
|
||||
msgstr "juli"
|
||||
msgstr "Juli"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "August"
|
||||
msgstr "august"
|
||||
msgstr "August"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "September"
|
||||
msgstr "september"
|
||||
msgstr "September"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "October"
|
||||
msgstr "oktober"
|
||||
msgstr "Oktober"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "November"
|
||||
msgstr "november"
|
||||
msgstr "November"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js
|
||||
#: pretix/static/pretixpresale/widget/src/i18n.ts
|
||||
msgid "December"
|
||||
msgstr "december"
|
||||
msgstr "December"
|
||||
|
||||
#~ msgid "iDEAL"
|
||||
#~ msgstr "iDEAL"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -94,8 +94,6 @@ Checkout
|
||||
Chrome
|
||||
Client-ID
|
||||
Client-Secret
|
||||
CNAME
|
||||
CNAME-Eintrag
|
||||
CODE.txt
|
||||
Community-Übersetzungen
|
||||
CONFIRM
|
||||
@@ -125,11 +123,6 @@ Debug-Modus
|
||||
dekodi
|
||||
Desktop-Apps
|
||||
Di
|
||||
DKIM
|
||||
DKIM-Eintrag
|
||||
DKIM-Schlüssel
|
||||
DMARC
|
||||
DMARC-Eintrag
|
||||
Do
|
||||
Downloadformat
|
||||
Dr
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -94,8 +94,6 @@ Checkout
|
||||
Chrome
|
||||
Client-ID
|
||||
Client-Secret
|
||||
CNAME
|
||||
CNAME-Eintrag
|
||||
CODE.txt
|
||||
Community-Übersetzungen
|
||||
CONFIRM
|
||||
@@ -125,11 +123,6 @@ Debug-Modus
|
||||
dekodi
|
||||
Desktop-Apps
|
||||
Di
|
||||
DKIM
|
||||
DKIM-Eintrag
|
||||
DKIM-Schlüssel
|
||||
DMARC
|
||||
DMARC-Eintrag
|
||||
Do
|
||||
Downloadformat
|
||||
Dr
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user