Compare commits

..
Author SHA1 Message Date
Mira Weller 43b9049a12 Fix test cases for checkinlist export 2024-07-12 10:53:37 +02:00
MiraandGitHub 7b16dfefbc New column and sort options for check-in-list export (#4300)
Allow check-in-list export to by sorted by order datetime (Z#23158159)
Add check-in text to export
2024-07-12 10:37:22 +02:00
Richard Schreiber 8a5b13dee9 Waitinglist: show time for subevent in overview 2024-07-09 15:37:51 +02:00
Richard Schreiber d7dde8c23e Fix CSS-color in alert-danger icon 2024-07-09 10:17:20 +02:00
Richard SchreiberandGitHub 1e2f93fbc5 Waitinglist: add time to subevent dropdown when sending vouchers (#4296) 2024-07-09 09:28:19 +02:00
Richard Schreiber 493fc03686 Fix PayPal CSP img-src 2024-07-09 09:26:46 +02:00
8d6d885f6e API: Add various filtering options
* API: Add various filtering options (#23158339)

* fix query-param description

* simplify payment provider qs-filter

---------

Co-authored-by: Richard Schreiber <schreiber@rami.io>
2024-07-08 21:31:54 +02:00
Martin Gross 2aa989c293 PPv2: Do not fail hard on refunds that are based on manually confirmed payments (Fixes: #PRETIXEU-AC1) 2024-07-04 15:12:53 +02:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
06b226f40f Update pillow requirement from ==10.3.* to ==10.4.* (#4280)
Updates the requirements on [pillow](https://github.com/python-pillow/Pillow) to permit the latest version.
- [Release notes](https://github.com/python-pillow/Pillow/releases)
- [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst)
- [Commits](https://github.com/python-pillow/Pillow/compare/10.3.0...10.4.0)

---
updated-dependencies:
- dependency-name: pillow
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-04 14:46:46 +02:00
Raphael MichelandGitHub 73038b0d97 Fix enforcement of restricted plugins (#4286) 2024-07-03 17:14:03 +02:00
Erik LöfmanandRaphael Michel 4513e31f0d Translations: Update Swedish
Currently translated at 63.0% (3585 of 5690 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2024-07-03 17:05:45 +02:00
Raphael MichelandRaphael Michel d34175114b Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (5690 of 5690 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de_Informal/

powered by weblate
2024-07-03 17:05:45 +02:00
Raphael MichelandRaphael Michel b2c71b47ce Translations: Update German
Currently translated at 100.0% (5690 of 5690 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/de/

powered by weblate
2024-07-03 17:05:45 +02:00
Raphael Michel a889abc52b Unify terminology choice Ticketshop (German) 2024-07-03 13:41:09 +02:00
Raphael Michel 8c01b2a469 API: Fix crash in creating variations 2024-07-03 12:37:41 +02:00
Raphael Michel 720c7fd7bb Fix crash in event cloning (PRETIXEU-ABX) 2024-07-03 11:52:57 +02:00
Raphael MichelandGitHub 6ae6eba4de API: Add details of seats (#4282) 2024-07-03 09:48:59 +02:00
Raphael Michel a173e347ea Optimize availability queries 2024-07-02 18:29:44 +02:00
Raphael Michel 94d13e4cdd API: Raise the right validation error (PRETIXEU-ABV) 2024-07-02 17:49:09 +02:00
Raphael Michel e618441231 API: Fix crash expanding variations 2024-07-02 14:44:35 +02:00
Raphael Michel cd57f1f024 API: Fix creation of embedded variations with explicit sales channels 2024-07-02 09:25:19 +02:00
Raphael Michel 075b9c187f Item list: Fix exclusive tax rules 2024-07-02 09:03:57 +02:00
Erik LöfmanandRaphael Michel d9f46cb817 Translations: Update Swedish
Currently translated at 59.2% (3374 of 5690 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/sv/

powered by weblate
2024-07-01 18:24:27 +02:00
Anarion DunedainandRaphael Michel 2892d16861 Translations: Update Polish
Currently translated at 100.0% (5690 of 5690 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/pl/

powered by weblate
2024-07-01 18:24:27 +02:00
NikolaiandRaphael Michel 9128624d68 Translations: Update Danish
Currently translated at 34.8% (1985 of 5690 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2024-07-01 18:24:27 +02:00
Raphael Michel d2cf8f801d Sales channels: Fix update view 2024-07-01 17:50:27 +02:00
Raphael Michel 682d0f886d Fix order change edge case (PRETIXEU-ABH) 2024-07-01 14:39:34 +02:00
Raphael Michel d2cbd41a19 Fix ticket preview (PRETIXEU-ABF) 2024-07-01 14:38:25 +02:00
Raphael Michel 828f4e3168 Fix isort and docs test 2024-07-01 11:46:46 +02:00
56 changed files with 1390 additions and 1183 deletions
+5
View File
@@ -40,6 +40,11 @@ answers list of objects Answers to user
seat objects The assigned seat (or ``null``) seat objects The assigned seat (or ``null``)
├ id integer Internal ID of the seat instance ├ id integer Internal ID of the seat instance
├ name string Human-readable seat name ├ name string Human-readable seat name
├ zone_name string Name of the zone the seat is in
├ row_name string Name/number of the row the seat is in
├ row_label string Additional label of the row (or ``null``)
├ seat_number string Number of the seat within the row
├ seat_label string Additional label of the seat (or ``null``)
└ seat_guid string Identifier of the seat within the seating plan └ seat_guid string Identifier of the seat within the seating plan
===================================== ========================== ======================================================= ===================================== ========================== =======================================================
+2
View File
@@ -96,6 +96,8 @@ Endpoints
:query integer page: The page number in case of a multi-page result set, default is 1 :query integer page: The page number in case of a multi-page result set, default is 1
:query string secret: Only show gift cards with the given secret. :query string secret: Only show gift cards with the given secret.
:query string value: Only show gift cards with the given value.
:query boolean expired: Filter for gift cards that are (not) expired.
:query boolean testmode: Filter for gift cards that are (not) in test mode. :query boolean testmode: Filter for gift cards that are (not) in test mode.
:query boolean include_accepted: Also show gift cards issued by other organizers that are accepted by this organizer. :query boolean include_accepted: Also show gift cards issued by other organizers that are accepted by this organizer.
:query string expand: If you pass ``"owner_ticket"``, the respective field will be shown as a nested value instead of just an ID. :query string expand: If you pass ``"owner_ticket"``, the respective field will be shown as a nested value instead of just an ID.
+1
View File
@@ -164,6 +164,7 @@ Endpoints
} }
:query integer page: The page number in case of a multi-page result set, default is 1 :query integer page: The page number in case of a multi-page result set, default is 1
:query string search: Filter the list by the value of the variation (substring search).
:query boolean active: If set to ``true`` or ``false``, only items with this value for the field ``active`` will be :query boolean active: If set to ``true`` or ``false``, only items with this value for the field ``active`` will be
returned. returned.
:param organizer: The ``slug`` field of the organizer to fetch :param organizer: The ``slug`` field of the organizer to fetch
+1
View File
@@ -392,6 +392,7 @@ Endpoints
} }
:query integer page: The page number in case of a multi-page result set, default is 1 :query integer page: The page number in case of a multi-page result set, default is 1
:query string search: Filter the list by internal name or name of the item (substring search).
:query boolean active: If set to ``true`` or ``false``, only items with this value for the field ``active`` will be :query boolean active: If set to ``true`` or ``false``, only items with this value for the field ``active`` will be
returned. returned.
:query integer category: If set to the ID of a category, only items within that category will be returned. :query integer category: If set to the ID of a category, only items within that category will be returned.
+9 -1
View File
@@ -215,6 +215,11 @@ answers list of objects Answers to user
seat objects The assigned seat. Can be ``null``. seat objects The assigned seat. Can be ``null``.
├ id integer Internal ID of the seat instance ├ id integer Internal ID of the seat instance
├ name string Human-readable seat name ├ name string Human-readable seat name
├ zone_name string Name of the zone the seat is in
├ row_name string Name/number of the row the seat is in
├ row_label string Additional label of the row (or ``null``)
├ seat_number string Number of the seat within the row
├ seat_label string Additional label of the seat (or ``null``)
└ seat_guid string Identifier of the seat within the seating plan └ seat_guid string Identifier of the seat within the seating plan
pdf_data object Data object required for ticket PDF generation. By default, pdf_data object Data object required for ticket PDF generation. By default,
this field is missing. It will be added only if you add the this field is missing. It will be added only if you add the
@@ -455,10 +460,13 @@ List of all orders
:query datetime modified_since: Only return orders that have changed since the given date. Be careful: We only :query datetime modified_since: Only return orders that have changed since the given date. Be careful: We only
recommend using this in combination with ``testmode=false``, since test mode orders can vanish at any time and recommend using this in combination with ``testmode=false``, since test mode orders can vanish at any time and
you will not notice it using this method. you will not notice it using this method.
:query datetime created_since: Only return orders that have been created since the given date. :query datetime created_since: Only return orders that have been created since the given date (inclusive).
:query datetime created_before: Only return orders that have been created before the given date (exclusive).
:query integer subevent: Only return orders with a position that contains this subevent ID. *Warning:* Result will also include orders if they contain mixed subevents, and it will even return orders where the subevent is only contained in a canceled position. :query integer subevent: Only return orders with a position that contains this subevent ID. *Warning:* Result will also include orders if they contain mixed subevents, and it will even return orders where the subevent is only contained in a canceled position.
:query datetime subevent_after: Only return orders that contain a ticket for a subevent taking place after the given date. This is an exclusive after, and it considers the **end** of the subevent (or its start, if the end is not set). :query datetime subevent_after: Only return orders that contain a ticket for a subevent taking place after the given date. This is an exclusive after, and it considers the **end** of the subevent (or its start, if the end is not set).
:query datetime subevent_before: Only return orders that contain a ticket for a subevent taking place after the given date. This is an exclusive before, and it considers the **start** of the subevent. :query datetime subevent_before: Only return orders that contain a ticket for a subevent taking place after the given date. This is an exclusive before, and it considers the **start** of the subevent.
:query string sales_channel: Only return orders with the given sales channel identifier (e.g. ``"web"``).
:query string payment_provider: Only return orders that contain a payment using the given payment provider. Note that this also searches for partial incomplete, or failed payments within the order and is not useful to get a sum of payment amounts without further processing.
:query string exclude: Exclude a field from the output, e.g. ``fees`` or ``positions.downloads``. Can be used as a performance optimization. Can be passed multiple times. :query string exclude: Exclude a field from the output, e.g. ``fees`` or ``positions.downloads``. Can be used as a performance optimization. Can be passed multiple times.
:query string include: Include only the given field in the output, e.g. ``fees`` or ``positions.downloads``. Can be used as a performance optimization. Can be passed multiple times. ``include`` is applied before ``exclude``, so ``exclude`` takes precedence. :query string include: Include only the given field in the output, e.g. ``fees`` or ``positions.downloads``. Can be used as a performance optimization. Can be passed multiple times. ``include`` is applied before ``exclude``, so ``exclude`` takes precedence.
:param organizer: The ``slug`` field of the organizer to fetch :param organizer: The ``slug`` field of the organizer to fetch
+1 -1
View File
@@ -35,7 +35,7 @@ Frontend
-------- --------
.. automodule:: pretix.presale.signals .. automodule:: pretix.presale.signals
:members: html_head, html_footer, footer_link, global_footer_link, front_page_top, front_page_bottom, front_page_bottom_widget, fee_calculation_for_cart, contact_form_fields, question_form_fields, contact_form_fields_overrides, question_form_fields_overrides, checkout_confirm_messages, checkout_confirm_page_content, checkout_all_optional, html_page_header, render_seating_plan, checkout_flow_steps, position_info, position_info_top, item_description, global_html_head, global_html_footer, global_html_page_header :members: html_head, html_footer, footer_link, global_footer_link, front_page_top, front_page_bottom, front_page_bottom_widget, fee_calculation_for_cart, contact_form_fields, question_form_fields, contact_form_fields_overrides, question_form_fields_overrides, checkout_confirm_messages, checkout_confirm_page_content, checkout_all_optional, html_page_header, render_seating_plan, checkout_flow_steps, position_info, position_info_top, item_description, global_html_head, global_html_footer, global_html_page_header, seatingframe_html_head
.. automodule:: pretix.presale.signals .. automodule:: pretix.presale.signals
+1 -1
View File
@@ -17,7 +17,7 @@ The project pretix is split into several components. The main components are:
create and manage their events, items, orders and tickets. create and manage their events, items, orders and tickets.
**presale** **presale**
This is the ticket-shop itself, containing all of the parts visible to the This is the ticket shop itself, containing all of the parts visible to the
end user. Also called "frontend" in parts of this documentation. end user. Also called "frontend" in parts of this documentation.
**api** **api**
+1 -1
View File
@@ -75,7 +75,7 @@ dependencies = [
"paypal-checkout-serversdk==1.0.*", "paypal-checkout-serversdk==1.0.*",
"PyJWT==2.8.*", "PyJWT==2.8.*",
"phonenumberslite==8.13.*", "phonenumberslite==8.13.*",
"Pillow==10.3.*", "Pillow==10.4.*",
"pretix-plugin-build", "pretix-plugin-build",
"protobuf==5.27.*", "protobuf==5.27.*",
"psycopg2-binary", "psycopg2-binary",
+1 -1
View File
@@ -21,8 +21,8 @@
# #
import json import json
from django.core.exceptions import ValidationError
from rest_framework import serializers from rest_framework import serializers
from rest_framework.exceptions import ValidationError
class AsymmetricField(serializers.Field): class AsymmetricField(serializers.Field):
+5 -1
View File
@@ -281,13 +281,17 @@ class EventSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
from pretix.base.plugins import get_all_plugins from pretix.base.plugins import get_all_plugins
plugins_available = { plugins_available = {
p.module for p in get_all_plugins(self.instance) p.module: p for p in get_all_plugins(self.instance)
if not p.name.startswith('.') and getattr(p, 'visible', True) if not p.name.startswith('.') and getattr(p, 'visible', True)
} }
settings_holder = self.instance if self.instance and self.instance.pk else self.context['organizer']
for plugin in value.get('plugins'): for plugin in value.get('plugins'):
if plugin not in plugins_available: if plugin not in plugins_available:
raise ValidationError(_('Unknown plugin: \'{name}\'.').format(name=plugin)) raise ValidationError(_('Unknown plugin: \'{name}\'.').format(name=plugin))
if getattr(plugins_available[plugin], 'restricted', False):
if plugin not in settings_holder.settings.allowed_restricted_plugins:
raise ValidationError(_('Restricted plugin: \'{name}\'.').format(name=plugin))
return value return value
+11 -1
View File
@@ -76,7 +76,9 @@ class InlineItemVariationSerializer(SalesChannelMigrationMixin, I18nAwareModelSe
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['require_membership_types'].queryset = lazy(lambda: self.context['event'].organizer.membership_types.all(), QuerySet) self.fields['require_membership_types'].queryset = lazy(lambda: self.context['event'].organizer.membership_types.all(), QuerySet)
self.fields['limit_sales_channels'].child_relation.queryset = lazy(lambda: self.context['event'].organizer.sales_channels.all(), QuerySet) self.fields['limit_sales_channels'].child_relation.queryset = (
self.context['event'].organizer.sales_channels.all() if 'event' in self.context else SalesChannel.objects.none()
)
def validate_meta_data(self, value): def validate_meta_data(self, value):
for key in value['meta_data'].keys(): for key in value['meta_data'].keys():
@@ -115,11 +117,15 @@ class ItemVariationSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializ
def create(self, validated_data): def create(self, validated_data):
meta_data = validated_data.pop('meta_data', None) meta_data = validated_data.pop('meta_data', None)
require_membership_types = validated_data.pop('require_membership_types', []) require_membership_types = validated_data.pop('require_membership_types', [])
limit_sales_channels = validated_data.pop('limit_sales_channels', [])
variation = ItemVariation.objects.create(**validated_data) variation = ItemVariation.objects.create(**validated_data)
if require_membership_types: if require_membership_types:
variation.require_membership_types.add(*require_membership_types) variation.require_membership_types.add(*require_membership_types)
if limit_sales_channels:
variation.limit_sales_channels.add(*limit_sales_channels)
# Meta data # Meta data
if meta_data is not None: if meta_data is not None:
for key, value in meta_data.items(): for key, value in meta_data.items():
@@ -284,6 +290,7 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
self.fields['require_membership_types'].queryset = self.context['event'].organizer.membership_types.all() self.fields['require_membership_types'].queryset = self.context['event'].organizer.membership_types.all()
self.fields['grant_membership_type'].queryset = self.context['event'].organizer.membership_types.all() self.fields['grant_membership_type'].queryset = self.context['event'].organizer.membership_types.all()
self.fields['limit_sales_channels'].child_relation.queryset = self.context['event'].organizer.sales_channels.all() self.fields['limit_sales_channels'].child_relation.queryset = self.context['event'].organizer.sales_channels.all()
self.fields['variations'].child.fields['limit_sales_channels'].child_relation.queryset = self.context['event'].organizer.sales_channels.all()
def validate(self, data): def validate(self, data):
data = super().validate(data) data = super().validate(data)
@@ -371,10 +378,13 @@ class ItemSerializer(SalesChannelMigrationMixin, I18nAwareModelSerializer):
for variation_data in variations_data: for variation_data in variations_data:
require_membership_types = variation_data.pop('require_membership_types', []) require_membership_types = variation_data.pop('require_membership_types', [])
limit_sales_channels = variation_data.pop('limit_sales_channels', [])
var_meta_data = variation_data.pop('meta_data', {}) var_meta_data = variation_data.pop('meta_data', {})
v = ItemVariation.objects.create(item=item, **variation_data) v = ItemVariation.objects.create(item=item, **variation_data)
if require_membership_types: if require_membership_types:
v.require_membership_types.add(*require_membership_types) v.require_membership_types.add(*require_membership_types)
if limit_sales_channels:
v.limit_sales_channels.add(*limit_sales_channels)
if var_meta_data is not None: if var_meta_data is not None:
for key, value in var_meta_data.items(): for key, value in var_meta_data.items():
+2 -2
View File
@@ -165,7 +165,7 @@ class InlineSeatSerializer(I18nAwareModelSerializer):
class Meta: class Meta:
model = Seat model = Seat
fields = ('id', 'name', 'seat_guid') fields = ('id', 'name', 'seat_guid', 'zone_name', 'row_name', 'row_label', 'seat_label', 'seat_number')
class AnswerSerializer(I18nAwareModelSerializer): class AnswerSerializer(I18nAwareModelSerializer):
@@ -585,7 +585,7 @@ class CheckinListOrderPositionSerializer(OrderPositionSerializer):
self.fields['item'] = ItemSerializer(read_only=True, context=self.context) self.fields['item'] = ItemSerializer(read_only=True, context=self.context)
if 'variation' in self.context['expand']: if 'variation' in self.context['expand']:
self.fields['variation'] = InlineItemVariationSerializer(read_only=True) self.fields['variation'] = InlineItemVariationSerializer(read_only=True, context=self.context)
if 'answers.question' in self.context['expand']: if 'answers.question' in self.context['expand']:
self.fields['answers'].child.fields['question'] = QuestionSerializer(read_only=True) self.fields['answers'].child.fields['question'] = QuestionSerializer(read_only=True)
+1 -1
View File
@@ -406,7 +406,7 @@ def _checkin_list_position_queryset(checkinlists, ignore_status=False, ignore_pr
'item__variations').select_related('item__tax_rule') 'item__variations').select_related('item__tax_rule')
if expand and 'variation' in expand: if expand and 'variation' in expand:
qs = qs.prefetch_related('variation') qs = qs.prefetch_related('variation', 'variation__meta_values')
return qs return qs
+15 -2
View File
@@ -41,6 +41,7 @@ from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled from django_scopes import scopes_disabled
from rest_framework import serializers, views, viewsets from rest_framework import serializers, views, viewsets
from rest_framework.exceptions import PermissionDenied, ValidationError from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.generics import get_object_or_404
from rest_framework.response import Response from rest_framework.response import Response
from pretix.api.auth.permission import EventCRUDPermission from pretix.api.auth.permission import EventCRUDPermission
@@ -162,7 +163,13 @@ class EventViewSet(viewsets.ModelViewSet):
qs = filter_qs_by_attr(qs, self.request) qs = filter_qs_by_attr(qs, self.request)
if 'with_availability_for' in self.request.GET: if 'with_availability_for' in self.request.GET:
qs = Event.annotated(qs, channel=self.request.GET.get('with_availability_for')) qs = Event.annotated(
qs,
channel=get_object_or_404(
self.request.organizer.sales_channels,
identifier=self.request.GET.get('with_availability_for')
)
)
return qs.prefetch_related( return qs.prefetch_related(
'organizer', 'organizer',
@@ -442,7 +449,13 @@ class SubEventViewSet(ConditionalListView, viewsets.ModelViewSet):
qs = filter_qs_by_attr(qs, self.request) qs = filter_qs_by_attr(qs, self.request)
if 'with_availability_for' in self.request.GET: if 'with_availability_for' in self.request.GET:
qs = SubEvent.annotated(qs, channel=self.request.GET.get('with_availability_for')) qs = SubEvent.annotated(
qs,
channel=get_object_or_404(
self.request.organizer.sales_channels,
identifier=self.request.GET.get('with_availability_for')
)
)
return qs.prefetch_related( return qs.prefetch_related(
'event', 'event',
+20
View File
@@ -56,10 +56,17 @@ from pretix.base.models import (
) )
from pretix.base.services.quotas import QuotaAvailability from pretix.base.services.quotas import QuotaAvailability
from pretix.helpers.dicts import merge_dicts from pretix.helpers.dicts import merge_dicts
from pretix.helpers.i18n import i18ncomp
with scopes_disabled(): with scopes_disabled():
class ItemFilter(FilterSet): class ItemFilter(FilterSet):
tax_rate = django_filters.CharFilter(method='tax_rate_qs') tax_rate = django_filters.CharFilter(method='tax_rate_qs')
search = django_filters.CharFilter(method='search_qs')
def search_qs(self, queryset, name, value):
return queryset.filter(
Q(internal_name__icontains=value) | Q(name__icontains=i18ncomp(value))
)
def tax_rate_qs(self, queryset, name, value): def tax_rate_qs(self, queryset, name, value):
if value in ("0", "None", "0.00"): if value in ("0", "None", "0.00"):
@@ -71,6 +78,18 @@ with scopes_disabled():
model = Item model = Item
fields = ['active', 'category', 'admission', 'tax_rate', 'free_price'] fields = ['active', 'category', 'admission', 'tax_rate', 'free_price']
class ItemVariationFilter(FilterSet):
search = django_filters.CharFilter(method='search_qs')
def search_qs(self, queryset, name, value):
return queryset.filter(
Q(value__icontains=i18ncomp(value))
)
class Meta:
model = ItemVariation
fields = ['active']
class ItemViewSet(ConditionalListView, viewsets.ModelViewSet): class ItemViewSet(ConditionalListView, viewsets.ModelViewSet):
serializer_class = ItemSerializer serializer_class = ItemSerializer
@@ -140,6 +159,7 @@ class ItemVariationViewSet(viewsets.ModelViewSet):
serializer_class = ItemVariationSerializer serializer_class = ItemVariationSerializer
queryset = ItemVariation.objects.none() queryset = ItemVariation.objects.none()
filter_backends = (DjangoFilterBackend, TotalOrderingFilter,) filter_backends = (DjangoFilterBackend, TotalOrderingFilter,)
filterset_class = ItemVariationFilter
ordering_fields = ('id', 'position') ordering_fields = ('id', 'position')
ordering = ('id',) ordering = ('id',)
permission = None permission = None
+8
View File
@@ -108,6 +108,7 @@ with scopes_disabled():
status = django_filters.CharFilter(field_name='status', lookup_expr='iexact') status = django_filters.CharFilter(field_name='status', lookup_expr='iexact')
modified_since = django_filters.IsoDateTimeFilter(field_name='last_modified', lookup_expr='gte') modified_since = django_filters.IsoDateTimeFilter(field_name='last_modified', lookup_expr='gte')
created_since = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='gte') created_since = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='gte')
created_before = django_filters.IsoDateTimeFilter(field_name='datetime', lookup_expr='lt')
subevent_after = django_filters.IsoDateTimeFilter(method='subevent_after_qs') subevent_after = django_filters.IsoDateTimeFilter(method='subevent_after_qs')
subevent_before = django_filters.IsoDateTimeFilter(method='subevent_before_qs') subevent_before = django_filters.IsoDateTimeFilter(method='subevent_before_qs')
search = django_filters.CharFilter(method='search_qs') search = django_filters.CharFilter(method='search_qs')
@@ -115,6 +116,8 @@ with scopes_disabled():
variation = django_filters.CharFilter(field_name='all_positions', lookup_expr='variation_id', distinct=True) variation = django_filters.CharFilter(field_name='all_positions', lookup_expr='variation_id', distinct=True)
subevent = django_filters.CharFilter(field_name='all_positions', lookup_expr='subevent_id', distinct=True) subevent = django_filters.CharFilter(field_name='all_positions', lookup_expr='subevent_id', distinct=True)
customer = django_filters.CharFilter(field_name='customer__identifier') customer = django_filters.CharFilter(field_name='customer__identifier')
sales_channel = django_filters.CharFilter(field_name='sales_channel__identifier')
payment_provider = django_filters.CharFilter(method='provider_qs')
class Meta: class Meta:
model = Order model = Order
@@ -138,6 +141,11 @@ with scopes_disabled():
) )
return qs return qs
def provider_qs(self, qs, name, value):
return qs.filter(Exists(
OrderPayment.objects.filter(order=OuterRef('pk'), provider=value)
))
def subevent_before_qs(self, qs, name, value): def subevent_before_qs(self, qs, name, value):
if getattr(self.request, 'event', None): if getattr(self.request, 'event', None):
subevents = self.request.event.subevents subevents = self.request.event.subevents
+10 -1
View File
@@ -24,10 +24,11 @@ from decimal import Decimal
import django_filters import django_filters
from django.contrib.auth.hashers import make_password from django.contrib.auth.hashers import make_password
from django.db import transaction from django.db import transaction
from django.db.models import OuterRef, Subquery, Sum from django.db.models import OuterRef, Q, Subquery, Sum
from django.db.models.functions import Coalesce from django.db.models.functions import Coalesce
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.timezone import now
from django_filters.rest_framework import DjangoFilterBackend, FilterSet from django_filters.rest_framework import DjangoFilterBackend, FilterSet
from django_scopes import scopes_disabled from django_scopes import scopes_disabled
from rest_framework import mixins, serializers, status, views, viewsets from rest_framework import mixins, serializers, status, views, viewsets
@@ -136,11 +137,19 @@ class SeatingPlanViewSet(viewsets.ModelViewSet):
with scopes_disabled(): with scopes_disabled():
class GiftCardFilter(FilterSet): class GiftCardFilter(FilterSet):
secret = django_filters.CharFilter(field_name='secret', lookup_expr='iexact') secret = django_filters.CharFilter(field_name='secret', lookup_expr='iexact')
expired = django_filters.BooleanFilter(method='expired_qs')
value = django_filters.NumberFilter(field_name='cached_value')
class Meta: class Meta:
model = GiftCard model = GiftCard
fields = ['secret', 'testmode'] fields = ['secret', 'testmode']
def expired_qs(self, qs, name, value):
if value:
return qs.filter(expires__isnull=False, expires__lt=now())
else:
return qs.filter(Q(expires__isnull=True) | Q(expires__gte=now()))
class GiftCardViewSet(viewsets.ModelViewSet): class GiftCardViewSet(viewsets.ModelViewSet):
serializer_class = GiftCardSerializer serializer_class = GiftCardSerializer
@@ -1,6 +1,7 @@
# Generated by Django 4.2.8 on 2024-07-01 09:26 # Generated by Django 4.2.8 on 2024-07-01 09:26
from django.db import migrations, models from django.db import migrations, models
import pretix.base.models.orders import pretix.base.models.orders
+18 -7
View File
@@ -304,10 +304,13 @@ class EventMixin:
return safe_string(json.dumps(eventdict)) return safe_string(json.dumps(eventdict))
@classmethod @classmethod
def annotated(cls, qs, channel='web', voucher=None): def annotated(cls, qs, channel, voucher=None):
from pretix.base.models import Item, ItemVariation, Quota # Channel can currently be a SalesChannel or a str, since we need that compatibility, but a SalesChannel
# makes the query SIGNIFICANTLY faster
from pretix.base.models import Item, ItemVariation, Quota, SalesChannel
assert isinstance(channel, (SalesChannel, str))
assert isinstance(channel, str)
sq_active_item = Item.objects.using(settings.DATABASE_REPLICA).filter_available(channel=channel, voucher=voucher).filter( sq_active_item = Item.objects.using(settings.DATABASE_REPLICA).filter_available(channel=channel, voucher=voucher).filter(
Q(variations__isnull=True) Q(variations__isnull=True)
& Q(quotas__pk=OuterRef('pk')) & Q(quotas__pk=OuterRef('pk'))
@@ -317,18 +320,23 @@ class EventMixin:
q_variation = ( q_variation = (
Q(active=True) Q(active=True)
& Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
& Q(Q(available_from__isnull=True) | Q(available_from__lte=time_machine_now())) & Q(Q(available_from__isnull=True) | Q(available_from__lte=time_machine_now()))
& Q(Q(available_until__isnull=True) | Q(available_until__gte=time_machine_now())) & Q(Q(available_until__isnull=True) | Q(available_until__gte=time_machine_now()))
& Q(item__active=True) & Q(item__active=True)
& Q(Q(item__available_from__isnull=True) | Q(item__available_from__lte=time_machine_now())) & Q(Q(item__available_from__isnull=True) | Q(item__available_from__lte=time_machine_now()))
& Q(Q(item__available_until__isnull=True) | Q(item__available_until__gte=time_machine_now())) & Q(Q(item__available_until__isnull=True) | Q(item__available_until__gte=time_machine_now()))
& Q(Q(item__category__isnull=True) | Q(item__category__is_addon=False)) & Q(Q(item__category__isnull=True) | Q(item__category__is_addon=False))
& Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__identifier=channel))
& Q(item__require_bundling=False) & Q(item__require_bundling=False)
& Q(quotas__pk=OuterRef('pk')) & Q(quotas__pk=OuterRef('pk'))
) )
if isinstance(channel, str):
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__identifier=channel))
else:
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels=channel))
if voucher: if voucher:
if voucher.variation_id: if voucher.variation_id:
q_variation &= Q(pk=voucher.variation_id) q_variation &= Q(pk=voucher.variation_id)
@@ -962,7 +970,7 @@ class Event(EventMixin, LoggedModel):
): ):
c_items = list(d.condition_limit_products.all()) c_items = list(d.condition_limit_products.all())
b_items = list(d.benefit_limit_products.all()) b_items = list(d.benefit_limit_products.all())
limit_sales_channels = list(v.limit_sales_channels.all()) limit_sales_channels = list(d.limit_sales_channels.all())
d.pk = None d.pk = None
d.event = self d.event = self
d._prefetched_objects_cache = {} d._prefetched_objects_cache = {}
@@ -1536,8 +1544,11 @@ class SubEvent(EventMixin, LoggedModel):
return qs_annotated return qs_annotated
@classmethod @classmethod
def annotated(cls, qs, channel='web', voucher=None): def annotated(cls, qs, channel, voucher=None):
from .items import SubEventItem, SubEventItemVariation from .items import SubEventItem, SubEventItemVariation
from .organizer import SalesChannel
assert isinstance(channel, (str, SalesChannel))
qs = super().annotated(qs, channel, voucher=voucher) qs = super().annotated(qs, channel, voucher=voucher)
qs = qs.annotate( qs = qs.annotate(
+10 -2
View File
@@ -271,16 +271,24 @@ class SubEventItemVariation(models.Model):
def filter_available(qs, channel='web', voucher=None, allow_addons=False): def filter_available(qs, channel='web', voucher=None, allow_addons=False):
assert isinstance(channel, str) # Channel can currently be a SalesChannel or a str, since we need that compatibility, but a SalesChannel
# makes the query SIGNIFICANTLY faster
from .organizer import SalesChannel
assert isinstance(channel, (SalesChannel, str))
q = ( q = (
# IMPORTANT: If this is updated, also update the ItemVariation query # IMPORTANT: If this is updated, also update the ItemVariation query
# in models/event.py: EventMixin.annotated() # in models/event.py: EventMixin.annotated()
Q(active=True) Q(active=True)
& Q(Q(available_from__isnull=True) | Q(available_from__lte=time_machine_now()) | Q(available_from_mode='info')) & Q(Q(available_from__isnull=True) | Q(available_from__lte=time_machine_now()) | Q(available_from_mode='info'))
& Q(Q(available_until__isnull=True) | Q(available_until__gte=time_machine_now()) | Q(available_until_mode='info')) & Q(Q(available_until__isnull=True) | Q(available_until__gte=time_machine_now()) | Q(available_until_mode='info'))
& Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
& Q(require_bundling=False) & Q(require_bundling=False)
) )
if isinstance(channel, str):
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
else:
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
if not allow_addons: if not allow_addons:
q &= Q(Q(category__isnull=True) | Q(category__is_addon=False)) q &= Q(Q(category__isnull=True) | Q(category__is_addon=False))
+1 -1
View File
@@ -2042,7 +2042,7 @@ class OrderChangeManager:
# This also prevents accidental removal through the UI because a hidden product will no longer # This also prevents accidental removal through the UI because a hidden product will no longer
# be part of the input. # be part of the input.
(a.variation and a.variation.unavailability_reason(has_voucher=True, subevent=a.subevent)) (a.variation and a.variation.unavailability_reason(has_voucher=True, subevent=a.subevent))
or (a.variation and self.order.sales_channel not in a.variation.sales_channels) or (a.variation and not a.variation.all_sales_channels and not a.variation.limit_sales_channels.contains(self.order.sales_channel))
or a.item.unavailability_reason(has_voucher=True, subevent=a.subevent) or a.item.unavailability_reason(has_voucher=True, subevent=a.subevent)
or ( or (
not item.all_sales_channels and not item.all_sales_channels and
+1
View File
@@ -105,6 +105,7 @@ def preview(event: int, provider: str):
order = event.orders.create(status=Order.STATUS_PENDING, datetime=now(), order = event.orders.create(status=Order.STATUS_PENDING, datetime=now(),
email='sample@pretix.eu', email='sample@pretix.eu',
locale=event.settings.locale, locale=event.settings.locale,
sales_channel=event.organizer.sales_channels.get(identifier="web"),
expires=now(), code="PREVIEW1234", total=119) expires=now(), code="PREVIEW1234", total=119)
scheme = PERSON_NAME_SCHEMES[event.settings.name_scheme] scheme = PERSON_NAME_SCHEMES[event.settings.name_scheme]
@@ -136,9 +136,15 @@
{% if i.tax_rule and i.default_price %} {% if i.tax_rule and i.default_price %}
<br/> <br/>
<small class="text-muted"> <small class="text-muted">
{% blocktrans trimmed with rate=i.tax_rule.rate|floatformat:-2 taxname=i.tax_rule.name|default:s_taxes %} {% if not i.tax_rule.price_includes_tax %}
incl. {{ rate }}% {{ taxname }} {% blocktrans trimmed with rate=i.tax_rule.rate|floatformat:-2 taxname=i.tax_rule.name %}
{% endblocktrans %} <strong>plus</strong> {{ rate }}% {{ taxname }}
{% endblocktrans %}
{% else %}
{% blocktrans trimmed with rate=i.tax_rule.rate|floatformat:-2 taxname=i.tax_rule.name|default:s_taxes %}
incl. {{ rate }}% {{ taxname }}
{% endblocktrans %}
{% endif %}
</small> </small>
{% endif %} {% endif %}
</td> </td>
@@ -57,7 +57,7 @@
{% for se in request.event.subevents.all %} {% for se in request.event.subevents.all %}
<option value="{{ se.id }}" <option value="{{ se.id }}"
{% if request.GET.subevent|add:0 == se.id %}selected="selected"{% endif %}> {% if request.GET.subevent|add:0 == se.id %}selected="selected"{% endif %}>
{{ se.name }} {{ se.get_date_range_display }} {{ se }}
</option> </option>
{% endfor %} {% endfor %}
</select> </select>
@@ -119,7 +119,7 @@
{% for se in request.event.subevents.all %} {% for se in request.event.subevents.all %}
<option value="{{ se.id }}" <option value="{{ se.id }}"
{% if request.GET.subevent|add:0 == se.id %}selected="selected"{% endif %}> {% if request.GET.subevent|add:0 == se.id %}selected="selected"{% endif %}>
{{ se.name }} {{ se.get_date_range_display }} {{ se }}
</option> </option>
{% endfor %} {% endfor %}
</select> </select>
@@ -195,7 +195,7 @@
{% endif %} {% endif %}
</td> </td>
{% if request.event.has_subevents %} {% if request.event.has_subevents %}
<td>{{ e.subevent.name }} {{ e.subevent.get_date_range_display }}</td> <td>{{ e.subevent }}</td>
{% endif %} {% endif %}
<td> <td>
{{ e.created|date:"SHORT_DATETIME_FORMAT" }} {{ e.created|date:"SHORT_DATETIME_FORMAT" }}
+1 -1
View File
@@ -400,7 +400,7 @@ class EventPlugins(EventSettingsViewMixin, EventPermissionRequiredMixin, Templat
if key.startswith("plugin:"): if key.startswith("plugin:"):
module = key.split(":")[1] module = key.split(":")[1]
if value == "enable" and module in plugins_available: if value == "enable" and module in plugins_available:
if getattr(plugins_available[module].app, 'restricted', False): if getattr(plugins_available[module], 'restricted', False):
if module not in request.event.settings.allowed_restricted_plugins: if module not in request.event.settings.allowed_restricted_plugins:
continue continue
+1 -1
View File
@@ -103,7 +103,7 @@ class ItemList(ListView):
def get_queryset(self): def get_queryset(self):
return Item.objects.filter( return Item.objects.filter(
event=self.request.event event=self.request.event
).annotate( ).select_related("tax_rule").annotate(
var_count=Count('variations') var_count=Count('variations')
).prefetch_related("category", "limit_sales_channels").order_by( ).prefetch_related("category", "limit_sales_channels").order_by(
F('category__position').asc(nulls_first=True), F('category__position').asc(nulls_first=True),
+1 -1
View File
@@ -3161,7 +3161,7 @@ class ChannelUpdateView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMix
} }
def form_valid(self, form): def form_valid(self, form):
if form.has_changed() or self.formset.has_changed(): if form.has_changed():
self.object.log_action('pretix.saleschannel.changed', user=self.request.user, data={ self.object.log_action('pretix.saleschannel.changed', user=self.request.user, data={
k: getattr(self.object, k) k: getattr(self.object, k)
for k in form.changed_data for k in form.changed_data
File diff suppressed because it is too large Load Diff
+20 -20
View File
@@ -5,7 +5,7 @@ msgstr ""
"Project-Id-Version: 1\n" "Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-30 18:55+0000\n" "POT-Creation-Date: 2024-06-30 18:55+0000\n"
"PO-Revision-Date: 2024-06-30 21:07+0000\n" "PO-Revision-Date: 2024-07-02 19:00+0000\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n" "Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/de/" "Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/de/"
">\n" ">\n"
@@ -3536,7 +3536,7 @@ msgstr "Sie können keinen Ticketcode verwenden, der bereits existiert."
#: pretix/base/modelimport_orders.py:490 #: pretix/base/modelimport_orders.py:490
msgid "Please enter a valid language code." msgid "Please enter a valid language code."
msgstr "Bitte geben Sie einen gültigen Sprachcode ein." msgstr "Bitte einen gültigen Sprachcode eingeben."
#: pretix/base/modelimport_orders.py:558 pretix/base/modelimport_orders.py:560 #: pretix/base/modelimport_orders.py:558 pretix/base/modelimport_orders.py:560
msgid "Please enter a valid sales channel." msgid "Please enter a valid sales channel."
@@ -9608,7 +9608,7 @@ msgstr ""
#: pretix/base/settings.py:1346 #: pretix/base/settings.py:1346
msgid "Ask search engines not to index the ticket shop" msgid "Ask search engines not to index the ticket shop"
msgstr "Der Ticket-Shop soll von Suchmaschinen nicht indiziert werden" msgstr "Der Ticketshop soll von Suchmaschinen nicht indiziert werden"
#: pretix/base/settings.py:1355 #: pretix/base/settings.py:1355
msgid "Show variations of a product expanded by default" msgid "Show variations of a product expanded by default"
@@ -10874,7 +10874,7 @@ msgstr ""
"Sie haben sich auf die Warteliste für {event} \n" "Sie haben sich auf die Warteliste für {event} \n"
"für das Produkt {product} eingetragen.\n" "für das Produkt {product} eingetragen.\n"
"\n" "\n"
"Wir haben nun ein Ticket für Sie! Sie können es in unserem Ticket-Shop " "Wir haben nun ein Ticket für Sie! Sie können es in unserem Ticketshop "
"erwerben,\n" "erwerben,\n"
"indem Sie in den nächsten {hours} Stunden den folgenden Gutscheincode " "indem Sie in den nächsten {hours} Stunden den folgenden Gutscheincode "
"eingeben:\n" "eingeben:\n"
@@ -11971,7 +11971,7 @@ msgid ""
"If you just configured this as a domain for your ticket shop, you now need " "If you just configured this as a domain for your ticket shop, you now need "
"to set this up as a \"custom domain\" in your organizer account." "to set this up as a \"custom domain\" in your organizer account."
msgstr "" msgstr ""
"Wenn Sie gerade diese Domain für Ihren Ticket-Shop eingerichtet haben, " "Wenn Sie gerade diese Domain für Ihren Ticketshop eingerichtet haben, "
"müssen Sie diese nun in Ihrem Veranstalterkonto als \"eigene Domain\" " "müssen Sie diese nun in Ihrem Veranstalterkonto als \"eigene Domain\" "
"eintragen." "eintragen."
@@ -18403,7 +18403,7 @@ msgid ""
"You can instead take your shop offline. This will hide it from everyone " "You can instead take your shop offline. This will hide it from everyone "
"except from the organizer teams you configured to have access to the event." "except from the organizer teams you configured to have access to the event."
msgstr "" msgstr ""
"Sie können stattdessen den Ticket-Shop abschalten. Dies wird die " "Sie können stattdessen den Ticketshop abschalten. Dies wird die "
"Veranstaltung vor allen außer den zugewiesenen Veranstalter-Teams verstecken." "Veranstaltung vor allen außer den zugewiesenen Veranstalter-Teams verstecken."
#: pretix/control/templates/pretixcontrol/event/delete.html:66 #: pretix/control/templates/pretixcontrol/event/delete.html:66
@@ -18629,14 +18629,14 @@ msgid ""
"Your ticket shop is currently not live. It is thus only visible to you and " "Your ticket shop is currently not live. It is thus only visible to you and "
"your team, not to any visitors." "your team, not to any visitors."
msgstr "" msgstr ""
"Ihr Ticket-Shop ist zur Zeit offline und daher nur für Sie und Ihr Team " "Ihr Ticketshop ist zur Zeit offline und daher nur für Sie und Ihr Team "
"verfügbar und nicht für Besucher." "verfügbar und nicht für Besucher."
#: pretix/control/templates/pretixcontrol/event/live.html:41 #: pretix/control/templates/pretixcontrol/event/live.html:41
msgid "" msgid ""
"To publish your ticket shop, you first need to resolve the following issues:" "To publish your ticket shop, you first need to resolve the following issues:"
msgstr "" msgstr ""
"Um Ihren Ticket-Shop zu veröffentlichen, müssen Sie zuerst die folgenden " "Um Ihren Ticketshop zu veröffentlichen, müssen Sie zuerst die folgenden "
"Probleme beheben:" "Probleme beheben:"
#: pretix/control/templates/pretixcontrol/event/live.html:51 #: pretix/control/templates/pretixcontrol/event/live.html:51
@@ -18646,7 +18646,7 @@ msgstr "Shop veröffentlichen"
#: pretix/control/templates/pretixcontrol/event/live.html:59 #: pretix/control/templates/pretixcontrol/event/live.html:59
msgid "If you want to, you can publish your ticket shop now." msgid "If you want to, you can publish your ticket shop now."
msgstr "Sie können Ihren Ticket-Shop jederzeit veröffentlichen." msgstr "Sie können Ihren Ticketshop jederzeit veröffentlichen."
#: pretix/control/templates/pretixcontrol/event/live.html:83 #: pretix/control/templates/pretixcontrol/event/live.html:83
msgid "" msgid ""
@@ -19488,7 +19488,7 @@ msgid ""
"website. This way, your visitors can buy their ticket right away without " "website. This way, your visitors can buy their ticket right away without "
"leaving your website." "leaving your website."
msgstr "" msgstr ""
"Das pretix-Widget ist ein Weg, den Ticket-Shop in Ihre Event-Website " "Das pretix-Widget ist ein Weg, den Ticketshop in Ihre Event-Website "
"einzubetten. Auf diese Weise können Besucher Ihrer Website ein Ticket " "einzubetten. Auf diese Weise können Besucher Ihrer Website ein Ticket "
"erwerben, ohne die Website verlassen zu müssen." "erwerben, ohne die Website verlassen zu müssen."
@@ -19515,7 +19515,7 @@ msgid ""
"JavaScript is disabled in your browser. To access our ticket shop without " "JavaScript is disabled in your browser. To access our ticket shop without "
"JavaScript, please &lt;a %(a_attr)s&gt;click here&lt;/a&gt;." "JavaScript, please &lt;a %(a_attr)s&gt;click here&lt;/a&gt;."
msgstr "" msgstr ""
"JavaScript ist in Ihrem Browser deaktiviert. Um unseren Ticket-Shop ohne " "JavaScript ist in Ihrem Browser deaktiviert. Um unseren Ticketshop ohne "
"JavaScript aufzurufen, klicken Sie bitte &lt;a %(a_attr)s&gt;hier&lt;/a&gt;." "JavaScript aufzurufen, klicken Sie bitte &lt;a %(a_attr)s&gt;hier&lt;/a&gt;."
#: pretix/control/templates/pretixcontrol/event/widget.html:64 #: pretix/control/templates/pretixcontrol/event/widget.html:64
@@ -19580,7 +19580,7 @@ msgid ""
"less than 10 characters that can be easily remembered, but you can also " "less than 10 characters that can be easily remembered, but you can also "
"choose to use a random value." "choose to use a random value."
msgstr "" msgstr ""
"Dies ist die Adresse, unter der Ihr Ticket-Shop verfügbar sein wird. Sie " "Dies ist die Adresse, unter der Ihr Ticketshop verfügbar sein wird. Sie "
"sollte kurz sein und darf nur Kleinbuchstaben, Zahlen, Punkte und " "sollte kurz sein und darf nur Kleinbuchstaben, Zahlen, Punkte und "
"Bindestriche enthalten. Sie muss unter Ihren Veranstaltungen einmalig sein. " "Bindestriche enthalten. Sie muss unter Ihren Veranstaltungen einmalig sein. "
"Wir empfehlen eine Abkürzung oder ein Datum mit weniger als 10 Zeichen, das " "Wir empfehlen eine Abkürzung oder ein Datum mit weniger als 10 Zeichen, das "
@@ -22464,7 +22464,7 @@ msgstr "Veröffentlichen Sie Ihren Shop"
#: pretix/control/templates/pretixcontrol/orders/index.html:27 #: pretix/control/templates/pretixcontrol/orders/index.html:27
msgid "Go to the ticket shop" msgid "Go to the ticket shop"
msgstr "Zum Ticket-Shop" msgstr "Zum Ticketshop"
#: pretix/control/templates/pretixcontrol/orders/index.html:35 #: pretix/control/templates/pretixcontrol/orders/index.html:35
msgid "Search query:" msgid "Search query:"
@@ -23102,7 +23102,7 @@ msgid ""
"usage, the legal details in your specific jurisdiction, or the agreements " "usage, the legal details in your specific jurisdiction, or the agreements "
"you have with third parties such as payment or tracking providers." "you have with third parties such as payment or tracking providers."
msgstr "" msgstr ""
"Trotzdem bleibt es Ihre Verantwortung, dass Ihr Ticket-Shop allen " "Trotzdem bleibt es Ihre Verantwortung, dass Ihr Ticketshop allen "
"anwendbaren Gesetzen entspricht. Wir versuchen mit diesen Einstellungen zu " "anwendbaren Gesetzen entspricht. Wir versuchen mit diesen Einstellungen zu "
"helfen, aber können keine Haftung übernehmen, da wir unter anderem die " "helfen, aber können keine Haftung übernehmen, da wir unter anderem die "
"genaue Konfiguration Ihres Ticketshops, die rechtlichen Details der " "genaue Konfiguration Ihres Ticketshops, die rechtlichen Details der "
@@ -25624,7 +25624,7 @@ msgstr "{quota} übrig"
#: pretix/control/views/dashboards.py:269 #: pretix/control/views/dashboards.py:269
msgid "Your ticket shop is" msgid "Your ticket shop is"
msgstr "Ihr Ticket-Shop ist" msgstr "Ihr Ticketshop ist"
#: pretix/control/views/dashboards.py:269 #: pretix/control/views/dashboards.py:269
msgid "Click here to change" msgid "Click here to change"
@@ -31490,7 +31490,7 @@ msgstr "Warnung"
#: pretix/presale/templates/pretixpresale/event/base.html:127 #: pretix/presale/templates/pretixpresale/event/base.html:127
#: pretix/presale/templates/pretixpresale/event/base.html:201 #: pretix/presale/templates/pretixpresale/event/base.html:201
msgid "This ticket shop is currently in test mode." msgid "This ticket shop is currently in test mode."
msgstr "Dieser Ticket-Shop ist momentan im Testmodus." msgstr "Dieser Ticketshop ist momentan im Testmodus."
#: pretix/presale/templates/pretixpresale/event/base.html:130 #: pretix/presale/templates/pretixpresale/event/base.html:130
#: pretix/presale/templates/pretixpresale/event/base.html:204 #: pretix/presale/templates/pretixpresale/event/base.html:204
@@ -32857,7 +32857,7 @@ msgstr "Shop ausgeschaltet"
#: pretix/presale/templates/pretixpresale/event/offline.html:9 #: pretix/presale/templates/pretixpresale/event/offline.html:9
msgid "This ticket shop is currently turned off." msgid "This ticket shop is currently turned off."
msgstr "Dieser Ticket-Shop ist im Moment nicht aktiv." msgstr "Dieser Ticketshop ist im Moment nicht aktiv."
#: pretix/presale/templates/pretixpresale/event/offline.html:10 #: pretix/presale/templates/pretixpresale/event/offline.html:10
msgid "It is only accessible to authenticated team members." msgid "It is only accessible to authenticated team members."
@@ -33684,7 +33684,7 @@ msgid ""
"open source ticket sales software</a>." "open source ticket sales software</a>."
msgstr "" msgstr ""
"Dies ist eine selbst-gehostete Installation von <a %(a_attr)s>pretix, dem " "Dies ist eine selbst-gehostete Installation von <a %(a_attr)s>pretix, dem "
"freundlichen Open Source Ticket-Shop</a>." "freundlichen Open Source Ticketshop</a>."
#: pretix/presale/templates/pretixpresale/index.html:15 #: pretix/presale/templates/pretixpresale/index.html:15
msgid "" msgid ""
@@ -34215,7 +34215,7 @@ msgstr ""
#: pretix/presale/views/widget.py:372 #: pretix/presale/views/widget.py:372
msgid "This ticket shop is currently disabled." msgid "This ticket shop is currently disabled."
msgstr "Dieser Ticket-Shop ist im Moment nicht verfügbar." msgstr "Dieser Ticketshop ist im Moment nicht verfügbar."
#: pretix/presale/views/widget.py:386 #: pretix/presale/views/widget.py:386
msgid "The selected date does not exist in this event series." msgid "The selected date does not exist in this event series."
@@ -34336,7 +34336,7 @@ msgstr "Kosovo"
#~ msgstr "Sie können nicht fortfahren." #~ msgstr "Sie können nicht fortfahren."
#~ msgid "The selected ticket shop is currently not available." #~ msgid "The selected ticket shop is currently not available."
#~ msgstr "Der ausgewählte Ticket-Shop ist im Moment nicht verfügbar." #~ msgstr "Der ausgewählte Ticketshop ist im Moment nicht verfügbar."
#~ msgid "Needs to be enabled in your Stripe account first." #~ msgid "Needs to be enabled in your Stripe account first."
#~ msgstr "Muss erst im Stripe-Account aktiviert werden." #~ msgstr "Muss erst im Stripe-Account aktiviert werden."
+3 -3
View File
@@ -871,12 +871,12 @@ msgstr "minimale Bestellmenge: %s"
#: pretix/static/pretixpresale/js/widget/widget.js:39 #: pretix/static/pretixpresale/js/widget/widget.js:39
msgctxt "widget" msgctxt "widget"
msgid "Close ticket shop" msgid "Close ticket shop"
msgstr "Ticket-Shop schließen" msgstr "Ticketshop schließen"
#: pretix/static/pretixpresale/js/widget/widget.js:40 #: pretix/static/pretixpresale/js/widget/widget.js:40
msgctxt "widget" msgctxt "widget"
msgid "The ticket shop could not be loaded." msgid "The ticket shop could not be loaded."
msgstr "Der Ticket-Shop konnte nicht geladen werden." msgstr "Der Ticketshop konnte nicht geladen werden."
#: pretix/static/pretixpresale/js/widget/widget.js:41 #: pretix/static/pretixpresale/js/widget/widget.js:41
msgctxt "widget" msgctxt "widget"
@@ -890,7 +890,7 @@ msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:43 #: pretix/static/pretixpresale/js/widget/widget.js:43
msgctxt "widget" msgctxt "widget"
msgid "Open ticket shop" msgid "Open ticket shop"
msgstr "Ticket-Shop öffnen" msgstr "Ticketshop öffnen"
#: pretix/static/pretixpresale/js/widget/widget.js:44 #: pretix/static/pretixpresale/js/widget/widget.js:44
msgctxt "widget" msgctxt "widget"
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: 1\n" "Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-30 18:55+0000\n" "POT-Creation-Date: 2024-06-30 18:55+0000\n"
"PO-Revision-Date: 2024-06-30 21:07+0000\n" "PO-Revision-Date: 2024-07-02 19:00+0000\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n" "Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: German (informal) <https://translate.pretix.eu/projects/" "Language-Team: German (informal) <https://translate.pretix.eu/projects/"
"pretix/pretix/de_Informal/>\n" "pretix/pretix/de_Informal/>\n"
@@ -3536,7 +3536,7 @@ msgstr "Sie können keinen Ticketcode verwenden, der bereits existiert."
#: pretix/base/modelimport_orders.py:490 #: pretix/base/modelimport_orders.py:490
msgid "Please enter a valid language code." msgid "Please enter a valid language code."
msgstr "Bitte gib einen gültigen Sprachcode ein." msgstr "Bitte einen gültigen Sprachcode eingeben."
#: pretix/base/modelimport_orders.py:558 pretix/base/modelimport_orders.py:560 #: pretix/base/modelimport_orders.py:558 pretix/base/modelimport_orders.py:560
msgid "Please enter a valid sales channel." msgid "Please enter a valid sales channel."
@@ -9594,7 +9594,7 @@ msgstr ""
#: pretix/base/settings.py:1346 #: pretix/base/settings.py:1346
msgid "Ask search engines not to index the ticket shop" msgid "Ask search engines not to index the ticket shop"
msgstr "Der Ticket-Shop soll von Suchmaschinen nicht indiziert werden" msgstr "Der Ticketshop soll von Suchmaschinen nicht indiziert werden"
#: pretix/base/settings.py:1355 #: pretix/base/settings.py:1355
msgid "Show variations of a product expanded by default" msgid "Show variations of a product expanded by default"
@@ -10856,7 +10856,7 @@ msgstr ""
"du hast dich auf die Warteliste für {event} \n" "du hast dich auf die Warteliste für {event} \n"
"für das Produkt {product} eingetragen.\n" "für das Produkt {product} eingetragen.\n"
"\n" "\n"
"Wir haben nun ein Ticket für dich! Du kannst es in unserem Ticket-Shop " "Wir haben nun ein Ticket für dich! Du kannst es in unserem Ticketshop "
"erwerben,\n" "erwerben,\n"
"indem du in den nächsten {hours} Stunden den folgenden Gutscheincode " "indem du in den nächsten {hours} Stunden den folgenden Gutscheincode "
"eingibst:\n" "eingibst:\n"
@@ -11950,7 +11950,7 @@ msgid ""
"If you just configured this as a domain for your ticket shop, you now need " "If you just configured this as a domain for your ticket shop, you now need "
"to set this up as a \"custom domain\" in your organizer account." "to set this up as a \"custom domain\" in your organizer account."
msgstr "" msgstr ""
"Wenn du gerade diese Domain für deinen Ticket-Shop eingerichtet hast, musst " "Wenn du gerade diese Domain für deinen Ticketshop eingerichtet hast, musst "
"du diese nun in deinem Veranstalterkonto als \"eigene Domain\" eintragen." "du diese nun in deinem Veranstalterkonto als \"eigene Domain\" eintragen."
#: pretix/base/templates/403.html:4 pretix/base/templates/403.html:8 #: pretix/base/templates/403.html:4 pretix/base/templates/403.html:8
@@ -18371,7 +18371,7 @@ msgid ""
"You can instead take your shop offline. This will hide it from everyone " "You can instead take your shop offline. This will hide it from everyone "
"except from the organizer teams you configured to have access to the event." "except from the organizer teams you configured to have access to the event."
msgstr "" msgstr ""
"Du kannst stattdessen den Ticket-Shop abschalten. Dies wird die " "Du kannst stattdessen den Ticketshop abschalten. Dies wird die "
"Veranstaltung vor allen außer den zugewiesenen Veranstalter-Teams verstecken." "Veranstaltung vor allen außer den zugewiesenen Veranstalter-Teams verstecken."
#: pretix/control/templates/pretixcontrol/event/delete.html:66 #: pretix/control/templates/pretixcontrol/event/delete.html:66
@@ -18596,14 +18596,14 @@ msgid ""
"Your ticket shop is currently not live. It is thus only visible to you and " "Your ticket shop is currently not live. It is thus only visible to you and "
"your team, not to any visitors." "your team, not to any visitors."
msgstr "" msgstr ""
"Dein Ticket-Shop ist zur Zeit offline und daher nur für dich und dein Team " "Dein Ticketshop ist zur Zeit offline und daher nur für dich und dein Team "
"verfügbar und nicht für Besucher." "verfügbar und nicht für Besucher."
#: pretix/control/templates/pretixcontrol/event/live.html:41 #: pretix/control/templates/pretixcontrol/event/live.html:41
msgid "" msgid ""
"To publish your ticket shop, you first need to resolve the following issues:" "To publish your ticket shop, you first need to resolve the following issues:"
msgstr "" msgstr ""
"Um deinen Ticket-Shop zu veröffentlichen, musst du zuerst die folgenden " "Um deinen Ticketshop zu veröffentlichen, musst du zuerst die folgenden "
"Probleme beheben:" "Probleme beheben:"
#: pretix/control/templates/pretixcontrol/event/live.html:51 #: pretix/control/templates/pretixcontrol/event/live.html:51
@@ -18613,7 +18613,7 @@ msgstr "Shop veröffentlichen"
#: pretix/control/templates/pretixcontrol/event/live.html:59 #: pretix/control/templates/pretixcontrol/event/live.html:59
msgid "If you want to, you can publish your ticket shop now." msgid "If you want to, you can publish your ticket shop now."
msgstr "Du kannst deinen Ticket-Shop jederzeit veröffentlichen." msgstr "Du kannst deinen Ticketshop jederzeit veröffentlichen."
#: pretix/control/templates/pretixcontrol/event/live.html:83 #: pretix/control/templates/pretixcontrol/event/live.html:83
msgid "" msgid ""
@@ -19454,7 +19454,7 @@ msgid ""
"website. This way, your visitors can buy their ticket right away without " "website. This way, your visitors can buy their ticket right away without "
"leaving your website." "leaving your website."
msgstr "" msgstr ""
"Das pretix-Widget ist ein Weg, den Ticket-Shop in deine Event-Website " "Das pretix-Widget ist ein Weg, den Ticketshop in deine Event-Website "
"einzubetten. Auf diese Weise können Besucher deiner Website ein Ticket " "einzubetten. Auf diese Weise können Besucher deiner Website ein Ticket "
"erwerben, ohne die Website verlassen zu müssen." "erwerben, ohne die Website verlassen zu müssen."
@@ -19481,7 +19481,7 @@ msgid ""
"JavaScript is disabled in your browser. To access our ticket shop without " "JavaScript is disabled in your browser. To access our ticket shop without "
"JavaScript, please &lt;a %(a_attr)s&gt;click here&lt;/a&gt;." "JavaScript, please &lt;a %(a_attr)s&gt;click here&lt;/a&gt;."
msgstr "" msgstr ""
"JavaScript ist in deinem Browser deaktiviert. Um unseren Ticket-Shop ohne " "JavaScript ist in deinem Browser deaktiviert. Um unseren Ticketshop ohne "
"JavaScript aufzurufen, klicke bitte &lt;a %(a_attr)s&gt;hier&lt;/a&gt;." "JavaScript aufzurufen, klicke bitte &lt;a %(a_attr)s&gt;hier&lt;/a&gt;."
#: pretix/control/templates/pretixcontrol/event/widget.html:64 #: pretix/control/templates/pretixcontrol/event/widget.html:64
@@ -19546,7 +19546,7 @@ msgid ""
"less than 10 characters that can be easily remembered, but you can also " "less than 10 characters that can be easily remembered, but you can also "
"choose to use a random value." "choose to use a random value."
msgstr "" msgstr ""
"Dies ist die Adresse, unter der dein Ticket-Shop verfügbar sein wird. Sie " "Dies ist die Adresse, unter der dein Ticketshop verfügbar sein wird. Sie "
"sollte kurz sein und darf nur Kleinbuchstaben, Zahlen, Punkte und " "sollte kurz sein und darf nur Kleinbuchstaben, Zahlen, Punkte und "
"Bindestriche enthalten. Sie muss unter deinen Veranstaltungen einmalig sein. " "Bindestriche enthalten. Sie muss unter deinen Veranstaltungen einmalig sein. "
"Wir empfehlen eine Abkürzung oder ein Datum mit unter 10 Zeichen, das man " "Wir empfehlen eine Abkürzung oder ein Datum mit unter 10 Zeichen, das man "
@@ -22425,7 +22425,7 @@ msgstr "Veröffentliche deinen Shop"
#: pretix/control/templates/pretixcontrol/orders/index.html:27 #: pretix/control/templates/pretixcontrol/orders/index.html:27
msgid "Go to the ticket shop" msgid "Go to the ticket shop"
msgstr "Zum Ticket-Shop" msgstr "Zum Ticketshop"
#: pretix/control/templates/pretixcontrol/orders/index.html:35 #: pretix/control/templates/pretixcontrol/orders/index.html:35
msgid "Search query:" msgid "Search query:"
@@ -23063,7 +23063,7 @@ msgid ""
"usage, the legal details in your specific jurisdiction, or the agreements " "usage, the legal details in your specific jurisdiction, or the agreements "
"you have with third parties such as payment or tracking providers." "you have with third parties such as payment or tracking providers."
msgstr "" msgstr ""
"Trotzdem bleibt es deine Verantwortung, dass dein Ticket-Shop allen " "Trotzdem bleibt es deine Verantwortung, dass dein Ticketshop allen "
"anwendbaren Gesetzen entspricht. Wir versuchen mit diesen Einstellungen zu " "anwendbaren Gesetzen entspricht. Wir versuchen mit diesen Einstellungen zu "
"helfen, aber können keine Haftung übernehmen, da wir unter anderem die " "helfen, aber können keine Haftung übernehmen, da wir unter anderem die "
"genaue Konfiguration deines Ticketshops, die rechtlichen Details der " "genaue Konfiguration deines Ticketshops, die rechtlichen Details der "
@@ -25579,7 +25579,7 @@ msgstr "{quota} übrig"
#: pretix/control/views/dashboards.py:269 #: pretix/control/views/dashboards.py:269
msgid "Your ticket shop is" msgid "Your ticket shop is"
msgstr "Dein Ticket-Shop ist" msgstr "Dein Ticketshop ist"
#: pretix/control/views/dashboards.py:269 #: pretix/control/views/dashboards.py:269
msgid "Click here to change" msgid "Click here to change"
@@ -31432,7 +31432,7 @@ msgstr "Warnung"
#: pretix/presale/templates/pretixpresale/event/base.html:127 #: pretix/presale/templates/pretixpresale/event/base.html:127
#: pretix/presale/templates/pretixpresale/event/base.html:201 #: pretix/presale/templates/pretixpresale/event/base.html:201
msgid "This ticket shop is currently in test mode." msgid "This ticket shop is currently in test mode."
msgstr "Dieser Ticket-Shop ist momentan im Testmodus." msgstr "Dieser Ticketshop ist momentan im Testmodus."
#: pretix/presale/templates/pretixpresale/event/base.html:130 #: pretix/presale/templates/pretixpresale/event/base.html:130
#: pretix/presale/templates/pretixpresale/event/base.html:204 #: pretix/presale/templates/pretixpresale/event/base.html:204
@@ -32794,7 +32794,7 @@ msgstr "Shop ausgeschaltet"
#: pretix/presale/templates/pretixpresale/event/offline.html:9 #: pretix/presale/templates/pretixpresale/event/offline.html:9
msgid "This ticket shop is currently turned off." msgid "This ticket shop is currently turned off."
msgstr "Dieser Ticket-Shop ist im Moment nicht aktiv." msgstr "Dieser Ticketshop ist im Moment nicht aktiv."
#: pretix/presale/templates/pretixpresale/event/offline.html:10 #: pretix/presale/templates/pretixpresale/event/offline.html:10
msgid "It is only accessible to authenticated team members." msgid "It is only accessible to authenticated team members."
@@ -33622,7 +33622,7 @@ msgid ""
"open source ticket sales software</a>." "open source ticket sales software</a>."
msgstr "" msgstr ""
"Dies ist eine selbst-gehostete Installation von <a %(a_attr)s>pretix, dem " "Dies ist eine selbst-gehostete Installation von <a %(a_attr)s>pretix, dem "
"freundlichen Open Source Ticket-Shop</a>." "freundlichen Open Source Ticketshop</a>."
#: pretix/presale/templates/pretixpresale/index.html:15 #: pretix/presale/templates/pretixpresale/index.html:15
msgid "" msgid ""
@@ -34150,7 +34150,7 @@ msgstr ""
#: pretix/presale/views/widget.py:372 #: pretix/presale/views/widget.py:372
msgid "This ticket shop is currently disabled." msgid "This ticket shop is currently disabled."
msgstr "Dieser Ticket-Shop ist im Moment nicht verfügbar." msgstr "Dieser Ticketshop ist im Moment nicht verfügbar."
#: pretix/presale/views/widget.py:386 #: pretix/presale/views/widget.py:386
msgid "The selected date does not exist in this event series." msgid "The selected date does not exist in this event series."
@@ -34271,7 +34271,7 @@ msgstr "Kosovo"
#~ msgstr "Du kannst daher nicht fortfahren." #~ msgstr "Du kannst daher nicht fortfahren."
#~ msgid "The selected ticket shop is currently not available." #~ msgid "The selected ticket shop is currently not available."
#~ msgstr "Der ausgewählte Ticket-Shop ist im Moment nicht verfügbar." #~ msgstr "Der ausgewählte Ticketshop ist im Moment nicht verfügbar."
#~ msgid "Needs to be enabled in your Stripe account first." #~ msgid "Needs to be enabled in your Stripe account first."
#~ msgstr "Muss erst im Stripe-Account aktiviert werden." #~ msgstr "Muss erst im Stripe-Account aktiviert werden."
@@ -870,12 +870,12 @@ msgstr "minimale Bestellmenge: %s"
#: pretix/static/pretixpresale/js/widget/widget.js:39 #: pretix/static/pretixpresale/js/widget/widget.js:39
msgctxt "widget" msgctxt "widget"
msgid "Close ticket shop" msgid "Close ticket shop"
msgstr "Ticket-Shop schließen" msgstr "Ticketshop schließen"
#: pretix/static/pretixpresale/js/widget/widget.js:40 #: pretix/static/pretixpresale/js/widget/widget.js:40
msgctxt "widget" msgctxt "widget"
msgid "The ticket shop could not be loaded." msgid "The ticket shop could not be loaded."
msgstr "Der Ticket-Shop konnte nicht geladen werden." msgstr "Der Ticketshop konnte nicht geladen werden."
#: pretix/static/pretixpresale/js/widget/widget.js:41 #: pretix/static/pretixpresale/js/widget/widget.js:41
msgctxt "widget" msgctxt "widget"
@@ -889,7 +889,7 @@ msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:43 #: pretix/static/pretixpresale/js/widget/widget.js:43
msgctxt "widget" msgctxt "widget"
msgid "Open ticket shop" msgid "Open ticket shop"
msgstr "Ticket-Shop öffnen" msgstr "Ticketshop öffnen"
#: pretix/static/pretixpresale/js/widget/widget.js:44 #: pretix/static/pretixpresale/js/widget/widget.js:44
msgctxt "widget" msgctxt "widget"
+53 -116
View File
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-06-30 18:55+0000\n" "POT-Creation-Date: 2024-06-30 18:55+0000\n"
"PO-Revision-Date: 2024-06-27 17:00+0000\n" "PO-Revision-Date: 2024-07-01 16:00+0000\n"
"Last-Translator: Anarion Dunedain <anarion80@gmail.com>\n" "Last-Translator: Anarion Dunedain <anarion80@gmail.com>\n"
"Language-Team: Polish <https://translate.pretix.eu/projects/pretix/pretix/pl/" "Language-Team: Polish <https://translate.pretix.eu/projects/pretix/pretix/pl/"
">\n" ">\n"
@@ -122,7 +122,7 @@ msgstr "Słowacki"
#: pretix/_base_settings.py:103 #: pretix/_base_settings.py:103
msgid "Swedish" msgid "Swedish"
msgstr "" msgstr "Szwedzki"
#: pretix/_base_settings.py:104 #: pretix/_base_settings.py:104
msgid "Spanish" msgid "Spanish"
@@ -640,13 +640,15 @@ msgstr "Sklep online"
#: pretix/base/channels.py:174 #: pretix/base/channels.py:174
msgid "API" msgid "API"
msgstr "" msgstr "API"
#: pretix/base/channels.py:175 #: pretix/base/channels.py:175
msgid "" msgid ""
"API sales channels come with no built-in functionality, but may be used for " "API sales channels come with no built-in functionality, but may be used for "
"custom integrations." "custom integrations."
msgstr "" msgstr ""
"Kanały sprzedaży API nie mają wbudowanych funkcji, ale mogą być używane do "
"niestandardowych integracji."
#: pretix/base/context.py:45 #: pretix/base/context.py:45
#, python-brace-format #, python-brace-format
@@ -4041,10 +4043,8 @@ msgid "Position"
msgstr "Pozycja" msgstr "Pozycja"
#: pretix/base/models/discount.py:68 #: pretix/base/models/discount.py:68
#, fuzzy
#| msgid "Sales channels"
msgid "All supported sales channels" msgid "All supported sales channels"
msgstr "Kanały sprzedaży" msgstr "Wszystkie obsługiwane kanały sprzedaży"
#: pretix/base/models/discount.py:89 #: pretix/base/models/discount.py:89
msgid "Event series handling" msgid "Event series handling"
@@ -4257,10 +4257,8 @@ msgid "Seating plan"
msgstr "Plan miejsc" msgstr "Plan miejsc"
#: pretix/base/models/event.py:639 pretix/base/models/items.py:618 #: pretix/base/models/event.py:639 pretix/base/models/items.py:618
#, fuzzy
#| msgid "Sales channels"
msgid "Sell on all sales channels" msgid "Sell on all sales channels"
msgstr "Kanały sprzedaży" msgstr "Sprzedawaj we wszystkich kanałach sprzedaży"
#: pretix/base/models/event.py:644 pretix/base/models/items.py:623 #: pretix/base/models/event.py:644 pretix/base/models/items.py:623
#: pretix/base/models/items.py:1170 pretix/base/payment.py:417 #: pretix/base/models/items.py:1170 pretix/base/payment.py:417
@@ -4570,9 +4568,6 @@ msgid "{category} (Add-On products)"
msgstr "{category} (Produkty dodatkowe)" msgstr "{category} (Produkty dodatkowe)"
#: pretix/base/models/items.py:128 #: pretix/base/models/items.py:128
#, fuzzy
#| msgctxt "checkoutflow"
#| msgid "Add-on products"
msgid "Add-On products" msgid "Add-On products"
msgstr "Produkty dodatkowe" msgstr "Produkty dodatkowe"
@@ -4859,11 +4854,8 @@ msgstr ""
"przeceny. Ustawienie kosmetyczne bez wzgędlu na faktyczną cenę sprzedaży." "przeceny. Ustawienie kosmetyczne bez wzgędlu na faktyczną cenę sprzedaży."
#: pretix/base/models/items.py:624 #: pretix/base/models/items.py:624
#, fuzzy
#| msgid "Only sell tickets for this event on the following sales channels."
msgid "Only sell tickets for this product on the selected sales channels." msgid "Only sell tickets for this product on the selected sales channels."
msgstr "" msgstr "Sprzedaj bilety na ten produkt tylko w wybranych kanałach sprzedaży."
"Sprzedaj bilety tylko na to wydarzenie na następujących kanałach sprzedaży."
#: pretix/base/models/items.py:629 #: pretix/base/models/items.py:629
msgid "" msgid ""
@@ -5114,6 +5106,8 @@ msgstr "Ten wariant nie będzie sprzedawany po podanej dacie."
#: pretix/base/models/items.py:1165 #: pretix/base/models/items.py:1165
msgid "Sell on all sales channels the product is sold on" msgid "Sell on all sales channels the product is sold on"
msgstr "" msgstr ""
"Sprzedaj we wszystkich kanałach sprzedaży, w których sprzedawany jest ten "
"produkt."
#: pretix/base/models/items.py:1171 #: pretix/base/models/items.py:1171
msgid "" msgid ""
@@ -6053,9 +6047,6 @@ msgstr "Zaproszenie do zespołu '{team}' dla '{email}'"
#: pretix/base/models/organizer.py:538 #: pretix/base/models/organizer.py:538
#: pretix/control/templates/pretixcontrol/organizers/channels.html:23 #: pretix/control/templates/pretixcontrol/organizers/channels.html:23
#, fuzzy
#| msgctxt "reusable_medium"
#| msgid "Identifier"
msgid "Identifier" msgid "Identifier"
msgstr "Identyfikator" msgstr "Identyfikator"
@@ -12050,6 +12041,8 @@ msgid ""
"This sales channel cannot be used properly since the respective plugin is " "This sales channel cannot be used properly since the respective plugin is "
"not active for this event." "not active for this event."
msgstr "" msgstr ""
"Ten kanał sprzedaży nie może być używany prawidłowo, ponieważ odpowiednia "
"wtyczka nie jest aktywna dla tego wydarzenia."
#: pretix/base/templates/pretixbase/forms/widgets/portrait_image.html:10 #: pretix/base/templates/pretixbase/forms/widgets/portrait_image.html:10
msgid "Upload photo" msgid "Upload photo"
@@ -14061,6 +14054,8 @@ msgid ""
"You have selected dynamic validity but have not entered a time period. This " "You have selected dynamic validity but have not entered a time period. This "
"would render the tickets unusable." "would render the tickets unusable."
msgstr "" msgstr ""
"Wybrałeś dynamiczną ważność, ale nie wprowadziłeś okresu czasu. Spowoduje "
"to, że bilety będą bezużyteczne."
#: pretix/control/forms/item.py:858 #: pretix/control/forms/item.py:858
#, python-format #, python-format
@@ -14807,10 +14802,8 @@ msgid "The selected organizer has already been invited."
msgstr "Wybrany organizator został już zaproszony." msgstr "Wybrany organizator został już zaproszony."
#: pretix/control/forms/organizer.py:1128 #: pretix/control/forms/organizer.py:1128
#, fuzzy
#| msgid "A voucher with this code already exists."
msgid "A sales channel with the same identifier already exists." msgid "A sales channel with the same identifier already exists."
msgstr "Voucher o tym kodzie już istnieje." msgstr "Kanał sprzedaży o tym samym identyfikatorze już istnieje."
#: pretix/control/forms/renderers.py:56 #: pretix/control/forms/renderers.py:56
#: pretix/control/templates/pretixcontrol/items/question_edit.html:139 #: pretix/control/templates/pretixcontrol/items/question_edit.html:139
@@ -15423,23 +15416,16 @@ msgid "The membership type has been deleted."
msgstr "Typ członkostwa został usunięty." msgstr "Typ członkostwa został usunięty."
#: pretix/control/logdisplay.py:360 pretix/control/views/organizer.py:3119 #: pretix/control/logdisplay.py:360 pretix/control/views/organizer.py:3119
#, fuzzy
#| msgctxt "subevent"
#| msgid "The new date has been created."
msgid "The sales channel has been created." msgid "The sales channel has been created."
msgstr "Nowa data została utworzona." msgstr "Kanał sprzedaży został utworzony."
#: pretix/control/logdisplay.py:361 #: pretix/control/logdisplay.py:361
#, fuzzy
#| msgid "The device has been changed."
msgid "The sales channel has been changed." msgid "The sales channel has been changed."
msgstr "Urządzenie zostało zmienione." msgstr "Kanał sprzedaży został zmieniony."
#: pretix/control/logdisplay.py:362 #: pretix/control/logdisplay.py:362
#, fuzzy
#| msgid "The selected list has been deleted."
msgid "The sales channel has been deleted." msgid "The sales channel has been deleted."
msgstr "Wybrana lista została usunięta." msgstr "Kanał sprzedaży został usunięty."
#: pretix/control/logdisplay.py:363 #: pretix/control/logdisplay.py:363
msgid "The account has been created." msgid "The account has been created."
@@ -20190,14 +20176,14 @@ msgstr "Utwórz nową kategorię"
#: pretix/control/templates/pretixcontrol/items/index.html:146 #: pretix/control/templates/pretixcontrol/items/index.html:146
#: pretix/control/templates/pretixcontrol/organizers/properties.html:54 #: pretix/control/templates/pretixcontrol/organizers/properties.html:54
msgid "Move up" msgid "Move up"
msgstr "" msgstr "Przesuń w górę"
#: pretix/control/templates/pretixcontrol/items/categories.html:45 #: pretix/control/templates/pretixcontrol/items/categories.html:45
#: pretix/control/templates/pretixcontrol/items/discounts.html:142 #: pretix/control/templates/pretixcontrol/items/discounts.html:142
#: pretix/control/templates/pretixcontrol/items/index.html:147 #: pretix/control/templates/pretixcontrol/items/index.html:147
#: pretix/control/templates/pretixcontrol/organizers/properties.html:55 #: pretix/control/templates/pretixcontrol/organizers/properties.html:55
msgid "Move down" msgid "Move down"
msgstr "" msgstr "Przesuń w dół"
#: pretix/control/templates/pretixcontrol/items/categories.html:46 #: pretix/control/templates/pretixcontrol/items/categories.html:46
#: pretix/control/templates/pretixcontrol/items/discounts.html:145 #: pretix/control/templates/pretixcontrol/items/discounts.html:145
@@ -20207,6 +20193,8 @@ msgid ""
"Click and drag this button to reorder. Double click to show buttons for " "Click and drag this button to reorder. Double click to show buttons for "
"reordering." "reordering."
msgstr "" msgstr ""
"Kliknij i przeciągnij ten przycisk, aby zmienić kolejność. Kliknij "
"dwukrotnie, aby wyświetlić przyciski do zmiany kolejności."
#: pretix/control/templates/pretixcontrol/items/category.html:27 #: pretix/control/templates/pretixcontrol/items/category.html:27
msgid "Category history" msgid "Category history"
@@ -20350,15 +20338,12 @@ msgstr ""
"produktu" "produktu"
#: pretix/control/templates/pretixcontrol/items/discounts.html:111 #: pretix/control/templates/pretixcontrol/items/discounts.html:111
#, fuzzy
#| msgctxt "discount"
#| msgid "Condition"
msgid "Condition:" msgid "Condition:"
msgstr "Stan" msgstr "Stan:"
#: pretix/control/templates/pretixcontrol/items/discounts.html:126 #: pretix/control/templates/pretixcontrol/items/discounts.html:126
msgid "Applies to:" msgid "Applies to:"
msgstr "" msgstr "Dotyczy:"
#: pretix/control/templates/pretixcontrol/items/fragment_quota_availability.html:3 #: pretix/control/templates/pretixcontrol/items/fragment_quota_availability.html:3
msgid "Closed" msgid "Closed"
@@ -20398,12 +20383,6 @@ msgid "taxes"
msgstr "podatki" msgstr "podatki"
#: pretix/control/templates/pretixcontrol/items/index.html:10 #: pretix/control/templates/pretixcontrol/items/index.html:10
#, fuzzy
#| msgid ""
#| "Below, you find a list of all available products. You can click on a "
#| "product name to inspect and change product details. You can also use the "
#| "buttons on the right to change the order of products within a give "
#| "category."
msgid "" msgid ""
"Below, you find a list of all available products. You can click on a product " "Below, you find a list of all available products. You can click on a product "
"name to inspect and change product details. You can also use the buttons on " "name to inspect and change product details. You can also use the buttons on "
@@ -20412,8 +20391,8 @@ msgid ""
msgstr "" msgstr ""
"Poniżej znajduje się lista wszystkich dostępnych produktów. Możesz kliknąć " "Poniżej znajduje się lista wszystkich dostępnych produktów. Możesz kliknąć "
"nazwę produktu, aby sprawdzić i zmienić jego szczegóły. Możesz także użyć " "nazwę produktu, aby sprawdzić i zmienić jego szczegóły. Możesz także użyć "
"przycisków po prawej stronie, aby zmienić kolejność produktów w danej " "przycisków po prawej stronie, aby zmienić kolejność produktów lub przenieść "
"kategorii." "produkty do innej kategorii."
#: pretix/control/templates/pretixcontrol/items/index.html:19 #: pretix/control/templates/pretixcontrol/items/index.html:19
msgid "You haven't created any products yet." msgid "You haven't created any products yet."
@@ -22479,48 +22458,34 @@ msgstr "Wyszukiwanie zamówień"
#: pretix/control/templates/pretixcontrol/organizers/channel_add.html:6 #: pretix/control/templates/pretixcontrol/organizers/channel_add.html:6
#: pretix/control/templates/pretixcontrol/organizers/channel_add_choice.html:6 #: pretix/control/templates/pretixcontrol/organizers/channel_add_choice.html:6
#, fuzzy
#| msgid "Sales channel"
msgid "Add sales channel" msgid "Add sales channel"
msgstr "Kanał sprzedaży" msgstr "Dodaj kanał sprzedaży"
#: pretix/control/templates/pretixcontrol/organizers/channel_add.html:13 #: pretix/control/templates/pretixcontrol/organizers/channel_add.html:13
#: pretix/control/templates/pretixcontrol/organizers/channel_edit.html:13 #: pretix/control/templates/pretixcontrol/organizers/channel_edit.html:13
#: pretix/control/templates/pretixcontrol/organizers/channels.html:24 #: pretix/control/templates/pretixcontrol/organizers/channels.html:24
#, fuzzy
#| msgid "Scan type"
msgid "Channel type" msgid "Channel type"
msgstr "Typ skanowania" msgstr "Typ kanału"
#: pretix/control/templates/pretixcontrol/organizers/channel_delete.html:5 #: pretix/control/templates/pretixcontrol/organizers/channel_delete.html:5
#, fuzzy
#| msgid "Sales channel"
msgid "Delete sales channel:" msgid "Delete sales channel:"
msgstr "Kanał sprzedaży" msgstr "Usuń kanał sprzedaży:"
#: pretix/control/templates/pretixcontrol/organizers/channel_delete.html:10 #: pretix/control/templates/pretixcontrol/organizers/channel_delete.html:10
#, fuzzy
#| msgid "Are you sure you want to delete the gate?"
msgid "Are you sure you want to delete this sales channel?" msgid "Are you sure you want to delete this sales channel?"
msgstr "Czy na pewno chcesz usunąć bramkę?" msgstr "Czy na pewno chcesz usunąć ten kanał sprzedaży?"
#: pretix/control/templates/pretixcontrol/organizers/channel_delete.html:15 #: pretix/control/templates/pretixcontrol/organizers/channel_delete.html:15
#, fuzzy
#| msgid ""
#| "This membership cannot be deleted since it has been used in an order. "
#| "Change its end date to the past instead."
msgid "" msgid ""
"This sales channel cannot be deleted since it has already been used to sell " "This sales channel cannot be deleted since it has already been used to sell "
"orders or because it is a core element of the system." "orders or because it is a core element of the system."
msgstr "" msgstr ""
"Tego członkostwa nie można usunąć, ponieważ zostało użyte w zamówieniu. " "Tego kanału sprzedaży nie można usunąć, ponieważ został już użyty do "
"Zamiast tego zmień jego datę końcową na przeszłą." "sprzedaży zamówień lub jest podstawowym elementem systemu."
#: pretix/control/templates/pretixcontrol/organizers/channel_edit.html:6 #: pretix/control/templates/pretixcontrol/organizers/channel_edit.html:6
#, fuzzy
#| msgid "Sales channel"
msgid "Sales channel:" msgid "Sales channel:"
msgstr "Kanał sprzedaży" msgstr "Kanał sprzedaży:"
#: pretix/control/templates/pretixcontrol/organizers/channels.html:8 #: pretix/control/templates/pretixcontrol/organizers/channels.html:8
msgid "" msgid ""
@@ -22528,18 +22493,17 @@ msgid ""
"through. This is useful to unlock new revenue streams or to separate revenue " "through. This is useful to unlock new revenue streams or to separate revenue "
"between different sources for reporting purchases." "between different sources for reporting purchases."
msgstr "" msgstr ""
"Na tej stronie można zarządzać różnymi kanałami sprzedaży biletów. Jest to "
"przydatne do odblokowania nowych źródeł przychodów lub rozdzielenia "
"przychodów między różne źródła w celu raportowania zakupów."
#: pretix/control/templates/pretixcontrol/organizers/channels.html:15 #: pretix/control/templates/pretixcontrol/organizers/channels.html:15
#, fuzzy
#| msgid "Add a new value"
msgid "Add a new channel" msgid "Add a new channel"
msgstr "Dodaj nową wartość" msgstr "Dodaj nowy kanał"
#: pretix/control/templates/pretixcontrol/organizers/channels.html:22 #: pretix/control/templates/pretixcontrol/organizers/channels.html:22
#, fuzzy
#| msgid "Change"
msgid "Channel" msgid "Channel"
msgstr "Zmień" msgstr "Kanał"
#: pretix/control/templates/pretixcontrol/organizers/customer.html:7 #: pretix/control/templates/pretixcontrol/organizers/customer.html:7
#: pretix/control/templates/pretixcontrol/organizers/customer.html:13 #: pretix/control/templates/pretixcontrol/organizers/customer.html:13
@@ -26776,34 +26740,24 @@ msgid "The customer account has been anonymized."
msgstr "Konto klienta zostało zanonimizowane." msgstr "Konto klienta zostało zanonimizowane."
#: pretix/control/views/organizer.py:3201 #: pretix/control/views/organizer.py:3201
#, fuzzy
#| msgid "This organizer can not be deleted."
msgid "This channel can not be deleted." msgid "This channel can not be deleted."
msgstr "Tego organizatora nie można usunąć." msgstr "Tego kanału nie można usunąć."
#: pretix/control/views/organizer.py:3206 #: pretix/control/views/organizer.py:3206
#, fuzzy
#| msgid "The selected list has been deleted."
msgid "The selected sales channel has been deleted." msgid "The selected sales channel has been deleted."
msgstr "Wybrana lista została usunięta." msgstr "Wybrany kanał sprzedaży został usunięty."
#: pretix/control/views/organizer.py:3208 #: pretix/control/views/organizer.py:3208
#, fuzzy
#| msgid ""
#| "The team could not be deleted as some constraints (e.g. data created by "
#| "plug-ins) do not allow it."
msgid "" msgid ""
"The channel could not be deleted as some constraints (e.g. data created by " "The channel could not be deleted as some constraints (e.g. data created by "
"plug-ins) did not allow it." "plug-ins) did not allow it."
msgstr "" msgstr ""
"Zespół nie mógł zostać usunięty, ponieważ niektóre ograniczenia (np. dane " "Kanał nie mógł zostać usunięty, ponieważ niektóre ograniczenia (np. dane "
"utworzone przez wtyczki) na to nie pozwalają." "utworzone przez wtyczki) na to nie pozwoliły."
#: pretix/control/views/organizer.py:3232 #: pretix/control/views/organizer.py:3232
#, fuzzy
#| msgid "The order of discounts has been updated."
msgid "The order of sales channels has been updated." msgid "The order of sales channels has been updated."
msgstr "Kolejność rabatów została zaktualizowana." msgstr "Kolejność kanałów sprzedaży została zaktualizowana."
#: pretix/control/views/pdf.py:83 #: pretix/control/views/pdf.py:83
msgid "The uploaded PDF file is too large." msgid "The uploaded PDF file is too large."
@@ -28613,13 +28567,6 @@ msgid "Your PayPal account has been disconnected."
msgstr "Twoje konto PayPal zostało odłączone." msgstr "Twoje konto PayPal zostało odłączone."
#: pretix/plugins/paypal2/apps.py:40 #: pretix/plugins/paypal2/apps.py:40
#, fuzzy
#| msgid ""
#| "Accept payments with your PayPal account. In addition to regular PayPal "
#| "payments, you can now also offer payments in a variety of local payment "
#| "methods such as giropay, SOFORT, iDEAL and many more to your customers - "
#| "they don't even need a PayPal account. PayPal is one of the most popular "
#| "payment methods world-wide."
msgid "" msgid ""
"Accept payments with your PayPal account. In addition to regular PayPal " "Accept payments with your PayPal account. In addition to regular PayPal "
"payments, you can now also offer payments in a variety of local payment " "payments, you can now also offer payments in a variety of local payment "
@@ -28629,9 +28576,9 @@ msgid ""
msgstr "" msgstr ""
"Akceptuj płatności za pomocą konta PayPal. Oprócz zwykłych płatności PayPal, " "Akceptuj płatności za pomocą konta PayPal. Oprócz zwykłych płatności PayPal, "
"możesz teraz oferować swoim klientom płatności za pomocą różnych lokalnych " "możesz teraz oferować swoim klientom płatności za pomocą różnych lokalnych "
"metod płatności, takich jak giropay, SOFORT, iDEAL i wiele innych - nie " "metod płatności, takich jak eps, iDEAL i wiele innych - nie potrzebują oni "
"potrzebują oni nawet konta PayPal. PayPal jest jedną z najpopularniejszych " "nawet konta PayPal. PayPal jest jedną z najpopularniejszych metod płatności "
"metod płatności na całym świecie." "na całym świecie."
#: pretix/plugins/paypal2/payment.py:99 #: pretix/plugins/paypal2/payment.py:99
msgid "PayPal Merchant ID" msgid "PayPal Merchant ID"
@@ -28652,14 +28599,6 @@ msgid "Alternative Payment Methods"
msgstr "Alternatywne metody płatności" msgstr "Alternatywne metody płatności"
#: pretix/plugins/paypal2/payment.py:151 #: pretix/plugins/paypal2/payment.py:151
#, fuzzy
#| msgid ""
#| "In addition to payments through a PayPal account, you can also offer your "
#| "customers the option to pay with credit cards and other, local payment "
#| "methods such as SOFORT, giropay, iDEAL, and many more - even when they do "
#| "not have a PayPal account. Eligible payment methods will be determined "
#| "based on the shoppers location. For German merchants, this is the direct "
#| "successor of PayPal Plus."
msgid "" msgid ""
"In addition to payments through a PayPal account, you can also offer your " "In addition to payments through a PayPal account, you can also offer your "
"customers the option to pay with credit cards and other, local payment " "customers the option to pay with credit cards and other, local payment "
@@ -28670,10 +28609,10 @@ msgid ""
msgstr "" msgstr ""
"Oprócz płatności za pośrednictwem konta PayPal, możesz również zaoferować " "Oprócz płatności za pośrednictwem konta PayPal, możesz również zaoferować "
"swoim klientom możliwość płacenia kartami kredytowymi i innymi lokalnymi " "swoim klientom możliwość płacenia kartami kredytowymi i innymi lokalnymi "
"metodami płatności, takimi jak SOFORT, giropay, iDEAL i wiele innych - nawet " "metodami płatności, takimi jak eps, iDEAL i wiele innych - nawet jeśli nie "
"jeśli nie mają konta PayPal. Kwalifikujące się metody płatności zostaną " "mają konta PayPal. Kwalifikujące się metody płatności zostaną określone na "
"określone na podstawie lokalizacji kupującego. Dla niemieckich sprzedawców " "podstawie lokalizacji kupującego. Dla niemieckich sprzedawców jest to "
"jest to bezpośredni następca PayPal Plus." "bezpośredni następca PayPal Plus."
#: pretix/plugins/paypal2/payment.py:166 #: pretix/plugins/paypal2/payment.py:166
msgid "Disable SEPA Direct Debit" msgid "Disable SEPA Direct Debit"
@@ -29880,11 +29819,6 @@ msgid "Stripe"
msgstr "Stripe" msgstr "Stripe"
#: pretix/plugins/stripe/apps.py:40 #: pretix/plugins/stripe/apps.py:40
#, fuzzy
#| msgid ""
#| "Accept payments via Stripe, a globally popular payment service provider. "
#| "Stripe supports payments via credit cards as well as many local payment "
#| "methods such as giropay, iDEAL, Alipay,and many more."
msgid "" msgid ""
"Accept payments via Stripe, a globally popular payment service provider. " "Accept payments via Stripe, a globally popular payment service provider. "
"Stripe supports payments via credit cards as well as many local payment " "Stripe supports payments via credit cards as well as many local payment "
@@ -33278,6 +33212,9 @@ msgid ""
"been added to the waiting list. We will only contact you once a spot opens " "been added to the waiting list. We will only contact you once a spot opens "
"up." "up."
msgstr "" msgstr ""
"Po dodaniu do listy oczekujących <strong>nie</strong> otrzymasz wiadomość e-"
"mail z potwierdzeniem. Skontaktujemy się z Tobą dopiero, gdy zwolni się "
"miejsce."
#: pretix/presale/templates/pretixpresale/event/waitinglist.html:44 #: pretix/presale/templates/pretixpresale/event/waitinglist.html:44
msgid "Add me to the list" msgid "Add me to the list"
File diff suppressed because it is too large Load Diff
@@ -119,6 +119,7 @@ class CheckInListMixin(BaseExporter):
choices=[ choices=[
('name', _('Attendee name')), ('name', _('Attendee name')),
('code', _('Order code')), ('code', _('Order code')),
('order_datetime', _('Order date')),
] + ([ ] + ([
('name:{}'.format(k), _('Attendee name: {part}').format(part=label)) ('name:{}'.format(k), _('Attendee name: {part}').format(part=label))
for k, label, w in name_scheme['fields'] for k, label, w in name_scheme['fields']
@@ -229,6 +230,8 @@ class CheckInListMixin(BaseExporter):
) )
elif sort == 'code': elif sort == 'code':
qs = qs.order_by(*o, 'order__code') qs = qs.order_by(*o, 'order__code')
elif sort == 'order_datetime':
qs = qs.order_by(*o, '-order__datetime')
elif sort.startswith('name:'): elif sort.startswith('name:'):
part = sort[5:] part = sort[5:]
qs = qs.annotate( qs = qs.annotate(
@@ -516,6 +519,7 @@ class CSVCheckinList(CheckInListMixin, ListExporter):
headers.append(_('Order time')) headers.append(_('Order time'))
headers.append(_('Requires special attention')) headers.append(_('Requires special attention'))
headers.append(_('Comment')) headers.append(_('Comment'))
headers.append(_('Check-in text'))
headers.append(_('Seat ID')) headers.append(_('Seat ID'))
headers.append(_('Seat name')) headers.append(_('Seat name'))
headers.append(_('Seat zone')) headers.append(_('Seat zone'))
@@ -623,6 +627,7 @@ class CSVCheckinList(CheckInListMixin, ListExporter):
row.append(op.order.datetime.astimezone(self.event.timezone).strftime('%H:%M:%S')) row.append(op.order.datetime.astimezone(self.event.timezone).strftime('%H:%M:%S'))
row.append(_('Yes') if op.require_checkin_attention else _('No')) row.append(_('Yes') if op.require_checkin_attention else _('No'))
row.append(op.order.comment or "") row.append(op.order.comment or "")
row.append("\n".join(text for text in [op.order.checkin_text, op.item.checkin_text] if text))
if op.seat: if op.seat:
row += [ row += [
+3
View File
@@ -949,6 +949,9 @@ class PaypalMethod(BasePaymentProvider):
} }
}) })
response = self.client.execute(req) response = self.client.execute(req)
except KeyError:
raise PaymentException(_('Refunding the amount via PayPal failed: The original payment does not contain '
'the required information to issue an automated refund.'))
except IOError as e: except IOError as e:
refund.order.log_action('pretix.event.order.refund.failed', { refund.order.log_action('pretix.event.order.refund.failed', {
'local_id': refund.local_id, 'local_id': refund.local_id,
+1 -1
View File
@@ -163,7 +163,7 @@ def signal_process_response(sender, request: HttpRequest, response: HttpResponse
# 'frame-src': ['https://www.paypal.com', 'https://www.sandbox.paypal.com', "'nonce-{}'".format(_nonce(request))], # 'frame-src': ['https://www.paypal.com', 'https://www.sandbox.paypal.com', "'nonce-{}'".format(_nonce(request))],
'frame-src': ['https:', "'nonce-{}'".format(_nonce(request))], 'frame-src': ['https:', "'nonce-{}'".format(_nonce(request))],
'connect-src': ['https://www.paypal.com', 'https://www.sandbox.paypal.com'], # Or not - seems to only affect PayPal logging... 'connect-src': ['https://www.paypal.com', 'https://www.sandbox.paypal.com'], # Or not - seems to only affect PayPal logging...
'img-src': ['https://t.paypal.com'], 'img-src': ['https://t.paypal.com', 'https://www.paypalobjects.com'],
'style-src': ["'unsafe-inline'"] # PayPal does not comply with our nonce unfortunately, see Z#23113213 'style-src': ["'unsafe-inline'"] # PayPal does not comply with our nonce unfortunately, see Z#23113213
} }
+1
View File
@@ -84,6 +84,7 @@ seatingframe_html_head = EventPluginSignal()
""" """
Arguments: ``request`` Arguments: ``request``
**Temporary workaround, might be removed again later.**
This signal allows you to put code inside the HTML ``<head>`` tag This signal allows you to put code inside the HTML ``<head>`` tag
of the seatingframe page in the frontend. You will get the request as the keyword argument of the seatingframe page in the frontend. You will get the request as the keyword argument
``request`` and are expected to return plain HTML. ``request`` and are expected to return plain HTML.
+4 -4
View File
@@ -151,7 +151,7 @@ def get_grouped_items(event, *, channel: SalesChannel, subevent=None, voucher=No
), ),
).filter( ).filter(
variation_q, variation_q,
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel.identifier), Q(all_sales_channels=True) | Q(limit_sales_channels=channel),
active=True, active=True,
quotas__isnull=False, quotas__isnull=False,
subevent_disabled=False subevent_disabled=False
@@ -685,7 +685,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
add_subevents_for_days( add_subevents_for_days(
filter_qs_by_attr( filter_qs_by_attr(
self.request.event.subevents_annotated( self.request.event.subevents_annotated(
self.request.sales_channel.identifier, self.request.sales_channel,
voucher, voucher,
).using(settings.DATABASE_REPLICA), ).using(settings.DATABASE_REPLICA),
self.request self.request
@@ -744,7 +744,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
add_subevents_for_days( add_subevents_for_days(
filter_qs_by_attr( filter_qs_by_attr(
self.request.event.subevents_annotated( self.request.event.subevents_annotated(
self.request.sales_channel.identifier, self.request.sales_channel,
voucher=voucher, voucher=voucher,
).using(settings.DATABASE_REPLICA), ).using(settings.DATABASE_REPLICA),
self.request self.request
@@ -793,7 +793,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
context['subevent_list'] = self.request.event.subevents_sorted( context['subevent_list'] = self.request.event.subevents_sorted(
filter_qs_by_attr( filter_qs_by_attr(
self.request.event.subevents_annotated( self.request.event.subevents_annotated(
self.request.sales_channel.identifier, self.request.sales_channel,
voucher=voucher, voucher=voucher,
).using(settings.DATABASE_REPLICA), ).using(settings.DATABASE_REPLICA),
self.request self.request
+22 -22
View File
@@ -185,7 +185,7 @@ class EventListMixin:
def _get_event_list_queryset(self): def _get_event_list_queryset(self):
query = Q(is_public=True) & Q(live=True) query = Q(is_public=True) & Q(live=True)
qs = self.request.organizer.events.using(settings.DATABASE_REPLICA).filter(query) qs = self.request.organizer.events.using(settings.DATABASE_REPLICA).filter(query)
qs = qs.filter(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier)) qs = qs.filter(Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel))
qs = qs.annotate( qs = qs.annotate(
min_from=Min('subevents__date_from'), min_from=Min('subevents__date_from'),
min_to=Min('subevents__date_to'), min_to=Min('subevents__date_to'),
@@ -213,7 +213,7 @@ class EventListMixin:
).order_by('order_from') ).order_by('order_from')
qs = Event.annotated(filter_qs_by_attr( qs = Event.annotated(filter_qs_by_attr(
qs, self.request, match_subevents_with_conditions=Q(active=True) & Q(is_public=True) & date_q qs, self.request, match_subevents_with_conditions=Q(active=True) & Q(is_public=True) & date_q
)) ), self.request.sales_channel)
return qs return qs
def _set_month_to_next_subevent(self): def _set_month_to_next_subevent(self):
@@ -724,10 +724,10 @@ class CalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
ctx['has_before'], ctx['has_after'] = has_before_after( ctx['has_before'], ctx['has_after'] = has_before_after(
self.request.organizer.events.filter( self.request.organizer.events.filter(
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
), ),
SubEvent.objects.filter( SubEvent.objects.filter(
Q(event__all_sales_channels=True) | Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(event__all_sales_channels=True) | Q(event__limit_sales_channels=self.request.sales_channel),
event__organizer=self.request.organizer, event__organizer=self.request.organizer,
event__is_public=True, event__is_public=True,
event__live=True, event__live=True,
@@ -746,14 +746,14 @@ class CalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
def _events_by_day(self, before, after): def _events_by_day(self, before, after):
ebd = defaultdict(list) ebd = defaultdict(list)
timezones = set() timezones = set()
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, 'web').using( add_events_for_days(self.request, Event.annotated(self.request.organizer.events, self.request.sales_channel).using(
settings.DATABASE_REPLICA settings.DATABASE_REPLICA
).filter( ).filter(
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
), before, after, ebd, timezones) ), before, after, ebd, timezones)
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter( add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
Q(event__all_sales_channels=True) | Q(event__all_sales_channels=True) |
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(event__limit_sales_channels=self.request.sales_channel),
event__organizer=self.request.organizer, event__organizer=self.request.organizer,
event__is_public=True, event__is_public=True,
event__live=True, event__live=True,
@@ -768,7 +768,7 @@ class CalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
) )
) )
) )
)), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones) ), self.request.sales_channel), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones)
self._multiple_timezones = len(timezones) > 1 self._multiple_timezones = len(timezones) > 1
return ebd return ebd
@@ -807,11 +807,11 @@ class WeekCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
ctx['has_before'], ctx['has_after'] = has_before_after( ctx['has_before'], ctx['has_after'] = has_before_after(
self.request.organizer.events.filter( self.request.organizer.events.filter(
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
), ),
SubEvent.objects.filter( SubEvent.objects.filter(
Q(event__all_sales_channels=True) | Q(event__all_sales_channels=True) |
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(event__limit_sales_channels=self.request.sales_channel),
event__organizer=self.request.organizer, event__organizer=self.request.organizer,
event__is_public=True, event__is_public=True,
event__live=True, event__live=True,
@@ -842,14 +842,14 @@ class WeekCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
def _events_by_day(self, before, after): def _events_by_day(self, before, after):
ebd = defaultdict(list) ebd = defaultdict(list)
timezones = set() timezones = set()
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, 'web').using( add_events_for_days(self.request, Event.annotated(self.request.organizer.events, self.request.sales_channel).using(
settings.DATABASE_REPLICA settings.DATABASE_REPLICA
).filter( ).filter(
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
), before, after, ebd, timezones) ), before, after, ebd, timezones)
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter( add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
Q(event__all_sales_channels=True) | Q(event__all_sales_channels=True) |
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(event__limit_sales_channels=self.request.sales_channel),
event__organizer=self.request.organizer, event__organizer=self.request.organizer,
event__is_public=True, event__is_public=True,
event__live=True, event__live=True,
@@ -864,7 +864,7 @@ class WeekCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
) )
) )
) )
)), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones) ), self.request.sales_channel), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones)
self._multiple_timezones = len(timezones) > 1 self._multiple_timezones = len(timezones) > 1
return ebd return ebd
@@ -946,11 +946,11 @@ class DayCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
ctx['has_before'], ctx['has_after'] = has_before_after( ctx['has_before'], ctx['has_after'] = has_before_after(
self.request.organizer.events.filter( self.request.organizer.events.filter(
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
), ),
SubEvent.objects.filter( SubEvent.objects.filter(
Q(event__all_sales_channels=True) | Q(event__all_sales_channels=True) |
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(event__limit_sales_channels=self.request.sales_channel),
event__organizer=self.request.organizer, event__organizer=self.request.organizer,
event__is_public=True, event__is_public=True,
event__live=True, event__live=True,
@@ -1194,14 +1194,14 @@ class DayCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
def _events_by_day(self, before, after): def _events_by_day(self, before, after):
ebd = defaultdict(list) ebd = defaultdict(list)
timezones = set() timezones = set()
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, 'web').using( add_events_for_days(self.request, Event.annotated(self.request.organizer.events, self.request.sales_channel).using(
settings.DATABASE_REPLICA settings.DATABASE_REPLICA
).filter( ).filter(
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
), before, after, ebd, timezones) ), before, after, ebd, timezones)
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter( add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
Q(event__all_sales_channels=True) | Q(event__all_sales_channels=True) |
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(event__limit_sales_channels=self.request.sales_channel),
event__organizer=self.request.organizer, event__organizer=self.request.organizer,
event__is_public=True, event__is_public=True,
event__live=True, event__live=True,
@@ -1216,7 +1216,7 @@ class DayCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
) )
) )
) )
)), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones) ), self.request.sales_channel), self.request).using(settings.DATABASE_REPLICA), before, after, ebd, timezones)
self._multiple_timezones = len(timezones) > 1 self._multiple_timezones = len(timezones) > 1
return ebd return ebd
@@ -1229,7 +1229,7 @@ class OrganizerIcalDownload(OrganizerViewMixin, View):
filter_qs_by_attr( filter_qs_by_attr(
self.request.organizer.events.filter( self.request.organizer.events.filter(
Q(date_from__gt=cutoff) | Q(date_to__gt=cutoff), Q(date_from__gt=cutoff) | Q(date_to__gt=cutoff),
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
is_public=True, is_public=True,
live=True, live=True,
has_subevents=False, has_subevents=False,
@@ -1250,7 +1250,7 @@ class OrganizerIcalDownload(OrganizerViewMixin, View):
SubEvent.objects.filter( SubEvent.objects.filter(
Q(date_from__gt=cutoff) | Q(date_to__gt=cutoff), Q(date_from__gt=cutoff) | Q(date_to__gt=cutoff),
Q(event__all_sales_channels=True) | Q(event__all_sales_channels=True) |
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(event__limit_sales_channels=self.request.sales_channel),
event__organizer=self.request.organizer, event__organizer=self.request.organizer,
event__is_public=True, event__is_public=True,
event__live=True, event__live=True,
+9 -9
View File
@@ -545,9 +545,9 @@ class WidgetAPIProductList(EventListMixin, View):
if hasattr(self.request, 'event'): if hasattr(self.request, 'event'):
add_subevents_for_days( add_subevents_for_days(
filter_qs_by_attr( filter_qs_by_attr(
self.request.event.subevents_annotated('web').filter( self.request.event.subevents_annotated(self.request.sales_channel).filter(
Q(event__all_sales_channels=True) | Q(event__all_sales_channels=True) |
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(event__limit_sales_channels=self.request.sales_channel),
), self.request ), self.request
), ),
limit_before, after, ebd, set(), self.request.event, limit_before, after, ebd, set(), self.request.event,
@@ -558,8 +558,8 @@ class WidgetAPIProductList(EventListMixin, View):
add_events_for_days( add_events_for_days(
self.request, self.request,
filter_qs_by_attr( filter_qs_by_attr(
Event.annotated(self.request.organizer.events, 'web').filter( Event.annotated(self.request.organizer.events, self.request.sales_channel).filter(
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier), Q(all_sales_channels=True) | Q(limit_sales_channels=self.request.sales_channel),
), self.request ), self.request
), ),
limit_before, after, ebd, timezones limit_before, after, ebd, timezones
@@ -572,7 +572,7 @@ class WidgetAPIProductList(EventListMixin, View):
event__live=True, event__live=True,
).prefetch_related( ).prefetch_related(
'event___settings_objects', 'event__organizer___settings_objects' 'event___settings_objects', 'event__organizer___settings_objects'
)), self.request), limit_before, after, ebd, timezones) ), self.request.sales_channel), self.request), limit_before, after, ebd, timezones)
data['weeks'] = weeks_for_template(ebd, self.year, self.month) data['weeks'] = weeks_for_template(ebd, self.year, self.month)
for w in data['weeks']: for w in data['weeks']:
@@ -605,7 +605,7 @@ class WidgetAPIProductList(EventListMixin, View):
ebd = defaultdict(list) ebd = defaultdict(list)
if hasattr(self.request, 'event'): if hasattr(self.request, 'event'):
add_subevents_for_days( add_subevents_for_days(
filter_qs_by_attr(self.request.event.subevents_annotated('web'), self.request), filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel), self.request),
limit_before, after, ebd, set(), self.request.event, limit_before, after, ebd, set(), self.request.event,
kwargs.get('cart_namespace') kwargs.get('cart_namespace')
) )
@@ -613,7 +613,7 @@ class WidgetAPIProductList(EventListMixin, View):
timezones = set() timezones = set()
add_events_for_days( add_events_for_days(
self.request, self.request,
filter_qs_by_attr(Event.annotated(self.request.organizer.events, 'web'), self.request), filter_qs_by_attr(Event.annotated(self.request.organizer.events, self.request.sales_channel), self.request),
limit_before, after, ebd, timezones limit_before, after, ebd, timezones
) )
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter( add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
@@ -622,7 +622,7 @@ class WidgetAPIProductList(EventListMixin, View):
event__live=True, event__live=True,
).prefetch_related( ).prefetch_related(
'event___settings_objects', 'event__organizer___settings_objects' 'event___settings_objects', 'event__organizer___settings_objects'
)), self.request), limit_before, after, ebd, timezones) ), self.request.sales_channel), self.request), limit_before, after, ebd, timezones)
data['days'] = days_for_template(ebd, week) data['days'] = days_for_template(ebd, week)
for d in data['days']: for d in data['days']:
@@ -632,7 +632,7 @@ class WidgetAPIProductList(EventListMixin, View):
limit = 50 limit = 50
if hasattr(self.request, 'event'): if hasattr(self.request, 'event'):
evs = filter_qs_by_attr( evs = filter_qs_by_attr(
self.request.event.subevents_annotated(self.request.sales_channel.identifier), self.request.event.subevents_annotated(self.request.sales_channel),
self.request, self.request,
match_subevents_with_conditions=( match_subevents_with_conditions=(
Q(Q(date_to__isnull=True) & Q(date_from__gte=now() - timedelta(hours=24))) Q(Q(date_to__isnull=True) & Q(date_from__gte=now() - timedelta(hours=24)))
@@ -195,7 +195,7 @@ input[type=number]::-webkit-outer-spin-button {
} }
.alert-danger::before { .alert-danger::before {
background-color: $state-danger-border; background-color: $state-danger-border;
background-image: url("data:image/svg+xml,%3Csvg%20viewBox='0%200%2036%2036'%20xmlns='http://www.w3.org/2000/svg'%20xml:space='preserve'%3E%3Cpath%20d='M12.14%204.62h11.64l8.24%208.24V23.4l-8.24%208.24H12.14L3.9%2023.39V12.86l8.24-8.24Z'%20fill='%23fff'/%3E%3Cpath%20d='M24.74%2022.6c0-.28-.11-.56-.31-.76l-3.27-3.27%203.27-3.27a1.08%201.08%200%200%200%200-1.52l-1.51-1.5a1.08%201.08%200%200%200-1.52%200l-3.27%203.26-3.27-3.27a1.08%201.08%200%200%200-1.52%200l-1.5%201.51a1.08%201.08%200%200%200%200%201.52l3.26%203.27-3.27%203.27a1.08%201.08%200%200%200%200%201.52l1.51%201.51a1.08%201.08%200%200%200%201.52%200l3.27-3.27%203.27%203.27a1.08%201.08%200%200%200%201.52%200l1.51-1.51c.2-.2.31-.48.31-.76Z'%20fill='#{url-friendly-colour($state-danger-text)}'/%3E%3C/svg%3E%0A"); background-image: url('data:image/svg+xml,<svg viewBox="0 0 36 36" xmlns="http://www.w3.org/2000/svg" xml:space="preserve"><path d="M12.14 4.62h11.64l8.24 8.24V23.4l-8.24 8.24H12.14L3.9 23.39V12.86l8.24-8.24Zm12.6 17.98c0-.28-.11-.56-.31-.76l-3.27-3.27 3.27-3.27a1.085 1.085 0 0 0 0-1.52l-1.51-1.5a1.085 1.085 0 0 0-1.52 0l-3.27 3.26-3.27-3.27a1.085 1.085 0 0 0-1.52 0l-1.5 1.51a1.085 1.085 0 0 0 0 1.52l3.26 3.27-3.27 3.27a1.085 1.085 0 0 0 0 1.52l1.51 1.51a1.085 1.085 0 0 0 1.52 0l3.27-3.27 3.27 3.27a1.085 1.085 0 0 0 1.52 0l1.51-1.51c.2-.2.31-.48.31-.76Z" style="fill:%23fff"/></svg>');
} }
.alert-primary::before { .alert-primary::before {
background: $brand-primary !important; background: $brand-primary !important;
+15
View File
@@ -1381,3 +1381,18 @@ def test_checkin_pdf_data_requires_permission(token_client, event, team, organiz
organizer.slug, event.slug, clist_all.pk organizer.slug, event.slug, clist_all.pk
)) ))
assert not resp.data['results'][0].get('pdf_data') assert not resp.data['results'][0].get('pdf_data')
@pytest.mark.django_db
def test_expand(token_client, organizer, event, clist, clist_all, item, other_item, order, django_assert_max_num_queries):
with scopes_disabled():
op = order.positions.first()
var1 = item.variations.create(value="XS")
op.variation = var1
op.save()
resp = token_client.get('/api/v1/organizers/{}/events/{}/checkinlists/{}/positions/?search=z3fsn8jyu&expand=variation'.format(
organizer.slug, event.slug, clist_all.pk
))
assert resp.status_code == 200
assert 'value' in resp.data['results'][0]['variation']
+44
View File
@@ -763,6 +763,50 @@ def test_event_update(token_client, organizer, event, item, meta_prop):
assert cnt == event.all_logentries().count() assert cnt == event.all_logentries().count()
@pytest.mark.django_db
def test_event_update_plugins_validation(token_client, organizer, event, item, meta_prop):
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"plugins": ["pretix.plugins.paypal2", "unknown"]
},
format='json'
)
assert resp.status_code == 400
assert resp.data == {"plugins": ["Unknown plugin: 'unknown'."]}
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"plugins": ["pretix.plugins.paypal2", "tests.testdummyhidden"]
},
format='json'
)
assert resp.status_code == 400
assert resp.data == {"plugins": ["Unknown plugin: 'tests.testdummyhidden'."]}
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"plugins": ["pretix.plugins.paypal2", "tests.testdummyrestricted"]
},
format='json'
)
assert resp.status_code == 400
assert resp.data == {"plugins": ["Restricted plugin: 'tests.testdummyrestricted'."]}
organizer.settings.allowed_restricted_plugins = ["tests.testdummyrestricted"]
resp = token_client.patch(
'/api/v1/organizers/{}/events/{}/'.format(organizer.slug, event.slug),
{
"plugins": ["pretix.plugins.paypal2", "tests.testdummyrestricted"]
},
format='json'
)
assert resp.status_code == 200
@pytest.mark.django_db @pytest.mark.django_db
def test_event_test_mode(token_client, organizer, event): def test_event_test_mode(token_client, organizer, event):
resp = token_client.patch( resp = token_client.patch(
+12
View File
@@ -86,6 +86,18 @@ def test_giftcard_list(token_client, organizer, event, giftcard, other_giftcard)
assert resp.status_code == 200 assert resp.status_code == 200
assert 2 == len(resp.data['results']) assert 2 == len(resp.data['results'])
resp = token_client.get('/api/v1/organizers/{}/giftcards/?expired=false'.format(organizer.slug))
assert 1 == len(resp.data['results'])
resp = token_client.get('/api/v1/organizers/{}/giftcards/?expired=true'.format(organizer.slug))
assert 0 == len(resp.data['results'])
resp = token_client.get('/api/v1/organizers/{}/giftcards/?value=23.00'.format(organizer.slug))
assert 1 == len(resp.data['results'])
resp = token_client.get('/api/v1/organizers/{}/giftcards/?value=23'.format(organizer.slug))
assert 1 == len(resp.data['results'])
resp = token_client.get('/api/v1/organizers/{}/giftcards/?value=24'.format(organizer.slug))
assert 0 == len(resp.data['results'])
@pytest.mark.django_db @pytest.mark.django_db
def test_giftcard_detail(token_client, organizer, event, giftcard): def test_giftcard_detail(token_client, organizer, event, giftcard):
+46 -1
View File
@@ -370,6 +370,13 @@ def test_item_list(token_client, organizer, event, team, item):
assert resp.status_code == 200 assert resp.status_code == 200
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/?search=Budget'.format(organizer.slug, event.slug))
assert resp.status_code == 200
assert [res] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/?search=Free'.format(organizer.slug, event.slug))
assert resp.status_code == 200
assert [] == resp.data['results']
@pytest.mark.django_db @pytest.mark.django_db
def test_item_detail(token_client, organizer, event, team, item): def test_item_detail(token_client, organizer, event, team, item):
@@ -590,7 +597,28 @@ def test_item_create_with_variation(token_client, organizer, event, item, catego
"meta_data": { "meta_data": {
"day": "Wednesday", "day": "Wednesday",
}, },
} },
{
"value": {
"de": "web",
"en": "web"
},
"active": True,
"require_approval": True,
"checkin_attention": False,
"checkin_text": None,
"require_membership": False,
"require_membership_hidden": False,
"require_membership_types": [],
"description": None,
"position": 0,
"default_price": None,
"sales_channels": ["web"],
"price": "23.00",
"meta_data": {
"day": "Wednesday",
},
},
] ]
}, },
format='json' format='json'
@@ -604,6 +632,8 @@ def test_item_create_with_variation(token_client, organizer, event, item, catego
assert new_item.variations.first().all_sales_channels is True assert new_item.variations.first().all_sales_channels is True
assert not new_item.variations.first().limit_sales_channels.exists() assert not new_item.variations.first().limit_sales_channels.exists()
assert new_item.variations.first().meta_data == {"day": "Wednesday"} assert new_item.variations.first().meta_data == {"day": "Wednesday"}
assert new_item.variations.last().all_sales_channels is False
assert new_item.variations.last().limit_sales_channels.exists()
@pytest.mark.django_db @pytest.mark.django_db
@@ -1389,6 +1419,21 @@ def test_variations_list(token_client, organizer, event, item, variation):
assert res['position'] == resp.data['results'][0]['position'] assert res['position'] == resp.data['results'][0]['position']
assert res['price'] == resp.data['results'][0]['price'] assert res['price'] == resp.data['results'][0]['price']
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/variations/?active=true'.format(organizer.slug, event.slug, item.pk))
assert resp.status_code == 200
assert res['value'] == resp.data['results'][0]['value']
resp = token_client.get(
'/api/v1/organizers/{}/events/{}/items/{}/variations/?active=false'.format(organizer.slug, event.slug, item.pk))
assert resp.status_code == 200
assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/variations/?search=Child'.format(organizer.slug, event.slug, item.pk))
assert resp.status_code == 200
assert res['value'] == resp.data['results'][0]['value']
resp = token_client.get('/api/v1/organizers/{}/events/{}/items/{}/variations/?search=Incorrect'.format(organizer.slug, event.slug, item.pk))
assert resp.status_code == 200
assert [] == resp.data['results']
@pytest.mark.django_db @pytest.mark.django_db
def test_variations_detail(token_client, organizer, event, item, variation): def test_variations_detail(token_client, organizer, event, item, variation):
+40
View File
@@ -414,6 +414,16 @@ def test_order_list(token_client, organizer, event, order, item, taxrule, questi
'/api/v1/organizers/{}/events/{}/orders/?email=foo@example.org'.format(organizer.slug, event.slug)) '/api/v1/organizers/{}/events/{}/orders/?email=foo@example.org'.format(organizer.slug, event.slug))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?payment_provider=banktransfer'.format(organizer.slug, event.slug))
assert [res] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?payment_provider=manual'.format(organizer.slug, event.slug))
assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?sales_channel=web'.format(organizer.slug, event.slug))
assert [res] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?sales_channel=bar'.format(organizer.slug, event.slug))
assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?locale=en'.format(organizer.slug, event.slug)) resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?locale=en'.format(organizer.slug, event.slug))
assert [res] == resp.data['results'] assert [res] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?locale=de'.format(organizer.slug, event.slug)) resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?locale=de'.format(organizer.slug, event.slug))
@@ -434,6 +444,36 @@ def test_order_list(token_client, organizer, event, order, item, taxrule, questi
)) ))
assert [] == resp.data['results'] assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
organizer.slug, event.slug,
(order.datetime - datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
))
assert [res] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
organizer.slug, event.slug, order.datetime.isoformat().replace('+00:00', 'Z')
))
assert [res] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_since={}'.format(
organizer.slug, event.slug,
(order.datetime + datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
))
assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
organizer.slug, event.slug,
(order.datetime - datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
))
assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
organizer.slug, event.slug, order.datetime.isoformat().replace('+00:00', 'Z')
))
assert [] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?created_before={}'.format(
organizer.slug, event.slug,
(order.datetime + datetime.timedelta(hours=1)).isoformat().replace('+00:00', 'Z')
))
assert [res] == resp.data['results']
resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?include_canceled_positions=false'.format(organizer.slug, event.slug)) resp = token_client.get('/api/v1/organizers/{}/events/{}/orders/?include_canceled_positions=false'.format(organizer.slug, event.slug))
assert resp.status_code == 200 assert resp.status_code == 200
assert len(resp.data['results'][0]['positions']) == 1 assert len(resp.data['results'][0]['positions']) == 1
+32 -30
View File
@@ -2329,8 +2329,8 @@ class EventTest(TestCase):
item2 = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=False) item2 = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=False)
q.items.add(item) q.items.add(item)
q.items.add(item2) q.items.add(item2)
assert Event.annotated(Event.objects).first().active_quotas == [q] assert Event.annotated(Event.objects, 'web').first().active_quotas == [q]
assert Event.annotated(Event.objects, 'foo').first().active_quotas == [] assert Event.annotated(Event.objects, self.organizer.sales_channels.get(identifier="bar")).first().active_quotas == []
@classscope(attr='organizer') @classscope(attr='organizer')
def test_active_quotas_annotation_product_inactive(self): def test_active_quotas_annotation_product_inactive(self):
@@ -2341,7 +2341,7 @@ class EventTest(TestCase):
q = Quota.objects.create(event=event, name='Quota', size=2) q = Quota.objects.create(event=event, name='Quota', size=2)
item = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=False) item = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=False)
q.items.add(item) q.items.add(item)
assert Event.annotated(Event.objects).first().active_quotas == [] assert Event.annotated(Event.objects, 'web').first().active_quotas == []
@classscope(attr='organizer') @classscope(attr='organizer')
def test_active_quotas_annotation_product_hidden_by_voucher(self): def test_active_quotas_annotation_product_hidden_by_voucher(self):
@@ -2354,16 +2354,16 @@ class EventTest(TestCase):
q.items.add(item) q.items.add(item)
voucher = Voucher.objects.create(event=event, code='a', item=item, show_hidden_items=True) voucher = Voucher.objects.create(event=event, code='a', item=item, show_hidden_items=True)
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q] assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == [q]
voucher = Voucher.objects.create(event=event, code='b', item=item, show_hidden_items=False) voucher = Voucher.objects.create(event=event, code='b', item=item, show_hidden_items=False)
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [] assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == []
voucher = Voucher.objects.create(event=event, code='c', show_hidden_items=True) voucher = Voucher.objects.create(event=event, code='c', show_hidden_items=True)
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q] assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == [q]
voucher = Voucher.objects.create(event=event, code='d', quota=q, show_hidden_items=True) voucher = Voucher.objects.create(event=event, code='d', quota=q, show_hidden_items=True)
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q] assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == [q]
item2 = Item.objects.create(event=event, name='Early-bird ticket', default_price=0) item2 = Item.objects.create(event=event, name='Early-bird ticket', default_price=0)
var = item2.variations.create(item=item2, value='Test', hide_without_voucher=True) var = item2.variations.create(item=item2, value='Test', hide_without_voucher=True)
@@ -2373,13 +2373,13 @@ class EventTest(TestCase):
q.variations.add(var) q.variations.add(var)
voucher = Voucher.objects.create(event=event, code='e', item=item2, variation=var, show_hidden_items=True) voucher = Voucher.objects.create(event=event, code='e', item=item2, variation=var, show_hidden_items=True)
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q] assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == [q]
voucher = Voucher.objects.create(event=event, code='f', item=item2, variation=var2, show_hidden_items=True) voucher = Voucher.objects.create(event=event, code='f', item=item2, variation=var2, show_hidden_items=True)
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [] assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == []
voucher = Voucher.objects.create(event=event, code='g', quota=q, show_hidden_items=True) voucher = Voucher.objects.create(event=event, code='g', quota=q, show_hidden_items=True)
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q] assert Event.annotated(Event.objects, "web", voucher=voucher).first().active_quotas == [q]
@classscope(attr='organizer') @classscope(attr='organizer')
def test_active_quotas_annotation_product_addon(self): def test_active_quotas_annotation_product_addon(self):
@@ -2395,7 +2395,7 @@ class EventTest(TestCase):
item.category = cat item.category = cat
item.save() item.save()
q.items.add(item) q.items.add(item)
assert Event.annotated(Event.objects).first().active_quotas == [] assert Event.annotated(Event.objects, 'web').first().active_quotas == []
@classscope(attr='organizer') @classscope(attr='organizer')
def test_active_quotas_annotation_product_unavailable(self): def test_active_quotas_annotation_product_unavailable(self):
@@ -2407,7 +2407,7 @@ class EventTest(TestCase):
item = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=True, item = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=True,
available_until=now() - timedelta(days=1)) available_until=now() - timedelta(days=1))
q.items.add(item) q.items.add(item)
assert Event.annotated(Event.objects).first().active_quotas == [] assert Event.annotated(Event.objects, 'web').first().active_quotas == []
@classscope(attr='organizer') @classscope(attr='organizer')
def test_active_quotas_annotation_variation_not_in_quota(self): def test_active_quotas_annotation_variation_not_in_quota(self):
@@ -2419,7 +2419,7 @@ class EventTest(TestCase):
item = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=True) item = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, active=True)
item.variations.create(value="foo") item.variations.create(value="foo")
q.items.add(item) q.items.add(item)
assert Event.annotated(Event.objects).first().active_quotas == [] assert Event.annotated(Event.objects, 'web').first().active_quotas == []
@classscope(attr='organizer') @classscope(attr='organizer')
def test_active_quotas_annotation_variation(self): def test_active_quotas_annotation_variation(self):
@@ -2434,29 +2434,29 @@ class EventTest(TestCase):
v.limit_sales_channels.add(self.organizer.sales_channels.get(identifier="web")) v.limit_sales_channels.add(self.organizer.sales_channels.get(identifier="web"))
q.items.add(item) q.items.add(item)
q.variations.add(v) q.variations.add(v)
assert Event.annotated(Event.objects).first().active_quotas == [q] assert Event.annotated(Event.objects, 'web').first().active_quotas == [q]
item.available_until = now() - timedelta(days=1) item.available_until = now() - timedelta(days=1)
item.save() item.save()
assert Event.annotated(Event.objects).first().active_quotas == [] assert Event.annotated(Event.objects, 'web').first().active_quotas == []
item.available_until = None item.available_until = None
item.available_from = now() + timedelta(days=1) item.available_from = now() + timedelta(days=1)
item.save() item.save()
assert Event.annotated(Event.objects).first().active_quotas == [] assert Event.annotated(Event.objects, 'web').first().active_quotas == []
item.available_until = None item.available_until = None
item.available_from = None item.available_from = None
item.active = False item.active = False
item.save() item.save()
assert Event.annotated(Event.objects).first().active_quotas == [] assert Event.annotated(Event.objects, 'web').first().active_quotas == []
item.active = True item.active = True
item.save() item.save()
assert Event.annotated(Event.objects).first().active_quotas == [q] assert Event.annotated(Event.objects, 'web').first().active_quotas == [q]
assert Event.annotated(Event.objects, 'foo').first().active_quotas == [] assert Event.annotated(Event.objects, self.organizer.sales_channels.get(identifier="bar")).first().active_quotas == []
v.active = False v.active = False
v.save() v.save()
assert Event.annotated(Event.objects).first().active_quotas == [] assert Event.annotated(Event.objects, 'web').first().active_quotas == []
item.hide_without_voucher = True item.hide_without_voucher = True
item.save() item.save()
assert Event.annotated(Event.objects).first().active_quotas == [] assert Event.annotated(Event.objects, 'web').first().active_quotas == []
class SubEventTest(TestCase): class SubEventTest(TestCase):
@@ -2502,8 +2502,10 @@ class SubEventTest(TestCase):
all_sales_channels=False) all_sales_channels=False)
item.limit_sales_channels.add(self.organizer.sales_channels.get(identifier="web")) item.limit_sales_channels.add(self.organizer.sales_channels.get(identifier="web"))
q.items.add(item) q.items.add(item)
assert SubEvent.annotated(SubEvent.objects).first().active_quotas == [q] assert SubEvent.annotated(SubEvent.objects, 'web').first().active_quotas == [q]
assert SubEvent.annotated(SubEvent.objects, 'foo').first().active_quotas == [] assert SubEvent.annotated(SubEvent.objects, 'bar').first().active_quotas == []
assert SubEvent.annotated(SubEvent.objects, self.organizer.sales_channels.get(identifier="web")).first().active_quotas == [q]
assert SubEvent.annotated(SubEvent.objects, self.organizer.sales_channels.get(identifier="bar")).first().active_quotas == []
@classscope(attr='organizer') @classscope(attr='organizer')
def test_active_quotas_annotation_no_interference(self): def test_active_quotas_annotation_no_interference(self):
@@ -2514,8 +2516,8 @@ class SubEventTest(TestCase):
subevent=se2) subevent=se2)
item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True) item = Item.objects.create(event=self.event, name='Early-bird ticket', default_price=0, active=True)
q.items.add(item) q.items.add(item)
assert SubEvent.annotated(SubEvent.objects).filter(pk=self.se.pk).first().active_quotas == [] assert SubEvent.annotated(SubEvent.objects, 'web').filter(pk=self.se.pk).first().active_quotas == []
assert SubEvent.annotated(SubEvent.objects).filter(pk=se2.pk).first().active_quotas == [q] assert SubEvent.annotated(SubEvent.objects, 'web').filter(pk=se2.pk).first().active_quotas == [q]
@classscope(attr='organizer') @classscope(attr='organizer')
def test_best_availability(self): def test_best_availability(self):
@@ -2540,7 +2542,7 @@ class SubEventTest(TestCase):
q = Quota.objects.create(event=self.event, name='Quota', size=1, q = Quota.objects.create(event=self.event, name='Quota', size=1,
subevent=self.se) subevent=self.se)
q.items.add(item) q.items.add(item)
obj = SubEvent.annotated(SubEvent.objects).first() obj = SubEvent.annotated(SubEvent.objects, 'web').first()
assert len(obj.active_quotas) == 1 assert len(obj.active_quotas) == 1
assert obj.best_availability == (Quota.AVAILABILITY_GONE, 0, 1) assert obj.best_availability == (Quota.AVAILABILITY_GONE, 0, 1)
@@ -2548,14 +2550,14 @@ class SubEventTest(TestCase):
q2 = Quota.objects.create(event=self.event, name='Quota 2', size=2, q2 = Quota.objects.create(event=self.event, name='Quota 2', size=2,
subevent=self.se) subevent=self.se)
q2.items.add(item) q2.items.add(item)
obj = SubEvent.annotated(SubEvent.objects).first() obj = SubEvent.annotated(SubEvent.objects, 'web').first()
assert len(obj.active_quotas) == 2 assert len(obj.active_quotas) == 2
assert obj.best_availability == (Quota.AVAILABILITY_GONE, 0, 1) assert obj.best_availability == (Quota.AVAILABILITY_GONE, 0, 1)
# 2 quotas - 2 items. Higher quota wins since second item is only connected to second quota. # 2 quotas - 2 items. Higher quota wins since second item is only connected to second quota.
item2 = Item.objects.create(event=self.event, name='Regular ticket', default_price=10, active=True) item2 = Item.objects.create(event=self.event, name='Regular ticket', default_price=10, active=True)
q2.items.add(item2) q2.items.add(item2)
obj = SubEvent.annotated(SubEvent.objects).first() obj = SubEvent.annotated(SubEvent.objects, 'web').first()
assert len(obj.active_quotas) == 2 assert len(obj.active_quotas) == 2
assert obj.best_availability == (Quota.AVAILABILITY_OK, 1, 2) assert obj.best_availability == (Quota.AVAILABILITY_OK, 1, 2)
assert obj.best_availability_is_low assert obj.best_availability_is_low
@@ -2564,7 +2566,7 @@ class SubEventTest(TestCase):
q.size = 10 q.size = 10
q.save() q.save()
q2.delete() q2.delete()
obj = SubEvent.annotated(SubEvent.objects).first() obj = SubEvent.annotated(SubEvent.objects, 'web').first()
assert len(obj.active_quotas) == 1 assert len(obj.active_quotas) == 1
assert obj.best_availability == (Quota.AVAILABILITY_OK, 9, 10) assert obj.best_availability == (Quota.AVAILABILITY_OK, 9, 10)
assert not obj.best_availability_is_low assert not obj.best_availability_is_low
@@ -2572,7 +2574,7 @@ class SubEventTest(TestCase):
# Unlimited quota # Unlimited quota
q.size = None q.size = None
q.save() q.save()
obj = SubEvent.annotated(SubEvent.objects).first() obj = SubEvent.annotated(SubEvent.objects, 'web').first()
assert obj.best_availability == (Quota.AVAILABILITY_OK, None, None) assert obj.best_availability == (Quota.AVAILABILITY_OK, None, None)
assert not obj.best_availability_is_low assert not obj.best_availability_is_low
+19
View File
@@ -299,6 +299,8 @@ class EventsTest(SoupTest):
doc = self.get_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug)) doc = self.get_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug))
self.assertIn("Stripe", doc.select(".form-plugins")[0].text) self.assertIn("Stripe", doc.select(".form-plugins")[0].text)
self.assertIn("Enable", doc.select("[name=\"plugin:pretix.plugins.stripe\"]")[0].text) self.assertIn("Enable", doc.select("[name=\"plugin:pretix.plugins.stripe\"]")[0].text)
assert not doc.select("[name=\"plugin:tests.testdummyrestricted\"]")
assert not doc.select("[name=\"plugin:tests.testdummyhidden\"]")
doc = self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug), doc = self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
{'plugin:pretix.plugins.stripe': 'enable'}) {'plugin:pretix.plugins.stripe': 'enable'})
@@ -308,6 +310,23 @@ class EventsTest(SoupTest):
{'plugin:pretix.plugins.stripe': 'disable'}) {'plugin:pretix.plugins.stripe': 'disable'})
self.assertIn("Enable", doc.select("[name=\"plugin:pretix.plugins.stripe\"]")[0].text) self.assertIn("Enable", doc.select("[name=\"plugin:pretix.plugins.stripe\"]")[0].text)
self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
{'plugin:tests.testdummyhidden': 'enable'})
self.event1.refresh_from_db()
assert "testdummyhidden" not in self.event1.plugins
self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
{'plugin:tests.testdummyrestricted': 'enable'})
self.event1.refresh_from_db()
assert "testdummyrestricted" not in self.event1.plugins
self.orga1.settings.allowed_restricted_plugins = ["tests.testdummyrestricted"]
self.post_doc('/control/event/%s/%s/settings/plugins' % (self.orga1.slug, self.event1.slug),
{'plugin:tests.testdummyrestricted': 'enable'})
self.event1.refresh_from_db()
assert "testdummyrestricted" in self.event1.plugins
def test_testmode_enable(self): def test_testmode_enable(self):
self.event1.testmode = False self.event1.testmode = False
self.event1.save() self.event1.save()
+64 -18
View File
@@ -91,12 +91,12 @@ def test_csv_simple(event):
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title","Attendee name: assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title","Attendee name:
First name","Attendee name: Middle name","Attendee name: Family name","Product","Price","Checked in","Checked out","Automatically First name","Attendee name: Middle name","Attendee name: Family name","Product","Price","Checked in","Checked out","Automatically
checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special attention", checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special attention",
"Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until","Address","ZIP code", "Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until","Address","ZIP code",
"City","Country","State" "City","Country","State"
"FOO","Mr Peter A Jones","Mr","Peter","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx", "FOO","Mr Peter A Jones","Mr","Peter","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
"FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k", "FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k",
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
""") """)
@@ -113,12 +113,12 @@ def test_csv_order_by_name_parts(event): # noqa
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title", assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price", "Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
"Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special "Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special
attention","Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until", attention","Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
"Address","ZIP code","City","Country","State" "Address","ZIP code","City","Country","State"
"FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k", "FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k",
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
"FOO","Mr Peter A Jones","Mr","Peter","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx", "FOO","Mr Peter A Jones","Mr","Peter","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
""") """)
c = CSVCheckinList(event, organizer=event.organizer) c = CSVCheckinList(event, organizer=event.organizer)
_, _, content = c.render({ _, _, content = c.render({
@@ -131,12 +131,12 @@ def test_csv_order_by_name_parts(event): # noqa
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title", assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price", "Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
"Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special "Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special
attention","Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until", attention","Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
"Address","ZIP code","City","Country","State" "Address","ZIP code","City","Country","State"
"FOO","Mr Peter A Jones","Mr","Peter","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx", "FOO","Mr Peter A Jones","Mr","Peter","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
"FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k", "FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k",
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
""") """)
@@ -184,12 +184,12 @@ def test_csv_order_by_inherited_name_parts(event): # noqa
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title", assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price", "Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
"Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special "Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special
attention","Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until", attention","Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
"Address","ZIP code","City","Country","State" "Address","ZIP code","City","Country","State"
"BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy", "BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy",
"dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
"FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx", "FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
"dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
""") """)
c = CSVCheckinList(event, organizer=event.organizer) c = CSVCheckinList(event, organizer=event.organizer)
_, _, content = c.render({ _, _, content = c.render({
@@ -202,12 +202,12 @@ def test_csv_order_by_inherited_name_parts(event): # noqa
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title", assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price", "Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
"Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special "Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special
attention","Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until", attention","Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
"Address","ZIP code","City","Country","State" "Address","ZIP code","City","Country","State"
"BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy", "BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy",
"dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
"FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx", "FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
"dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
""") """)
c = CSVCheckinList(event, organizer=event.organizer) c = CSVCheckinList(event, organizer=event.organizer)
_, _, content = c.render({ _, _, content = c.render({
@@ -220,10 +220,56 @@ def test_csv_order_by_inherited_name_parts(event): # noqa
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title", assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title",
"Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price", "Attendee name: First name","Attendee name: Middle name","Attendee name: Family name","Product","Price",
"Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special "Checked in","Checked out","Automatically checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special
attention","Comment","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until", attention","Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until",
"Address","ZIP code","City","Country","State" "Address","ZIP code","City","Country","State"
"FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx", "FOO","Mr Paul A Jones","Mr","Paul","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
"dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","FOOCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
"BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy", "BAR","Mr Albert J Zulu","Mr","Albert","J","Zulu","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytyy",
"dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","" "dummy@dummy.test","'+498912345678","BARCORP","","2019-02-22","14:00:00","No","","","","","","","","","","","","","","",""
""") """)
@pytest.mark.django_db
def test_csv_order_by_orderdatetime(event):
order1 = event.orders.first()
order1.checkin_text = 'meow'
order1.save()
order2 = Order.objects.create(
code='FOO2', event=event, email='dummy@dummy.test', phone="+498912345678",
status=Order.STATUS_PAID,
datetime=datetime.datetime(2019, 2, 22, 22, 0, 0, tzinfo=datetime.timezone.utc),
expires=now() + datetime.timedelta(days=10),
total=33, locale='en', checkin_text='beep',
sales_channel=event.organizer.sales_channels.get(identifier="web"),
)
item_ticket = Item.objects.create(event=event, name="Ticket2", default_price=23, admission=True, checkin_text='boop')
OrderPosition.objects.create(
order=order2,
item=item_ticket,
variation=None,
price=Decimal("23"),
attendee_name_parts={"title": "Mx", "given_name": "Alex", "middle_name": "F", "family_name": "Nord"},
secret='asdfasdfasdfasdfasdfasdfasfdasdf'
)
c = CSVCheckinList(event, organizer=event.organizer)
_, _, content = c.render({
'list': event.checkin_lists.first().pk,
'secrets': True,
'sort': 'order_datetime',
'_format': 'default',
'questions': []
})
assert clean(content.decode()) == clean(""""Order code","Attendee name","Attendee name: Title","Attendee name:
First name","Attendee name: Middle name","Attendee name: Family name","Product","Price","Checked in","Checked out","Automatically
checked in","Secret","E-mail","Phone number","Company","Voucher code","Order date","Order time","Requires special attention",
"Comment","Check-in text","Seat ID","Seat name","Seat zone","Seat row","Seat number","Blocked","Valid from","Valid until","Address","ZIP code",
"City","Country","State"
"FOO2","Mx Alex F Nord","Mx","Alex","F","Nord","Ticket2","23.00","","","No","asdfasdfasdfasdfasdfasdfasfdasdf",
"dummy@dummy.test","'+498912345678","","","2019-02-22","22:00:00","No","","beep\nboop","","","","","","","","","","","","",""
"FOO","Mr Peter A Jones","Mr","Peter","A","Jones","Ticket","23.00","","","No","hutjztuxhkbtwnesv2suqv26k6ttytxx",
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","meow","","","","","","","","","","","","",""
"FOO","Mrs Andrea J Zulu","Mrs","Andrea","J","Zulu","Ticket","13.00","","","No","ggsngqtnmhx74jswjngw3fk8pfwz2a7k",
"dummy@dummy.test","'+498912345678","","","2019-02-22","14:00:00","No","","meow","","","","","","","","","","","","",""
""")
+2
View File
@@ -28,6 +28,8 @@ TEST_DIR = os.path.dirname(__file__)
TEMPLATES[0]['DIRS'].append(os.path.join(TEST_DIR, 'templates')) # NOQA TEMPLATES[0]['DIRS'].append(os.path.join(TEST_DIR, 'templates')) # NOQA
INSTALLED_APPS.append('tests.testdummy') # NOQA INSTALLED_APPS.append('tests.testdummy') # NOQA
INSTALLED_APPS.append('tests.testdummyrestricted') # NOQA
INSTALLED_APPS.append('tests.testdummyhidden') # NOQA
PRETIX_AUTH_BACKENDS = [ PRETIX_AUTH_BACKENDS = [
'pretix.base.auth.NativeAuthBackend', 'pretix.base.auth.NativeAuthBackend',
-18
View File
@@ -1,18 +0,0 @@
from io import StringIO
import pytest
from django.core.management import call_command
@pytest.mark.django_db
def test_no_pending_migrations():
out = StringIO()
try:
call_command(
"makemigrations",
"--check",
stdout=out,
stderr=StringIO(),
)
except SystemExit: # pragma: no cover
raise AssertionError("Pending migrations:\n" + out.getvalue()) from None
+21
View File
@@ -0,0 +1,21 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# 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/>.
#
+35
View File
@@ -0,0 +1,35 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# 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/>.
#
from django.apps import AppConfig
class TestDummyHiddenApp(AppConfig):
name = 'tests.testdummyhidden'
verbose_name = 'testdummyhidden'
class PretixPluginMeta:
name = 'testdummyhidden'
version = '1.0.0'
restricted = True
def is_available(self, event):
return False
+21
View File
@@ -0,0 +1,21 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# 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/>.
#
+32
View File
@@ -0,0 +1,32 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# 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/>.
#
from django.apps import AppConfig
class TestDummyRestrictedApp(AppConfig):
name = 'tests.testdummyrestricted'
verbose_name = 'testdummyrestricted'
class PretixPluginMeta:
name = 'testdummyrestricted'
version = '1.0.0'
restricted = True