mirror of
https://github.com/pretix/pretix.git
synced 2026-08-25 13:12:00 +00:00
Compare commits
75
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f44765cc88 | ||
|
|
3352ee2bbe | ||
|
|
af28785fb9 | ||
|
|
54e4957e89 | ||
|
|
f3597f1a44 | ||
|
|
2e01887e79 | ||
|
|
5a7e7fbde3 | ||
|
|
7b296107c5 | ||
|
|
4f449ce6b4 | ||
|
|
e6ea8fb5bf | ||
|
|
547910beec | ||
|
|
eef1560ede | ||
|
|
3d68bbb619 | ||
|
|
dc4556d428 | ||
|
|
5099fa16e0 | ||
|
|
f3fb1e66dc | ||
|
|
99e9690d48 | ||
|
|
e63e82e854 | ||
|
|
c662e627d5 | ||
|
|
f2121c7853 | ||
|
|
3ce6dbf798 | ||
|
|
43b91af5e6 | ||
|
|
034d6b997e | ||
|
|
345ad35fcf | ||
|
|
347337e76f | ||
|
|
c07ba31307 | ||
|
|
87b3e0c417 | ||
|
|
d3fd031639 | ||
|
|
9253327334 | ||
|
|
080b9cacaf | ||
|
|
9c2cc02df1 | ||
|
|
fceae0a2fe | ||
|
|
9fc3fdf751 | ||
|
|
04f79b7014 | ||
|
|
9d0b9387e6 | ||
|
|
b25e6f598d | ||
|
|
e8e2648f7e | ||
|
|
e0fac42225 | ||
|
|
3e9bc7675b | ||
|
|
1541033467 | ||
|
|
6b8c3ef15c | ||
|
|
135e07c183 | ||
|
|
fe97915b36 | ||
|
|
233281cea4 | ||
|
|
0300a44634 | ||
|
|
449d930565 | ||
|
|
49f49bd8a6 | ||
|
|
e896704fe0 | ||
|
|
cfee402a27 | ||
|
|
f8878e53a3 | ||
|
|
fd6a342bc6 | ||
|
|
865433276e | ||
|
|
f616f64f47 | ||
|
|
26550887b7 | ||
|
|
0f3de911b8 | ||
|
|
b648390dbf | ||
|
|
50fec0b31c | ||
|
|
e44af04e43 | ||
|
|
276c3177f5 | ||
|
|
27ac004a0b | ||
|
|
6d517d4e8d | ||
|
|
d9c3deda8a | ||
|
|
fe6add618a | ||
|
|
3615a52cc4 | ||
|
|
e3ae3b08bd | ||
|
|
959e926a67 | ||
|
|
876ddf1321 | ||
|
|
005b1d54d3 | ||
|
|
2066471086 | ||
|
|
a25bca7471 | ||
|
|
da43984ad2 | ||
|
|
7cce1c9219 | ||
|
|
cb9c4466f9 | ||
|
|
3398cda74b | ||
|
|
e5c8f19984 |
@@ -1719,6 +1719,56 @@ List of all order positions
|
|||||||
:statuscode 401: Authentication failure
|
:statuscode 401: Authentication failure
|
||||||
:statuscode 403: The requested organizer/event does not exist **or** you have no permission to view this resource.
|
: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
|
Fetching individual positions
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -77,7 +77,7 @@ dependencies = [
|
|||||||
"phonenumberslite==9.0.*",
|
"phonenumberslite==9.0.*",
|
||||||
"Pillow==12.1.*",
|
"Pillow==12.1.*",
|
||||||
"pretix-plugin-build",
|
"pretix-plugin-build",
|
||||||
"protobuf==6.33.*",
|
"protobuf==7.34.*",
|
||||||
"psycopg2-binary",
|
"psycopg2-binary",
|
||||||
"pycountry",
|
"pycountry",
|
||||||
"pycparser==3.0",
|
"pycparser==3.0",
|
||||||
@@ -92,7 +92,7 @@ dependencies = [
|
|||||||
"redis==7.1.*",
|
"redis==7.1.*",
|
||||||
"reportlab==4.4.*",
|
"reportlab==4.4.*",
|
||||||
"requests==2.32.*",
|
"requests==2.32.*",
|
||||||
"sentry-sdk==2.53.*",
|
"sentry-sdk==2.54.*",
|
||||||
"sepaxml==2.7.*",
|
"sepaxml==2.7.*",
|
||||||
"stripe==7.9.*",
|
"stripe==7.9.*",
|
||||||
"text-unidecode==1.*",
|
"text-unidecode==1.*",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||||
# <https://www.gnu.org/licenses/>.
|
# <https://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from collections import Counter, defaultdict
|
from collections import Counter, defaultdict
|
||||||
@@ -636,6 +637,14 @@ class OrderPositionSerializer(I18nAwareModelSerializer):
|
|||||||
return entry
|
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):
|
class RequireAttentionField(serializers.Field):
|
||||||
def to_representation(self, instance: OrderPosition):
|
def to_representation(self, instance: OrderPosition):
|
||||||
return instance.require_checkin_attention
|
return instance.require_checkin_attention
|
||||||
@@ -1215,6 +1224,18 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
|
|||||||
raise ValidationError('The given payment provider is not known.')
|
raise ValidationError('The given payment provider is not known.')
|
||||||
return pp
|
return pp
|
||||||
|
|
||||||
|
def validate_payment_info(self, info):
|
||||||
|
if info:
|
||||||
|
try:
|
||||||
|
obj = json.loads(info)
|
||||||
|
except ValueError:
|
||||||
|
raise ValidationError('payment_info must be valid JSON.')
|
||||||
|
|
||||||
|
if not isinstance(obj, dict):
|
||||||
|
# only objects are allowed
|
||||||
|
raise ValidationError('payment_info must be a JSON object.')
|
||||||
|
return info
|
||||||
|
|
||||||
def validate_expires(self, expires):
|
def validate_expires(self, expires):
|
||||||
if expires < now():
|
if expires < now():
|
||||||
raise ValidationError('Expiration date must be in the future.')
|
raise ValidationError('Expiration date must be in the future.')
|
||||||
|
|||||||
@@ -365,9 +365,10 @@ class TeamInviteSerializer(serializers.ModelSerializer):
|
|||||||
def _send_invite(self, instance):
|
def _send_invite(self, instance):
|
||||||
mail(
|
mail(
|
||||||
instance.email,
|
instance.email,
|
||||||
_('pretix account invitation'),
|
_('Account invitation'),
|
||||||
'pretixcontrol/email/invitation.txt',
|
'pretixcontrol/email/invitation.txt',
|
||||||
{
|
{
|
||||||
|
'instance': settings.PRETIX_INSTANCE_NAME,
|
||||||
'user': self,
|
'user': self,
|
||||||
'organizer': self.context['organizer'].name,
|
'organizer': self.context['organizer'].name,
|
||||||
'team': instance.team.name,
|
'team': instance.team.name,
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ orga_router.register(r'invoices', order.InvoiceViewSet)
|
|||||||
orga_router.register(r'scheduled_exports', exporters.ScheduledOrganizerExportViewSet)
|
orga_router.register(r'scheduled_exports', exporters.ScheduledOrganizerExportViewSet)
|
||||||
orga_router.register(r'exporters', exporters.OrganizerExportersViewSet, basename='exporters')
|
orga_router.register(r'exporters', exporters.OrganizerExportersViewSet, basename='exporters')
|
||||||
orga_router.register(r'transactions', order.OrganizerTransactionViewSet)
|
orga_router.register(r'transactions', order.OrganizerTransactionViewSet)
|
||||||
|
orga_router.register(r'orderpositions', order.OrganizerOrderPositionViewSet, basename='orderpositions')
|
||||||
|
|
||||||
team_router = routers.DefaultRouter()
|
team_router = routers.DefaultRouter()
|
||||||
team_router.register(r'members', organizer.TeamMemberViewSet)
|
team_router.register(r'members', organizer.TeamMemberViewSet)
|
||||||
@@ -83,7 +84,7 @@ event_router.register(r'discounts', discount.DiscountViewSet)
|
|||||||
event_router.register(r'quotas', item.QuotaViewSet)
|
event_router.register(r'quotas', item.QuotaViewSet)
|
||||||
event_router.register(r'vouchers', voucher.VoucherViewSet)
|
event_router.register(r'vouchers', voucher.VoucherViewSet)
|
||||||
event_router.register(r'orders', order.EventOrderViewSet)
|
event_router.register(r'orders', order.EventOrderViewSet)
|
||||||
event_router.register(r'orderpositions', order.OrderPositionViewSet)
|
event_router.register(r'orderpositions', order.EventOrderPositionViewSet)
|
||||||
event_router.register(r'transactions', order.TransactionViewSet)
|
event_router.register(r'transactions', order.TransactionViewSet)
|
||||||
event_router.register(r'invoices', order.InvoiceViewSet)
|
event_router.register(r'invoices', order.InvoiceViewSet)
|
||||||
event_router.register(r'revokedsecrets', order.RevokedSecretViewSet, basename='revokedsecrets')
|
event_router.register(r'revokedsecrets', order.RevokedSecretViewSet, basename='revokedsecrets')
|
||||||
|
|||||||
@@ -57,9 +57,10 @@ from pretix.api.serializers.order import (
|
|||||||
BlockedTicketSecretSerializer, InvoiceSerializer, OrderCreateSerializer,
|
BlockedTicketSecretSerializer, InvoiceSerializer, OrderCreateSerializer,
|
||||||
OrderPaymentCreateSerializer, OrderPaymentSerializer,
|
OrderPaymentCreateSerializer, OrderPaymentSerializer,
|
||||||
OrderPositionSerializer, OrderRefundCreateSerializer,
|
OrderPositionSerializer, OrderRefundCreateSerializer,
|
||||||
OrderRefundSerializer, OrderSerializer, OrganizerTransactionSerializer,
|
OrderRefundSerializer, OrderSerializer, OrganizerOrderPositionSerializer,
|
||||||
PriceCalcSerializer, PrintLogSerializer, RevokedTicketSecretSerializer,
|
OrganizerTransactionSerializer, PriceCalcSerializer, PrintLogSerializer,
|
||||||
SimulatedOrderSerializer, TransactionSerializer,
|
RevokedTicketSecretSerializer, SimulatedOrderSerializer,
|
||||||
|
TransactionSerializer,
|
||||||
)
|
)
|
||||||
from pretix.api.serializers.orderchange import (
|
from pretix.api.serializers.orderchange import (
|
||||||
BlockNameSerializer, OrderChangeOperationSerializer,
|
BlockNameSerializer, OrderChangeOperationSerializer,
|
||||||
@@ -1065,8 +1066,7 @@ with scopes_disabled():
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class OrderPositionViewSet(viewsets.ModelViewSet):
|
class OrderPositionViewSetMixin:
|
||||||
serializer_class = OrderPositionSerializer
|
|
||||||
queryset = OrderPosition.all.none()
|
queryset = OrderPosition.all.none()
|
||||||
filter_backends = (DjangoFilterBackend, RichOrderingFilter)
|
filter_backends = (DjangoFilterBackend, RichOrderingFilter)
|
||||||
ordering = ('order__datetime', 'positionid')
|
ordering = ('order__datetime', 'positionid')
|
||||||
@@ -1087,8 +1087,7 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
|
|||||||
|
|
||||||
def get_serializer_context(self):
|
def get_serializer_context(self):
|
||||||
ctx = super().get_serializer_context()
|
ctx = super().get_serializer_context()
|
||||||
ctx['event'] = self.request.event
|
ctx['pdf_data'] = False
|
||||||
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'
|
ctx['check_quotas'] = self.request.query_params.get('check_quotas', 'true').lower() == 'true'
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
@@ -1097,9 +1096,8 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
|
|||||||
qs = OrderPosition.all
|
qs = OrderPosition.all
|
||||||
else:
|
else:
|
||||||
qs = OrderPosition.objects
|
qs = OrderPosition.objects
|
||||||
|
qs = qs.filter(order__event__organizer=self.request.organizer)
|
||||||
qs = qs.filter(order__event=self.request.event)
|
if self.request.query_params.get('pdf_data', 'false').lower() == 'true' and getattr(self.request, 'event', None):
|
||||||
if self.request.query_params.get('pdf_data', 'false').lower() == 'true':
|
|
||||||
prefetch_related_objects([self.request.organizer], 'meta_properties')
|
prefetch_related_objects([self.request.organizer], 'meta_properties')
|
||||||
prefetch_related_objects(
|
prefetch_related_objects(
|
||||||
[self.request.event],
|
[self.request.event],
|
||||||
@@ -1154,9 +1152,9 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
|
|||||||
qs = qs.prefetch_related(
|
qs = qs.prefetch_related(
|
||||||
Prefetch('checkins', queryset=Checkin.objects.select_related("device")),
|
Prefetch('checkins', queryset=Checkin.objects.select_related("device")),
|
||||||
Prefetch('print_logs', queryset=PrintLog.objects.select_related('device')),
|
Prefetch('print_logs', queryset=PrintLog.objects.select_related('device')),
|
||||||
'answers', 'answers__options', 'answers__question',
|
'answers', 'answers__options', 'answers__question', 'order__event', 'order__event__organizer'
|
||||||
).select_related(
|
).select_related(
|
||||||
'item', 'order', 'order__event', 'order__event__organizer', 'seat'
|
'item', 'order', 'seat'
|
||||||
)
|
)
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
@@ -1168,6 +1166,45 @@ class OrderPositionViewSet(viewsets.ModelViewSet):
|
|||||||
return prov
|
return prov
|
||||||
raise NotFound('Unknown output provider.')
|
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')
|
@action(detail=True, methods=['POST'], url_name='price_calc')
|
||||||
def price_calc(self, request, *args, **kwargs):
|
def price_calc(self, request, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -216,7 +216,10 @@ class OutboundSyncProvider:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
mapped_objects = self.sync_order(sq.order)
|
mapped_objects = self.sync_order(sq.order)
|
||||||
if not all(all(not res or res.sync_info.get("action", "") == "nothing_to_do" for res in res_list) for res_list in mapped_objects.values()):
|
actions_taken = [res and res.sync_info.get("action", "") for res_list in mapped_objects.values() for res in res_list]
|
||||||
|
should_write_logentry = any(action not in (None, "nothing_to_do") for action in actions_taken)
|
||||||
|
logger.info('Synced order %s to %s, actions: %r, log: %r', sq.order.code, sq.sync_provider, actions_taken, should_write_logentry)
|
||||||
|
if should_write_logentry:
|
||||||
sq.order.log_action("pretix.event.order.data_sync.success", {
|
sq.order.log_action("pretix.event.order.data_sync.success", {
|
||||||
"provider": self.identifier,
|
"provider": self.identifier,
|
||||||
"objects": {
|
"objects": {
|
||||||
@@ -237,7 +240,7 @@ class OutboundSyncProvider:
|
|||||||
sq.set_sync_error("exceeded", e.messages, e.full_message)
|
sq.set_sync_error("exceeded", e.messages, e.full_message)
|
||||||
else:
|
else:
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Could not sync order {sq.order.code} to {type(self).__name__} "
|
f"Could not sync order {sq.order.code} to {sq.sync_provider} "
|
||||||
f"(transient error, attempt #{sq.failed_attempts}, next {sq.not_before})",
|
f"(transient error, attempt #{sq.failed_attempts}, next {sq.not_before})",
|
||||||
exc_info=True,
|
exc_info=True,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -315,8 +315,9 @@ class OrderListExporter(MultiSheetListExporter):
|
|||||||
for id, vn in payment_methods:
|
for id, vn in payment_methods:
|
||||||
headers.append(_('Paid by {method}').format(method=vn))
|
headers.append(_('Paid by {method}').format(method=vn))
|
||||||
|
|
||||||
# get meta_data labels from first cached event
|
if self.event_object_cache:
|
||||||
headers += next(iter(self.event_object_cache.values())).meta_data.keys()
|
# get meta_data labels from first cached event if any
|
||||||
|
headers += next(iter(self.event_object_cache.values())).meta_data.keys()
|
||||||
yield headers
|
yield headers
|
||||||
|
|
||||||
full_fee_sum_cache = {
|
full_fee_sum_cache = {
|
||||||
@@ -503,8 +504,9 @@ class OrderListExporter(MultiSheetListExporter):
|
|||||||
headers.append(_('External customer ID'))
|
headers.append(_('External customer ID'))
|
||||||
headers.append(_('Payment providers'))
|
headers.append(_('Payment providers'))
|
||||||
|
|
||||||
# get meta_data labels from first cached event
|
if self.event_object_cache:
|
||||||
headers += next(iter(self.event_object_cache.values())).meta_data.keys()
|
# get meta_data labels from first cached event if any
|
||||||
|
headers += next(iter(self.event_object_cache.values())).meta_data.keys()
|
||||||
yield headers
|
yield headers
|
||||||
|
|
||||||
yield self.ProgressSetTotal(total=qs.count())
|
yield self.ProgressSetTotal(total=qs.count())
|
||||||
@@ -707,9 +709,9 @@ class OrderListExporter(MultiSheetListExporter):
|
|||||||
_('Position order link')
|
_('Position order link')
|
||||||
]
|
]
|
||||||
|
|
||||||
# get meta_data labels from first cached event
|
|
||||||
meta_data_labels = next(iter(self.event_object_cache.values())).meta_data.keys()
|
|
||||||
if has_subevents:
|
if has_subevents:
|
||||||
|
# get meta_data labels from first cached event
|
||||||
|
meta_data_labels = next(iter(self.event_object_cache.values())).meta_data.keys()
|
||||||
headers += meta_data_labels
|
headers += meta_data_labels
|
||||||
yield headers
|
yield headers
|
||||||
|
|
||||||
|
|||||||
@@ -1415,6 +1415,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
|
|||||||
if not data.get(r):
|
if not data.get(r):
|
||||||
raise ValidationError({r: _("This field is required for the selected type of invoice transmission.")})
|
raise ValidationError({r: _("This field is required for the selected type of invoice transmission.")})
|
||||||
|
|
||||||
|
transmission_type.validate_invoice_address_data(data)
|
||||||
self.instance.transmission_type = transmission_type.identifier
|
self.instance.transmission_type = transmission_type.identifier
|
||||||
self.instance.transmission_info = transmission_type.form_data_to_transmission_info(data)
|
self.instance.transmission_info = transmission_type.form_data_to_transmission_info(data)
|
||||||
elif transmission_type.is_exclusive(self.event, data.get("country"), data.get("is_business")):
|
elif transmission_type.is_exclusive(self.event, data.get("country"), data.get("is_business")):
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ from django.utils.html import escape
|
|||||||
from django.utils.timezone import get_current_timezone, now
|
from django.utils.timezone import get_current_timezone, now
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
from pretix.helpers.format import PlainHtmlAlternativeString
|
||||||
|
|
||||||
|
|
||||||
def replace_arabic_numbers(inp):
|
def replace_arabic_numbers(inp):
|
||||||
if not isinstance(inp, str):
|
if not isinstance(inp, str):
|
||||||
@@ -61,11 +63,18 @@ def replace_arabic_numbers(inp):
|
|||||||
return inp.translate(table)
|
return inp.translate(table)
|
||||||
|
|
||||||
|
|
||||||
|
def format_placeholder_help_text(placeholder_name, sample_value):
|
||||||
|
if isinstance(sample_value, PlainHtmlAlternativeString):
|
||||||
|
sample_value = sample_value.plain
|
||||||
|
title = (_("Sample: %s") % sample_value) if sample_value else ""
|
||||||
|
return ('<button type="button" class="content-placeholder" title="%s">{%s}</button>' % (escape(title), escape(placeholder_name)))
|
||||||
|
|
||||||
|
|
||||||
def format_placeholders_help_text(placeholders, event=None):
|
def format_placeholders_help_text(placeholders, event=None):
|
||||||
placeholders = [(k, v.render_sample(event) if event else v) for k, v in placeholders.items()]
|
placeholders = [(k, v.render_sample(event) if event else v) for k, v in placeholders.items()]
|
||||||
placeholders.sort(key=lambda x: x[0])
|
placeholders.sort(key=lambda x: x[0])
|
||||||
phs = [
|
phs = [
|
||||||
'<button type="button" class="content-placeholder" title="%s">{%s}</button>' % (escape(_("Sample: %s") % v) if v else "", escape(k))
|
format_placeholder_help_text(k, v)
|
||||||
for k, v in placeholders
|
for k, v in placeholders
|
||||||
]
|
]
|
||||||
return _('Available placeholders: {list}').format(
|
return _('Available placeholders: {list}').format(
|
||||||
|
|||||||
@@ -33,8 +33,7 @@ from pretix.base.invoicing.transmission import (
|
|||||||
transmission_types,
|
transmission_types,
|
||||||
)
|
)
|
||||||
from pretix.base.models import Invoice, InvoiceAddress
|
from pretix.base.models import Invoice, InvoiceAddress
|
||||||
from pretix.base.services.mail import mail, render_mail
|
from pretix.base.services.mail import mail
|
||||||
from pretix.helpers.format import format_map
|
|
||||||
|
|
||||||
|
|
||||||
@transmission_types.new()
|
@transmission_types.new()
|
||||||
@@ -134,9 +133,7 @@ class EmailTransmissionProvider(TransmissionProvider):
|
|||||||
subject = invoice.order.event.settings.get('mail_subject_order_invoice', as_type=LazyI18nString)
|
subject = invoice.order.event.settings.get('mail_subject_order_invoice', as_type=LazyI18nString)
|
||||||
|
|
||||||
# Do not set to completed because that is done by the email sending task
|
# Do not set to completed because that is done by the email sending task
|
||||||
subject = format_map(subject, context)
|
outgoing_mail = mail(
|
||||||
email_content = render_mail(template, context)
|
|
||||||
mail(
|
|
||||||
[recipient],
|
[recipient],
|
||||||
subject,
|
subject,
|
||||||
template,
|
template,
|
||||||
@@ -151,19 +148,10 @@ class EmailTransmissionProvider(TransmissionProvider):
|
|||||||
plain_text_only=True,
|
plain_text_only=True,
|
||||||
no_order_links=True,
|
no_order_links=True,
|
||||||
)
|
)
|
||||||
invoice.order.log_action(
|
if outgoing_mail:
|
||||||
'pretix.event.order.email.invoice',
|
invoice.order.log_action(
|
||||||
user=None,
|
'pretix.event.order.email.invoice',
|
||||||
auth=None,
|
user=None,
|
||||||
data={
|
auth=None,
|
||||||
'subject': subject,
|
data=outgoing_mail.log_data()
|
||||||
'message': email_content,
|
)
|
||||||
'position': None,
|
|
||||||
'recipient': recipient,
|
|
||||||
'invoices': [invoice.pk],
|
|
||||||
'attach_tickets': False,
|
|
||||||
'attach_ical': False,
|
|
||||||
'attach_other_files': [],
|
|
||||||
'attach_cached_files': [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -148,6 +148,10 @@ class NumberedCanvas(Canvas):
|
|||||||
self.restoreState()
|
self.restoreState()
|
||||||
|
|
||||||
|
|
||||||
|
class InvoiceNotReadyException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class BaseInvoiceRenderer:
|
class BaseInvoiceRenderer:
|
||||||
"""
|
"""
|
||||||
This is the base class for all invoice renderers.
|
This is the base class for all invoice renderers.
|
||||||
|
|||||||
@@ -204,6 +204,12 @@ class PeppolTransmissionType(TransmissionType):
|
|||||||
}
|
}
|
||||||
return base | {"transmission_peppol_participant_id"}
|
return base | {"transmission_peppol_participant_id"}
|
||||||
|
|
||||||
|
def validate_invoice_address_data(self, address_data: dict):
|
||||||
|
# Special case Belgium: If a Belgian business ID is used as Peppol ID, it should match the VAT ID
|
||||||
|
if address_data.get("transmission_peppol_participant_id").startswith("0208:") and address_data.get("vat_id"):
|
||||||
|
if address_data["vat_id"].removeprefix("BE") != address_data["transmission_peppol_participant_id"].removeprefix("0208:"):
|
||||||
|
raise ValidationError({"transmission_peppol_participant_id": _("The Peppol participant ID does not match your VAT ID.")})
|
||||||
|
|
||||||
def pdf_watermark(self) -> str:
|
def pdf_watermark(self) -> str:
|
||||||
return pgettext("peppol_invoice", "Visual copy")
|
return pgettext("peppol_invoice", "Visual copy")
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ from typing import Optional
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_countries.fields import Country
|
from django_countries.fields import Country
|
||||||
|
|
||||||
from pretix.base.models import Invoice, InvoiceAddress
|
from pretix.base.models import Invoice
|
||||||
from pretix.base.signals import EventPluginRegistry, Registry
|
from pretix.base.signals import EventPluginRegistry, Registry
|
||||||
|
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ class TransmissionType:
|
|||||||
def invoice_address_form_fields_visible(self, country: Country, is_business: bool) -> set:
|
def invoice_address_form_fields_visible(self, country: Country, is_business: bool) -> set:
|
||||||
return set(self.invoice_address_form_fields.keys())
|
return set(self.invoice_address_form_fields.keys())
|
||||||
|
|
||||||
def validate_address(self, ia: InvoiceAddress):
|
def validate_invoice_address_data(self, address_data: dict):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -346,7 +346,8 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
|||||||
{
|
{
|
||||||
'user': self,
|
'user': self,
|
||||||
'messages': msg,
|
'messages': msg,
|
||||||
'url': build_absolute_uri('control:user.settings')
|
'url': build_absolute_uri('control:user.settings'),
|
||||||
|
'instance': settings.PRETIX_INSTANCE_NAME,
|
||||||
},
|
},
|
||||||
event=None,
|
event=None,
|
||||||
user=self,
|
user=self,
|
||||||
@@ -391,6 +392,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
|||||||
'user': self,
|
'user': self,
|
||||||
'reason': msg,
|
'reason': msg,
|
||||||
'code': code,
|
'code': code,
|
||||||
|
'instance': settings.PRETIX_INSTANCE_NAME,
|
||||||
},
|
},
|
||||||
event=None,
|
event=None,
|
||||||
user=self,
|
user=self,
|
||||||
@@ -430,6 +432,7 @@ class User(AbstractBaseUser, PermissionsMixin, LoggingMixin):
|
|||||||
mail(
|
mail(
|
||||||
self.email, _('Password recovery'), 'pretixcontrol/email/forgot.txt',
|
self.email, _('Password recovery'), 'pretixcontrol/email/forgot.txt',
|
||||||
{
|
{
|
||||||
|
'instance': settings.PRETIX_INSTANCE_NAME,
|
||||||
'user': self,
|
'user': self,
|
||||||
'url': (build_absolute_uri('control:auth.forgot.recover')
|
'url': (build_absolute_uri('control:auth.forgot.recover')
|
||||||
+ '?id=%d&token=%s' % (self.id, default_token_generator.make_token(self)))
|
+ '?id=%d&token=%s' % (self.id, default_token_generator.make_token(self)))
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ class OrderSyncQueue(models.Model):
|
|||||||
|
|
||||||
def set_sync_error(self, failure_mode, messages, full_message):
|
def set_sync_error(self, failure_mode, messages, full_message):
|
||||||
logger.exception(
|
logger.exception(
|
||||||
f"Could not sync order {self.order.code} to {type(self).__name__} ({failure_mode})"
|
f"Could not sync order {self.order.code} to {self.sync_provider} ({failure_mode})"
|
||||||
)
|
)
|
||||||
self.order.log_action(f"pretix.event.order.data_sync.failed.{failure_mode}", {
|
self.order.log_action(f"pretix.event.order.data_sync.failed.{failure_mode}", {
|
||||||
"provider": self.sync_provider,
|
"provider": self.sync_provider,
|
||||||
|
|||||||
@@ -220,3 +220,20 @@ class OutgoingMail(models.Model):
|
|||||||
error_log_action_type = 'pretix.email.error'
|
error_log_action_type = 'pretix.email.error'
|
||||||
log_target = None
|
log_target = None
|
||||||
return log_target, error_log_action_type
|
return log_target, error_log_action_type
|
||||||
|
|
||||||
|
def log_data(self):
|
||||||
|
return {
|
||||||
|
"subject": self.subject,
|
||||||
|
"message": self.body_plain,
|
||||||
|
"to": self.to,
|
||||||
|
"cc": self.cc,
|
||||||
|
"bcc": self.bcc,
|
||||||
|
|
||||||
|
"invoices": [i.pk for i in self.should_attach_invoices.all()],
|
||||||
|
"attach_tickets": self.should_attach_tickets,
|
||||||
|
"attach_ical": self.should_attach_ical,
|
||||||
|
"attach_other_files": self.should_attach_other_files,
|
||||||
|
"attach_cached_files": [cf.filename for cf in self.should_attach_cached_files.all()],
|
||||||
|
|
||||||
|
"position": self.orderposition.positionid if self.orderposition else None,
|
||||||
|
}
|
||||||
|
|||||||
@@ -87,7 +87,6 @@ from pretix.base.timemachine import time_machine_now
|
|||||||
|
|
||||||
from ...helpers import OF_SELF
|
from ...helpers import OF_SELF
|
||||||
from ...helpers.countries import CachedCountries, FastCountryField
|
from ...helpers.countries import CachedCountries, FastCountryField
|
||||||
from ...helpers.format import FormattedString, format_map
|
|
||||||
from ...helpers.names import build_name
|
from ...helpers.names import build_name
|
||||||
from ...testutils.middleware import debugflags_var
|
from ...testutils.middleware import debugflags_var
|
||||||
from ._transactions import (
|
from ._transactions import (
|
||||||
@@ -1167,7 +1166,7 @@ class Order(LockModel, LoggedModel):
|
|||||||
only be attached for this position and child positions, the link will only point to the
|
only be attached for this position and child positions, the link will only point to the
|
||||||
position and the attendee email will be used if available.
|
position and the attendee email will be used if available.
|
||||||
"""
|
"""
|
||||||
from pretix.base.services.mail import mail, render_mail
|
from pretix.base.services.mail import mail
|
||||||
|
|
||||||
if not self.email and not (position and position.attendee_email):
|
if not self.email and not (position and position.attendee_email):
|
||||||
return
|
return
|
||||||
@@ -1177,32 +1176,20 @@ class Order(LockModel, LoggedModel):
|
|||||||
if position and position.attendee_email:
|
if position and position.attendee_email:
|
||||||
recipient = position.attendee_email
|
recipient = position.attendee_email
|
||||||
|
|
||||||
email_content = render_mail(template, context)
|
outgoing_mail = mail(
|
||||||
if not isinstance(subject, FormattedString):
|
|
||||||
subject = format_map(subject, context)
|
|
||||||
mail(
|
|
||||||
recipient, subject, template, context,
|
recipient, subject, template, context,
|
||||||
self.event, self.locale, self, headers=headers, sender=sender,
|
self.event, self.locale, self, headers=headers, sender=sender,
|
||||||
invoices=invoices, attach_tickets=attach_tickets,
|
invoices=invoices, attach_tickets=attach_tickets,
|
||||||
position=position, auto_email=auto_email, attach_ical=attach_ical,
|
position=position, auto_email=auto_email, attach_ical=attach_ical,
|
||||||
attach_other_files=attach_other_files, attach_cached_files=attach_cached_files,
|
attach_other_files=attach_other_files, attach_cached_files=attach_cached_files,
|
||||||
)
|
)
|
||||||
self.log_action(
|
if outgoing_mail:
|
||||||
log_entry_type,
|
self.log_action(
|
||||||
user=user,
|
log_entry_type,
|
||||||
auth=auth,
|
user=user,
|
||||||
data={
|
auth=auth,
|
||||||
'subject': subject,
|
data=outgoing_mail.log_data(),
|
||||||
'message': email_content,
|
)
|
||||||
'position': position.positionid if position else None,
|
|
||||||
'recipient': recipient,
|
|
||||||
'invoices': [i.pk for i in invoices] if invoices else [],
|
|
||||||
'attach_tickets': attach_tickets,
|
|
||||||
'attach_ical': attach_ical,
|
|
||||||
'attach_other_files': attach_other_files,
|
|
||||||
'attach_cached_files': [cf.filename for cf in attach_cached_files] if attach_cached_files else [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def resend_link(self, user=None, auth=None):
|
def resend_link(self, user=None, auth=None):
|
||||||
with language(self.locale, self.event.settings.region):
|
with language(self.locale, self.event.settings.region):
|
||||||
@@ -2900,17 +2887,14 @@ class OrderPosition(AbstractPosition):
|
|||||||
:param attach_tickets: Attach tickets of this order, if they are existing and ready to download
|
:param attach_tickets: Attach tickets of this order, if they are existing and ready to download
|
||||||
:param attach_ical: Attach relevant ICS files
|
:param attach_ical: Attach relevant ICS files
|
||||||
"""
|
"""
|
||||||
from pretix.base.services.mail import mail, render_mail
|
from pretix.base.services.mail import mail
|
||||||
|
|
||||||
if not self.attendee_email:
|
if not self.attendee_email:
|
||||||
return
|
return
|
||||||
|
|
||||||
with language(self.order.locale, self.order.event.settings.region):
|
with language(self.order.locale, self.order.event.settings.region):
|
||||||
recipient = self.attendee_email
|
recipient = self.attendee_email
|
||||||
email_content = render_mail(template, context)
|
outgoing_mail = mail(
|
||||||
if not isinstance(subject, FormattedString):
|
|
||||||
subject = format_map(subject, context)
|
|
||||||
mail(
|
|
||||||
recipient, subject, template, context,
|
recipient, subject, template, context,
|
||||||
self.event, self.order.locale, order=self.order, headers=headers, sender=sender,
|
self.event, self.order.locale, order=self.order, headers=headers, sender=sender,
|
||||||
position=self,
|
position=self,
|
||||||
@@ -2919,21 +2903,13 @@ class OrderPosition(AbstractPosition):
|
|||||||
attach_ical=attach_ical,
|
attach_ical=attach_ical,
|
||||||
attach_other_files=attach_other_files,
|
attach_other_files=attach_other_files,
|
||||||
)
|
)
|
||||||
self.order.log_action(
|
if outgoing_mail:
|
||||||
log_entry_type,
|
self.order.log_action(
|
||||||
user=user,
|
log_entry_type,
|
||||||
auth=auth,
|
user=user,
|
||||||
data={
|
auth=auth,
|
||||||
'subject': subject,
|
data=outgoing_mail.log_data(),
|
||||||
'message': email_content,
|
)
|
||||||
'recipient': recipient,
|
|
||||||
'invoices': [i.pk for i in invoices] if invoices else [],
|
|
||||||
'attach_tickets': attach_tickets,
|
|
||||||
'attach_ical': attach_ical,
|
|
||||||
'attach_other_files': attach_other_files,
|
|
||||||
'attach_cached_files': [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def resend_link(self, user=None, auth=None):
|
def resend_link(self, user=None, auth=None):
|
||||||
|
|
||||||
|
|||||||
@@ -34,10 +34,9 @@ from phonenumber_field.modelfields import PhoneNumberField
|
|||||||
from pretix.base.email import get_email_context
|
from pretix.base.email import get_email_context
|
||||||
from pretix.base.i18n import language
|
from pretix.base.i18n import language
|
||||||
from pretix.base.models import User, Voucher
|
from pretix.base.models import User, Voucher
|
||||||
from pretix.base.services.mail import mail, render_mail
|
from pretix.base.services.mail import mail
|
||||||
from pretix.helpers import OF_SELF
|
from pretix.helpers import OF_SELF
|
||||||
|
|
||||||
from ...helpers.format import format_map
|
|
||||||
from ...helpers.names import build_name
|
from ...helpers.names import build_name
|
||||||
from .base import LoggedModel
|
from .base import LoggedModel
|
||||||
from .event import Event, SubEvent
|
from .event import Event, SubEvent
|
||||||
@@ -181,10 +180,11 @@ class WaitingListEntry(LoggedModel):
|
|||||||
block_quota=True,
|
block_quota=True,
|
||||||
item_id=self.item_id,
|
item_id=self.item_id,
|
||||||
subevent_id=self.subevent_id,
|
subevent_id=self.subevent_id,
|
||||||
waitinglistentries__isnull=False
|
waitinglistentries__isnull=False,
|
||||||
|
seat__isnull=True
|
||||||
).aggregate(free=Sum(F('max_usages') - F('redeemed')))['free'] or 0
|
).aggregate(free=Sum(F('max_usages') - F('redeemed')))['free'] or 0
|
||||||
free_seats = num_free_seats_for_product - num_valid_vouchers_for_product
|
free_seats = num_free_seats_for_product - num_valid_vouchers_for_product
|
||||||
if not free_seats:
|
if free_seats < 1:
|
||||||
raise WaitingListException(_('No seat with this product is currently available.'))
|
raise WaitingListException(_('No seat with this product is currently available.'))
|
||||||
|
|
||||||
if '@' not in self.email:
|
if '@' not in self.email:
|
||||||
@@ -272,9 +272,7 @@ class WaitingListEntry(LoggedModel):
|
|||||||
with language(self.locale, self.event.settings.region):
|
with language(self.locale, self.event.settings.region):
|
||||||
recipient = self.email
|
recipient = self.email
|
||||||
|
|
||||||
email_content = render_mail(template, context)
|
outgoing_mail = mail(
|
||||||
subject = format_map(subject, context)
|
|
||||||
mail(
|
|
||||||
recipient, subject, template, context,
|
recipient, subject, template, context,
|
||||||
self.event,
|
self.event,
|
||||||
self.locale,
|
self.locale,
|
||||||
@@ -284,18 +282,13 @@ class WaitingListEntry(LoggedModel):
|
|||||||
attach_other_files=attach_other_files,
|
attach_other_files=attach_other_files,
|
||||||
attach_cached_files=attach_cached_files,
|
attach_cached_files=attach_cached_files,
|
||||||
)
|
)
|
||||||
self.log_action(
|
if outgoing_mail:
|
||||||
log_entry_type,
|
self.log_action(
|
||||||
user=user,
|
log_entry_type,
|
||||||
auth=auth,
|
user=user,
|
||||||
data={
|
auth=auth,
|
||||||
'subject': subject,
|
data=outgoing_mail.log_data(),
|
||||||
'message': email_content,
|
)
|
||||||
'recipient': recipient,
|
|
||||||
'attach_other_files': attach_other_files,
|
|
||||||
'attach_cached_files': [cf.filename for cf in attach_cached_files] if attach_cached_files else [],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def clean_itemvar(event, item, variation):
|
def clean_itemvar(event, item, variation):
|
||||||
|
|||||||
@@ -1295,6 +1295,7 @@ class ManualPayment(BasePaymentProvider):
|
|||||||
|
|
||||||
def format_map(self, order, payment):
|
def format_map(self, order, payment):
|
||||||
return {
|
return {
|
||||||
|
# Possible placeholder injection, we should make sure to never include user-controlled variables here
|
||||||
'order': order.code,
|
'order': order.code,
|
||||||
'amount': payment.amount,
|
'amount': payment.amount,
|
||||||
'currency': self.event.currency,
|
'currency': self.event.currency,
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ from pretix.base.services.tax import split_fee_for_taxes
|
|||||||
from pretix.base.templatetags.money import money_filter
|
from pretix.base.templatetags.money import money_filter
|
||||||
from pretix.celery_app import app
|
from pretix.celery_app import app
|
||||||
from pretix.helpers import OF_SELF
|
from pretix.helpers import OF_SELF
|
||||||
from pretix.helpers.format import format_map
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -55,7 +54,7 @@ def _send_wle_mail(wle: WaitingListEntry, subject: LazyI18nString, message: Lazy
|
|||||||
email_context = get_email_context(event_or_subevent=subevent or wle.event, event=wle.event)
|
email_context = get_email_context(event_or_subevent=subevent or wle.event, event=wle.event)
|
||||||
mail(
|
mail(
|
||||||
wle.email,
|
wle.email,
|
||||||
format_map(subject, email_context),
|
str(subject),
|
||||||
message,
|
message,
|
||||||
email_context,
|
email_context,
|
||||||
wle.event,
|
wle.event,
|
||||||
@@ -73,9 +72,8 @@ def _send_mail(order: Order, subject: LazyI18nString, message: LazyI18nString, s
|
|||||||
|
|
||||||
email_context = get_email_context(event_or_subevent=subevent or order.event, refund_amount=refund_amount,
|
email_context = get_email_context(event_or_subevent=subevent or order.event, refund_amount=refund_amount,
|
||||||
order=order, position_or_address=ia, event=order.event)
|
order=order, position_or_address=ia, event=order.event)
|
||||||
real_subject = format_map(subject, email_context)
|
|
||||||
order.send_mail(
|
order.send_mail(
|
||||||
real_subject, message, email_context,
|
subject, message, email_context,
|
||||||
'pretix.event.order.email.event_canceled',
|
'pretix.event.order.email.event_canceled',
|
||||||
user,
|
user,
|
||||||
)
|
)
|
||||||
@@ -85,14 +83,13 @@ def _send_mail(order: Order, subject: LazyI18nString, message: LazyI18nString, s
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email:
|
if p.addon_to_id is None and p.attendee_email and p.attendee_email != order.email:
|
||||||
real_subject = format_map(subject, email_context)
|
|
||||||
email_context = get_email_context(event_or_subevent=p.subevent or order.event,
|
email_context = get_email_context(event_or_subevent=p.subevent or order.event,
|
||||||
event=order.event,
|
event=order.event,
|
||||||
refund_amount=refund_amount,
|
refund_amount=refund_amount,
|
||||||
position_or_address=p,
|
position_or_address=p,
|
||||||
order=order, position=p)
|
order=order, position=p)
|
||||||
order.send_mail(
|
order.send_mail(
|
||||||
real_subject, message, email_context,
|
subject, message, email_context,
|
||||||
'pretix.event.order.email.event_canceled',
|
'pretix.event.order.email.event_canceled',
|
||||||
position=p,
|
position=p,
|
||||||
user=user
|
user=user
|
||||||
|
|||||||
@@ -334,7 +334,8 @@ def _check_position_constraints(
|
|||||||
raise CartPositionError(error_messages['voucher_invalid_subevent'])
|
raise CartPositionError(error_messages['voucher_invalid_subevent'])
|
||||||
|
|
||||||
# Voucher expired
|
# 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'])
|
raise CartPositionError(error_messages['voucher_expired'])
|
||||||
|
|
||||||
# Subevent has been disabled
|
# Subevent has been disabled
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ from django_scopes import scope, scopes_disabled
|
|||||||
from i18nfield.strings import LazyI18nString
|
from i18nfield.strings import LazyI18nString
|
||||||
|
|
||||||
from pretix.base.i18n import language
|
from pretix.base.i18n import language
|
||||||
|
from pretix.base.invoicing.pdf import InvoiceNotReadyException
|
||||||
from pretix.base.invoicing.transmission import (
|
from pretix.base.invoicing.transmission import (
|
||||||
get_transmission_types, transmission_providers,
|
get_transmission_types, transmission_providers,
|
||||||
)
|
)
|
||||||
@@ -504,7 +505,7 @@ def generate_invoice(order: Order, trigger_pdf=True):
|
|||||||
return invoice
|
return invoice
|
||||||
|
|
||||||
|
|
||||||
@app.task(base=TransactionAwareTask)
|
@app.task(base=TransactionAwareTask, throws=(InvoiceNotReadyException,))
|
||||||
def invoice_pdf_task(invoice: int):
|
def invoice_pdf_task(invoice: int):
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
i = Invoice.objects.get(pk=invoice)
|
i = Invoice.objects.get(pk=invoice)
|
||||||
|
|||||||
@@ -149,13 +149,13 @@ def prefix_subject(settings_holder, subject, highlight=False):
|
|||||||
return subject
|
return subject
|
||||||
|
|
||||||
|
|
||||||
def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, LazyI18nString],
|
def mail(email: Union[str, Sequence[str]], subject: Union[str, FormattedString], template: Union[str, LazyI18nString],
|
||||||
context: Dict[str, Any] = None, event: Event = None, locale: str = None, order: Order = None,
|
context: Dict[str, Any] = None, event: Event = None, locale: str = None, order: Order = None,
|
||||||
position: OrderPosition = None, *, headers: dict = None, sender: str = None, organizer: Organizer = None,
|
position: OrderPosition = None, *, headers: dict = None, sender: str = None, organizer: Organizer = None,
|
||||||
customer: Customer = None, invoices: Sequence = None, attach_tickets=False, auto_email=True, user=None,
|
customer: Customer = None, invoices: Sequence = None, attach_tickets=False, auto_email=True, user=None,
|
||||||
attach_ical=False, attach_cached_files: Sequence = None, attach_other_files: list=None,
|
attach_ical=False, attach_cached_files: Sequence = None, attach_other_files: list=None,
|
||||||
plain_text_only=False, no_order_links=False, cc: Sequence[str]=None, bcc: Sequence[str]=None,
|
plain_text_only=False, no_order_links=False, cc: Sequence[str]=None, bcc: Sequence[str]=None,
|
||||||
sensitive: bool=False):
|
sensitive: bool=False) -> Optional[OutgoingMail]:
|
||||||
"""
|
"""
|
||||||
Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation.
|
Sends out an email to a user. The mail will be sent synchronously or asynchronously depending on the installation.
|
||||||
|
|
||||||
@@ -335,14 +335,26 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
|
|||||||
should_attach_other_files=attach_other_files or [],
|
should_attach_other_files=attach_other_files or [],
|
||||||
sensitive=sensitive,
|
sensitive=sensitive,
|
||||||
)
|
)
|
||||||
|
m._prefetched_objects_cache = {}
|
||||||
if invoices and not position:
|
if invoices and not position:
|
||||||
m.should_attach_invoices.add(*invoices)
|
m.should_attach_invoices.add(*invoices)
|
||||||
|
# Hack: For logging, we'll later make a `should_attach_invoices.all()` call. We can prevent a useless
|
||||||
|
# DB query by filling the cache
|
||||||
|
m._prefetched_objects_cache[m.should_attach_invoices.prefetch_cache_name] = invoices
|
||||||
|
else:
|
||||||
|
m._prefetched_objects_cache[m.should_attach_invoices.prefetch_cache_name] = Invoice.objects.none()
|
||||||
if attach_cached_files:
|
if attach_cached_files:
|
||||||
|
cf_list = []
|
||||||
for cf in attach_cached_files:
|
for cf in attach_cached_files:
|
||||||
if not isinstance(cf, CachedFile):
|
if not isinstance(cf, CachedFile):
|
||||||
m.should_attach_cached_files.add(CachedFile.objects.get(pk=cf))
|
cf = CachedFile.objects.get(pk=cf)
|
||||||
else:
|
m.should_attach_cached_files.add(cf)
|
||||||
m.should_attach_cached_files.add(cf)
|
cf_list.append(cf)
|
||||||
|
# Hack: For logging, we'll later make a `should_attach_cached_files.all()` call. We can prevent a useless
|
||||||
|
# DB query by filling the cache
|
||||||
|
m._prefetched_objects_cache[m.should_attach_cached_files.prefetch_cache_name] = cf_list
|
||||||
|
else:
|
||||||
|
m._prefetched_objects_cache[m.should_attach_cached_files.prefetch_cache_name] = CachedFile.objects.none()
|
||||||
|
|
||||||
send_task = mail_send_task.si(
|
send_task = mail_send_task.si(
|
||||||
outgoing_mail=m.id
|
outgoing_mail=m.id
|
||||||
@@ -364,6 +376,8 @@ def mail(email: Union[str, Sequence[str]], subject: str, template: Union[str, La
|
|||||||
lambda: chain(*task_chain).apply_async()
|
lambda: chain(*task_chain).apply_async()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
return m
|
||||||
|
|
||||||
|
|
||||||
class CustomEmail(EmailMultiAlternatives):
|
class CustomEmail(EmailMultiAlternatives):
|
||||||
def _create_mime_attachment(self, content, mimetype):
|
def _create_mime_attachment(self, content, mimetype):
|
||||||
@@ -409,6 +423,18 @@ def mail_send_task(self, **kwargs) -> bool:
|
|||||||
outgoing_mail.inflight_since = now()
|
outgoing_mail.inflight_since = now()
|
||||||
outgoing_mail.save(update_fields=["status", "inflight_since"])
|
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 = dict(outgoing_mail.headers)
|
||||||
headers.setdefault('X-PX-Correlation', str(outgoing_mail.guid))
|
headers.setdefault('X-PX-Correlation', str(outgoing_mail.guid))
|
||||||
email = CustomEmail(
|
email = CustomEmail(
|
||||||
|
|||||||
@@ -1799,8 +1799,6 @@ class OrderChangeManager:
|
|||||||
tax_rule = tax_rules.get(pos.pk, pos.tax_rule)
|
tax_rule = tax_rules.get(pos.pk, pos.tax_rule)
|
||||||
if not tax_rule:
|
if not tax_rule:
|
||||||
continue
|
continue
|
||||||
if not pos.price:
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_rate = tax_rule.tax_rate_for(ia)
|
new_rate = tax_rule.tax_rate_for(ia)
|
||||||
@@ -1817,7 +1815,9 @@ class OrderChangeManager:
|
|||||||
override_tax_rate=new_rate, override_tax_code=new_code)
|
override_tax_rate=new_rate, override_tax_code=new_code)
|
||||||
self._totaldiff_guesstimate += new_tax.gross - pos.price
|
self._totaldiff_guesstimate += new_tax.gross - pos.price
|
||||||
self._operations.append(self.PriceOperation(pos, new_tax, new_tax.gross - pos.price))
|
self._operations.append(self.PriceOperation(pos, new_tax, new_tax.gross - pos.price))
|
||||||
self._invoice_dirty = True
|
if pos.price:
|
||||||
|
# We do not consider the invoice dirty if only 0€-valued taxes are changed
|
||||||
|
self._invoice_dirty = True
|
||||||
|
|
||||||
def cancel_fee(self, fee: OrderFee):
|
def cancel_fee(self, fee: OrderFee):
|
||||||
self._totaldiff_guesstimate -= fee.value
|
self._totaldiff_guesstimate -= fee.value
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import logging
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
|
||||||
|
from django.db.models import Prefetch, prefetch_related_objects
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.utils.formats import date_format
|
from django.utils.formats import date_format
|
||||||
from django.utils.html import escape, mark_safe
|
from django.utils.html import escape, mark_safe
|
||||||
@@ -35,6 +36,7 @@ from pretix.base.forms.widgets import format_placeholders_help_text
|
|||||||
from pretix.base.i18n import (
|
from pretix.base.i18n import (
|
||||||
LazyCurrencyNumber, LazyDate, LazyExpiresDate, LazyNumber,
|
LazyCurrencyNumber, LazyDate, LazyExpiresDate, LazyNumber,
|
||||||
)
|
)
|
||||||
|
from pretix.base.models import EventMetaValue
|
||||||
from pretix.base.reldate import RelativeDateWrapper
|
from pretix.base.reldate import RelativeDateWrapper
|
||||||
from pretix.base.settings import PERSON_NAME_SCHEMES, get_name_parts_localized
|
from pretix.base.settings import PERSON_NAME_SCHEMES, get_name_parts_localized
|
||||||
from pretix.base.signals import (
|
from pretix.base.signals import (
|
||||||
@@ -752,6 +754,11 @@ def base_placeholders(sender, **kwargs):
|
|||||||
name_scheme['sample'][f]
|
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():
|
for k, v in sender.meta_data.items():
|
||||||
ph.append(MarkdownTextPlaceholder(
|
ph.append(MarkdownTextPlaceholder(
|
||||||
'meta_%s' % k, ['event'], lambda event, k=k: event.meta_data[k],
|
'meta_%s' % k, ['event'], lambda event, k=k: event.meta_data[k],
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ def shred(self, event: Event, fileid: str, confirm_code: str, user: int=None, lo
|
|||||||
_('Data shredding completed'),
|
_('Data shredding completed'),
|
||||||
'pretixbase/email/shred_completed.txt',
|
'pretixbase/email/shred_completed.txt',
|
||||||
{
|
{
|
||||||
|
'instance': settings.PRETIX_INSTANCE_NAME,
|
||||||
'user': user,
|
'user': user,
|
||||||
'organizer': event.organizer.name,
|
'organizer': event.organizer.name,
|
||||||
'event': str(event.name),
|
'event': str(event.name),
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ def vouchers_send(event: Event, vouchers: list, subject: str, message: str, reci
|
|||||||
with language(event.settings.locale):
|
with language(event.settings.locale):
|
||||||
email_context = get_email_context(event=event, name=r.get('name') or '',
|
email_context = get_email_context(event=event, name=r.get('name') or '',
|
||||||
voucher_list=[v.code for v in voucher_list])
|
voucher_list=[v.code for v in voucher_list])
|
||||||
mail(
|
outgoing_mail = mail(
|
||||||
r['email'],
|
r['email'],
|
||||||
subject,
|
subject,
|
||||||
LazyI18nString(message),
|
LazyI18nString(message),
|
||||||
@@ -60,8 +60,8 @@ def vouchers_send(event: Event, vouchers: list, subject: str, message: str, reci
|
|||||||
data={
|
data={
|
||||||
'recipient': r['email'],
|
'recipient': r['email'],
|
||||||
'name': r.get('name'),
|
'name': r.get('name'),
|
||||||
'subject': subject,
|
'subject': outgoing_mail.subject,
|
||||||
'message': message,
|
'message': outgoing_mail.body_plain,
|
||||||
},
|
},
|
||||||
save=False
|
save=False
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -363,7 +363,7 @@ class EmailAddressShredder(BaseDataShredder):
|
|||||||
le.save(update_fields=['data', 'shredded'])
|
le.save(update_fields=['data', 'shredded'])
|
||||||
else:
|
else:
|
||||||
shred_log_fields(le, banlist=[
|
shred_log_fields(le, banlist=[
|
||||||
'recipient', 'message', 'subject', 'full_mail', 'old_email', 'new_email'
|
'recipient', 'message', 'subject', 'full_mail', 'old_email', 'new_email', 'bcc', 'cc',
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="icon" href="{% static "pretixbase/img/favicon.ico" %}">
|
<link rel="icon" href="{% static "pretixbase/img/favicon.ico" %}">
|
||||||
{% block custom_header %}{% endblock %}
|
{% block custom_header %}{% endblock %}
|
||||||
|
{% if css_theme %}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ css_theme }}" />
|
||||||
|
{% endif %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ Start time: {{ start_time }} (new data added after this time might not have been
|
|||||||
|
|
||||||
Best regards,
|
Best regards,
|
||||||
|
|
||||||
Your pretix team
|
Your {{ instance }} team
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
#
|
||||||
|
# This file is part of pretix (Community Edition).
|
||||||
|
#
|
||||||
|
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||||
|
# Copyright (C) 2020-today pretix 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 import template
|
||||||
|
from django.utils.html import mark_safe
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter("anon_email")
|
||||||
|
def anon_email(value):
|
||||||
|
"""Replaces @ with [at] and . with [dot] for anonymization."""
|
||||||
|
if not isinstance(value, str):
|
||||||
|
return value
|
||||||
|
value = value.replace("@", "[at]").replace(".", "[dot]")
|
||||||
|
return mark_safe(''.join(['&#{0};'.format(ord(char)) for char in value]))
|
||||||
@@ -423,7 +423,7 @@ def resolve_timeframe_to_dates_inclusive(ref_dt, frame, timezone) -> Tuple[Optio
|
|||||||
raise ValueError(f"Invalid timeframe '{frame}'")
|
raise ValueError(f"Invalid timeframe '{frame}'")
|
||||||
|
|
||||||
|
|
||||||
def resolve_timeframe_to_datetime_start_inclusive_end_exclusive(ref_dt, frame, timezone) -> Tuple[Optional[date], Optional[date]]:
|
def resolve_timeframe_to_datetime_start_inclusive_end_exclusive(ref_dt, frame, timezone) -> Tuple[Optional[datetime], Optional[datetime]]:
|
||||||
"""
|
"""
|
||||||
Given a serialized timeframe, evaluate it relative to `ref_dt` and return a tuple of datetimes
|
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
|
where the first element ist the first possible datetime within the timeframe and the second
|
||||||
|
|||||||
@@ -518,6 +518,7 @@ def pretixcontrol_orderposition_blocked_display(sender: Event, orderposition, bl
|
|||||||
'The order requires approval before it can continue to be processed.'),
|
'The order requires approval before it can continue to be processed.'),
|
||||||
'pretix.event.order.approved': _('The order has been approved.'),
|
'pretix.event.order.approved': _('The order has been approved.'),
|
||||||
'pretix.event.order.denied': _('The order has been denied (comment: "{comment}").'),
|
'pretix.event.order.denied': _('The order has been denied (comment: "{comment}").'),
|
||||||
|
'pretix.event.order.vatid.validated': _('The customer VAT ID has been verified.'),
|
||||||
'pretix.event.order.contact.changed': _('The email address has been changed from "{old_email}" '
|
'pretix.event.order.contact.changed': _('The email address has been changed from "{old_email}" '
|
||||||
'to "{new_email}".'),
|
'to "{new_email}".'),
|
||||||
'pretix.event.order.contact.confirmed': _(
|
'pretix.event.order.contact.confirmed': _(
|
||||||
@@ -640,6 +641,7 @@ class TeamMembershipLogEntryType(LogEntryType):
|
|||||||
'pretix.team.member.added': _('{user} has been added to the team.'),
|
'pretix.team.member.added': _('{user} has been added to the team.'),
|
||||||
'pretix.team.member.removed': _('{user} has been removed from the team.'),
|
'pretix.team.member.removed': _('{user} has been removed from the team.'),
|
||||||
'pretix.team.invite.created': _('{user} has been invited to the team.'),
|
'pretix.team.invite.created': _('{user} has been invited to the team.'),
|
||||||
|
'pretix.team.invite.deleted': _('Invite for {user} has been deleted.'),
|
||||||
'pretix.team.invite.resent': _('Invite for {user} has been resent.'),
|
'pretix.team.invite.resent': _('Invite for {user} has been resent.'),
|
||||||
})
|
})
|
||||||
class CoreTeamMembershipLogEntryType(TeamMembershipLogEntryType):
|
class CoreTeamMembershipLogEntryType(TeamMembershipLogEntryType):
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ Please do never give this code to another person. Our support team will never as
|
|||||||
If this code was not requested by you, please contact us immediately.
|
If this code was not requested by you, please contact us immediately.
|
||||||
|
|
||||||
Best regards,
|
Best regards,
|
||||||
Your pretix team
|
Your {{ instance }} team
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ you requested a new password. Please go to the following page to reset your pass
|
|||||||
{{ url }}
|
{{ url }}
|
||||||
|
|
||||||
Best regards,
|
Best regards,
|
||||||
Your pretix team
|
Your {{ instance }} team
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% load i18n %}{% blocktrans with url=url|safe %}Hello,
|
{% load i18n %}{% blocktrans with url=url|safe %}Hello,
|
||||||
|
|
||||||
you have been invited to a team on pretix, a platform to perform event
|
you have been invited to a team on {{ instance }}, a platform to perform event
|
||||||
ticket sales.
|
ticket sales.
|
||||||
|
|
||||||
Organizer: {{ organizer }}
|
Organizer: {{ organizer }}
|
||||||
@@ -13,5 +13,5 @@ If you do not want to join, you can safely ignore or delete this email.
|
|||||||
|
|
||||||
Best regards,
|
Best regards,
|
||||||
|
|
||||||
Your pretix team
|
Your {{ instance }} team
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{% load i18n %}{% blocktrans with url=url|safe messages=messages|safe %}Hello,
|
{% load i18n %}{% blocktrans with url=url|safe messages=messages|safe %}Hello,
|
||||||
|
|
||||||
this is to inform you that the account information of your pretix account has been
|
this is to inform you that the account information of your {{ instance }} account has been
|
||||||
changed. In particular, the following changes have been performed:
|
changed. In particular, the following changes have been performed:
|
||||||
|
|
||||||
{{ messages }}
|
{{ messages }}
|
||||||
@@ -12,5 +12,5 @@ You can review and change your account settings here:
|
|||||||
{{ url }}
|
{{ url }}
|
||||||
|
|
||||||
Best regards,
|
Best regards,
|
||||||
Your pretix team
|
Your {{ instance }} team
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load urlreplace %}
|
{% load urlreplace %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
{% load static %}
|
||||||
{% block title %}{% trans "Events" %}{% endblock %}
|
{% block title %}{% trans "Events" %}{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>{% trans "Events" %}</h1>
|
<h1>{% trans "Events" %}</h1>
|
||||||
@@ -74,6 +75,7 @@
|
|||||||
<a href="?{% url_replace request 'ordering' 'organizer' %}"><i class="fa fa-caret-up"></i></a>
|
<a href="?{% url_replace request 'ordering' 'organizer' %}"><i class="fa fa-caret-up"></i></a>
|
||||||
</th>
|
</th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<th>{% trans "Sales channels" %}</th>
|
||||||
<th>
|
<th>
|
||||||
{% trans "Start date" %}
|
{% trans "Start date" %}
|
||||||
<a href="?{% url_replace request 'ordering' '-date_from' %}"><i class="fa fa-caret-down"></i></a>
|
<a href="?{% url_replace request 'ordering' '-date_from' %}"><i class="fa fa-caret-down"></i></a>
|
||||||
@@ -108,6 +110,21 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
{% if not hide_orga %}<td>{{ e.organizer }}</td>{% endif %}
|
{% if not hide_orga %}<td>{{ e.organizer }}</td>{% endif %}
|
||||||
|
<td>
|
||||||
|
{% for c in e.organizer.sales_channels.all %}
|
||||||
|
{% if e.all_sales_channels or c in e.limit_sales_channels.all %}
|
||||||
|
{% if "." in c.icon %}
|
||||||
|
<img src="{% static c.icon %}" class="fa-like-image"
|
||||||
|
data-toggle="tooltip" title="{{ c.label }}">
|
||||||
|
{% else %}
|
||||||
|
<span class="fa fa-fw fa-{{ c.icon }} text-muted"
|
||||||
|
data-toggle="tooltip" title="{{ c.label }}"></span>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<span class="fa fa-fw"></span>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</td>
|
||||||
<td class="event-date-col">
|
<td class="event-date-col">
|
||||||
{% if e.has_subevents %}
|
{% if e.has_subevents %}
|
||||||
<span class="fa fa-fw- fa-calendar"></span>
|
<span class="fa fa-fw- fa-calendar"></span>
|
||||||
|
|||||||
@@ -24,7 +24,9 @@
|
|||||||
{% if log.display %}
|
{% if log.display %}
|
||||||
<br/><span class="fa fa-fw fa-comment-o"></span> {{ log.display }}
|
<br/><span class="fa fa-fw fa-comment-o"></span> {{ log.display }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if log.parsed_data.recipient %}
|
{% if log.parsed_data.to %}
|
||||||
|
<br/><span class="fa fa-fw fa-envelope-o"></span> {{ log.parsed_data.to|join:", " }}
|
||||||
|
{% elif log.parsed_data.recipient %} {# legacy #}
|
||||||
<br/><span class="fa fa-fw fa-envelope-o"></span> {{ log.parsed_data.recipient }}
|
<br/><span class="fa fa-fw fa-envelope-o"></span> {{ log.parsed_data.recipient }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
{% extends "pretixcontrol/organizers/base.html" %}
|
{% extends "pretixcontrol/organizers/base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load bootstrap3 %}
|
{% load bootstrap3 %}
|
||||||
|
{% load static %}
|
||||||
{% block inner %}
|
{% block inner %}
|
||||||
<h1>
|
<h1>
|
||||||
{% blocktrans with name=request.organizer.name %}Organizer: {{ name }}{% endblocktrans %}
|
{% blocktrans with name=request.organizer.name %}Organizer: {{ name }}{% endblocktrans %}
|
||||||
@@ -62,6 +63,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Event name" %}</th>
|
<th>{% trans "Event name" %}</th>
|
||||||
|
<th>{% trans "Sales channels" %}</th>
|
||||||
<th>
|
<th>
|
||||||
{% trans "Start date" %}
|
{% trans "Start date" %}
|
||||||
/
|
/
|
||||||
@@ -77,10 +79,30 @@
|
|||||||
<td>
|
<td>
|
||||||
<strong><a
|
<strong><a
|
||||||
href="{% url "control:event.index" organizer=e.organizer.slug event=e.slug %}">{{ e.name }}</a></strong>
|
href="{% url "control:event.index" organizer=e.organizer.slug event=e.slug %}">{{ e.name }}</a></strong>
|
||||||
<br><small>{{ e.slug }}</small>
|
<br>
|
||||||
{% for k, v in e.meta_data.items %}
|
<small>
|
||||||
{% if v %}
|
{{ e.slug }}
|
||||||
<small class="text-muted">· {{ k }}: {{ v }}</small>
|
</small>
|
||||||
|
<small class="text-muted">
|
||||||
|
{% for k, v in e.meta_data.items %}
|
||||||
|
{% if v %}
|
||||||
|
· {{ k }}: {{ v }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</small>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{% for c in sales_channels %}
|
||||||
|
{% if e.all_sales_channels or c in e.limit_sales_channels.all %}
|
||||||
|
{% if "." in c.icon %}
|
||||||
|
<img src="{% static c.icon %}" class="fa-like-image"
|
||||||
|
data-toggle="tooltip" title="{{ c.label }}">
|
||||||
|
{% else %}
|
||||||
|
<span class="fa fa-fw fa-{{ c.icon }} text-muted"
|
||||||
|
data-toggle="tooltip" title="{{ c.label }}"></span>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<span class="fa fa-fw"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -264,12 +264,17 @@
|
|||||||
The paper size will match the PDF.
|
The paper size will match the PDF.
|
||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p class="text-center">
|
||||||
<span class="btn btn-default fileinput-button background-button btn-block">
|
<span class="btn btn-default fileinput-button background-button btn-block">
|
||||||
<i class="fa fa-upload"></i>
|
<i class="fa fa-upload"></i>
|
||||||
<span>{% trans "Upload PDF as background" %}</span>
|
<span>{% trans "Upload PDF as background" %}</span>
|
||||||
<input id="fileupload" type="file" name="background" accept="application/pdf">
|
<input id="fileupload" type="file" name="background" accept="application/pdf">
|
||||||
</span>
|
</span>
|
||||||
|
<small class="text-muted">
|
||||||
|
{% blocktrans trimmed with size=maxfilesize|filesizeformat %}
|
||||||
|
max. {{ size }}, smaller is better
|
||||||
|
{% endblocktrans %}
|
||||||
|
</small>
|
||||||
</p>
|
</p>
|
||||||
<p class="text-center">
|
<p class="text-center">
|
||||||
<a class="btn btn-link background-download-button" href="{{ pdf }}" target="_blank">
|
<a class="btn btn-link background-download-button" href="{{ pdf }}" target="_blank">
|
||||||
|
|||||||
@@ -67,7 +67,12 @@ class EventList(PaginationMixin, ListView):
|
|||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
qs = self.request.user.get_events_with_any_permission(self.request).prefetch_related(
|
qs = self.request.user.get_events_with_any_permission(self.request).prefetch_related(
|
||||||
'organizer', '_settings_objects', 'organizer___settings_objects', 'organizer__meta_properties',
|
'organizer',
|
||||||
|
'organizer__sales_channels',
|
||||||
|
'_settings_objects',
|
||||||
|
'organizer___settings_objects',
|
||||||
|
'organizer__meta_properties',
|
||||||
|
'limit_sales_channels',
|
||||||
Prefetch(
|
Prefetch(
|
||||||
'meta_values',
|
'meta_values',
|
||||||
EventMetaValue.objects.select_related('property'),
|
EventMetaValue.objects.select_related('property'),
|
||||||
|
|||||||
@@ -1641,9 +1641,17 @@ class OrderCheckVATID(OrderView):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
normalized_id = validate_vat_id(ia.vat_id, str(ia.country))
|
normalized_id = validate_vat_id(ia.vat_id, str(ia.country))
|
||||||
ia.vat_id_validated = True
|
with transaction.atomic():
|
||||||
ia.vat_id = normalized_id
|
ia.vat_id_validated = True
|
||||||
ia.save()
|
ia.vat_id = normalized_id
|
||||||
|
ia.save()
|
||||||
|
self.order.log_action(
|
||||||
|
'pretix.event.order.vatid.validated',
|
||||||
|
data={
|
||||||
|
'vat_id': normalized_id,
|
||||||
|
},
|
||||||
|
user=self.request.user,
|
||||||
|
)
|
||||||
except VATIDFinalError as e:
|
except VATIDFinalError as e:
|
||||||
messages.error(self.request, e.message)
|
messages.error(self.request, e.message)
|
||||||
except VATIDTemporaryError:
|
except VATIDTemporaryError:
|
||||||
@@ -2413,9 +2421,9 @@ class OrderSendMail(EventPermissionRequiredMixin, OrderViewMixin, FormView):
|
|||||||
with language(order.locale, self.request.event.settings.region):
|
with language(order.locale, self.request.event.settings.region):
|
||||||
email_context = get_email_context(event=order.event, order=order)
|
email_context = get_email_context(event=order.event, order=order)
|
||||||
email_template = LazyI18nString(form.cleaned_data['message'])
|
email_template = LazyI18nString(form.cleaned_data['message'])
|
||||||
email_subject = format_map(str(form.cleaned_data['subject']), email_context)
|
|
||||||
email_content = render_mail(email_template, email_context)
|
|
||||||
if self.request.POST.get('action') == 'preview':
|
if self.request.POST.get('action') == 'preview':
|
||||||
|
email_subject = format_map(form.cleaned_data['subject'], email_context)
|
||||||
|
email_content = render_mail(email_template, email_context)
|
||||||
self.preview_output = {
|
self.preview_output = {
|
||||||
'subject': mark_safe(_('Subject: {subject}').format(
|
'subject': mark_safe(_('Subject: {subject}').format(
|
||||||
subject=prefix_subject(order.event, escape(email_subject), highlight=True)
|
subject=prefix_subject(order.event, escape(email_subject), highlight=True)
|
||||||
@@ -2477,9 +2485,9 @@ class OrderPositionSendMail(OrderSendMail):
|
|||||||
with language(position.order.locale, self.request.event.settings.region):
|
with language(position.order.locale, self.request.event.settings.region):
|
||||||
email_context = get_email_context(event=position.order.event, order=position.order, position=position)
|
email_context = get_email_context(event=position.order.event, order=position.order, position=position)
|
||||||
email_template = LazyI18nString(form.cleaned_data['message'])
|
email_template = LazyI18nString(form.cleaned_data['message'])
|
||||||
email_subject = format_map(str(form.cleaned_data['subject']), email_context)
|
|
||||||
email_content = render_mail(email_template, email_context)
|
|
||||||
if self.request.POST.get('action') == 'preview':
|
if self.request.POST.get('action') == 'preview':
|
||||||
|
email_subject = format_map(str(form.cleaned_data['subject']), email_context)
|
||||||
|
email_content = render_mail(email_template, email_context)
|
||||||
self.preview_output = {
|
self.preview_output = {
|
||||||
'subject': mark_safe(_('Subject: {subject}').format(
|
'subject': mark_safe(_('Subject: {subject}').format(
|
||||||
subject=prefix_subject(position.order.event, escape(email_subject), highlight=True))
|
subject=prefix_subject(position.order.event, escape(email_subject), highlight=True))
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ class OrganizerDetail(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin
|
|||||||
'organizer').prefetch_related(
|
'organizer').prefetch_related(
|
||||||
'organizer', '_settings_objects', 'organizer___settings_objects',
|
'organizer', '_settings_objects', 'organizer___settings_objects',
|
||||||
'organizer__meta_properties',
|
'organizer__meta_properties',
|
||||||
|
'limit_sales_channels',
|
||||||
Prefetch(
|
Prefetch(
|
||||||
'meta_values',
|
'meta_values',
|
||||||
EventMetaValue.objects.select_related('property'),
|
EventMetaValue.objects.select_related('property'),
|
||||||
@@ -237,6 +238,7 @@ class OrganizerDetail(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin
|
|||||||
self.filter_form['meta_{}'.format(p.name)] for p in
|
self.filter_form['meta_{}'.format(p.name)] for p in
|
||||||
self.organizer.meta_properties.filter(filter_allowed=True)
|
self.organizer.meta_properties.filter(filter_allowed=True)
|
||||||
]
|
]
|
||||||
|
ctx['sales_channels'] = self.request.organizer.sales_channels.all()
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
@@ -1039,9 +1041,10 @@ class TeamMemberView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMixin,
|
|||||||
def _send_invite(self, instance):
|
def _send_invite(self, instance):
|
||||||
mail(
|
mail(
|
||||||
instance.email,
|
instance.email,
|
||||||
_('pretix account invitation'),
|
_('Account invitation'),
|
||||||
'pretixcontrol/email/invitation.txt',
|
'pretixcontrol/email/invitation.txt',
|
||||||
{
|
{
|
||||||
|
'instance': settings.PRETIX_INSTANCE_NAME,
|
||||||
'user': self,
|
'user': self,
|
||||||
'organizer': self.request.organizer.name,
|
'organizer': self.request.organizer.name,
|
||||||
'team': instance.team.name,
|
'team': instance.team.name,
|
||||||
|
|||||||
@@ -292,6 +292,7 @@ class BaseEditorView(EventPermissionRequiredMixin, TemplateView):
|
|||||||
ctx['layout'] = json.dumps(self.get_current_layout())
|
ctx['layout'] = json.dumps(self.get_current_layout())
|
||||||
ctx['title'] = self.title
|
ctx['title'] = self.title
|
||||||
ctx['locales'] = [p for p in settings.LANGUAGES if p[0] in self.request.event.settings.locales]
|
ctx['locales'] = [p for p in settings.LANGUAGES if p[0] in self.request.event.settings.locales]
|
||||||
|
ctx['maxfilesize'] = self.maxfilesize
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ class VoucherList(PaginationMixin, EventPermissionRequiredMixin, ListView):
|
|||||||
elif v.quota:
|
elif v.quota:
|
||||||
prod = _('Any product in quota "{quota}"').format(quota=str(v.quota.name))
|
prod = _('Any product in quota "{quota}"').format(quota=str(v.quota.name))
|
||||||
else:
|
else:
|
||||||
prod = _('Any product')
|
prod = ""
|
||||||
row = [
|
row = [
|
||||||
v.code,
|
v.code,
|
||||||
v.valid_until.isoformat() if v.valid_until else "",
|
v.valid_until.isoformat() if v.valid_until else "",
|
||||||
|
|||||||
@@ -280,11 +280,12 @@ class WaitingListView(EventPermissionRequiredMixin, WaitingListQuerySetMixin, Pa
|
|||||||
block_quota=True,
|
block_quota=True,
|
||||||
item_id=wle.item_id,
|
item_id=wle.item_id,
|
||||||
subevent=wle.subevent_id,
|
subevent=wle.subevent_id,
|
||||||
waitinglistentries__isnull=False
|
waitinglistentries__isnull=False,
|
||||||
|
seat__isnull=True
|
||||||
).aggregate(free=Sum(F('max_usages') - F('redeemed')))['free'] or 0
|
).aggregate(free=Sum(F('max_usages') - F('redeemed')))['free'] or 0
|
||||||
free_seats = num_free_seats_for_product - num_valid_vouchers_for_product
|
free_seats = num_free_seats_for_product - num_valid_vouchers_for_product
|
||||||
wle.availability = (
|
wle.availability = (
|
||||||
Quota.AVAILABILITY_GONE if free_seats == 0 else wle.availability[0],
|
Quota.AVAILABILITY_GONE if free_seats < 1 else wle.availability[0],
|
||||||
min(free_seats, wle.availability[1]) if wle.availability[1] is not None else free_seats,
|
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"
|
"Project-Id-Version: 1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||||
"PO-Revision-Date: 2026-02-19 22:00+0000\n"
|
"PO-Revision-Date: 2026-03-05 20:00+0000\n"
|
||||||
"Last-Translator: Mie Frydensbjerg <mif@aarhus.dk>\n"
|
"Last-Translator: Mie Frydensbjerg <mif@aarhus.dk>\n"
|
||||||
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix/da/"
|
"Language-Team: Danish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||||
">\n"
|
"da/>\n"
|
||||||
"Language: da\n"
|
"Language: da\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 5.16\n"
|
"X-Generator: Weblate 5.16.1\n"
|
||||||
|
|
||||||
#: pretix/_base_settings.py:87
|
#: pretix/_base_settings.py:87
|
||||||
msgid "English"
|
msgid "English"
|
||||||
@@ -34285,7 +34285,7 @@ msgstr ""
|
|||||||
#: pretix/presale/templates/pretixpresale/event/voucher.html:293
|
#: pretix/presale/templates/pretixpresale/event/voucher.html:293
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "minimum amount to order: %(num)s"
|
msgid "minimum amount to order: %(num)s"
|
||||||
msgstr ""
|
msgstr "Minimumsbestilling: %(num)s"
|
||||||
|
|
||||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:76
|
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:76
|
||||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:160
|
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:160
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ msgstr ""
|
|||||||
"Project-Id-Version: 1\n"
|
"Project-Id-Version: 1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||||
"PO-Revision-Date: 2026-02-24 12:07+0000\n"
|
"PO-Revision-Date: 2026-03-07 23:00+0000\n"
|
||||||
"Last-Translator: Raphael Michel <michel@rami.io>\n"
|
"Last-Translator: argonimos <jonas@pfeiffer-wagner.de>\n"
|
||||||
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/"
|
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||||
"de/>\n"
|
"de/>\n"
|
||||||
"Language: de\n"
|
"Language: de\n"
|
||||||
@@ -14,7 +14,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 5.16\n"
|
"X-Generator: Weblate 5.16.2\n"
|
||||||
"X-Poedit-Bookmarks: -1,-1,904,-1,-1,-1,-1,-1,-1,-1\n"
|
"X-Poedit-Bookmarks: -1,-1,904,-1,-1,-1,-1,-1,-1,-1\n"
|
||||||
|
|
||||||
#: pretix/_base_settings.py:87
|
#: pretix/_base_settings.py:87
|
||||||
@@ -3845,7 +3845,7 @@ msgstr "Restbetrag"
|
|||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgctxt "invoice"
|
msgctxt "invoice"
|
||||||
msgid "Invoice period: {daterange}"
|
msgid "Invoice period: {daterange}"
|
||||||
msgstr "Rechungsperiode: {daterange}"
|
msgstr "Rechnungsperiode: {daterange}"
|
||||||
|
|
||||||
#: pretix/base/invoicing/pdf.py:1039
|
#: pretix/base/invoicing/pdf.py:1039
|
||||||
msgctxt "invoice"
|
msgctxt "invoice"
|
||||||
|
|||||||
@@ -8,16 +8,16 @@ msgstr ""
|
|||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||||
"PO-Revision-Date: 2025-02-14 21:00+0000\n"
|
"PO-Revision-Date: 2026-02-25 23:00+0000\n"
|
||||||
"Last-Translator: deborahfoell <deborah.foell@om.org>\n"
|
"Last-Translator: David Ibáñez Cerdeira <dibanez@gmail.com>\n"
|
||||||
"Language-Team: Greek <https://translate.pretix.eu/projects/pretix/pretix/el/"
|
"Language-Team: Greek <https://translate.pretix.eu/projects/pretix/pretix/el/>"
|
||||||
">\n"
|
"\n"
|
||||||
"Language: el\n"
|
"Language: el\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 5.9.2\n"
|
"X-Generator: Weblate 5.16\n"
|
||||||
|
|
||||||
#: pretix/_base_settings.py:87
|
#: pretix/_base_settings.py:87
|
||||||
msgid "English"
|
msgid "English"
|
||||||
@@ -20467,7 +20467,7 @@ msgstr "Ορίστε νέο κωδικό πρόσβασης"
|
|||||||
#: pretix/presale/templates/pretixpresale/organizers/customer_password.html:25
|
#: pretix/presale/templates/pretixpresale/organizers/customer_password.html:25
|
||||||
#: pretix/presale/templates/pretixpresale/organizers/customer_setpassword.html:25
|
#: pretix/presale/templates/pretixpresale/organizers/customer_setpassword.html:25
|
||||||
msgid "Save"
|
msgid "Save"
|
||||||
msgstr "Αποθηκεύση"
|
msgstr "gardar"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/auth/register.html:7
|
#: pretix/control/templates/pretixcontrol/auth/register.html:7
|
||||||
msgid "Create a new account"
|
msgid "Create a new account"
|
||||||
|
|||||||
@@ -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: 2026-02-24 11:50+0000\n"
|
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||||
"PO-Revision-Date: 2026-02-21 18:00+0000\n"
|
"PO-Revision-Date: 2026-03-03 20:00+0000\n"
|
||||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix/"
|
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||||
"es/>\n"
|
"es/>\n"
|
||||||
@@ -17,7 +17,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 5.16\n"
|
"X-Generator: Weblate 5.16.1\n"
|
||||||
|
|
||||||
#: pretix/_base_settings.py:87
|
#: pretix/_base_settings.py:87
|
||||||
msgid "English"
|
msgid "English"
|
||||||
@@ -17058,28 +17058,20 @@ msgid "You need to specify as many seats as voucher codes."
|
|||||||
msgstr "Debe especificar tantas butacas como vales de compra."
|
msgstr "Debe especificar tantas butacas como vales de compra."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:39
|
#: pretix/control/forms/waitinglist.py:39
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Please select a valid seat."
|
|
||||||
msgid "Select a valid choice."
|
msgid "Select a valid choice."
|
||||||
msgstr "Por favor seleccione una butaca válida."
|
msgstr "Seleccione una opción válida."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:107
|
#: pretix/control/forms/waitinglist.py:107
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Active products"
|
|
||||||
msgid "Only includes active products."
|
msgid "Only includes active products."
|
||||||
msgstr "Productos activos"
|
msgstr "Solo incluir productos activos."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:115
|
#: pretix/control/forms/waitinglist.py:115
|
||||||
#, fuzzy
|
|
||||||
#| msgid "A voucher with this code already exists."
|
|
||||||
msgid "A voucher for this waiting list entry was already sent out."
|
msgid "A voucher for this waiting list entry was already sent out."
|
||||||
msgstr "Ya existe un vale de compra con este código."
|
msgstr "Ya se ha enviado un vale para esta entrada en la lista de espera."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:125
|
#: pretix/control/forms/waitinglist.py:125
|
||||||
#, fuzzy
|
|
||||||
#| msgid "The selected product has been deactivated."
|
|
||||||
msgid "The selected product is not active."
|
msgid "The selected product is not active."
|
||||||
msgstr "El producto seleccionado ha sido desactivado."
|
msgstr "El producto seleccionado no está activo."
|
||||||
|
|
||||||
#: pretix/control/logdisplay.py:73 pretix/control/logdisplay.py:83
|
#: pretix/control/logdisplay.py:73 pretix/control/logdisplay.py:83
|
||||||
msgid "The order has been changed:"
|
msgid "The order has been changed:"
|
||||||
@@ -17729,7 +17721,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: pretix/control/logdisplay.py:589
|
#: pretix/control/logdisplay.py:589
|
||||||
msgid "The voucher has been changed."
|
msgid "The voucher has been changed."
|
||||||
msgstr "EL vale de compra ha sido cambiado."
|
msgstr "El vale de compra ha sido cambiado."
|
||||||
|
|
||||||
#: pretix/control/logdisplay.py:590
|
#: pretix/control/logdisplay.py:590
|
||||||
msgid "The voucher has been deleted."
|
msgid "The voucher has been deleted."
|
||||||
@@ -18643,7 +18635,7 @@ msgstr "Entradas"
|
|||||||
#: pretix/control/templates/pretixcontrol/order/index.html:764
|
#: pretix/control/templates/pretixcontrol/order/index.html:764
|
||||||
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:457
|
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:457
|
||||||
msgid "Taxes"
|
msgid "Taxes"
|
||||||
msgstr "gravámenes"
|
msgstr "Impuestos"
|
||||||
|
|
||||||
#: pretix/control/navigation.py:97
|
#: pretix/control/navigation.py:97
|
||||||
msgid "Invoicing"
|
msgid "Invoicing"
|
||||||
@@ -18883,6 +18875,10 @@ msgid ""
|
|||||||
"in repeatedly. Please check if your browser is set to block cookies, or "
|
"in repeatedly. Please check if your browser is set to block cookies, or "
|
||||||
"delete all existing cookies and retry."
|
"delete all existing cookies and retry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Parece que el navegador no acepta nuestras cookies y es necesario iniciar "
|
||||||
|
"sesión repetidamente. Por favor, compruebe si el navegador está configurado "
|
||||||
|
"para bloquear cookies o elimine todas las cookies existentes y vuelva a "
|
||||||
|
"intentarlo."
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/auth/login.html:35
|
#: pretix/control/templates/pretixcontrol/auth/login.html:35
|
||||||
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:19
|
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:19
|
||||||
@@ -18994,8 +18990,9 @@ msgid ""
|
|||||||
"This application has <strong>not</strong> been reviewed by the pretix team. "
|
"This application has <strong>not</strong> been reviewed by the pretix team. "
|
||||||
"Granting access to your pretix account happens at your own risk."
|
"Granting access to your pretix account happens at your own risk."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Esta aplicación<strong>no</strong> ha sido revisada por el equipo de pretix. "
|
"Esta aplicación <strong>no</strong> ha sido revisada por el equipo de "
|
||||||
"La concesión del acceso a su cuenta pretix se realiza bajo su propio riesgo."
|
"pretix. La concesión del acceso a su cuenta pretix se realiza bajo su propio "
|
||||||
|
"riesgo."
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/auth/oauth_authorization.html:54
|
#: pretix/control/templates/pretixcontrol/auth/oauth_authorization.html:54
|
||||||
msgid "Error:"
|
msgid "Error:"
|
||||||
@@ -19129,8 +19126,8 @@ msgid ""
|
|||||||
"We've detected that you are using <strong>Microsoft Internet Explorer</"
|
"We've detected that you are using <strong>Microsoft Internet Explorer</"
|
||||||
"strong>."
|
"strong>."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Hemos detectado que estás usando <strong> Microsoft Internet Explorer </"
|
"Hemos detectado que estás usando <strong>Microsoft Internet Explorer</strong>"
|
||||||
"strong>."
|
"."
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/base.html:332
|
#: pretix/control/templates/pretixcontrol/base.html:332
|
||||||
#: pretix/presale/templates/pretixpresale/base.html:54
|
#: pretix/presale/templates/pretixpresale/base.html:54
|
||||||
@@ -19169,7 +19166,7 @@ msgid ""
|
|||||||
"people from actually buying tickets."
|
"people from actually buying tickets."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Tu evento contiene <strong>pedidos de modo de prueba</strong> a pesar de que "
|
"Tu evento contiene <strong>pedidos de modo de prueba</strong> a pesar de que "
|
||||||
"<strong> el modo de prueba se ha deshabilitado</strong>. Deberías eliminar "
|
"<strong>el modo de prueba se ha deshabilitado</strong>. Deberías eliminar "
|
||||||
"estes pedidos para asegurarte que no se muestren en tus reportes "
|
"estes pedidos para asegurarte que no se muestren en tus reportes "
|
||||||
"estadísticos y bloquear la compra de entradas a las personas."
|
"estadísticos y bloquear la compra de entradas a las personas."
|
||||||
|
|
||||||
@@ -20764,7 +20761,7 @@ msgid ""
|
|||||||
"duplicate payment attempts. You should review the cases and consider "
|
"duplicate payment attempts. You should review the cases and consider "
|
||||||
"refunding the overpaid amount to the user."
|
"refunding the overpaid amount to the user."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Este evento contiene <strong> pedidos pagados en exceso</strong>, por "
|
"Este evento contiene <strong>pedidos pagados en exceso</strong>, por "
|
||||||
"ejemplo, debido a que hay intentos de pago duplicados. Debe revisar los "
|
"ejemplo, debido a que hay intentos de pago duplicados. Debe revisar los "
|
||||||
"casos y considerar la devolución de la cantidad pagada en exceso al usuario."
|
"casos y considerar la devolución de la cantidad pagada en exceso al usuario."
|
||||||
|
|
||||||
@@ -20777,7 +20774,7 @@ msgid ""
|
|||||||
"This event contains <strong>pending refunds</strong> that you should take "
|
"This event contains <strong>pending refunds</strong> that you should take "
|
||||||
"care of."
|
"care of."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Este evento contiene <strong>devoluciones pendientes </strong> sobre las que "
|
"Este evento contiene <strong>devoluciones pendientes</strong> sobre las que "
|
||||||
"debe prestar atención."
|
"debe prestar atención."
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/event/index.html:50
|
#: pretix/control/templates/pretixcontrol/event/index.html:50
|
||||||
@@ -20815,7 +20812,7 @@ msgid ""
|
|||||||
"arrived. You should review the cases and consider either refunding the "
|
"arrived. You should review the cases and consider either refunding the "
|
||||||
"customer or creating more space."
|
"customer or creating more space."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Este evento contiene <strong> pedidos completamente pagados</strong> que no "
|
"Este evento contiene <strong>pedidos completamente pagados</strong> que no "
|
||||||
"están marcadas como pagados, probablemente porque no se dejo ningún cupo al "
|
"están marcadas como pagados, probablemente porque no se dejo ningún cupo al "
|
||||||
"momento que llegó el pago. Debería revisar estos casos y considerar, "
|
"momento que llegó el pago. Debería revisar estos casos y considerar, "
|
||||||
"devolver el dinero o crear más espacio."
|
"devolver el dinero o crear más espacio."
|
||||||
@@ -21479,7 +21476,7 @@ msgid ""
|
|||||||
"as examples, you can add more in the \"Settings\" part of your event."
|
"as examples, you can add more in the \"Settings\" part of your event."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"pretix soporta un <a href=\"https://pretix.eu/about/en/features/payment\" "
|
"pretix soporta un <a href=\"https://pretix.eu/about/en/features/payment\" "
|
||||||
"target=\"_blank\">amplio rango de proveedores de pago </a> permitiéndole "
|
"target=\"_blank\">amplio rango de proveedores de pago</a> permitiéndole "
|
||||||
"elegir los métodos de pago que mejor se adapten a su flujo de trabajo. Aquí "
|
"elegir los métodos de pago que mejor se adapten a su flujo de trabajo. Aquí "
|
||||||
"hay sólo dos de ellos a modo de ejemplo, puede añadir más en la parte "
|
"hay sólo dos de ellos a modo de ejemplo, puede añadir más en la parte "
|
||||||
"\"Configuración\" de su evento."
|
"\"Configuración\" de su evento."
|
||||||
@@ -23891,8 +23888,8 @@ msgid ""
|
|||||||
"Do you really want to delete this order? <strong>You really cannot revert "
|
"Do you really want to delete this order? <strong>You really cannot revert "
|
||||||
"this action and we can't either.</strong>"
|
"this action and we can't either.</strong>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"¿Realmente quieres eliminar este pedido? <strong> No puedes revertir esta "
|
"¿Realmente quieres eliminar este pedido? <strong>No puedes revertir esta "
|
||||||
"acción y tampoco nosotros. </strong>"
|
"acción y tampoco nosotros.</strong>"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/order/delete.html:25
|
#: pretix/control/templates/pretixcontrol/order/delete.html:25
|
||||||
msgid "Yes, delete order"
|
msgid "Yes, delete order"
|
||||||
@@ -24516,9 +24513,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Hemos recibido la notificación de que <strong>%(amount)s</strong> ha sido "
|
"Hemos recibido la notificación de que <strong>%(amount)s</strong> ha sido "
|
||||||
"devuelto a través de <strong>%(method)s</strong>. Si este reembolso está "
|
"devuelto a través de <strong>%(method)s</strong>. Si este reembolso está "
|
||||||
"procesado, el pedido habrá sido pagado con un importe inferior "
|
"procesado, el pedido habrá sido pagado con un importe inferior en <strong>%"
|
||||||
"en<strong>%(pending)s</strong>. El total del pedido es <strong>%(total)s</"
|
"(pending)s</strong>. El total del pedido es <strong>%(total)s</strong>."
|
||||||
"strong>."
|
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/order/refund_process.html:30
|
#: pretix/control/templates/pretixcontrol/order/refund_process.html:30
|
||||||
msgid "Since the order is already canceled, this will not affect its state."
|
msgid "Since the order is already canceled, this will not affect its state."
|
||||||
@@ -27262,7 +27258,7 @@ msgid ""
|
|||||||
"Using this option will <strong>delete all current quotas</strong> from "
|
"Using this option will <strong>delete all current quotas</strong> from "
|
||||||
"<strong>all selected dates</strong>."
|
"<strong>all selected dates</strong>."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Al utilizar esta opción se <strong> eliminarán todas las cuotas actuales </"
|
"Al utilizar esta opción se <strong>eliminarán todas las cuotas actuales</"
|
||||||
"strong> de <strong>todas las fechas seleccionadas</strong>."
|
"strong> de <strong>todas las fechas seleccionadas</strong>."
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html:277
|
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html:277
|
||||||
@@ -27998,7 +27994,7 @@ msgstr "Borrar vale de compra"
|
|||||||
msgid ""
|
msgid ""
|
||||||
"Are you sure you want to delete the voucher <strong>%(voucher)s</strong>?"
|
"Are you sure you want to delete the voucher <strong>%(voucher)s</strong>?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"¿Está seguro de que desea borrar el vale de compra<strong>%(voucher)s</"
|
"¿Está seguro de que desea borrar el vale de compra <strong>%(voucher)s</"
|
||||||
"strong>?"
|
"strong>?"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/vouchers/delete_bulk.html:4
|
#: pretix/control/templates/pretixcontrol/vouchers/delete_bulk.html:4
|
||||||
@@ -28191,10 +28187,8 @@ msgstr ""
|
|||||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:4
|
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:4
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:6
|
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:6
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:273
|
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:273
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Entry"
|
|
||||||
msgid "Edit entry"
|
msgid "Edit entry"
|
||||||
msgstr "Ingreso"
|
msgstr "Editar entrada"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:17
|
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:17
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -28256,7 +28250,7 @@ msgid ""
|
|||||||
"quota is available) or you can press the big button below this text to send "
|
"quota is available) or you can press the big button below this text to send "
|
||||||
"out as many vouchers as currently possible to the persons who waited longest."
|
"out as many vouchers as currently possible to the persons who waited longest."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Ha configurado que los vales de compra se enviarán <strong>no </strong> "
|
"Ha configurado que los vales de compra se enviarán <strong>no</strong> "
|
||||||
"automáticamente. Puede enviarlos uno por uno en un orden de su elección "
|
"automáticamente. Puede enviarlos uno por uno en un orden de su elección "
|
||||||
"haciendo clic en los botones junto a una línea de esta tabla (si hay "
|
"haciendo clic en los botones junto a una línea de esta tabla (si hay "
|
||||||
"suficiente cuota disponible) o puede presionar el botón grande debajo de "
|
"suficiente cuota disponible) o puede presionar el botón grande debajo de "
|
||||||
@@ -30133,15 +30127,7 @@ msgstr ""
|
|||||||
"La autenticación de dos factores ahora está desactivada para su cuenta."
|
"La autenticación de dos factores ahora está desactivada para su cuenta."
|
||||||
|
|
||||||
#: pretix/control/views/user.py:635
|
#: pretix/control/views/user.py:635
|
||||||
#, fuzzy, python-brace-format
|
#, python-brace-format
|
||||||
#| msgid ""
|
|
||||||
#| "Your emergency codes have been newly generated. Remember to store them in "
|
|
||||||
#| "a safe place in case you lose access to your devices. You will not be "
|
|
||||||
#| "able to view them again here.\n"
|
|
||||||
#| "\n"
|
|
||||||
#| "Your emergency codes:\n"
|
|
||||||
#| "- \n"
|
|
||||||
#| "- "
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Your emergency codes have been newly generated. Remember to store them in a "
|
"Your emergency codes have been newly generated. Remember to store them in a "
|
||||||
"safe place in case you lose access to your devices. You will not be able to "
|
"safe place in case you lose access to your devices. You will not be able to "
|
||||||
@@ -30155,8 +30141,7 @@ msgstr ""
|
|||||||
"verlos aquí.\n"
|
"verlos aquí.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Sus códigos de emergencias:\n"
|
"Sus códigos de emergencias:\n"
|
||||||
"- \n"
|
"{tokens}"
|
||||||
"- "
|
|
||||||
|
|
||||||
#: pretix/control/views/user.py:655
|
#: pretix/control/views/user.py:655
|
||||||
msgid "Your notifications have been disabled."
|
msgid "Your notifications have been disabled."
|
||||||
@@ -30326,10 +30311,8 @@ msgid "The selected entry has been deleted."
|
|||||||
msgstr "Se ha borrado la entrada seleccionada."
|
msgstr "Se ha borrado la entrada seleccionada."
|
||||||
|
|
||||||
#: pretix/control/views/waitinglist.py:417
|
#: pretix/control/views/waitinglist.py:417
|
||||||
#, fuzzy
|
|
||||||
#| msgid "The waitinglist entry has been transferred."
|
|
||||||
msgid "The waitinglist entry has been changed."
|
msgid "The waitinglist entry has been changed."
|
||||||
msgstr "Las entradas de la lista de espera han sido transferidas."
|
msgstr "Se ha modificado la entrada de la lista de espera."
|
||||||
|
|
||||||
#: pretix/helpers/countries.py:134
|
#: pretix/helpers/countries.py:134
|
||||||
msgid "Belarus"
|
msgid "Belarus"
|
||||||
@@ -37011,8 +36994,8 @@ msgid ""
|
|||||||
"If you're looking to buy a ticket, you need to follow a direct link to an "
|
"If you're looking to buy a ticket, you need to follow a direct link to an "
|
||||||
"event or organizer profile."
|
"event or organizer profile."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"SI buscas comprar una entrada, necesitar seguir un enlace directo a un "
|
"Si busca comprar una entrada, necesita seguir un enlace directo a un evento "
|
||||||
"evento o a un perfil de organizador."
|
"o a un perfil de organizador."
|
||||||
|
|
||||||
#: pretix/presale/templates/pretixpresale/index.html:20
|
#: pretix/presale/templates/pretixpresale/index.html:20
|
||||||
#, python-format
|
#, python-format
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ msgstr ""
|
|||||||
"Project-Id-Version: 1\n"
|
"Project-Id-Version: 1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||||
"PO-Revision-Date: 2026-02-21 18:00+0000\n"
|
"PO-Revision-Date: 2026-03-03 20:00+0000\n"
|
||||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||||
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix/fr/"
|
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||||
">\n"
|
"fr/>\n"
|
||||||
"Language: fr\n"
|
"Language: fr\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||||
"X-Generator: Weblate 5.16\n"
|
"X-Generator: Weblate 5.16.1\n"
|
||||||
|
|
||||||
#: pretix/_base_settings.py:87
|
#: pretix/_base_settings.py:87
|
||||||
msgid "English"
|
msgid "English"
|
||||||
@@ -13011,7 +13011,9 @@ msgstr "Texte d’aide du champ email"
|
|||||||
|
|
||||||
#: pretix/base/settings.py:3398
|
#: pretix/base/settings.py:3398
|
||||||
msgid "Allow creating a new team during event creation"
|
msgid "Allow creating a new team during event creation"
|
||||||
msgstr "Ancienne API de l’appareil d’enregistrement"
|
msgstr ""
|
||||||
|
"Autoriser la création d'une nouvelle équipe lors de la création d'un "
|
||||||
|
"événement"
|
||||||
|
|
||||||
#: pretix/base/settings.py:3399
|
#: pretix/base/settings.py:3399
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -17204,28 +17206,20 @@ msgid "You need to specify as many seats as voucher codes."
|
|||||||
msgstr "Vous devez spécifier autant de sièges que de codes promotionnels."
|
msgstr "Vous devez spécifier autant de sièges que de codes promotionnels."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:39
|
#: pretix/control/forms/waitinglist.py:39
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Please select a valid seat."
|
|
||||||
msgid "Select a valid choice."
|
msgid "Select a valid choice."
|
||||||
msgstr "Veuillez sélectionner un siège valide."
|
msgstr "Sélectionnez une option valide."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:107
|
#: pretix/control/forms/waitinglist.py:107
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Active products"
|
|
||||||
msgid "Only includes active products."
|
msgid "Only includes active products."
|
||||||
msgstr "Produits actifs"
|
msgstr "Comprend uniquement les produits actifs."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:115
|
#: pretix/control/forms/waitinglist.py:115
|
||||||
#, fuzzy
|
|
||||||
#| msgid "A voucher with this code already exists."
|
|
||||||
msgid "A voucher for this waiting list entry was already sent out."
|
msgid "A voucher for this waiting list entry was already sent out."
|
||||||
msgstr "Un bon de réduction avec ce code existe déjà."
|
msgstr "Un bon pour cette inscription sur la liste d'attente a déjà été envoyé."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:125
|
#: pretix/control/forms/waitinglist.py:125
|
||||||
#, fuzzy
|
|
||||||
#| msgid "The selected product has been deactivated."
|
|
||||||
msgid "The selected product is not active."
|
msgid "The selected product is not active."
|
||||||
msgstr "Le produit sélectionné a été désactivé."
|
msgstr "Le produit sélectionné n'est pas actif."
|
||||||
|
|
||||||
#: pretix/control/logdisplay.py:73 pretix/control/logdisplay.py:83
|
#: pretix/control/logdisplay.py:73 pretix/control/logdisplay.py:83
|
||||||
msgid "The order has been changed:"
|
msgid "The order has been changed:"
|
||||||
@@ -19021,6 +19015,10 @@ msgid ""
|
|||||||
"in repeatedly. Please check if your browser is set to block cookies, or "
|
"in repeatedly. Please check if your browser is set to block cookies, or "
|
||||||
"delete all existing cookies and retry."
|
"delete all existing cookies and retry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Il semble que votre navigateur n'accepte pas nos cookies et que vous deviez "
|
||||||
|
"vous connecter à plusieurs reprises. Veuillez vérifier si votre navigateur "
|
||||||
|
"est configuré pour bloquer les cookies, ou supprimez tous les cookies "
|
||||||
|
"existants et réessayez."
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/auth/login.html:35
|
#: pretix/control/templates/pretixcontrol/auth/login.html:35
|
||||||
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:19
|
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:19
|
||||||
@@ -19108,8 +19106,8 @@ msgid ""
|
|||||||
"Do you really want to grant the application <strong>%(application)s</strong> "
|
"Do you really want to grant the application <strong>%(application)s</strong> "
|
||||||
"access to your pretix account?"
|
"access to your pretix account?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Voulez-vous vraiment accorder à l'application <strong>1%(application)s2</"
|
"Voulez-vous vraiment accorder à l'application <strong>%(application)s</"
|
||||||
"strong>3 un accès à votre compte pretix ?"
|
"strong> un accès à votre compte pretix ?"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/auth/oauth_authorization.html:24
|
#: pretix/control/templates/pretixcontrol/auth/oauth_authorization.html:24
|
||||||
#, python-format
|
#, python-format
|
||||||
@@ -19132,8 +19130,8 @@ msgid ""
|
|||||||
"This application has <strong>not</strong> been reviewed by the pretix team. "
|
"This application has <strong>not</strong> been reviewed by the pretix team. "
|
||||||
"Granting access to your pretix account happens at your own risk."
|
"Granting access to your pretix account happens at your own risk."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Cette application n'a <strong>1pas</strong>2 été véifiée par l'équipe "
|
"Cette application n'a <strong>pas</strong> été véifiée par l'équipe pretix. "
|
||||||
"pretix. L'accès à votre compte Pretix se fait à vos propres risques."
|
"L'accès à votre compte Pretix se fait à vos propres risques."
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/auth/oauth_authorization.html:54
|
#: pretix/control/templates/pretixcontrol/auth/oauth_authorization.html:54
|
||||||
msgid "Error:"
|
msgid "Error:"
|
||||||
@@ -19536,7 +19534,7 @@ msgstr[0] ""
|
|||||||
"Êtes-vous sûr de vouloir supprimer l'enregistrement <strong>d'un billet</"
|
"Êtes-vous sûr de vouloir supprimer l'enregistrement <strong>d'un billet</"
|
||||||
"strong> ?"
|
"strong> ?"
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
"Êtes-vous sûr de vouloir supprimer l'enregistrement <strong>%(count)s "
|
"Êtes-vous sûr de vouloir supprimer l'enregistrement <strong>%(count)s "
|
||||||
"billets</strong> ?"
|
"billets</strong> ?"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/checkin/bulk_revert_confirm.html:24
|
#: pretix/control/templates/pretixcontrol/checkin/bulk_revert_confirm.html:24
|
||||||
@@ -21634,7 +21632,7 @@ msgid ""
|
|||||||
"as examples, you can add more in the \"Settings\" part of your event."
|
"as examples, you can add more in the \"Settings\" part of your event."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"pretix supporte une <a href=\"https://pretix.eu/about/en/features/payment\" "
|
"pretix supporte une <a href=\"https://pretix.eu/about/en/features/payment\" "
|
||||||
"target=\"_blank\">large gamme de fournisseurs de paiement </a> vous "
|
"target=\"_blank\">large gamme de fournisseurs de paiement</a> vous "
|
||||||
"permettant de choisir les méthodes de paiement qui conviennent le mieux à "
|
"permettant de choisir les méthodes de paiement qui conviennent le mieux à "
|
||||||
"votre flux de travail. En voici deux à titre d'exemple, vous pouvez en "
|
"votre flux de travail. En voici deux à titre d'exemple, vous pouvez en "
|
||||||
"ajouter dans la partie \"Paramètres\" de votre événement."
|
"ajouter dans la partie \"Paramètres\" de votre événement."
|
||||||
@@ -23578,8 +23576,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Veuillez sélectionner les produits ou les variantes de produits auxquels ce "
|
"Veuillez sélectionner les produits ou les variantes de produits auxquels ce "
|
||||||
"quota doit s'appliquer. Si vous appliquez deux quotas à un même produit, il "
|
"quota doit s'appliquer. Si vous appliquez deux quotas à un même produit, il "
|
||||||
"ne sera seulement disponible si les quotas <strong>1 et </strong>2 ont "
|
"ne sera seulement disponible si les quotas <strong>et</strong> ont encore de "
|
||||||
"encore de la place."
|
"la place."
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/items/quota_edit.html:41
|
#: pretix/control/templates/pretixcontrol/items/quota_edit.html:41
|
||||||
msgid "Advanced options"
|
msgid "Advanced options"
|
||||||
@@ -23638,8 +23636,8 @@ msgid ""
|
|||||||
"Are you sure you want to disable the application <strong>%(application)s</"
|
"Are you sure you want to disable the application <strong>%(application)s</"
|
||||||
"strong> permanently?"
|
"strong> permanently?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Êtes-vous sûr de vouloir désactiver l'application <strong>1%(application)s2</"
|
"Êtes-vous sûr de vouloir désactiver l'application <strong>%(application)s</"
|
||||||
"strong>3 en permanence ?"
|
"strong> de manière permanente ?"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/oauth/app_list.html:4
|
#: pretix/control/templates/pretixcontrol/oauth/app_list.html:4
|
||||||
#: pretix/control/templates/pretixcontrol/oauth/app_list.html:6
|
#: pretix/control/templates/pretixcontrol/oauth/app_list.html:6
|
||||||
@@ -27465,8 +27463,8 @@ msgid ""
|
|||||||
"Using this option will <strong>delete all current quotas</strong> from "
|
"Using this option will <strong>delete all current quotas</strong> from "
|
||||||
"<strong>all selected dates</strong>."
|
"<strong>all selected dates</strong>."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Cette option permet de <strong> supprimer tous les quotas actuels</strong> "
|
"Cette option permet de <strong>supprimer tous les quotas actuels</strong> de "
|
||||||
"de <strong>toutes les dates sélectionnées</strong>."
|
"<strong>toutes les dates sélectionnées</strong>."
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html:277
|
#: pretix/control/templates/pretixcontrol/subevents/bulk_edit.html:277
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -28399,10 +28397,8 @@ msgstr ""
|
|||||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:4
|
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:4
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:6
|
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:6
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:273
|
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:273
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Entry"
|
|
||||||
msgid "Edit entry"
|
msgid "Edit entry"
|
||||||
msgstr "Entrée"
|
msgstr "Modifier l'entrée"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:17
|
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:17
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -28464,7 +28460,7 @@ msgid ""
|
|||||||
"quota is available) or you can press the big button below this text to send "
|
"quota is available) or you can press the big button below this text to send "
|
||||||
"out as many vouchers as currently possible to the persons who waited longest."
|
"out as many vouchers as currently possible to the persons who waited longest."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Vous avez configuré que les bons <strong>1not</strong>2 seront envoyés "
|
"Vous avez configuré que les bons <strong>ne</strong> seront envoyés "
|
||||||
"automatiquement. Vous pouvez soit les envoyer un par un dans l'ordre de "
|
"automatiquement. Vous pouvez soit les envoyer un par un dans l'ordre de "
|
||||||
"votre choix en cliquant sur les boutons à côté d'une ligne dans ce tableau "
|
"votre choix en cliquant sur les boutons à côté d'une ligne dans ce tableau "
|
||||||
"(si un quota suffisant est disponible), soit vous pouvez appuyer sur le gros "
|
"(si un quota suffisant est disponible), soit vous pouvez appuyer sur le gros "
|
||||||
@@ -30368,15 +30364,7 @@ msgstr ""
|
|||||||
"compte."
|
"compte."
|
||||||
|
|
||||||
#: pretix/control/views/user.py:635
|
#: pretix/control/views/user.py:635
|
||||||
#, fuzzy, python-brace-format
|
#, python-brace-format
|
||||||
#| msgid ""
|
|
||||||
#| "Your emergency codes have been newly generated. Remember to store them in "
|
|
||||||
#| "a safe place in case you lose access to your devices. You will not be "
|
|
||||||
#| "able to view them again here.\n"
|
|
||||||
#| "\n"
|
|
||||||
#| "Your emergency codes:\n"
|
|
||||||
#| "- \n"
|
|
||||||
#| "- "
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Your emergency codes have been newly generated. Remember to store them in a "
|
"Your emergency codes have been newly generated. Remember to store them in a "
|
||||||
"safe place in case you lose access to your devices. You will not be able to "
|
"safe place in case you lose access to your devices. You will not be able to "
|
||||||
@@ -30390,8 +30378,7 @@ msgstr ""
|
|||||||
"appareils. Vous ne pourrez plus les consulter ici.\n"
|
"appareils. Vous ne pourrez plus les consulter ici.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Vos codes d'urgence :\n"
|
"Vos codes d'urgence :\n"
|
||||||
"-\n"
|
"{tokens}"
|
||||||
"- "
|
|
||||||
|
|
||||||
#: pretix/control/views/user.py:655
|
#: pretix/control/views/user.py:655
|
||||||
msgid "Your notifications have been disabled."
|
msgid "Your notifications have been disabled."
|
||||||
@@ -30558,10 +30545,8 @@ msgid "The selected entry has been deleted."
|
|||||||
msgstr "L'entrée sélectionnée a été supprimée."
|
msgstr "L'entrée sélectionnée a été supprimée."
|
||||||
|
|
||||||
#: pretix/control/views/waitinglist.py:417
|
#: pretix/control/views/waitinglist.py:417
|
||||||
#, fuzzy
|
|
||||||
#| msgid "The waitinglist entry has been transferred."
|
|
||||||
msgid "The waitinglist entry has been changed."
|
msgid "The waitinglist entry has been changed."
|
||||||
msgstr "L’entrée de la liste d’attente a été transférée."
|
msgstr "L'entrée dans la liste d'attente a été modifiée."
|
||||||
|
|
||||||
#: pretix/helpers/countries.py:134
|
#: pretix/helpers/countries.py:134
|
||||||
msgid "Belarus"
|
msgid "Belarus"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -8,8 +8,8 @@ msgstr ""
|
|||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-01-26 09:10+0000\n"
|
"POT-Creation-Date: 2026-01-26 09:10+0000\n"
|
||||||
"PO-Revision-Date: 2025-12-03 23:00+0000\n"
|
"PO-Revision-Date: 2026-03-02 21:00+0000\n"
|
||||||
"Last-Translator: sandra r <sandrarial@gestiontickets.online>\n"
|
"Last-Translator: Sandra Rial Pérez <sandrarial@gestiontickets.online>\n"
|
||||||
"Language-Team: Galician <https://translate.pretix.eu/projects/pretix/pretix-"
|
"Language-Team: Galician <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||||
"js/gl/>\n"
|
"js/gl/>\n"
|
||||||
"Language: gl\n"
|
"Language: gl\n"
|
||||||
@@ -17,7 +17,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 5.14.3\n"
|
"X-Generator: Weblate 5.16.1\n"
|
||||||
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||||
@@ -162,12 +162,12 @@ msgstr "Pedidos pagados"
|
|||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
||||||
msgid "Attendees (ordered)"
|
msgid "Attendees (ordered)"
|
||||||
msgstr ""
|
msgstr "Asistentes (ordenados)"
|
||||||
|
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
||||||
msgid "Attendees (paid)"
|
msgid "Attendees (paid)"
|
||||||
msgstr ""
|
msgstr "Asistentes (de pago)"
|
||||||
|
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:51
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:51
|
||||||
msgid "Total revenue"
|
msgid "Total revenue"
|
||||||
@@ -732,8 +732,8 @@ msgid ""
|
|||||||
"The items in your cart are no longer reserved for you. You can still "
|
"The items in your cart are no longer reserved for you. You can still "
|
||||||
"complete your order as long as they’re available."
|
"complete your order as long as they’re available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Os artigos da túa cesta xa non están reservados para ti. Aínda podes "
|
"Os artigos do teu carro xa non están reservados para ti. Podes completar o "
|
||||||
"completar o teu pedido mentres estean dispoñibles."
|
"teu pedido sempre que estean dispoñibles."
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/cart.js:49
|
#: pretix/static/pretixpresale/js/ui/cart.js:49
|
||||||
msgid "Cart expired"
|
msgid "Cart expired"
|
||||||
|
|||||||
@@ -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: 2026-02-24 11:50+0000\n"
|
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||||
"PO-Revision-Date: 2026-02-24 11:49+0000\n"
|
"PO-Revision-Date: 2026-03-09 12:52+0000\n"
|
||||||
"Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n"
|
"Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n"
|
||||||
"Language-Team: Japanese <https://translate.pretix.eu/projects/pretix/pretix/"
|
"Language-Team: Japanese <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||||
"ja/>\n"
|
"ja/>\n"
|
||||||
@@ -17,7 +17,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||||
"X-Generator: Weblate 5.16\n"
|
"X-Generator: Weblate 5.16.2\n"
|
||||||
|
|
||||||
#: pretix/_base_settings.py:87
|
#: pretix/_base_settings.py:87
|
||||||
msgid "English"
|
msgid "English"
|
||||||
@@ -6997,22 +6997,22 @@ msgstr "2006/112/EC号指令の第309条に基づいて免除"
|
|||||||
#: pretix/base/models/tax.py:253
|
#: pretix/base/models/tax.py:253
|
||||||
msgctxt "tax_code"
|
msgctxt "tax_code"
|
||||||
msgid "Intra-Community acquisition from second hand means of transport"
|
msgid "Intra-Community acquisition from second hand means of transport"
|
||||||
msgstr "中古輸送手段のEU域内取得"
|
msgstr "中古輸送手段の域内取得"
|
||||||
|
|
||||||
#: pretix/base/models/tax.py:255
|
#: pretix/base/models/tax.py:255
|
||||||
msgctxt "tax_code"
|
msgctxt "tax_code"
|
||||||
msgid "Intra-Community acquisition of second hand goods"
|
msgid "Intra-Community acquisition of second hand goods"
|
||||||
msgstr "中古品のEU域内取得"
|
msgstr "中古品の域内取得"
|
||||||
|
|
||||||
#: pretix/base/models/tax.py:257
|
#: pretix/base/models/tax.py:257
|
||||||
msgctxt "tax_code"
|
msgctxt "tax_code"
|
||||||
msgid "Intra-Community acquisition of works of art"
|
msgid "Intra-Community acquisition of works of art"
|
||||||
msgstr "芸術作品のEU域内取得"
|
msgstr "芸術作品の域内取得"
|
||||||
|
|
||||||
#: pretix/base/models/tax.py:259
|
#: pretix/base/models/tax.py:259
|
||||||
msgctxt "tax_code"
|
msgctxt "tax_code"
|
||||||
msgid "Intra-Community acquisition of collectors items and antiques"
|
msgid "Intra-Community acquisition of collectors items and antiques"
|
||||||
msgstr "コレクターアイテムおよび骨董品のEU域内取得"
|
msgstr "コレクターアイテムおよび骨董品の域内取得"
|
||||||
|
|
||||||
#: pretix/base/models/tax.py:261
|
#: pretix/base/models/tax.py:261
|
||||||
msgctxt "tax_code"
|
msgctxt "tax_code"
|
||||||
@@ -11448,7 +11448,7 @@ msgstr ""
|
|||||||
"{event}のご注文が完了しました。無料製品のみのご注文のため、\n"
|
"{event}のご注文が完了しました。無料製品のみのご注文のため、\n"
|
||||||
"お支払いは不要です。\n"
|
"お支払いは不要です。\n"
|
||||||
"\n"
|
"\n"
|
||||||
"注文の詳細の変更やステータス確認は、以下のURLから行えます:\n"
|
"注文の詳細の変更やステータス確認は、以下のURLから行えます\n"
|
||||||
"{url}\n"
|
"{url}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"よろしくお願いいたします。\n"
|
"よろしくお願いいたします。\n"
|
||||||
@@ -11750,7 +11750,7 @@ msgstr ""
|
|||||||
"{event}のご注文のお支払いを受け取りました。\n"
|
"{event}のご注文のお支払いを受け取りました。\n"
|
||||||
"\n"
|
"\n"
|
||||||
"残念ながら、受け取った金額は必要な全額よりも少ないです。\n"
|
"残念ながら、受け取った金額は必要な全額よりも少ないです。\n"
|
||||||
"したがって、追加の**{pending_sum}**の支払いが不足しているため、\n"
|
"したがって、追加の **{pending_sum}** の支払いが不足しているため、\n"
|
||||||
"ご注文は未払いと見なされます。\n"
|
"ご注文は未払いと見なされます。\n"
|
||||||
"\n"
|
"\n"
|
||||||
"お支払い情報やご注文の状況は、以下のURLでご確認いただけます。\n"
|
"お支払い情報やご注文の状況は、以下のURLでご確認いただけます。\n"
|
||||||
@@ -16579,28 +16579,20 @@ msgid "You need to specify as many seats as voucher codes."
|
|||||||
msgstr "あなたはバウチャーコードの数と同じだけの席を指定する必要があります。"
|
msgstr "あなたはバウチャーコードの数と同じだけの席を指定する必要があります。"
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:39
|
#: pretix/control/forms/waitinglist.py:39
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Please select a valid seat."
|
|
||||||
msgid "Select a valid choice."
|
msgid "Select a valid choice."
|
||||||
msgstr "有効な座席を選択してください。"
|
msgstr "有効な選択肢を選んでください。"
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:107
|
#: pretix/control/forms/waitinglist.py:107
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Active products"
|
|
||||||
msgid "Only includes active products."
|
msgid "Only includes active products."
|
||||||
msgstr "有効な製品"
|
msgstr "有効な製品のみを含みます。"
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:115
|
#: pretix/control/forms/waitinglist.py:115
|
||||||
#, fuzzy
|
|
||||||
#| msgid "A voucher with this code already exists."
|
|
||||||
msgid "A voucher for this waiting list entry was already sent out."
|
msgid "A voucher for this waiting list entry was already sent out."
|
||||||
msgstr "このコードを持つバウチャーはすでに存在しています。"
|
msgstr "この空席待ちリストの内容を持つバウチャーはすでに発送済みです。"
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:125
|
#: pretix/control/forms/waitinglist.py:125
|
||||||
#, fuzzy
|
|
||||||
#| msgid "The selected product has been deactivated."
|
|
||||||
msgid "The selected product is not active."
|
msgid "The selected product is not active."
|
||||||
msgstr "選択された製品が無効化されました。"
|
msgstr "選択された製品無効です。"
|
||||||
|
|
||||||
#: pretix/control/logdisplay.py:73 pretix/control/logdisplay.py:83
|
#: pretix/control/logdisplay.py:73 pretix/control/logdisplay.py:83
|
||||||
msgid "The order has been changed:"
|
msgid "The order has been changed:"
|
||||||
@@ -18348,6 +18340,9 @@ msgid ""
|
|||||||
"in repeatedly. Please check if your browser is set to block cookies, or "
|
"in repeatedly. Please check if your browser is set to block cookies, or "
|
||||||
"delete all existing cookies and retry."
|
"delete all existing cookies and retry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"お使いのブラウザが私どものクッキーを受け入れていないようですので、繰り返し"
|
||||||
|
"ログインする必要があります。ブラウザがクッキーをブロックする設定になっている"
|
||||||
|
"か、既存のクッキーをすべて削除して再試行してください。"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/auth/login.html:35
|
#: pretix/control/templates/pretixcontrol/auth/login.html:35
|
||||||
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:19
|
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:19
|
||||||
@@ -18433,7 +18428,7 @@ msgid ""
|
|||||||
"Do you really want to grant the application <strong>%(application)s</strong> "
|
"Do you really want to grant the application <strong>%(application)s</strong> "
|
||||||
"access to your pretix account?"
|
"access to your pretix account?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"本当にアプリケーション<strong>%(application)s</strong>にPretixアカウントへの"
|
"本当にアプリケーション<strong>%(application)s</strong>にpretixアカウントへの"
|
||||||
"アクセスを許可しますか?"
|
"アクセスを許可しますか?"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/auth/oauth_authorization.html:24
|
#: pretix/control/templates/pretixcontrol/auth/oauth_authorization.html:24
|
||||||
@@ -24697,7 +24692,7 @@ msgstr "顧客履歴"
|
|||||||
#: pretix/control/templates/pretixcontrol/organizers/customer_anonymize.html:11
|
#: pretix/control/templates/pretixcontrol/organizers/customer_anonymize.html:11
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Anonymize customer #%(id)s"
|
msgid "Anonymize customer #%(id)s"
|
||||||
msgstr "顧客のID #%(id)s を匿名化"
|
msgstr "顧客 #%(id)s を匿名化"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/organizers/customer_anonymize.html:16
|
#: pretix/control/templates/pretixcontrol/organizers/customer_anonymize.html:16
|
||||||
msgid "Are you sure you want to anonymize this customer account?"
|
msgid "Are you sure you want to anonymize this customer account?"
|
||||||
@@ -27400,10 +27395,8 @@ msgstr "次のエントリはすでにバウチャーが添付されているた
|
|||||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:4
|
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:4
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:6
|
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:6
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:273
|
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:273
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Entry"
|
|
||||||
msgid "Edit entry"
|
msgid "Edit entry"
|
||||||
msgstr "入場"
|
msgstr "エントリーを編集する"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:17
|
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:17
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -29283,15 +29276,7 @@ msgid "Two-factor authentication is now disabled for your account."
|
|||||||
msgstr "アカウントの二要素認証が無効になりました。"
|
msgstr "アカウントの二要素認証が無効になりました。"
|
||||||
|
|
||||||
#: pretix/control/views/user.py:635
|
#: pretix/control/views/user.py:635
|
||||||
#, fuzzy, python-brace-format
|
#, python-brace-format
|
||||||
#| msgid ""
|
|
||||||
#| "Your emergency codes have been newly generated. Remember to store them in "
|
|
||||||
#| "a safe place in case you lose access to your devices. You will not be "
|
|
||||||
#| "able to view them again here.\n"
|
|
||||||
#| "\n"
|
|
||||||
#| "Your emergency codes:\n"
|
|
||||||
#| "- \n"
|
|
||||||
#| "- "
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Your emergency codes have been newly generated. Remember to store them in a "
|
"Your emergency codes have been newly generated. Remember to store them in a "
|
||||||
"safe place in case you lose access to your devices. You will not be able to "
|
"safe place in case you lose access to your devices. You will not be able to "
|
||||||
@@ -29305,8 +29290,7 @@ msgstr ""
|
|||||||
"ことはできません。\n"
|
"ことはできません。\n"
|
||||||
"\n"
|
"\n"
|
||||||
"あなたの緊急コード:\n"
|
"あなたの緊急コード:\n"
|
||||||
"-\n"
|
"{tokens}"
|
||||||
"- "
|
|
||||||
|
|
||||||
#: pretix/control/views/user.py:655
|
#: pretix/control/views/user.py:655
|
||||||
msgid "Your notifications have been disabled."
|
msgid "Your notifications have been disabled."
|
||||||
@@ -29471,10 +29455,8 @@ msgid "The selected entry has been deleted."
|
|||||||
msgstr "選択されたエントリは削除されました。"
|
msgstr "選択されたエントリは削除されました。"
|
||||||
|
|
||||||
#: pretix/control/views/waitinglist.py:417
|
#: pretix/control/views/waitinglist.py:417
|
||||||
#, fuzzy
|
|
||||||
#| msgid "The waitinglist entry has been transferred."
|
|
||||||
msgid "The waitinglist entry has been changed."
|
msgid "The waitinglist entry has been changed."
|
||||||
msgstr "空席待ちリスト登録が転送されました。"
|
msgstr "空席待ちリスト登録が変更されました。"
|
||||||
|
|
||||||
#: pretix/helpers/countries.py:134
|
#: pretix/helpers/countries.py:134
|
||||||
msgid "Belarus"
|
msgid "Belarus"
|
||||||
|
|||||||
@@ -7,16 +7,16 @@ msgstr ""
|
|||||||
"Project-Id-Version: 1\n"
|
"Project-Id-Version: 1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||||
"PO-Revision-Date: 2026-02-21 03:00+0000\n"
|
"PO-Revision-Date: 2026-03-03 20:00+0000\n"
|
||||||
"Last-Translator: Ruud Hendrickx <ruud@leckxicon.eu>\n"
|
"Last-Translator: Ruud Hendrickx <ruud@leckxicon.eu>\n"
|
||||||
"Language-Team: Dutch <https://translate.pretix.eu/projects/pretix/pretix/nl/"
|
"Language-Team: Dutch <https://translate.pretix.eu/projects/pretix/pretix/nl/>"
|
||||||
">\n"
|
"\n"
|
||||||
"Language: nl\n"
|
"Language: nl\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 5.16\n"
|
"X-Generator: Weblate 5.16.1\n"
|
||||||
|
|
||||||
#: pretix/_base_settings.py:87
|
#: pretix/_base_settings.py:87
|
||||||
msgid "English"
|
msgid "English"
|
||||||
@@ -7996,7 +7996,7 @@ msgstr "Deze cadeaubon is in de tussentijd gebruikt. Probeer het opnieuw."
|
|||||||
|
|
||||||
#: pretix/base/pdf.py:98
|
#: pretix/base/pdf.py:98
|
||||||
msgid "Ticket code (barcode content)"
|
msgid "Ticket code (barcode content)"
|
||||||
msgstr "Ticketcode (waarde van QR-code)"
|
msgstr "Ticketcode (inhoud van QR-code)"
|
||||||
|
|
||||||
#: pretix/base/pdf.py:110
|
#: pretix/base/pdf.py:110
|
||||||
msgid "Order position number"
|
msgid "Order position number"
|
||||||
@@ -9664,7 +9664,7 @@ msgstr "Het bedrag is van uw kaart afgeschreven."
|
|||||||
|
|
||||||
#: pretix/base/services/placeholders.py:699
|
#: pretix/base/services/placeholders.py:699
|
||||||
msgid "Please transfer money to this bank account: 9999-9999-9999-9999"
|
msgid "Please transfer money to this bank account: 9999-9999-9999-9999"
|
||||||
msgstr "Maak het geld over naar deze bankrekening: NL13 TEST 0123 4567 89"
|
msgstr "Maak het geld over naar deze bankrekening: 9999-9999-9999-9999"
|
||||||
|
|
||||||
#: pretix/base/services/placeholders.py:799
|
#: pretix/base/services/placeholders.py:799
|
||||||
#: pretix/control/views/organizer.py:349
|
#: pretix/control/views/organizer.py:349
|
||||||
@@ -11081,8 +11081,8 @@ msgid ""
|
|||||||
"If turned off, ticket downloads are only possible after an order has been "
|
"If turned off, ticket downloads are only possible after an order has been "
|
||||||
"marked as paid."
|
"marked as paid."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Als deze optie is uitgeschakeld, kunnen tickets alleen worden gedownload "
|
"Indien uitgeschakeld, kunnen tickets alleen gedownload worden als de "
|
||||||
"nadat een bestelling als betaald is gemarkeerd."
|
"bestelling als betaald gemarkeerd is."
|
||||||
|
|
||||||
#: pretix/base/settings.py:1763
|
#: pretix/base/settings.py:1763
|
||||||
msgid "Do not issue ticket before email address is validated"
|
msgid "Do not issue ticket before email address is validated"
|
||||||
@@ -13801,12 +13801,12 @@ msgstr "Altijd"
|
|||||||
#: pretix/base/timeline.py:60
|
#: pretix/base/timeline.py:60
|
||||||
msgctxt "timeline"
|
msgctxt "timeline"
|
||||||
msgid "Your event starts"
|
msgid "Your event starts"
|
||||||
msgstr "Uw evenement start"
|
msgstr "Start van uw evenement"
|
||||||
|
|
||||||
#: pretix/base/timeline.py:68
|
#: pretix/base/timeline.py:68
|
||||||
msgctxt "timeline"
|
msgctxt "timeline"
|
||||||
msgid "Your event ends"
|
msgid "Your event ends"
|
||||||
msgstr "Uw evenement eindigt"
|
msgstr "Einde van uw evenement"
|
||||||
|
|
||||||
#: pretix/base/timeline.py:76
|
#: pretix/base/timeline.py:76
|
||||||
msgctxt "timeline"
|
msgctxt "timeline"
|
||||||
@@ -17002,28 +17002,20 @@ msgid "You need to specify as many seats as voucher codes."
|
|||||||
msgstr "U moet evenveel stoelnummers als vouchercodes opgeven."
|
msgstr "U moet evenveel stoelnummers als vouchercodes opgeven."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:39
|
#: pretix/control/forms/waitinglist.py:39
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Please select a valid seat."
|
|
||||||
msgid "Select a valid choice."
|
msgid "Select a valid choice."
|
||||||
msgstr "Kies een geldige beschikbare stoel."
|
msgstr "Maak een geldige keuze."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:107
|
#: pretix/control/forms/waitinglist.py:107
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Active products"
|
|
||||||
msgid "Only includes active products."
|
msgid "Only includes active products."
|
||||||
msgstr "Actieve producten"
|
msgstr "Bevat alleen actieve producten."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:115
|
#: pretix/control/forms/waitinglist.py:115
|
||||||
#, fuzzy
|
|
||||||
#| msgid "A voucher with this code already exists."
|
|
||||||
msgid "A voucher for this waiting list entry was already sent out."
|
msgid "A voucher for this waiting list entry was already sent out."
|
||||||
msgstr "Er bestaat al een voucher met deze code."
|
msgstr "Er is al een voucher verzonden naar deze inschrijver op de wachtlijst."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:125
|
#: pretix/control/forms/waitinglist.py:125
|
||||||
#, fuzzy
|
|
||||||
#| msgid "The selected product has been deactivated."
|
|
||||||
msgid "The selected product is not active."
|
msgid "The selected product is not active."
|
||||||
msgstr "Het gekozen product is uitgeschakeld."
|
msgstr "Het gekozen product is niet actief."
|
||||||
|
|
||||||
#: pretix/control/logdisplay.py:73 pretix/control/logdisplay.py:83
|
#: pretix/control/logdisplay.py:73 pretix/control/logdisplay.py:83
|
||||||
msgid "The order has been changed:"
|
msgid "The order has been changed:"
|
||||||
@@ -18811,6 +18803,9 @@ msgid ""
|
|||||||
"in repeatedly. Please check if your browser is set to block cookies, or "
|
"in repeatedly. Please check if your browser is set to block cookies, or "
|
||||||
"delete all existing cookies and retry."
|
"delete all existing cookies and retry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Uw browser lijkt ons cookie niet te accepteren, waardoor u telkens opnieuw "
|
||||||
|
"moet inloggen. Controleer of uw browser cookies blokkeert of verwijder alle "
|
||||||
|
"opgeslagen cookies en probeer het opnieuw."
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/auth/login.html:35
|
#: pretix/control/templates/pretixcontrol/auth/login.html:35
|
||||||
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:19
|
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:19
|
||||||
@@ -22359,7 +22354,7 @@ msgstr ""
|
|||||||
#: pretix/control/templates/pretixcontrol/item/base.html:24
|
#: pretix/control/templates/pretixcontrol/item/base.html:24
|
||||||
#: pretix/control/templates/pretixcontrol/item/include_variations.html:79
|
#: pretix/control/templates/pretixcontrol/item/include_variations.html:79
|
||||||
msgid "Manage quotas"
|
msgid "Manage quotas"
|
||||||
msgstr "Vragen quotums"
|
msgstr "Quota beheren"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/item/base.html:27
|
#: pretix/control/templates/pretixcontrol/item/base.html:27
|
||||||
#: pretix/control/templates/pretixcontrol/item/include_variations.html:82
|
#: pretix/control/templates/pretixcontrol/item/include_variations.html:82
|
||||||
@@ -28077,10 +28072,8 @@ msgstr ""
|
|||||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:4
|
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:4
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:6
|
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:6
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:273
|
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:273
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Entry"
|
|
||||||
msgid "Edit entry"
|
msgid "Edit entry"
|
||||||
msgstr "Binnenkomst"
|
msgstr "Inschrijving bewerken"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:17
|
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:17
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -30020,15 +30013,7 @@ msgid "Two-factor authentication is now disabled for your account."
|
|||||||
msgstr "Twee-factor-authenticatie is nu uitgeschakeld voor uw account."
|
msgstr "Twee-factor-authenticatie is nu uitgeschakeld voor uw account."
|
||||||
|
|
||||||
#: pretix/control/views/user.py:635
|
#: pretix/control/views/user.py:635
|
||||||
#, fuzzy, python-brace-format
|
#, python-brace-format
|
||||||
#| msgid ""
|
|
||||||
#| "Your emergency codes have been newly generated. Remember to store them in "
|
|
||||||
#| "a safe place in case you lose access to your devices. You will not be "
|
|
||||||
#| "able to view them again here.\n"
|
|
||||||
#| "\n"
|
|
||||||
#| "Your emergency codes:\n"
|
|
||||||
#| "- \n"
|
|
||||||
#| "- "
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Your emergency codes have been newly generated. Remember to store them in a "
|
"Your emergency codes have been newly generated. Remember to store them in a "
|
||||||
"safe place in case you lose access to your devices. You will not be able to "
|
"safe place in case you lose access to your devices. You will not be able to "
|
||||||
@@ -30042,8 +30027,7 @@ msgstr ""
|
|||||||
"U kunt ze hier niet meer opnieuw laten tonen.\n"
|
"U kunt ze hier niet meer opnieuw laten tonen.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Uw noodcodes: \n"
|
"Uw noodcodes: \n"
|
||||||
"-\n"
|
"{tokens}"
|
||||||
"- "
|
|
||||||
|
|
||||||
#: pretix/control/views/user.py:655
|
#: pretix/control/views/user.py:655
|
||||||
msgid "Your notifications have been disabled."
|
msgid "Your notifications have been disabled."
|
||||||
@@ -30210,10 +30194,8 @@ msgid "The selected entry has been deleted."
|
|||||||
msgstr "De gekozen inschrijving is verwijderd."
|
msgstr "De gekozen inschrijving is verwijderd."
|
||||||
|
|
||||||
#: pretix/control/views/waitinglist.py:417
|
#: pretix/control/views/waitinglist.py:417
|
||||||
#, fuzzy
|
|
||||||
#| msgid "The waitinglist entry has been transferred."
|
|
||||||
msgid "The waitinglist entry has been changed."
|
msgid "The waitinglist entry has been changed."
|
||||||
msgstr "De wachtlijstinschrijving is overgedragen."
|
msgstr "De inschrijving op de wachtlijst is veranderd."
|
||||||
|
|
||||||
#: pretix/helpers/countries.py:134
|
#: pretix/helpers/countries.py:134
|
||||||
msgid "Belarus"
|
msgid "Belarus"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
"POT-Creation-Date: 2026-02-24 11:50+0000\n"
|
||||||
"PO-Revision-Date: 2026-02-21 03:00+0000\n"
|
"PO-Revision-Date: 2026-03-02 10:00+0000\n"
|
||||||
"Last-Translator: Ruud Hendrickx <ruud@leckxicon.eu>\n"
|
"Last-Translator: Ruud Hendrickx <ruud@leckxicon.eu>\n"
|
||||||
"Language-Team: Dutch (informal) <https://translate.pretix.eu/projects/pretix/"
|
"Language-Team: Dutch (informal) <https://translate.pretix.eu/projects/pretix/"
|
||||||
"pretix/nl_Informal/>\n"
|
"pretix/nl_Informal/>\n"
|
||||||
@@ -17,7 +17,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||||
"X-Generator: Weblate 5.16\n"
|
"X-Generator: Weblate 5.16.1\n"
|
||||||
|
|
||||||
#: pretix/_base_settings.py:87
|
#: pretix/_base_settings.py:87
|
||||||
msgid "English"
|
msgid "English"
|
||||||
@@ -9673,7 +9673,7 @@ msgstr "Het bedrag is van je kaart afgeschreven."
|
|||||||
|
|
||||||
#: pretix/base/services/placeholders.py:699
|
#: pretix/base/services/placeholders.py:699
|
||||||
msgid "Please transfer money to this bank account: 9999-9999-9999-9999"
|
msgid "Please transfer money to this bank account: 9999-9999-9999-9999"
|
||||||
msgstr "Maak het geld over naar deze bankrekening: NL13 TEST 0123 4567 89"
|
msgstr "Maak het geld over naar deze bankrekening: 9999-9999-9999-9999"
|
||||||
|
|
||||||
#: pretix/base/services/placeholders.py:799
|
#: pretix/base/services/placeholders.py:799
|
||||||
#: pretix/control/views/organizer.py:349
|
#: pretix/control/views/organizer.py:349
|
||||||
@@ -17032,28 +17032,20 @@ msgid "You need to specify as many seats as voucher codes."
|
|||||||
msgstr "Je moet evenveel stoelnummers als vouchercodes opgeven."
|
msgstr "Je moet evenveel stoelnummers als vouchercodes opgeven."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:39
|
#: pretix/control/forms/waitinglist.py:39
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Please select a valid seat."
|
|
||||||
msgid "Select a valid choice."
|
msgid "Select a valid choice."
|
||||||
msgstr "Kies een geldige beschikbare stoel."
|
msgstr "Maak een geldige keuze."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:107
|
#: pretix/control/forms/waitinglist.py:107
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Active products"
|
|
||||||
msgid "Only includes active products."
|
msgid "Only includes active products."
|
||||||
msgstr "Actieve producten"
|
msgstr "Bevat alleen actieve producten."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:115
|
#: pretix/control/forms/waitinglist.py:115
|
||||||
#, fuzzy
|
|
||||||
#| msgid "A voucher with this code already exists."
|
|
||||||
msgid "A voucher for this waiting list entry was already sent out."
|
msgid "A voucher for this waiting list entry was already sent out."
|
||||||
msgstr "Er bestaat al een voucher met deze code."
|
msgstr "Er is al een voucher verzonden naar deze inschrijver op de wachtlijst."
|
||||||
|
|
||||||
#: pretix/control/forms/waitinglist.py:125
|
#: pretix/control/forms/waitinglist.py:125
|
||||||
#, fuzzy
|
|
||||||
#| msgid "The selected product has been deactivated."
|
|
||||||
msgid "The selected product is not active."
|
msgid "The selected product is not active."
|
||||||
msgstr "Het gekozen product is uitgeschakeld."
|
msgstr "Het gekozen product is niet actief."
|
||||||
|
|
||||||
#: pretix/control/logdisplay.py:73 pretix/control/logdisplay.py:83
|
#: pretix/control/logdisplay.py:73 pretix/control/logdisplay.py:83
|
||||||
msgid "The order has been changed:"
|
msgid "The order has been changed:"
|
||||||
@@ -18844,6 +18836,9 @@ msgid ""
|
|||||||
"in repeatedly. Please check if your browser is set to block cookies, or "
|
"in repeatedly. Please check if your browser is set to block cookies, or "
|
||||||
"delete all existing cookies and retry."
|
"delete all existing cookies and retry."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Je browser lijkt ons cookie niet te accepteren, waardoor je telkens opnieuw "
|
||||||
|
"moet inloggen. Controleer of je browser cookies blokkeert of verwijder alle "
|
||||||
|
"opgeslagen cookies en probeer het opnieuw."
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/auth/login.html:35
|
#: pretix/control/templates/pretixcontrol/auth/login.html:35
|
||||||
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:19
|
#: pretix/presale/templates/pretixpresale/fragment_login_status.html:19
|
||||||
@@ -28141,10 +28136,8 @@ msgstr ""
|
|||||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:4
|
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:4
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:6
|
#: pretix/control/templates/pretixcontrol/waitinglist/edit.html:6
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:273
|
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:273
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Entry"
|
|
||||||
msgid "Edit entry"
|
msgid "Edit entry"
|
||||||
msgstr "Binnenkomst"
|
msgstr "Inschrijving bewerken"
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:17
|
#: pretix/control/templates/pretixcontrol/waitinglist/index.html:17
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -30080,15 +30073,7 @@ msgid "Two-factor authentication is now disabled for your account."
|
|||||||
msgstr "Twee-factor-authenticatie is nu uitgeschakeld voor je account."
|
msgstr "Twee-factor-authenticatie is nu uitgeschakeld voor je account."
|
||||||
|
|
||||||
#: pretix/control/views/user.py:635
|
#: pretix/control/views/user.py:635
|
||||||
#, fuzzy, python-brace-format
|
#, python-brace-format
|
||||||
#| msgid ""
|
|
||||||
#| "Your emergency codes have been newly generated. Remember to store them in "
|
|
||||||
#| "a safe place in case you lose access to your devices. You will not be "
|
|
||||||
#| "able to view them again here.\n"
|
|
||||||
#| "\n"
|
|
||||||
#| "Your emergency codes:\n"
|
|
||||||
#| "- \n"
|
|
||||||
#| "- "
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Your emergency codes have been newly generated. Remember to store them in a "
|
"Your emergency codes have been newly generated. Remember to store them in a "
|
||||||
"safe place in case you lose access to your devices. You will not be able to "
|
"safe place in case you lose access to your devices. You will not be able to "
|
||||||
@@ -30102,8 +30087,7 @@ msgstr ""
|
|||||||
"Je kunt ze hier niet meer opnieuw laten tonen.\n"
|
"Je kunt ze hier niet meer opnieuw laten tonen.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Je noodcodes:\n"
|
"Je noodcodes:\n"
|
||||||
"-\n"
|
"{tokens}"
|
||||||
"- "
|
|
||||||
|
|
||||||
#: pretix/control/views/user.py:655
|
#: pretix/control/views/user.py:655
|
||||||
msgid "Your notifications have been disabled."
|
msgid "Your notifications have been disabled."
|
||||||
@@ -30270,10 +30254,8 @@ msgid "The selected entry has been deleted."
|
|||||||
msgstr "De gekozen inschrijving is verwijderd."
|
msgstr "De gekozen inschrijving is verwijderd."
|
||||||
|
|
||||||
#: pretix/control/views/waitinglist.py:417
|
#: pretix/control/views/waitinglist.py:417
|
||||||
#, fuzzy
|
|
||||||
#| msgid "The waitinglist entry has been transferred."
|
|
||||||
msgid "The waitinglist entry has been changed."
|
msgid "The waitinglist entry has been changed."
|
||||||
msgstr "De wachtlijstvermelding is overgedragen."
|
msgstr "De inschrijving op de wachtlijst is veranderd."
|
||||||
|
|
||||||
#: pretix/helpers/countries.py:134
|
#: pretix/helpers/countries.py:134
|
||||||
msgid "Belarus"
|
msgid "Belarus"
|
||||||
@@ -34075,7 +34057,7 @@ msgid ""
|
|||||||
"completed your payment, you can refresh this page."
|
"completed your payment, you can refresh this page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Scan de QR-code hieronder om je WeChat-betaling uit te voeren. Als je de "
|
"Scan de QR-code hieronder om je WeChat-betaling uit te voeren. Als je de "
|
||||||
"betaling hebt afgerond kan je deze pagina verversen."
|
"betaling hebt afgerond, kan je deze pagina verversen."
|
||||||
|
|
||||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/pending.html:62
|
#: pretix/plugins/stripe/templates/pretixplugins/stripe/pending.html:62
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -35249,7 +35231,7 @@ msgstr "incl. belasting"
|
|||||||
#: pretix/presale/templates/pretixpresale/event/voucher.html:359
|
#: pretix/presale/templates/pretixpresale/event/voucher.html:359
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "<strong>plus</strong> %(rate)s%% %(name)s"
|
msgid "<strong>plus</strong> %(rate)s%% %(name)s"
|
||||||
msgstr "<strong>excl.</strong> %(rate)s%% %(name)s"
|
msgstr "<strong>plus</strong> %(rate)s%% %(name)s"
|
||||||
|
|
||||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:180
|
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:180
|
||||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:320
|
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:320
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -802,31 +802,37 @@ class PaypalMethod(BasePaymentProvider):
|
|||||||
all_captures_completed = False
|
all_captures_completed = False
|
||||||
else:
|
else:
|
||||||
any_captures = True
|
any_captures = True
|
||||||
if not (any_captures and all_captures_completed):
|
|
||||||
|
# Payment has at least one capture, but it is not yet completed
|
||||||
|
if any_captures and not all_captures_completed:
|
||||||
messages.warning(request, _('PayPal has not yet approved the payment. We will inform you as '
|
messages.warning(request, _('PayPal has not yet approved the payment. We will inform you as '
|
||||||
'soon as the payment completed.'))
|
'soon as the payment completed.'))
|
||||||
payment.info = json.dumps(pp_captured_order.dict())
|
payment.info = json.dumps(pp_captured_order.dict())
|
||||||
payment.state = OrderPayment.PAYMENT_STATE_PENDING
|
payment.state = OrderPayment.PAYMENT_STATE_PENDING
|
||||||
payment.save()
|
payment.save()
|
||||||
return
|
return
|
||||||
|
# Payment has at least one capture and all captures are completed
|
||||||
|
elif any_captures and all_captures_completed:
|
||||||
|
if pp_captured_order.status != 'COMPLETED':
|
||||||
|
payment.fail(info=pp_captured_order.dict())
|
||||||
|
logger.error('Invalid state: %s' % repr(pp_captured_order.dict()))
|
||||||
|
raise PaymentException(
|
||||||
|
_('We were unable to process your payment. See below for details on how to proceed.')
|
||||||
|
)
|
||||||
|
|
||||||
if pp_captured_order.status != 'COMPLETED':
|
if payment.state == OrderPayment.PAYMENT_STATE_CONFIRMED:
|
||||||
payment.fail(info=pp_captured_order.dict())
|
logger.warning('PayPal success event even though order is already marked as paid')
|
||||||
logger.error('Invalid state: %s' % repr(pp_captured_order.dict()))
|
return
|
||||||
raise PaymentException(
|
|
||||||
_('We were unable to process your payment. See below for details on how to proceed.')
|
|
||||||
)
|
|
||||||
|
|
||||||
if payment.state == OrderPayment.PAYMENT_STATE_CONFIRMED:
|
try:
|
||||||
logger.warning('PayPal success event even though order is already marked as paid')
|
payment.info = json.dumps(pp_captured_order.dict())
|
||||||
|
payment.save(update_fields=['info'])
|
||||||
|
payment.confirm()
|
||||||
|
except Quota.QuotaExceededException as e:
|
||||||
|
raise PaymentException(str(e))
|
||||||
|
# Payment has not any captures yet - so it's probably in created status
|
||||||
|
else:
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
|
||||||
payment.info = json.dumps(pp_captured_order.dict())
|
|
||||||
payment.save(update_fields=['info'])
|
|
||||||
payment.confirm()
|
|
||||||
except Quota.QuotaExceededException as e:
|
|
||||||
raise PaymentException(str(e))
|
|
||||||
finally:
|
finally:
|
||||||
if 'payment_paypal_oid' in request.session:
|
if 'payment_paypal_oid' in request.session:
|
||||||
del request.session['payment_paypal_oid']
|
del request.session['payment_paypal_oid']
|
||||||
@@ -836,7 +842,7 @@ class PaypalMethod(BasePaymentProvider):
|
|||||||
try:
|
try:
|
||||||
if (
|
if (
|
||||||
payment.info
|
payment.info
|
||||||
and payment.info_data['purchase_units'][0]['payments']['captures'][0]['status'] == 'pending'
|
and payment.info_data['purchase_units'][0]['payments']['captures'][0]['status'] == 'PENDING'
|
||||||
):
|
):
|
||||||
retry = False
|
retry = False
|
||||||
except (KeyError, IndexError):
|
except (KeyError, IndexError):
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ var pretixpaypal = {
|
|||||||
credit: gettext('PayPal Credit'),
|
credit: gettext('PayPal Credit'),
|
||||||
card: gettext('Credit Card'),
|
card: gettext('Credit Card'),
|
||||||
paylater: gettext('PayPal Pay Later'),
|
paylater: gettext('PayPal Pay Later'),
|
||||||
ideal: gettext('iDEAL'),
|
ideal: gettext('iDEAL | Wero'),
|
||||||
sepa: gettext('SEPA Direct Debit'),
|
sepa: gettext('SEPA Direct Debit'),
|
||||||
bancontact: gettext('Bancontact'),
|
bancontact: gettext('Bancontact'),
|
||||||
giropay: gettext('giropay'),
|
giropay: gettext('giropay'),
|
||||||
|
|||||||
@@ -38,13 +38,10 @@ from i18nfield.strings import LazyI18nString
|
|||||||
|
|
||||||
from pretix.base.email import get_email_context
|
from pretix.base.email import get_email_context
|
||||||
from pretix.base.i18n import language
|
from pretix.base.i18n import language
|
||||||
from pretix.base.models import (
|
from pretix.base.models import Checkin, Event, InvoiceAddress, Order, User
|
||||||
CachedFile, Checkin, Event, InvoiceAddress, Order, User,
|
|
||||||
)
|
|
||||||
from pretix.base.services.mail import mail
|
from pretix.base.services.mail import mail
|
||||||
from pretix.base.services.tasks import ProfiledEventTask
|
from pretix.base.services.tasks import ProfiledEventTask
|
||||||
from pretix.celery_app import app
|
from pretix.celery_app import app
|
||||||
from pretix.helpers.format import format_map
|
|
||||||
|
|
||||||
|
|
||||||
def _chunks(lst, n):
|
def _chunks(lst, n):
|
||||||
@@ -64,7 +61,6 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
|
|||||||
user = User.objects.get(pk=user) if user else None
|
user = User.objects.get(pk=user) if user else None
|
||||||
subject = LazyI18nString(subject)
|
subject = LazyI18nString(subject)
|
||||||
message = LazyI18nString(message)
|
message = LazyI18nString(message)
|
||||||
attachments_for_log = [cf.filename for cf in CachedFile.objects.filter(pk__in=attachments)] if attachments else []
|
|
||||||
|
|
||||||
def _send_to_order(o):
|
def _send_to_order(o):
|
||||||
send_to_order = recipients in ('both', 'orders')
|
send_to_order = recipients in ('both', 'orders')
|
||||||
@@ -122,7 +118,7 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
|
|||||||
|
|
||||||
with language(o.locale, event.settings.region):
|
with language(o.locale, event.settings.region):
|
||||||
email_context = get_email_context(event=event, order=o, invoice_address=ia, position=p)
|
email_context = get_email_context(event=event, order=o, invoice_address=ia, position=p)
|
||||||
mail(
|
outgoing_mail = mail(
|
||||||
p.attendee_email,
|
p.attendee_email,
|
||||||
subject,
|
subject,
|
||||||
message,
|
message,
|
||||||
@@ -135,25 +131,17 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
|
|||||||
attach_ical=attach_ical,
|
attach_ical=attach_ical,
|
||||||
attach_cached_files=attachments
|
attach_cached_files=attachments
|
||||||
)
|
)
|
||||||
o.log_action(
|
if outgoing_mail:
|
||||||
'pretix.plugins.sendmail.order.email.sent.attendee',
|
o.log_action(
|
||||||
user=user,
|
'pretix.plugins.sendmail.order.email.sent.attendee',
|
||||||
data={
|
user=user,
|
||||||
'position': p.positionid,
|
data=outgoing_mail.log_data(),
|
||||||
'subject': format_map(subject.localize(o.locale), email_context),
|
)
|
||||||
'message': format_map(message.localize(o.locale), email_context),
|
|
||||||
'recipient': p.attendee_email,
|
|
||||||
'attach_tickets': attach_tickets,
|
|
||||||
'attach_ical': attach_ical,
|
|
||||||
'attach_other_files': [],
|
|
||||||
'attach_cached_files': attachments_for_log,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if send_to_order and o.email:
|
if send_to_order and o.email:
|
||||||
with language(o.locale, event.settings.region):
|
with language(o.locale, event.settings.region):
|
||||||
email_context = get_email_context(event=event, order=o, invoice_address=ia)
|
email_context = get_email_context(event=event, order=o, invoice_address=ia)
|
||||||
mail(
|
outgoing_mail = mail(
|
||||||
o.email,
|
o.email,
|
||||||
subject,
|
subject,
|
||||||
message,
|
message,
|
||||||
@@ -165,19 +153,12 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
|
|||||||
attach_ical=attach_ical,
|
attach_ical=attach_ical,
|
||||||
attach_cached_files=attachments,
|
attach_cached_files=attachments,
|
||||||
)
|
)
|
||||||
o.log_action(
|
if outgoing_mail:
|
||||||
'pretix.plugins.sendmail.order.email.sent',
|
o.log_action(
|
||||||
user=user,
|
'pretix.plugins.sendmail.order.email.sent',
|
||||||
data={
|
user=user,
|
||||||
'subject': format_map(subject.localize(o.locale), email_context),
|
data=outgoing_mail.log_data(),
|
||||||
'message': format_map(message.localize(o.locale), email_context),
|
)
|
||||||
'recipient': o.email,
|
|
||||||
'attach_tickets': attach_tickets,
|
|
||||||
'attach_ical': attach_ical,
|
|
||||||
'attach_other_files': [],
|
|
||||||
'attach_cached_files': attachments_for_log,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
for chunk in _chunks(objects, 1000):
|
for chunk in _chunks(objects, 1000):
|
||||||
orders = Order.objects.filter(pk__in=chunk, event=event)
|
orders = Order.objects.filter(pk__in=chunk, event=event)
|
||||||
|
|||||||
@@ -92,70 +92,89 @@ logger = logging.getLogger('pretix.plugins.stripe')
|
|||||||
# State of the payment methods
|
# State of the payment methods
|
||||||
#
|
#
|
||||||
# Source: https://stripe.com/docs/payments/payment-methods/overview
|
# Source: https://stripe.com/docs/payments/payment-methods/overview
|
||||||
# Last Update: 2023-12-20
|
# Last Update: 2026-06-12
|
||||||
#
|
#
|
||||||
|
# pretix Staff: Do not forget to enable/"On by default" newly added payment methods in
|
||||||
|
# Stripe's managed payment methods configuration for the Stripe/pretix.eu connect platform.
|
||||||
|
#
|
||||||
|
# The categorization and order of payment methods is based on the list of the managed payment method configration
|
||||||
|
# in the Stripe Dashboard.
|
||||||
|
|
||||||
# Cards
|
# Cards
|
||||||
# - Credit and Debit Cards: ✓
|
# - Credit and Debit Cards: ✓
|
||||||
# - Apple, Google Pay: ✓
|
# * Cartes Bancaires: ✓
|
||||||
|
# * Korean cards: ✓
|
||||||
|
# * Japan installments: ✗
|
||||||
|
# * JCB: ✓
|
||||||
|
# * Meses sin intereses: ✗
|
||||||
#
|
#
|
||||||
# Bank debits
|
# Wallets
|
||||||
# - ACH Debit: ✗
|
# - Apple: ✓ (Cards)
|
||||||
# - Canadian PADs: ✗
|
# - Google Pay: ✓ (Cards)
|
||||||
# - BACS Direct Debit: ✗
|
# - Link: ✓ (PaymentRequestButton/Cards)
|
||||||
# - SEPA Direct Debit: ✓
|
# - Alipay: ✓
|
||||||
# - BECS Direct Debit: ✗
|
# - Stablecoins and Crypto: ✗
|
||||||
|
# - Kakao Pay: ✗
|
||||||
|
# - Naver Pay: ✗
|
||||||
|
# - MB Way: ✗
|
||||||
|
# - Satis Pay: ✗
|
||||||
|
# - WeChat Pay: ✓
|
||||||
|
# - PAYCO: ✗
|
||||||
|
# - PayPal: ✓ (No settings UI yet; incompatible with Connect+Direct Charges)
|
||||||
|
# - Samsung pay: ✗
|
||||||
|
# - MobilePay: ✓
|
||||||
|
# - Revolut Pay: ✓
|
||||||
|
# - Amazon Pay: ✗
|
||||||
|
# - PayPay: ✗
|
||||||
|
# - GrabPay: ✗
|
||||||
|
# - Cash App Pay: ✗
|
||||||
|
# - Secure Remote Commerce: ✗
|
||||||
#
|
#
|
||||||
# Bank redirects
|
# Bank redirects
|
||||||
# - Bancontact: ✓
|
# - Bancontact: ✓
|
||||||
# - BLIK: ✗
|
|
||||||
# - EPS: ✓
|
# - EPS: ✓
|
||||||
# - giropay: (deprecated)
|
|
||||||
# - iDEAL: ✓
|
# - iDEAL: ✓
|
||||||
# - P24: ✓
|
# - Przelewy24: ✓
|
||||||
# - Sofort: (deprecated)
|
# - BLIK: ✗
|
||||||
# - FPX: ✗
|
# - Pay By Bank: ✓
|
||||||
# - PayNow: ✗
|
|
||||||
# - UPI: ✗
|
|
||||||
# - Netbanking: ✗
|
|
||||||
# - TWINT: ✓
|
# - TWINT: ✓
|
||||||
# - Wero: ✓ (No settings UI yet)
|
# - Wero: ✓ (No settings UI yet)
|
||||||
#
|
# - giropay: ✗ (deprecated)
|
||||||
# Bank transfers
|
# - Sofort: ✗ (deprecated)
|
||||||
# - ACH Bank Transfer: ✗
|
|
||||||
# - SEPA Bank Transfer: ✗
|
|
||||||
# - UK Bank Transfer: ✗
|
|
||||||
# - Multibanco: ✗
|
|
||||||
# - Furikomi (Japan): ✗
|
|
||||||
# - Mexico Bank Transfer: ✗
|
|
||||||
#
|
#
|
||||||
# Buy now, pay later
|
# Buy now, pay later
|
||||||
# - Affirm: ✓
|
# - Billie: ✗
|
||||||
# - Afterpay/Clearpay: ✗
|
|
||||||
# - Klarna: ✓
|
# - Klarna: ✓
|
||||||
|
# - Afterpay/Clearpay: ✗
|
||||||
# - Zip: ✗
|
# - Zip: ✗
|
||||||
|
# - Alma: ✗
|
||||||
|
# - Affirm: ✓
|
||||||
|
#
|
||||||
|
# Bank debits
|
||||||
|
# - SEPA Direct Debit: ✓
|
||||||
|
# - ACH Direct Debit: ✗
|
||||||
|
# - Australian BECS Direct Debit: ✗
|
||||||
|
# - Canadian pre-authorized debits: ✗
|
||||||
|
# - BACS Direct Debit: ✗
|
||||||
|
# - FPX: ✗
|
||||||
|
# - NZ BECS Direct Debit: ✗
|
||||||
|
#
|
||||||
|
# Bank transfers
|
||||||
|
# - Bank Transfer: ✗
|
||||||
|
#
|
||||||
|
# Vouchers
|
||||||
|
# - Multibanco: ✓
|
||||||
|
# - Boleto: ✗
|
||||||
|
# - Konbini: ✗
|
||||||
|
# - OXXO: ✗
|
||||||
#
|
#
|
||||||
# Real-time payments
|
# Real-time payments
|
||||||
# - Swish: ✓
|
# - Swish: ✓
|
||||||
|
# - UPI: ✗
|
||||||
|
# - Pix: ✗
|
||||||
|
# - PayTo: ✗
|
||||||
# - PayNow: ✗
|
# - PayNow: ✗
|
||||||
# - PromptPay: ✓
|
# - PromptPay: ✓
|
||||||
# - Pix: ✗
|
|
||||||
#
|
|
||||||
# Vouchers
|
|
||||||
# - Konbini: ✗
|
|
||||||
# - OXXO: ✗
|
|
||||||
# - Boleto: ✗
|
|
||||||
#
|
|
||||||
# Wallets
|
|
||||||
# - Apple Pay: ✓ (Cards)
|
|
||||||
# - Google Pay: ✓ (Cards)
|
|
||||||
# - Secure Remote Commerce: ✗
|
|
||||||
# - Link: ✓ (PaymentRequestButton)
|
|
||||||
# - Cash App Pay: ✗
|
|
||||||
# - PayPal: ✓ (No settings UI yet)
|
|
||||||
# - MobilePay: ✓
|
|
||||||
# - Alipay: ✓
|
|
||||||
# - WeChat Pay: ✓
|
|
||||||
# - GrabPay: ✓
|
|
||||||
|
|
||||||
|
|
||||||
class StripeSettingsHolder(BasePaymentProvider):
|
class StripeSettingsHolder(BasePaymentProvider):
|
||||||
@@ -1550,7 +1569,7 @@ class StripeGiropay(StripeRedirectWithAccountNamePaymentIntentMethod):
|
|||||||
class StripeIdeal(StripeRedirectMethod):
|
class StripeIdeal(StripeRedirectMethod):
|
||||||
identifier = 'stripe_ideal'
|
identifier = 'stripe_ideal'
|
||||||
verbose_name = _('iDEAL via Stripe')
|
verbose_name = _('iDEAL via Stripe')
|
||||||
public_name = _('iDEAL')
|
public_name = _('iDEAL | Wero')
|
||||||
method = 'ideal'
|
method = 'ideal'
|
||||||
explanation = _(
|
explanation = _(
|
||||||
'iDEAL is an online payment method available to customers of Dutch banks. Please keep your online '
|
'iDEAL is an online payment method available to customers of Dutch banks. Please keep your online '
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
{% load eventurl %}
|
{% load eventurl %}
|
||||||
{% load safelink %}
|
{% load safelink %}
|
||||||
{% load rich_text %}
|
{% load rich_text %}
|
||||||
|
{% load anonymize_email %}
|
||||||
{% block thetitle %}
|
{% block thetitle %}
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
{{ messages|join:" " }} ::
|
{{ messages|join:" " }} ::
|
||||||
@@ -219,7 +220,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block footernav %}
|
{% block footernav %}
|
||||||
{% if request.event.settings.contact_mail %}
|
{% if request.event.settings.contact_mail %}
|
||||||
<li><a href="mailto:{{ request.event.settings.contact_mail }}" target="_blank" rel="noopener">{% trans "Contact" %}</a></li>
|
<li><a href="{{ 'mailto:'|add:request.event.settings.contact_mail|anon_email }}" target="_blank" rel="noopener">{% trans "Contact" %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if request.event.settings.privacy_url %}
|
{% if request.event.settings.privacy_url %}
|
||||||
<li><a href="{% safelink request.event.settings.privacy_url %}" target="_blank" rel="noopener">{% trans "Privacy policy" %}</a></li>
|
<li><a href="{% safelink request.event.settings.privacy_url %}" target="_blank" rel="noopener">{% trans "Privacy policy" %}</a></li>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="panel-group" id="questions_accordion">
|
<div class="panel-group" id="questions_accordion">
|
||||||
{% if invoice_address_asked or event.settings.invoice_name_required %}
|
{% if invoice_address_asked or event.settings.invoice_name_required %}
|
||||||
{% if invoice_address_asked and not request.GET.generate_invoice == "true" and not event.settings.invoice_reissue_after_modify %}
|
{% if invoice_address_asked and not request.GET.generate_invoice == "true" and not invoice_generation_selfservice %}
|
||||||
<div class="alert alert-info">
|
<div class="alert alert-info">
|
||||||
{% blocktrans trimmed %}
|
{% blocktrans trimmed %}
|
||||||
Modifying your invoice address will not automatically generate a new invoice.
|
Modifying your invoice address will not automatically generate a new invoice.
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
{% bootstrap_form_errors timemachine_form "all" %}
|
{% bootstrap_form_errors timemachine_form "all" %}
|
||||||
|
|
||||||
<p>{% trans "Test your shop as if it were a different date and time." %}</p>
|
<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="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
@@ -44,4 +45,4 @@
|
|||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -21,4 +21,5 @@
|
|||||||
<script type="text/javascript" src="{% static "pretixpresale/js/ui/cart.js" %}"></script>
|
<script type="text/javascript" src="{% static "pretixpresale/js/ui/cart.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "pretixpresale/js/ui/iframe.js" %}"></script>
|
<script type="text/javascript" src="{% static "pretixpresale/js/ui/iframe.js" %}"></script>
|
||||||
<script type="text/javascript" src="{% static "pretixbase/js/addressform.js" %}"></script>
|
<script type="text/javascript" src="{% static "pretixbase/js/addressform.js" %}"></script>
|
||||||
|
<script type="text/javascript" src="{% static "pretixbase/js/deanonymize_email.js" %}"></script>
|
||||||
{% endcompress %}
|
{% endcompress %}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
{% load thumb %}
|
{% load thumb %}
|
||||||
{% load eventurl %}
|
{% load eventurl %}
|
||||||
{% load safelink %}
|
{% load safelink %}
|
||||||
|
{% load anonymize_email %}
|
||||||
{% block thetitle %}
|
{% block thetitle %}
|
||||||
{% block title %}{% endblock %}{% if url_name != "organizer.index" %} :: {% endif %}{{ organizer.name }}
|
{% block title %}{% endblock %}{% if url_name != "organizer.index" %} :: {% endif %}{{ organizer.name }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -97,7 +98,7 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block footernav %}
|
{% block footernav %}
|
||||||
{% if not request.event and request.organizer.settings.contact_mail %}
|
{% if not request.event and request.organizer.settings.contact_mail %}
|
||||||
<li><a href="mailto:{{ request.organizer.settings.contact_mail }}" target="_blank" rel="noopener">{% trans "Contact" %}</a></li>
|
<li><a href="{{ 'mailto:'|add:request.organizer.settings.contact_mail|anon_email }}" target="_blank" rel="noopener">{% trans "Contact" %}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if not request.event and request.organizer.settings.privacy_url %}
|
{% if not request.event and request.organizer.settings.privacy_url %}
|
||||||
<li><a href="{% safelink request.organizer.settings.privacy_url %}" target="_blank" rel="noopener">{% trans "Privacy policy" %}</a></li>
|
<li><a href="{% safelink request.organizer.settings.privacy_url %}" target="_blank" rel="noopener">{% trans "Privacy policy" %}</a></li>
|
||||||
|
|||||||
@@ -909,6 +909,21 @@ class OrderModify(EventViewMixin, OrderDetailMixin, OrderQuestionsViewMixin, Tem
|
|||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
ctx = super().get_context_data(
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
ctx['invoice_generation_selfservice'] = (
|
||||||
|
self.request.event.settings.invoice_reissue_after_modify or
|
||||||
|
(
|
||||||
|
can_generate_invoice(self.request.event, self.order, ignore_payments=True) and
|
||||||
|
not self.order.invoices.exists()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
self.request = request
|
self.request = request
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
|
|||||||
+6
-6
@@ -2776,9 +2776,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
@@ -5642,9 +5642,9 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.0.4",
|
"version": "3.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
|
|||||||
@@ -173,8 +173,8 @@ $(function () {
|
|||||||
if (!dependents.transmission_peppol_participant_id.val()) {
|
if (!dependents.transmission_peppol_participant_id.val()) {
|
||||||
const fill_peppol_id = function () {
|
const fill_peppol_id = function () {
|
||||||
const vatId = dependents.vat_id.val();
|
const vatId = dependents.vat_id.val();
|
||||||
if (vatId && vatId.startsWith("BE") && dependents.transmission_type.val() === "peppol" && autofill_peppol_id) {
|
if (vatId && vatId.startsWith("BE") && dependents.transmission_type.val() === "peppol") {
|
||||||
dependents.transmission_peppol_participant_id.val("0201:" + vatId.substring(2))
|
dependents.transmission_peppol_participant_id.val("0208:" + vatId.substring(2))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dependents.vat_id.add(dependents.transmission_type).on("change", fill_peppol_id);
|
dependents.vat_id.add(dependents.transmission_type).on("change", fill_peppol_id);
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
document.querySelectorAll('a[href^="mailto:"]').forEach(function(link) {
|
||||||
|
// Replace [at] with @ and the [dot] with . in both the href and the displayed text (if needed)
|
||||||
|
link.href = link.href.replace('[at]', '@').replace('[dot]', '.');
|
||||||
|
link.textContent = link.textContent.replace('[at]', '@').replace('[dot]', '.');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -895,6 +895,41 @@ def test_order_create_payment_info_optional(token_client, organizer, event, item
|
|||||||
assert json.loads(p.info) == res['payment_info']
|
assert json.loads(p.info) == res['payment_info']
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_order_create_payment_info_valid_object(token_client, organizer, event, item, quota, question):
|
||||||
|
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
||||||
|
res['positions'][0]['item'] = item.pk
|
||||||
|
res['positions'][0]['answers'][0]['question'] = question.pk
|
||||||
|
|
||||||
|
res["payment_info"] = [{"should": "fail"}]
|
||||||
|
resp = token_client.post(
|
||||||
|
'/api/v1/organizers/{}/events/{}/orders/'.format(
|
||||||
|
organizer.slug, event.slug
|
||||||
|
), format='json', data=res
|
||||||
|
)
|
||||||
|
assert resp.status_code == 400
|
||||||
|
|
||||||
|
res['payment_info'] = {
|
||||||
|
'foo': {
|
||||||
|
'bar': [1, 2],
|
||||||
|
'test': False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resp = token_client.post(
|
||||||
|
'/api/v1/organizers/{}/events/{}/orders/'.format(
|
||||||
|
organizer.slug, event.slug
|
||||||
|
), format='json', data=res
|
||||||
|
)
|
||||||
|
assert resp.status_code == 201
|
||||||
|
with scopes_disabled():
|
||||||
|
o = Order.objects.get(code=resp.data['code'])
|
||||||
|
|
||||||
|
p = o.payments.first()
|
||||||
|
assert p.provider == "banktransfer"
|
||||||
|
assert p.amount == o.total
|
||||||
|
assert json.loads(p.info) == res['payment_info']
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_order_create_position_secret_optional(token_client, organizer, event, item, quota, question):
|
def test_order_create_position_secret_optional(token_client, organizer, event, item, quota, question):
|
||||||
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
res = copy.deepcopy(ORDER_CREATE_PAYLOAD)
|
||||||
|
|||||||
+129
-67
@@ -34,7 +34,7 @@ from stripe import error
|
|||||||
from tests.plugins.stripe.test_checkout import apple_domain_create
|
from tests.plugins.stripe.test_checkout import apple_domain_create
|
||||||
from tests.plugins.stripe.test_provider import MockedCharge
|
from tests.plugins.stripe.test_provider import MockedCharge
|
||||||
|
|
||||||
from pretix.base.models import InvoiceAddress, Order, OrderPosition
|
from pretix.base.models import InvoiceAddress, Order, OrderPosition, Team
|
||||||
from pretix.base.models.orders import OrderFee, OrderPayment, OrderRefund
|
from pretix.base.models.orders import OrderFee, OrderPayment, OrderRefund
|
||||||
|
|
||||||
|
|
||||||
@@ -180,6 +180,41 @@ def order2(event2, item2):
|
|||||||
return o
|
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 = {
|
TEST_ORDERPOSITION_RES = {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"order": "FOO",
|
"order": "FOO",
|
||||||
@@ -987,8 +1022,64 @@ def test_refund_cancel(token_client, organizer, event, order):
|
|||||||
assert resp.status_code == 400
|
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
|
@pytest.mark.django_db
|
||||||
def test_orderposition_list(token_client, organizer, device, event, order, item, subevent, subevent2, question, django_assert_num_queries):
|
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)
|
||||||
|
|
||||||
i2 = copy.copy(item)
|
i2 = copy.copy(item)
|
||||||
i2.pk = None
|
i2.pk = None
|
||||||
i2.save()
|
i2.save()
|
||||||
@@ -1005,88 +1096,64 @@ def test_orderposition_list(token_client, organizer, device, event, order, item,
|
|||||||
res["answers"][0]["question"] = question.pk
|
res["answers"][0]["question"] = question.pk
|
||||||
res["print_logs"][0]["id"] = op.print_logs.first().pk
|
res["print_logs"][0]["id"] = op.print_logs.first().pk
|
||||||
res["print_logs"][0]["device_id"] = device.device_id
|
res["print_logs"][0]["device_id"] = device.device_id
|
||||||
|
if endpoint_type == "organizer":
|
||||||
|
res["event"] = event.slug
|
||||||
|
|
||||||
resp = token_client.get('/api/v1/organizers/{}/events/{}/orderpositions/'.format(organizer.slug, event.slug))
|
resp = token_client.get(endpoint)
|
||||||
assert resp.status_code == 200
|
assert resp.status_code == 200
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
|
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?order__status=n')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?order__status=n'.format(organizer.slug, event.slug))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?order__status=p')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?order__status=p'.format(organizer.slug, event.slug))
|
|
||||||
assert [] == resp.data['results']
|
assert [] == resp.data['results']
|
||||||
|
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?item={}'.format(item.pk))
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?item={}'.format(organizer.slug, event.slug, item.pk))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?item__in={},{}'.format(item.pk, i2.pk))
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?item__in={},{}'.format(
|
|
||||||
organizer.slug, event.slug, item.pk, i2.pk
|
|
||||||
))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?item={}'.format(i2.pk))
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?item={}'.format(organizer.slug, event.slug, i2.pk))
|
|
||||||
assert [] == resp.data['results']
|
assert [] == resp.data['results']
|
||||||
|
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?variation={}'.format(var.pk))
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?variation={}'.format(organizer.slug, event.slug, var.pk))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?variation={}'.format(var2.pk))
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?variation={}'.format(organizer.slug, event.slug, var2.pk))
|
|
||||||
assert [] == resp.data['results']
|
assert [] == resp.data['results']
|
||||||
|
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?attendee_name=Peter')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=Peter'.format(organizer.slug, event.slug))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?attendee_name=peter')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=peter'.format(organizer.slug, event.slug))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?attendee_name=Mark')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?attendee_name=Mark'.format(organizer.slug, event.slug))
|
|
||||||
assert [] == resp.data['results']
|
assert [] == resp.data['results']
|
||||||
|
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?secret=z3fsn8jyufm5kpk768q69gkbyr5f4h6w')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?secret=z3fsn8jyufm5kpk768q69gkbyr5f4h6w'.format(
|
|
||||||
organizer.slug, event.slug))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?secret=abc123')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?secret=abc123'.format(organizer.slug, event.slug))
|
|
||||||
assert [] == resp.data['results']
|
assert [] == resp.data['results']
|
||||||
|
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?pseudonymization_id=ABCDEFGHKL')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?pseudonymization_id=ABCDEFGHKL'.format(
|
|
||||||
organizer.slug, event.slug))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?pseudonymization_id=FOO')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?pseudonymization_id=FOO'.format(organizer.slug, event.slug))
|
|
||||||
assert [] == resp.data['results']
|
assert [] == resp.data['results']
|
||||||
|
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?search=FO')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?search=FO'.format(organizer.slug, event.slug))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?search=z3fsn8j')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?search=z3fsn8j'.format(organizer.slug, event.slug))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?search=Peter')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?search=Peter'.format(organizer.slug, event.slug))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?search=5f4h6w')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?search=5f4h6w'.format(organizer.slug, event.slug))
|
|
||||||
assert [] == resp.data['results']
|
assert [] == resp.data['results']
|
||||||
|
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?order=FOO')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?order=FOO'.format(organizer.slug, event.slug))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?order=BAR')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?order=BAR'.format(organizer.slug, event.slug))
|
|
||||||
assert [] == resp.data['results']
|
assert [] == resp.data['results']
|
||||||
|
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?has_checkin=false')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=false'.format(organizer.slug, event.slug))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?has_checkin=true')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug))
|
|
||||||
assert [] == resp.data['results']
|
assert [] == resp.data['results']
|
||||||
|
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
@@ -1103,33 +1170,28 @@ def test_orderposition_list(token_client, organizer, device, event, order, item,
|
|||||||
'gate': None,
|
'gate': None,
|
||||||
'type': 'entry'
|
'type': 'entry'
|
||||||
}]
|
}]
|
||||||
with django_assert_num_queries(16):
|
if '/events/' in endpoint:
|
||||||
resp = token_client.get(
|
with django_assert_num_queries(18):
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?has_checkin=true'.format(organizer.slug, event.slug)
|
resp = token_client.get(endpoint + '?has_checkin=true')
|
||||||
)
|
else:
|
||||||
|
with django_assert_num_queries(17):
|
||||||
|
resp = token_client.get(endpoint + '?has_checkin=true')
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
|
|
||||||
op.subevent = subevent
|
op.subevent = subevent
|
||||||
op.save()
|
op.save()
|
||||||
res['subevent'] = subevent.pk
|
res['subevent'] = subevent.pk
|
||||||
|
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?subevent={}'.format(subevent.pk))
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug, subevent.pk))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?subevent__in={},{}'.format(subevent.pk, subevent2.pk))
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent__in={},{}'.format(organizer.slug, event.slug,
|
|
||||||
subevent.pk, subevent2.pk))
|
|
||||||
assert [res] == resp.data['results']
|
assert [res] == resp.data['results']
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?subevent={}'.format(subevent.pk + 1))
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?subevent={}'.format(organizer.slug, event.slug,
|
|
||||||
subevent.pk + 1))
|
|
||||||
assert [] == resp.data['results']
|
assert [] == resp.data['results']
|
||||||
|
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?include_canceled_positions=false')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?include_canceled_positions=false'.format(organizer.slug, event.slug))
|
|
||||||
assert len(resp.data['results']) == 1
|
assert len(resp.data['results']) == 1
|
||||||
resp = token_client.get(
|
resp = token_client.get(endpoint + '?include_canceled_positions=true')
|
||||||
'/api/v1/organizers/{}/events/{}/orderpositions/?include_canceled_positions=true'.format(organizer.slug, event.slug))
|
|
||||||
assert len(resp.data['results']) == 2
|
assert len(resp.data['results']) == 2
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ from pretix.base.models import (
|
|||||||
Event, Item, ItemVariation, Organizer, Quota, Team, User, Voucher,
|
Event, Item, ItemVariation, Organizer, Quota, Team, User, Voucher,
|
||||||
WaitingListEntry,
|
WaitingListEntry,
|
||||||
)
|
)
|
||||||
|
from pretix.base.models.seating import Seat, SeatingPlan
|
||||||
|
from pretix.base.models.waitinglist import WaitingListException
|
||||||
from pretix.control.views.dashboards import waitinglist_widgets
|
from pretix.control.views.dashboards import waitinglist_widgets
|
||||||
|
|
||||||
|
|
||||||
@@ -55,11 +57,11 @@ def env():
|
|||||||
WaitingListEntry.objects.create(
|
WaitingListEntry.objects.create(
|
||||||
event=event, item=item1, email='success@example.org', voucher=v
|
event=event, item=item1, email='success@example.org', voucher=v
|
||||||
)
|
)
|
||||||
v = Voucher.objects.create(item=item1, event=event, block_quota=True, redeemed=0, valid_until=now() - timedelta(days=5))
|
v = Voucher.objects.create(item=item2, event=event, block_quota=True, redeemed=0, valid_until=now() - timedelta(days=5))
|
||||||
WaitingListEntry.objects.create(
|
WaitingListEntry.objects.create(
|
||||||
event=event, item=item2, email='expired@example.org', voucher=v
|
event=event, item=item2, email='expired@example.org', voucher=v
|
||||||
)
|
)
|
||||||
v = Voucher.objects.create(item=item1, event=event, block_quota=True, redeemed=0, valid_until=now() + timedelta(days=5))
|
v = Voucher.objects.create(item=item2, event=event, block_quota=True, redeemed=0, valid_until=now() + timedelta(days=5))
|
||||||
WaitingListEntry.objects.create(
|
WaitingListEntry.objects.create(
|
||||||
event=event, item=item2, email='valid@example.org', voucher=v
|
event=event, item=item2, email='valid@example.org', voucher=v
|
||||||
)
|
)
|
||||||
@@ -345,5 +347,75 @@ def test_dashboard(client, env):
|
|||||||
quota.items.add(env['item1'])
|
quota.items.add(env['item1'])
|
||||||
w = waitinglist_widgets(env['event'])
|
w = waitinglist_widgets(env['event'])
|
||||||
|
|
||||||
assert '1' in w[0]['content']
|
assert '2' in w[0]['content']
|
||||||
assert '5' in w[1]['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