mirror of
https://github.com/pretix/pretix.git
synced 2026-03-10 13:42:27 +00:00
Compare commits
3 Commits
error-page
...
timemachin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12ba49e263 | ||
|
|
e37b032d4e | ||
|
|
3c3b5529bf |
@@ -1719,56 +1719,6 @@ List of all order positions
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
.. http:get:: /api/v1/organizers/(organizer)/orderpositions/
|
||||
|
||||
Returns a list of all order positions within all events of a given organizer (with sufficient access permissions).
|
||||
|
||||
The supported query parameters and output format of this endpoint are almost identical to those of the list endpoint
|
||||
within an event.
|
||||
The only changes are that responses also contain the ``event`` attribute in each result and that the 'pdf_data'
|
||||
parameter is not supported.
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /api/v1/organizers/bigevents/orderpositions/ HTTP/1.1
|
||||
Host: pretix.eu
|
||||
Accept: application/json, text/javascript
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
X-Page-Generated: 2017-12-01T10:00:00Z
|
||||
|
||||
{
|
||||
"count": 1,
|
||||
"next": null,
|
||||
"previous": null,
|
||||
"results": [
|
||||
{
|
||||
"id:": 23442
|
||||
"event": "sampleconf",
|
||||
"order": "ABC12",
|
||||
"positionid": 1,
|
||||
"canceled": false,
|
||||
"item": 1345,
|
||||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
:param organizer: The ``slug`` field of the organizer to fetch
|
||||
:statuscode 200: no error
|
||||
:statuscode 401: Authentication failure
|
||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
||||
|
||||
|
||||
|
||||
Fetching individual positions
|
||||
-----------------------------
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ dependencies = [
|
||||
"phonenumberslite==9.0.*",
|
||||
"Pillow==12.1.*",
|
||||
"pretix-plugin-build",
|
||||
"protobuf==7.34.*",
|
||||
"protobuf==6.33.*",
|
||||
"psycopg2-binary",
|
||||
"pycountry",
|
||||
"pycparser==3.0",
|
||||
@@ -92,7 +92,7 @@ dependencies = [
|
||||
"redis==7.1.*",
|
||||
"reportlab==4.4.*",
|
||||
"requests==2.32.*",
|
||||
"sentry-sdk==2.54.*",
|
||||
"sentry-sdk==2.53.*",
|
||||
"sepaxml==2.7.*",
|
||||
"stripe==7.9.*",
|
||||
"text-unidecode==1.*",
|
||||
|
||||
@@ -637,14 +637,6 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
|
||||
return entry
|
||||
|
||||
|
||||
class OrganizerOrderPositionSerializer(OrderPositionSerializer):
|
||||
event = SlugRelatedField(slug_field='slug', read_only=True)
|
||||
|
||||
class Meta(OrderPositionSerializer.Meta):
|
||||
fields = OrderPositionSerializer.Meta.fields + ('event',)
|
||||
read_only_fields = OrderPositionSerializer.Meta.read_only_fields + ('event',)
|
||||
|
||||
|
||||
class RequireAttentionField(serializers.Field):
|
||||
def to_representation(self, instance: OrderPosition):
|
||||
return instance.require_checkin_attention
|
||||
|
||||
@@ -67,7 +67,6 @@ orga_router.register(r'invoices', order.InvoiceViewSet)
|
||||
orga_router.register(r'scheduled_exports', exporters.ScheduledOrganizerExportViewSet)
|
||||
orga_router.register(r'exporters', exporters.OrganizerExportersViewSet, basename='exporters')
|
||||
orga_router.register(r'transactions', order.OrganizerTransactionViewSet)
|
||||
orga_router.register(r'orderpositions', order.OrganizerOrderPositionViewSet, basename='orderpositions')
|
||||
|
||||
team_router = routers.DefaultRouter()
|
||||
team_router.register(r'members', organizer.TeamMemberViewSet)
|
||||
@@ -84,7 +83,7 @@ event_router.register(r'discounts', discount.DiscountViewSet)
|
||||
event_router.register(r'quotas', item.QuotaViewSet)
|
||||
event_router.register(r'vouchers', voucher.VoucherViewSet)
|
||||
event_router.register(r'orders', order.EventOrderViewSet)
|
||||
event_router.register(r'orderpositions', order.EventOrderPositionViewSet)
|
||||
event_router.register(r'orderpositions', order.OrderPositionViewSet)
|
||||
event_router.register(r'transactions', order.TransactionViewSet)
|
||||
event_router.register(r'invoices', order.InvoiceViewSet)
|
||||
event_router.register(r'revokedsecrets', order.RevokedSecretViewSet, basename='revokedsecrets')
|
||||
|
||||
@@ -57,10 +57,9 @@ from pretix.api.serializers.order import (
|
||||
BlockedTicketSecretSerializer, InvoiceSerializer, OrderCreateSerializer,
|
||||
OrderPaymentCreateSerializer, OrderPaymentSerializer,
|
||||
OrderPositionSerializer, OrderRefundCreateSerializer,
|
||||
OrderRefundSerializer, OrderSerializer, OrganizerOrderPositionSerializer,
|
||||
OrganizerTransactionSerializer, PriceCalcSerializer, PrintLogSerializer,
|
||||
RevokedTicketSecretSerializer, SimulatedOrderSerializer,
|
||||
TransactionSerializer,
|
||||
OrderRefundSerializer, OrderSerializer, OrganizerTransactionSerializer,
|
||||
PriceCalcSerializer, PrintLogSerializer, RevokedTicketSecretSerializer,
|
||||
SimulatedOrderSerializer, TransactionSerializer,
|
||||
)
|
||||
from pretix.api.serializers.orderchange import (
|
||||
BlockNameSerializer, OrderChangeOperationSerializer,
|
||||
@@ -1066,7 +1065,8 @@ with scopes_disabled():
|
||||
}
|
||||
|
||||
|
||||
class OrderPositionViewSetMixin:
|
||||
class OrderPositionViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = OrderPositionSerializer
|
||||
queryset = OrderPosition.all.none()
|
||||
filter_backends = (DjangoFilterBackend, RichOrderingFilter)
|
||||
ordering = ('order__datetime', 'positionid')
|
||||
@@ -1087,7 +1087,8 @@ class OrderPositionViewSetMixin:
|
||||
|
||||
def get_serializer_context(self):
|
||||
ctx = super().get_serializer_context()
|
||||
ctx['pdf_data'] = False
|
||||
ctx['event'] = self.request.event
|
||||
ctx['pdf_data'] = self.request.query_params.get('pdf_data', 'false').lower() == 'true'
|
||||
ctx['check_quotas'] = self.request.query_params.get('check_quotas', 'true').lower() == 'true'
|
||||
return ctx
|
||||
|
||||
@@ -1096,8 +1097,9 @@ class OrderPositionViewSetMixin:
|
||||
qs = OrderPosition.all
|
||||
else:
|
||||
qs = OrderPosition.objects
|
||||
qs = qs.filter(order__event__organizer=self.request.organizer)
|
||||
if self.request.query_params.get('pdf_data', 'false').lower() == 'true' and getattr(self.request, 'event', None):
|
||||
|
||||
qs = qs.filter(order__event=self.request.event)
|
||||
if self.request.query_params.get('pdf_data', 'false').lower() == 'true':
|
||||
prefetch_related_objects([self.request.organizer], 'meta_properties')
|
||||
prefetch_related_objects(
|
||||
[self.request.event],
|
||||
@@ -1152,9 +1154,9 @@ class OrderPositionViewSetMixin:
|
||||
qs = qs.prefetch_related(
|
||||
Prefetch('checkins', queryset=Checkin.objects.select_related("device")),
|
||||
Prefetch('print_logs', queryset=PrintLog.objects.select_related('device')),
|
||||
'answers', 'answers__options', 'answers__question', 'order__event', 'order__event__organizer'
|
||||
'answers', 'answers__options', 'answers__question',
|
||||
).select_related(
|
||||
'item', 'order', 'seat'
|
||||
'item', 'order', 'order__event', 'order__event__organizer', 'seat'
|
||||
)
|
||||
return qs
|
||||
|
||||
@@ -1166,45 +1168,6 @@ class OrderPositionViewSetMixin:
|
||||
return prov
|
||||
raise NotFound('Unknown output provider.')
|
||||
|
||||
|
||||
class OrganizerOrderPositionViewSet(OrderPositionViewSetMixin, viewsets.ReadOnlyModelViewSet):
|
||||
serializer_class = OrganizerOrderPositionSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset()
|
||||
|
||||
perm = self.permission if self.request.method in SAFE_METHODS else self.write_permission
|
||||
|
||||
if isinstance(self.request.auth, (TeamAPIToken, Device)):
|
||||
auth_obj = self.request.auth
|
||||
elif self.request.user.is_authenticated:
|
||||
auth_obj = self.request.user
|
||||
else:
|
||||
raise PermissionDenied("Unknown authentication scheme")
|
||||
|
||||
qs = qs.filter(
|
||||
order__event__in=auth_obj.get_events_with_permission(perm, request=self.request).filter(
|
||||
organizer=self.request.organizer
|
||||
)
|
||||
)
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
class EventOrderPositionViewSet(OrderPositionViewSetMixin, viewsets.ModelViewSet):
|
||||
serializer_class = OrderPositionSerializer
|
||||
|
||||
def get_serializer_context(self):
|
||||
ctx = super().get_serializer_context()
|
||||
ctx['event'] = self.request.event
|
||||
ctx['pdf_data'] = self.request.query_params.get('pdf_data', 'false').lower() == 'true'
|
||||
return ctx
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset()
|
||||
qs = qs.filter(order__event=self.request.event)
|
||||
return qs
|
||||
|
||||
@action(detail=True, methods=['POST'], url_name='price_calc')
|
||||
def price_calc(self, request, *args, **kwargs):
|
||||
"""
|
||||
|
||||
@@ -148,10 +148,6 @@ class NumberedCanvas(Canvas):
|
||||
self.restoreState()
|
||||
|
||||
|
||||
class InvoiceNotReadyException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BaseInvoiceRenderer:
|
||||
"""
|
||||
This is the base class for all invoice renderers.
|
||||
|
||||
@@ -181,11 +181,10 @@ class WaitingListEntry(LoggedModel):
|
||||
block_quota=True,
|
||||
item_id=self.item_id,
|
||||
subevent_id=self.subevent_id,
|
||||
waitinglistentries__isnull=False,
|
||||
seat__isnull=True
|
||||
waitinglistentries__isnull=False
|
||||
).aggregate(free=Sum(F('max_usages') - F('redeemed')))['free'] or 0
|
||||
free_seats = num_free_seats_for_product - num_valid_vouchers_for_product
|
||||
if free_seats < 1:
|
||||
if not free_seats:
|
||||
raise WaitingListException(_('No seat with this product is currently available.'))
|
||||
|
||||
if '@' not in self.email:
|
||||
|
||||
@@ -334,7 +334,8 @@ def _check_position_constraints(
|
||||
raise CartPositionError(error_messages['voucher_invalid_subevent'])
|
||||
|
||||
# Voucher expired
|
||||
if voucher and voucher.valid_until and voucher.valid_until < time_machine_now_dt:
|
||||
# (checked using real_now_dt as vouchers influence quota calculations)
|
||||
if voucher and voucher.valid_until and voucher.valid_until < real_now_dt:
|
||||
raise CartPositionError(error_messages['voucher_expired'])
|
||||
|
||||
# Subevent has been disabled
|
||||
|
||||
@@ -51,7 +51,6 @@ from django_scopes import scope, scopes_disabled
|
||||
from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.invoicing.pdf import InvoiceNotReadyException
|
||||
from pretix.base.invoicing.transmission import (
|
||||
get_transmission_types, transmission_providers,
|
||||
)
|
||||
@@ -505,7 +504,7 @@ def generate_invoice(order: Order, trigger_pdf=True):
|
||||
return invoice
|
||||
|
||||
|
||||
@app.task(base=TransactionAwareTask, throws=(InvoiceNotReadyException,))
|
||||
@app.task(base=TransactionAwareTask)
|
||||
def invoice_pdf_task(invoice: int):
|
||||
with scopes_disabled():
|
||||
i = Invoice.objects.get(pk=invoice)
|
||||
|
||||
@@ -409,18 +409,6 @@ def mail_send_task(self, **kwargs) -> bool:
|
||||
outgoing_mail.inflight_since = now()
|
||||
outgoing_mail.save(update_fields=["status", "inflight_since"])
|
||||
|
||||
# Performance optimization, saves database queries later on if we resolve the known relationships
|
||||
if outgoing_mail.event_id:
|
||||
assert outgoing_mail.event.organizer_id == outgoing_mail.organizer.pk
|
||||
outgoing_mail.event.organizer = outgoing_mail.organizer
|
||||
if outgoing_mail.order_id:
|
||||
assert outgoing_mail.order.event_id == outgoing_mail.event_id
|
||||
outgoing_mail.order.event = outgoing_mail.event
|
||||
outgoing_mail.order.organizer = outgoing_mail.organizer
|
||||
if outgoing_mail.orderposition_id:
|
||||
assert outgoing_mail.orderposition.order_id == outgoing_mail.order_id
|
||||
outgoing_mail.orderposition.order = outgoing_mail.order
|
||||
|
||||
headers = dict(outgoing_mail.headers)
|
||||
headers.setdefault('X-PX-Correlation', str(outgoing_mail.guid))
|
||||
email = CustomEmail(
|
||||
|
||||
@@ -24,7 +24,6 @@ import logging
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
from django.db.models import Prefetch, prefetch_related_objects
|
||||
from django.dispatch import receiver
|
||||
from django.utils.formats import date_format
|
||||
from django.utils.html import escape, mark_safe
|
||||
@@ -36,7 +35,6 @@ from pretix.base.forms.widgets import format_placeholders_help_text
|
||||
from pretix.base.i18n import (
|
||||
LazyCurrencyNumber, LazyDate, LazyExpiresDate, LazyNumber,
|
||||
)
|
||||
from pretix.base.models import EventMetaValue
|
||||
from pretix.base.reldate import RelativeDateWrapper
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES, get_name_parts_localized
|
||||
from pretix.base.signals import (
|
||||
@@ -754,11 +752,6 @@ def base_placeholders(sender, **kwargs):
|
||||
name_scheme['sample'][f]
|
||||
))
|
||||
|
||||
prefetch_related_objects(
|
||||
[sender],
|
||||
Prefetch('meta_values', queryset=EventMetaValue.objects.select_related("property"), to_attr="meta_values_cached")
|
||||
)
|
||||
prefetch_related_objects([sender.organizer], Prefetch('meta_properties'))
|
||||
for k, v in sender.meta_data.items():
|
||||
ph.append(MarkdownTextPlaceholder(
|
||||
'meta_%s' % k, ['event'], lambda event, k=k: event.meta_data[k],
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" href="{% static "pretixbase/img/favicon.ico" %}">
|
||||
{% block custom_header %}{% endblock %}
|
||||
{% if css_theme %}
|
||||
<link rel="stylesheet" type="text/css" href="{{ css_theme }}" />
|
||||
{% endif %}
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
||||
@@ -423,7 +423,7 @@ def resolve_timeframe_to_dates_inclusive(ref_dt, frame, timezone) -> Tuple[Optio
|
||||
raise ValueError(f"Invalid timeframe '{frame}'")
|
||||
|
||||
|
||||
def resolve_timeframe_to_datetime_start_inclusive_end_exclusive(ref_dt, frame, timezone) -> Tuple[Optional[datetime], Optional[datetime]]:
|
||||
def resolve_timeframe_to_datetime_start_inclusive_end_exclusive(ref_dt, frame, timezone) -> Tuple[Optional[date], Optional[date]]:
|
||||
"""
|
||||
Given a serialized timeframe, evaluate it relative to `ref_dt` and return a tuple of datetimes
|
||||
where the first element ist the first possible datetime within the timeframe and the second
|
||||
|
||||
@@ -280,12 +280,11 @@ class WaitingListView(EventPermissionRequiredMixin, WaitingListQuerySetMixin, Pa
|
||||
block_quota=True,
|
||||
item_id=wle.item_id,
|
||||
subevent=wle.subevent_id,
|
||||
waitinglistentries__isnull=False,
|
||||
seat__isnull=True
|
||||
waitinglistentries__isnull=False
|
||||
).aggregate(free=Sum(F('max_usages') - F('redeemed')))['free'] or 0
|
||||
free_seats = num_free_seats_for_product - num_valid_vouchers_for_product
|
||||
wle.availability = (
|
||||
Quota.AVAILABILITY_GONE if free_seats < 1 else wle.availability[0],
|
||||
Quota.AVAILABILITY_GONE if free_seats == 0 else wle.availability[0],
|
||||
min(free_seats, wle.availability[1]) if wle.availability[1] is not None else free_seats,
|
||||
)
|
||||
|
||||
|
||||
@@ -4,16 +4,16 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||
"PO-Revision-Date: 2026-03-05 20:00+0000\n"
|
||||
"PO-Revision-Date: 2026-02-19 22:00+0000\n"
|
||||
"Last-Translator: Mie Frydensbjerg <mif@aarhus.dk>\n"
|
||||
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"da/>\n"
|
||||
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix/da/"
|
||||
">\n"
|
||||
"Language: da\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.16.1\n"
|
||||
"X-Generator: Weblate 5.16\n"
|
||||
|
||||
#: pretix/_base_settings.py:87
|
||||
msgid "English"
|
||||
@@ -34285,7 +34285,7 @@ msgstr ""
|
||||
#: pretix/presale/templates/pretixpresale/event/voucher.html:293
|
||||
#, python-format
|
||||
msgid "minimum amount to order: %(num)s"
|
||||
msgstr "Minimumsbestilling: %(num)s"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:76
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:160
|
||||
|
||||
@@ -5,8 +5,8 @@ msgstr ""
|
||||
"Project-Id-Version: 1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||
"PO-Revision-Date: 2026-03-07 23:00+0000\n"
|
||||
"Last-Translator: argonimos <jonas@pfeiffer-wagner.de>\n"
|
||||
"PO-Revision-Date: 2026-02-24 12:07+0000\n"
|
||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
||||
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"de/>\n"
|
||||
"Language: de\n"
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.16.2\n"
|
||||
"X-Generator: Weblate 5.16\n"
|
||||
"X-Poedit-Bookmarks: -1,-1,904,-1,-1,-1,-1,-1,-1,-1\n"
|
||||
|
||||
#: pretix/_base_settings.py:87
|
||||
@@ -3845,7 +3845,7 @@ msgstr "Restbetrag"
|
||||
#, python-brace-format
|
||||
msgctxt "invoice"
|
||||
msgid "Invoice period: {daterange}"
|
||||
msgstr "Rechnungsperiode: {daterange}"
|
||||
msgstr "Rechungsperiode: {daterange}"
|
||||
|
||||
#: pretix/base/invoicing/pdf.py:1039
|
||||
msgctxt "invoice"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||
"PO-Revision-Date: 2026-03-09 12:52+0000\n"
|
||||
"PO-Revision-Date: 2026-03-02 10:00+0000\n"
|
||||
"Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n"
|
||||
"Language-Team: Japanese <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"ja/>\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Weblate 5.16.2\n"
|
||||
"X-Generator: Weblate 5.16.1\n"
|
||||
|
||||
#: pretix/_base_settings.py:87
|
||||
msgid "English"
|
||||
@@ -11448,7 +11448,7 @@ msgstr ""
|
||||
"{event}のご注文が完了しました。無料製品のみのご注文のため、\n"
|
||||
"お支払いは不要です。\n"
|
||||
"\n"
|
||||
"注文の詳細の変更やステータス確認は、以下のURLから行えます\n"
|
||||
"注文の詳細の変更やステータス確認は、以下のURLから行えます:\n"
|
||||
"{url}\n"
|
||||
"\n"
|
||||
"よろしくお願いいたします。\n"
|
||||
@@ -11750,7 +11750,7 @@ msgstr ""
|
||||
"{event}のご注文のお支払いを受け取りました。\n"
|
||||
"\n"
|
||||
"残念ながら、受け取った金額は必要な全額よりも少ないです。\n"
|
||||
"したがって、追加の **{pending_sum}** の支払いが不足しているため、\n"
|
||||
"したがって、追加の**{pending_sum}**の支払いが不足しているため、\n"
|
||||
"ご注文は未払いと見なされます。\n"
|
||||
"\n"
|
||||
"お支払い情報やご注文の状況は、以下のURLでご確認いただけます。\n"
|
||||
@@ -18428,7 +18428,7 @@ msgid ""
|
||||
"Do you really want to grant the application <strong>%(application)s</strong> "
|
||||
"access to your pretix account?"
|
||||
msgstr ""
|
||||
"本当にアプリケーション<strong>%(application)s</strong>にpretixアカウントへの"
|
||||
"本当にアプリケーション<strong>%(application)s</strong>にPretixアカウントへの"
|
||||
"アクセスを許可しますか?"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/auth/oauth_authorization.html:24
|
||||
@@ -24692,7 +24692,7 @@ msgstr "顧客履歴"
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_anonymize.html:11
|
||||
#, python-format
|
||||
msgid "Anonymize customer #%(id)s"
|
||||
msgstr "顧客 #%(id)s を匿名化"
|
||||
msgstr "顧客のID #%(id)s を匿名化"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/organizers/customer_anonymize.html:16
|
||||
msgid "Are you sure you want to anonymize this customer account?"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||
"PO-Revision-Date: 2026-03-09 12:52+0000\n"
|
||||
"PO-Revision-Date: 2026-03-04 16:57+0000\n"
|
||||
"Last-Translator: Ruud Hendrickx <ruud@leckxicon.eu>\n"
|
||||
"Language-Team: Dutch (Belgium) <https://translate.pretix.eu/projects/pretix/"
|
||||
"pretix/nl_BE/>\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.16.2\n"
|
||||
"X-Generator: Weblate 5.16.1\n"
|
||||
|
||||
#: pretix/_base_settings.py:87
|
||||
msgid "English"
|
||||
@@ -26981,10 +26981,6 @@ msgid ""
|
||||
"the affected data in your legislation, e.g. for reasons of taxation. In many "
|
||||
"countries, you need to keep some data in the live system in case of an audit."
|
||||
msgstr ""
|
||||
"Het is uw eigen verantwoordelijkheid om te controleren of u de gegevens "
|
||||
"volgens uw wetgeving mag verwijderen, bijvoorbeeld om fiscale redenen. In "
|
||||
"veel landen moet u bepaalde gegevens in het livesysteem bewaren voor het "
|
||||
"geval er een audit plaatsvindt."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/shredder/index.html:32
|
||||
msgid ""
|
||||
@@ -26992,87 +26988,81 @@ msgid ""
|
||||
"to store it offline. Some kinds of data (such as some payment information) "
|
||||
"as well as historical log data cannot be downloaded at the moment."
|
||||
msgstr ""
|
||||
"U kunt voor de meeste categorieën de gegevens gedeeltelijk downloaden om ze "
|
||||
"offline op te slaan. Sommige soorten gegevens (bijvoorbeeld sommige "
|
||||
"betalingsinformatie) en historische loggegevens kunnen momenteel niet worden "
|
||||
"gedownload."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/shredder/index.html:46
|
||||
msgid "Data selection"
|
||||
msgstr "Gegevensselectie"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/shredder/index.html:63
|
||||
msgid ""
|
||||
"We recommend not to remove this data because you might need it in case of a "
|
||||
"tax audit."
|
||||
msgstr ""
|
||||
"We raden aan om deze gegevens niet te verwijderen, omdat u ze mogelijk nodig "
|
||||
"hebt bij een belastingaudit."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:10
|
||||
msgctxt "subevent"
|
||||
msgid "Create multiple dates"
|
||||
msgstr "Meerdere datums aanmaken"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:35
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:146
|
||||
msgid "Repetition rule"
|
||||
msgstr "Regel voor herhaling"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:81
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:192
|
||||
#, python-format
|
||||
msgid "Repeat every %(interval)s %(freq)s, starting at %(start)s."
|
||||
msgstr "Herhaal ieder(e) %(interval)s %(freq)s, beginnend op %(start)s."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:258
|
||||
msgctxt "subevent"
|
||||
msgid "Preview"
|
||||
msgstr "Voorbeeldweergave"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:265
|
||||
msgctxt "subevent"
|
||||
msgid "Times"
|
||||
msgstr "Tijden"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:339
|
||||
msgid "Start of first slot"
|
||||
msgstr "Begin van eerste tijdsslot"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:345
|
||||
msgid "End of time slots"
|
||||
msgstr "Einde van tijdsslots"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:351
|
||||
msgid "Length of slots"
|
||||
msgstr "Lengte van tijdsslots"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:360
|
||||
msgid "Break between slots"
|
||||
msgstr "Pauze tussen tijdsslots"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:370
|
||||
msgid "Create"
|
||||
msgstr "Aanmaken"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:377
|
||||
msgid "Add a single time slot"
|
||||
msgstr "Eén tijdsslot toevoegen"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:379
|
||||
msgid "Add many time slots"
|
||||
msgstr "Meerdere tijdsslots toevoegen"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:481
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html:266
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html:124
|
||||
msgid "Add a new quota"
|
||||
msgstr "Nieuw quotum toevoegen"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:485
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html:128
|
||||
msgid "Product settings"
|
||||
msgstr "Productinstellingen"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:487
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html:130
|
||||
@@ -27080,8 +27070,6 @@ msgid ""
|
||||
"These settings are optional, if you leave them empty, the default values "
|
||||
"from the product settings will be used."
|
||||
msgstr ""
|
||||
"Deze instellingen zijn optioneel. Als u deze instellingen leeg laat, zullen "
|
||||
"de standaardwaarden uit de productinstellingen worden gebruikt."
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:523
|
||||
#: pretix/control/templates/pretixcontrol/subevents/detail.html:166
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
{% bootstrap_form_errors timemachine_form "all" %}
|
||||
|
||||
<p>{% trans "Test your shop as if it were a different date and time." %}</p>
|
||||
<p>{% trans "Please note that the changed time is not taken into account for aspects of the shop that affect quotas, such as the validity period of carts and vouchers." %}</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
@@ -44,4 +45,4 @@
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
12
src/pretix/static/npm_dir/package-lock.json
generated
12
src/pretix/static/npm_dir/package-lock.json
generated
@@ -2776,9 +2776,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
@@ -5642,9 +5642,9 @@
|
||||
"optional": true
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
|
||||
@@ -34,7 +34,7 @@ from stripe import error
|
||||
from tests.plugins.stripe.test_checkout import apple_domain_create
|
||||
from tests.plugins.stripe.test_provider import MockedCharge
|
||||
|
||||
from pretix.base.models import InvoiceAddress, Order, OrderPosition, Team
|
||||
from pretix.base.models import InvoiceAddress, Order, OrderPosition
|
||||
from pretix.base.models.orders import OrderFee, OrderPayment, OrderRefund
|
||||
|
||||
|
||||
@@ -180,41 +180,6 @@ def order2(event2, item2):
|
||||
return o
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@scopes_disabled()
|
||||
def team2(organizer, event2):
|
||||
team2 = Team.objects.create(
|
||||
organizer=organizer,
|
||||
name="Test-Team 2",
|
||||
can_change_teams=True,
|
||||
can_manage_gift_cards=True,
|
||||
can_change_items=True,
|
||||
can_create_events=True,
|
||||
can_change_event_settings=True,
|
||||
can_change_vouchers=True,
|
||||
can_view_vouchers=True,
|
||||
can_change_orders=True,
|
||||
can_manage_customers=True,
|
||||
can_manage_reusable_media=True,
|
||||
can_change_organizer_settings=True,
|
||||
|
||||
)
|
||||
team2.limit_events.add(event2)
|
||||
team2.save()
|
||||
return team2
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@scopes_disabled()
|
||||
def limited_token_client(client, team2):
|
||||
team2.can_view_orders = True
|
||||
team2.can_view_vouchers = True
|
||||
team2.save()
|
||||
t = team2.tokens.create(name='Foo')
|
||||
client.credentials(HTTP_AUTHORIZATION='Token ' + t.token)
|
||||
return client
|
||||
|
||||
|
||||
TEST_ORDERPOSITION_RES = {
|
||||
"id": 1,
|
||||
"order": "FOO",
|
||||
@@ -1022,64 +987,8 @@ def test_refund_cancel(token_client, organizer, event, order):
|
||||
assert resp.status_code == 400
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"endpoint_template, response_code",
|
||||
[('/api/v1/organizers/{}/events/{}/orderpositions/', 403), ('/api/v1/organizers/{}/orderpositions/', 200)]
|
||||
)
|
||||
@pytest.mark.django_db
|
||||
def test_orderposition_list_limited_read(
|
||||
endpoint_template, response_code, limited_token_client, organizer, device, event, order, item, subevent, subevent2, question
|
||||
):
|
||||
endpoint = endpoint_template.format(organizer.slug, event.slug)
|
||||
|
||||
i2 = copy.copy(item)
|
||||
i2.pk = None
|
||||
i2.save()
|
||||
with scopes_disabled():
|
||||
var = item.variations.create(value="Children")
|
||||
res = copy.copy(TEST_ORDERPOSITION_RES)
|
||||
op = order.positions.first()
|
||||
op.variation = var
|
||||
op.save()
|
||||
res["id"] = op.pk
|
||||
res["item"] = item.pk
|
||||
res["variation"] = var.pk
|
||||
res["answers"][0]["question"] = question.pk
|
||||
res["print_logs"][0]["id"] = op.print_logs.first().pk
|
||||
res["print_logs"][0]["device_id"] = device.device_id
|
||||
|
||||
resp = limited_token_client.get(endpoint)
|
||||
assert resp.status_code == response_code
|
||||
if response_code == 200:
|
||||
assert resp.json() == {'count': 0, 'next': None, 'previous': None, 'results': []}
|
||||
else:
|
||||
assert resp.json() == {'detail': 'You do not have permission to perform this action.'}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("endpoint_template", "endpoint_type"),
|
||||
[
|
||||
('/api/v1/organizers/{}/events/{}/orderpositions/', "event"),
|
||||
('/api/v1/organizers/{}/orderpositions/', "organizer")
|
||||
],
|
||||
)
|
||||
@pytest.mark.django_db
|
||||
def test_orderposition_list(
|
||||
endpoint_template,
|
||||
endpoint_type,
|
||||
token_client,
|
||||
organizer,
|
||||
device,
|
||||
event,
|
||||
order,
|
||||
item,
|
||||
subevent,
|
||||
subevent2,
|
||||
question,
|
||||
django_assert_num_queries
|
||||
):
|
||||
endpoint = endpoint_template.format(organizer.slug, event.slug)
|
||||
|
||||
def test_orderposition_list(token_client, organizer, device, event, order, item, subevent, subevent2, question, django_assert_num_queries):
|
||||
i2 = copy.copy(item)
|
||||
i2.pk = None
|
||||
i2.save()
|
||||
@@ -1096,64 +1005,88 @@ def test_orderposition_list(
|
||||
res["answers"][0]["question"] = question.pk
|
||||
res["print_logs"][0]["id"] = op.print_logs.first().pk
|
||||
res["print_logs"][0]["device_id"] = device.device_id
|
||||
if endpoint_type == "organizer":
|
||||
res["event"] = event.slug
|
||||
|
||||
resp = token_client.get(endpoint)
|
||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/'.format(organizer.slug, event.slug))
|
||||
assert resp.status_code == 200
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
resp = token_client.get(endpoint + '?order__status=n')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?order__status=n'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?order__status=p')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?order__status=p'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get(endpoint + '?item={}'.format(item.pk))
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?item={}'.format(organizer.slug, event.slug, item.pk))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?item__in={},{}'.format(item.pk, i2.pk))
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?item__in={},{}'.format(
|
||||
organizer.slug, event.slug, item.pk, i2.pk
|
||||
))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?item={}'.format(i2.pk))
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?item={}'.format(organizer.slug, event.slug, i2.pk))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get(endpoint + '?variation={}'.format(var.pk))
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?variation={}'.format(organizer.slug, event.slug, var.pk))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?variation={}'.format(var2.pk))
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?variation={}'.format(organizer.slug, event.slug, var2.pk))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get(endpoint + '?attendee_name=Peter')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=Peter'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?attendee_name=peter')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=peter'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?attendee_name=Mark')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=Mark'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get(endpoint + '?secret=z3fsn8jyufm5kpk768q69gkbyr5f4h6w')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?secret=z3fsn8jyufm5kpk768q69gkbyr5f4h6w'.format(
|
||||
organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?secret=abc123')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?secret=abc123'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get(endpoint + '?pseudonymization_id=ABCDEFGHKL')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?pseudonymization_id=ABCDEFGHKL'.format(
|
||||
organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?pseudonymization_id=FOO')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?pseudonymization_id=FOO'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get(endpoint + '?search=FO')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?search=FO'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?search=z3fsn8j')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?search=z3fsn8j'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?search=Peter')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?search=Peter'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?search=5f4h6w')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?search=5f4h6w'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get(endpoint + '?order=FOO')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?order=FOO'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?order=BAR')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?order=BAR'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get(endpoint + '?has_checkin=false')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=false'.format(organizer.slug, event.slug))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?has_checkin=true')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
with scopes_disabled():
|
||||
@@ -1170,28 +1103,33 @@ def test_orderposition_list(
|
||||
'gate': None,
|
||||
'type': 'entry'
|
||||
}]
|
||||
if '/events/' in endpoint:
|
||||
with django_assert_num_queries(18):
|
||||
resp = token_client.get(endpoint + '?has_checkin=true')
|
||||
else:
|
||||
with django_assert_num_queries(17):
|
||||
resp = token_client.get(endpoint + '?has_checkin=true')
|
||||
with django_assert_num_queries(16):
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug)
|
||||
)
|
||||
assert [res] == resp.data['results']
|
||||
|
||||
op.subevent = subevent
|
||||
op.save()
|
||||
res['subevent'] = subevent.pk
|
||||
|
||||
resp = token_client.get(endpoint + '?subevent={}'.format(subevent.pk))
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?subevent__in={},{}'.format(subevent.pk, subevent2.pk))
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent__in={},{}'.format(organizer.slug, event.slug,
|
||||
subevent.pk, subevent2.pk))
|
||||
assert [res] == resp.data['results']
|
||||
resp = token_client.get(endpoint + '?subevent={}'.format(subevent.pk + 1))
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug,
|
||||
subevent.pk + 1))
|
||||
assert [] == resp.data['results']
|
||||
|
||||
resp = token_client.get(endpoint + '?include_canceled_positions=false')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?include_canceled_positions=false'.format(organizer.slug, event.slug))
|
||||
assert len(resp.data['results']) == 1
|
||||
resp = token_client.get(endpoint + '?include_canceled_positions=true')
|
||||
resp = token_client.get(
|
||||
'/api/v1/organizers/{}/events/{}/orderpositions/?include_canceled_positions=true'.format(organizer.slug, event.slug))
|
||||
assert len(resp.data['results']) == 2
|
||||
|
||||
|
||||
|
||||
@@ -29,8 +29,6 @@ from pretix.base.models import (
|
||||
Event, Item, ItemVariation, Organizer, Quota, Team, User, Voucher,
|
||||
WaitingListEntry,
|
||||
)
|
||||
from pretix.base.models.seating import Seat, SeatingPlan
|
||||
from pretix.base.models.waitinglist import WaitingListException
|
||||
from pretix.control.views.dashboards import waitinglist_widgets
|
||||
|
||||
|
||||
@@ -57,11 +55,11 @@ def env():
|
||||
WaitingListEntry.objects.create(
|
||||
event=event, item=item1, email='success@example.org', voucher=v
|
||||
)
|
||||
v = Voucher.objects.create(item=item2, event=event, block_quota=True, redeemed=0, valid_until=now() - timedelta(days=5))
|
||||
v = Voucher.objects.create(item=item1, event=event, block_quota=True, redeemed=0, valid_until=now() - timedelta(days=5))
|
||||
WaitingListEntry.objects.create(
|
||||
event=event, item=item2, email='expired@example.org', voucher=v
|
||||
)
|
||||
v = Voucher.objects.create(item=item2, event=event, block_quota=True, redeemed=0, valid_until=now() + timedelta(days=5))
|
||||
v = Voucher.objects.create(item=item1, event=event, block_quota=True, redeemed=0, valid_until=now() + timedelta(days=5))
|
||||
WaitingListEntry.objects.create(
|
||||
event=event, item=item2, email='valid@example.org', voucher=v
|
||||
)
|
||||
@@ -347,75 +345,5 @@ def test_dashboard(client, env):
|
||||
quota.items.add(env['item1'])
|
||||
w = waitinglist_widgets(env['event'])
|
||||
|
||||
assert '2' in w[0]['content']
|
||||
assert '1' in w[0]['content']
|
||||
assert '5' in w[1]['content']
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_waitinglist_seat_calc(client, env):
|
||||
item = env['item1']
|
||||
event = env['event']
|
||||
wle = env['wle']
|
||||
|
||||
SeatingPlan.objects.create(
|
||||
name="Plan", organizer=event.organizer, layout="{}"
|
||||
)
|
||||
event.seat_category_mappings.create(
|
||||
layout_category='Stalls', product=item
|
||||
)
|
||||
for i in range(2):
|
||||
event.seats.create(seat_number=f"A{i}", product=item, seat_guid=f"A{i}")
|
||||
|
||||
quota = Quota.objects.create(event=event, size=10)
|
||||
quota.items.add(item)
|
||||
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
|
||||
# Calculated availability should not be more than number of available seats
|
||||
response = client.get('/control/event/dummy/dummy/waitinglist/')
|
||||
assert len(response.context['entries']) == 5
|
||||
for entry in response.context['entries']:
|
||||
assert entry.availability == (Quota.AVAILABILITY_OK, 2)
|
||||
|
||||
# Sending out a voucher reduces availability by 1
|
||||
with scopes_disabled():
|
||||
wle.send_voucher()
|
||||
|
||||
voucher = wle.voucher
|
||||
assert voucher
|
||||
|
||||
response = client.get('/control/event/dummy/dummy/waitinglist/')
|
||||
assert len(response.context['entries']) == 4
|
||||
for entry in response.context['entries']:
|
||||
assert entry.availability == (Quota.AVAILABILITY_OK, 1)
|
||||
|
||||
# Assigning a seat to a voucher does not decrease availability further
|
||||
with scopes_disabled():
|
||||
voucher.seat = Seat.objects.get(seat_guid="A0")
|
||||
voucher.save()
|
||||
|
||||
response = client.get('/control/event/dummy/dummy/waitinglist/')
|
||||
assert len(response.context['entries']) == 4
|
||||
for entry in response.context['entries']:
|
||||
assert entry.availability == (Quota.AVAILABILITY_OK, 1)
|
||||
|
||||
with scopes_disabled():
|
||||
wle2 = WaitingListEntry.objects.filter(item=item, voucher__isnull=True).first()
|
||||
wle2.send_voucher()
|
||||
|
||||
# Overbooking is handled correctly
|
||||
# Regression test for calculation that used `not free_seats` instead of `free_seats < 1`
|
||||
with scopes_disabled():
|
||||
# Block seat
|
||||
seat = Seat.objects.get(seat_guid="A1")
|
||||
seat.blocked = True
|
||||
seat.save()
|
||||
|
||||
response = client.get('/control/event/dummy/dummy/waitinglist/')
|
||||
assert len(response.context['entries']) == 3
|
||||
for entry in response.context['entries']:
|
||||
assert entry.availability == (Quota.AVAILABILITY_GONE, -1)
|
||||
|
||||
with scopes_disabled(), pytest.raises(WaitingListException):
|
||||
wle3 = WaitingListEntry.objects.filter(item=item, voucher__isnull=True).first()
|
||||
wle3.send_voucher()
|
||||
|
||||
Reference in New Issue
Block a user