Compare commits

..

26 Commits

Author SHA1 Message Date
Raphael Michel
fa39cae95f Apply suggestion from @raphaelm 2026-01-16 14:33:27 +01:00
Raphael Michel
fc74978a13 Merge branch 'master' into banktransfer-invoice-reference 2026-01-16 14:32:13 +01:00
Raphael Michel
66255fe282 Update src/pretix/plugins/banktransfer/payment.py
Co-authored-by: Richard Schreiber <schreiber@pretix.eu>
2026-01-16 14:29:56 +01:00
Kian Cross
9cf66de437 Clarify fee inclusion in revenue-over-time graph help text (#5785)
Updates the help text for the revenue-over-time graph to clarify how fees are
treated. When viewing a subevent, revenue excludes all fees (including
cancellation fees). When viewing the full event, revenue includes all fees,
including cancellation fees from cancelled orders.
2026-01-16 14:27:14 +01:00
Kian Cross
9f4cbabd30 Include fee-cancelled positions in placed orders by product graph (#5791)
The 'placed orders by product' graph already includes orders that are pending,
expired, or fully cancelled without a fee. However, items cancelled with a fee
were omitted. This change ensures all placed orders are included in the graph,
including those cancelled with a fee.
2026-01-16 14:24:03 +01:00
Kian Cross
0fc2d6134f Add option to restrict anonymous access to order URLs (#4735)
* Add option to restrict anonymous access to order URLs

By default, users who place orders while logged in can still access
their order URLs without authentication. This raises potential
security risks, particularly if order confirmation emails are
forwarded.

This commit introduces an organiser-level setting to disable anonymous
access for such orders. When enabled, unauthenticated attempts to access
URLs starting with `/order/`, which are intended for the customer, are
redirected to the login page. Upon successful authentication, the user
is redirected back to the original order URL.

It is important to note that this change does not impact routes intended
for attendees (e.g., `/ticket/*`), which remain accessible without
authentication.

* Change name of setting for future clarity

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>

* Update message wording

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>

* Eliminate database query

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>

* Rename feature flag to fix breaking tests

* Refactor order access verification code into `OrderDetailsMixin`

* Add test for logged-in customer accessing another customer's order

* Refactor order access conditions to remove nesting

* Handle case where customer is not yet verified

* Add additional information to help message

* Fix multidomain issue

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>

* Merge order/position variants into single tests

* Add docstring explaining return type of `order` property

* Apply suggestion from @raphaelm

* Fix indentation

---------

Co-authored-by: Raphael Michel <mail@raphaelmichel.de>
Co-authored-by: Raphael Michel <michel@rami.io>
2026-01-16 13:46:08 +01:00
George Hickman
1e0e16642d Add more log entry types to the org-level logs page (#5787)
* Add more log entry types to the org-level logs page

all_logentries() limits the QuerySet to LogEntrys whose content object
is an Organizer.

This change expands that to get any LogEntry linked to the current
Organization.  It removes those that are linked directly to an Event,
since they are already served by the event-level logs page.

* Check active plugins with either Event or Organizer
2026-01-16 13:36:23 +01:00
Richard Schreiber
a58403559e Translations: Update Swedish
Currently translated at 89.9% (5572 of 6193 strings)

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

powered by weblate
2026-01-16 10:24:59 +01:00
Lukas Bockstaller
dfd53f0ea2 Waitinglist: lock entry to mitigate race-conditions when creating the voucher 2026-01-15 16:09:41 +01:00
Linnea Thelander
06250ef55e Translations: Update Swedish
Currently translated at 89.9% (5573 of 6193 strings)

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

powered by weblate
2026-01-15 16:01:46 +01:00
Mario Montes
ab3104fe65 Translations: Update Galician
Currently translated at 15.9% (985 of 6193 strings)

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

powered by weblate
2026-01-15 16:01:46 +01:00
CVZ-es
bb6e424cde Translations: Update Spanish
Currently translated at 100.0% (254 of 254 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/es/

powered by weblate
2026-01-15 16:01:46 +01:00
Mario Montes
c2623dba60 Translations: Update Spanish
Currently translated at 100.0% (6193 of 6193 strings)

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

powered by weblate
2026-01-15 16:01:46 +01:00
CVZ-es
d8f7465b03 Translations: Update Spanish
Currently translated at 100.0% (6193 of 6193 strings)

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

powered by weblate
2026-01-15 16:01:46 +01:00
Mario Montes
ac0546499b Translations: Update Spanish
Currently translated at 98.8% (251 of 254 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/es/

powered by weblate
2026-01-15 16:01:46 +01:00
Mario Montes
ebbb532478 Translations: Update Spanish
Currently translated at 99.9% (6192 of 6193 strings)

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

powered by weblate
2026-01-15 16:01:46 +01:00
Hijiri Umemoto
94dad4d0d2 Translations: Update Chinese (Traditional Han script)
Currently translated at 92.3% (5721 of 6193 strings)

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

powered by weblate
2026-01-15 16:01:46 +01:00
chondaen12
a06cd687ba Translations: Update Thai
Currently translated at 0.6% (41 of 6193 strings)

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

powered by weblate
2026-01-15 16:01:46 +01:00
sandra r
fd9f3ea6ed Translations: Update Galician
Currently translated at 15.8% (984 of 6193 strings)

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

powered by weblate
2026-01-15 16:01:46 +01:00
Hijiri Umemoto
608622e3f3 Translations: Update Japanese
Currently translated at 100.0% (6193 of 6193 strings)

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

powered by weblate
2026-01-15 16:01:46 +01:00
Ruud Hendrickx
4d94294e5a Translations: Update Dutch (informal) (nl_Informal)
Currently translated at 66.3% (4109 of 6193 strings)

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

powered by weblate
2026-01-15 16:01:46 +01:00
dependabot[bot]
4dbdadabb5 Update sphinx-rtd-theme requirement from ~=3.1.0rc2 to ~=3.1.0 (#5804) 2026-01-13 13:23:35 +01:00
Jiří Pastrňák
d494c61cba Translations: Update Czech
Currently translated at 70.0% (4339 of 6193 strings)

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

powered by weblate
2026-01-12 09:44:26 +01:00
Jiří Pastrňák
55a7dfbff3 Translations: Update Czech
Currently translated at 70.0% (4339 of 6193 strings)

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

powered by weblate
2026-01-12 09:44:26 +01:00
Jiří Pastrňák
b8c271cf9c Translations: Update Czech
Currently translated at 70.0% (4338 of 6193 strings)

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

powered by weblate
2026-01-12 09:44:26 +01:00
Raphael Michel
befa9a1d85 Bank transfer: Do not show reference before it is as complete as possible (fixes #5296) 2025-11-14 18:41:03 +01:00
27 changed files with 560 additions and 301 deletions

View File

@@ -1,5 +1,5 @@
sphinx==9.1.*
sphinx-rtd-theme~=3.1.0rc2
sphinx-rtd-theme~=3.1.0
sphinxcontrib-httpdomain~=1.8.1
sphinxcontrib-images~=1.0.1
sphinxcontrib-jquery~=4.1

View File

@@ -1,6 +1,6 @@
-e ../
sphinx==9.1.*
sphinx-rtd-theme~=3.1.0rc2
sphinx-rtd-theme~=3.1.0
sphinxcontrib-httpdomain~=1.8.1
sphinxcontrib-images~=1.0.1
sphinxcontrib-jquery~=4.1

View File

@@ -443,6 +443,7 @@ class OrganizerSettingsSerializer(SettingsSerializer):
'customer_accounts',
'customer_accounts_native',
'customer_accounts_link_by_email',
'customer_accounts_require_login_for_order_access',
'invoice_regenerate_allowed',
'contact_mail',
'imprint_url',

View File

@@ -966,7 +966,6 @@ class CheckinRPCSearchView(ListAPIView):
def get_serializer_context(self):
ctx = super().get_serializer_context()
ctx['expand'] = self.request.query_params.getlist('expand')
ctx['organizer'] = self.request.organizer
ctx['pdf_data'] = False
return ctx

View File

@@ -141,8 +141,9 @@ class LogEntry(models.Model):
log_entry_type, meta = log_entry_types.get(action_type=self.action_type)
if log_entry_type:
sender = self.event if self.event else self.organizer
link_info = log_entry_type.get_object_link_info(self)
if is_app_active(self.event, meta['plugin']):
if is_app_active(sender, meta['plugin']):
return make_link(link_info, log_entry_type.object_link_wrapper)
else:
return make_link(link_info, log_entry_type.object_link_wrapper, is_active=False,

View File

@@ -35,6 +35,7 @@ from pretix.base.email import get_email_context
from pretix.base.i18n import language
from pretix.base.models import User, Voucher
from pretix.base.services.mail import SendMailException, mail, render_mail
from pretix.helpers import OF_SELF
from ...helpers.format import format_map
from ...helpers.names import build_name
@@ -185,44 +186,47 @@ class WaitingListEntry(LoggedModel):
if not free_seats:
raise WaitingListException(_('No seat with this product is currently available.'))
if self.voucher:
raise WaitingListException(_('A voucher has already been sent to this person.'))
if '@' not in self.email:
raise WaitingListException(_('This entry is anonymized and can no longer be used.'))
with transaction.atomic():
e = self.email
if self.name:
e += ' / ' + self.name
locked_wle = WaitingListEntry.objects.select_for_update(of=OF_SELF).get(pk=self.pk)
if locked_wle.voucher:
raise WaitingListException(_('A voucher has already been sent to this person.'))
e = locked_wle.email
if locked_wle.name:
e += ' / ' + locked_wle.name
v = Voucher.objects.create(
event=self.event,
event=locked_wle.event,
max_usages=1,
valid_until=now() + timedelta(hours=self.event.settings.waiting_list_hours),
item=self.item,
variation=self.variation,
valid_until=now() + timedelta(hours=locked_wle.event.settings.waiting_list_hours),
item=locked_wle.item,
variation=locked_wle.variation,
tag='waiting-list',
comment=_('Automatically created from waiting list entry for {email}').format(
email=e
),
block_quota=True,
subevent=self.subevent,
subevent=locked_wle.subevent,
)
v.log_action('pretix.voucher.added', {
'item': self.item.pk,
'variation': self.variation.pk if self.variation else None,
'item': locked_wle.item.pk,
'variation': locked_wle.variation.pk if locked_wle.variation else None,
'tag': 'waiting-list',
'block_quota': True,
'valid_until': v.valid_until.isoformat(),
'max_usages': 1,
'subevent': self.subevent.pk if self.subevent else None,
'subevent': locked_wle.subevent.pk if locked_wle.subevent else None,
'source': 'waitinglist',
}, user=user, auth=auth)
v.log_action('pretix.voucher.added.waitinglist', {
'email': self.email,
'waitinglistentry': self.pk,
'email': locked_wle.email,
'waitinglistentry': locked_wle.pk,
}, user=user, auth=auth)
self.voucher = v
self.save()
locked_wle.voucher = v
locked_wle.save()
self.refresh_from_db()
with language(self.locale, self.event.settings.region):
self.send_mail(

View File

@@ -180,6 +180,19 @@ DEFAULTS = {
widget=forms.CheckboxInput(attrs={'data-display-dependency': '#id_settings-customer_accounts'}),
)
},
'customer_accounts_require_login_for_order_access': {
'default': 'False',
'type': bool,
'form_class': forms.BooleanField,
'serializer_class': serializers.BooleanField,
'form_kwargs': dict(
label=_("Require login to access order confirmation pages"),
help_text=_("If enabled, users who were logged in at the time of purchase must also log in to access their order information. "
"If a customer account is created while placing an order, the restriction only becomes active after the customer "
"account is activated."),
widget=forms.CheckboxInput(attrs={'data-display-dependency': '#id_settings-customer_accounts'}),
)
},
'customer_accounts_link_by_email': {
'default': 'False',
'type': bool,

View File

@@ -474,6 +474,7 @@ class OrganizerSettingsForm(SettingsForm):
'customer_accounts',
'customer_accounts_native',
'customer_accounts_link_by_email',
'customer_accounts_require_login_for_order_access',
'invoice_regenerate_allowed',
'contact_mail',
'imprint_url',

View File

@@ -132,6 +132,7 @@
<legend>{% trans "Customer accounts" %}</legend>
{% bootstrap_field sform.customer_accounts layout="control" %}
{% bootstrap_field sform.customer_accounts_native layout="control" %}
{% bootstrap_field sform.customer_accounts_require_login_for_order_access layout="control" %}
{% bootstrap_field sform.customer_accounts_link_by_email layout="control" %}
{% bootstrap_field sform.name_scheme layout="control" %}
{% bootstrap_field sform.name_scheme_titles layout="control" %}

View File

@@ -2583,7 +2583,7 @@ class LogView(OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
def get_queryset(self):
# technically, we'd also need to sort by pk since this is a paginated list, but in this case we just can't
# bear the performance cost
qs = self.request.organizer.all_logentries().select_related(
qs = self.request.organizer.logentry_set.filter(event=None).select_related(
'user', 'content_type', 'api_token', 'oauth_application', 'device'
).order_by('-datetime')
qs = qs.exclude(action_type__in=OVERVIEW_BANLIST)

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
"PO-Revision-Date: 2026-01-08 04:00+0000\n"
"PO-Revision-Date: 2026-01-11 22:00+0000\n"
"Last-Translator: Jiří Pastrňák <jiri@pastrnak.email>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix/cs/>"
"\n"
@@ -6672,7 +6672,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/organizers/index.html:6
#: pretix/control/templates/pretixcontrol/organizers/index.html:8
msgid "Organizers"
msgstr "Organizátor"
msgstr "Pořadatelé"
#: pretix/base/models/organizer.py:350
#: pretix/control/templates/pretixcontrol/organizers/teams.html:35
@@ -8070,14 +8070,12 @@ msgid "Printing time"
msgstr "Datum tisku"
#: pretix/base/pdf.py:422 pretix/control/forms/item.py:741
#, fuzzy
msgid "Purchase date"
msgstr "Zakoupeno"
msgstr "Zakoupeno dne"
#: pretix/base/pdf.py:430
#, fuzzy
msgid "Purchase date and time"
msgstr "Zakoupeno"
msgstr "Zakoupeno dne a v čase"
#: pretix/base/pdf.py:438
#, fuzzy
@@ -8136,7 +8134,7 @@ msgstr "Přízemí, řada 3, místo 4"
#: pretix/base/pdf.py:508 pretix/base/pdf.py:514
#: pretix/control/forms/orders.py:344
msgid "General admission"
msgstr "včetně všech daní"
msgstr "Základní vstupné"
#: pretix/base/pdf.py:511
msgid "Seat: zone"
@@ -18750,7 +18748,7 @@ msgstr "ID transakce"
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/control.html:32
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_assign.html:33
msgid "Reference"
msgstr "Důvod převodu"
msgstr "Zpráva pro příjemce"
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:100
msgid "Terminal ID"
@@ -23235,7 +23233,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/order/index.html:465
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:55
msgid "Voucher code used:"
msgstr ""
msgstr "Použitý poukaz:"
#: pretix/control/templates/pretixcontrol/order/index.html:467
#, python-format
@@ -34430,19 +34428,14 @@ msgid "Please note that we still await your payment to complete the process."
msgstr "Upozorňujeme, že k dokončení procesu stále čekáme na vaši platbu."
#: pretix/presale/templates/pretixpresale/event/order.html:56
#, fuzzy
#| msgid ""
#| "Please bookmark or save the link to this exact page if you want to access "
#| "your order later. We also sent you an email containing the link to the "
#| "address you specified."
msgid ""
"Please bookmark or save the link to this exact page if you want to access "
"your order later. We also sent you an email to the address you specified "
"containing the link to this page."
msgstr ""
"Pokud chcete mít přístup ke své objednávce později, přidejte si prosím odkaz "
"na tuto stránku do záložek nebo si jej uložte. Na vi zadanou adresu jsme "
"vám také zaslali e-mail s odkazem."
"Pokud chcete mít k objednávce přístup i později, přidejte si prosím tuto "
"stránku do záložek. Na vámi zadanou adresu jsme vám také zaslali e-mail s "
"odkazem na tuto stránku."
#: pretix/presale/templates/pretixpresale/event/order.html:60
msgid ""
@@ -34565,10 +34558,9 @@ msgid "Change your order"
msgstr "Změnit objednávku"
#: pretix/presale/templates/pretixpresale/event/order.html:358
#, fuzzy
msgctxt "action"
msgid "Cancel your order"
msgstr "Zrušit objednávku"
msgstr "Zrušení objednávky"
#: pretix/presale/templates/pretixpresale/event/order.html:366
msgid ""
@@ -34775,7 +34767,7 @@ msgid ""
"Modifying your invoice address will not automatically generate a new "
"invoice. Please contact us if you need a new invoice."
msgstr ""
"Úpravou adresy faktury se automaticky nevytvoří nová faktura. Pokud "
"Úpravou fakturačních údajů se automaticky nevytvoří nová faktura. Pokud "
"potřebujete novou fakturu, kontaktujte nás."
#: pretix/presale/templates/pretixpresale/event/order_modify.html:88
@@ -34823,7 +34815,7 @@ msgstr ""
#: pretix/presale/templates/pretixpresale/event/payment_qr_codes.html:36
msgid "Scan the QR code with your banking app"
msgstr ""
msgstr "Naskenujte QR kód svou bankovní aplikací"
#: pretix/presale/templates/pretixpresale/event/position.html:7
msgid "Registration details"

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
"PO-Revision-Date: 2026-01-06 23:00+0000\n"
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
"PO-Revision-Date: 2026-01-14 00:00+0000\n"
"Last-Translator: Mario Montes <mario@t3chfest.es>\n"
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix/"
"es/>\n"
"Language: es\n"
@@ -35588,7 +35588,8 @@ msgstr "El período de preventa para este evento ha terminado."
#: pretix/presale/views/widget.py:807
#, python-format
msgid "The booking period for this event will start on %(date)s at %(time)s."
msgstr "La preventa para este evento comenzará en %(date)s a %(time)s."
msgstr ""
"El periodo de reserva para este evento comenzará el %(date)s a las %(time)s."
#: pretix/presale/templates/pretixpresale/event/index.html:185
#: pretix/presale/templates/pretixpresale/event/seatingplan.html:23
@@ -36851,11 +36852,11 @@ msgstr ""
#: pretix/presale/views/cart.py:520
msgid "Your cart has been updated."
msgstr "Su carrito ha sido actualizada."
msgstr "Su carrito ha sido actualizado."
#: pretix/presale/views/cart.py:523 pretix/presale/views/cart.py:549
msgid "Your cart is now empty."
msgstr "Su carrito ha sido vaciada."
msgstr "Su carrito está vacio."
#: pretix/presale/views/cart.py:570
msgid ""

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-05 12:13+0000\n"
"PO-Revision-Date: 2025-10-22 16:00+0000\n"
"PO-Revision-Date: 2026-01-14 00:00+0000\n"
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-"
"js/es/>\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.13.3\n"
"X-Generator: Weblate 5.15.1\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
@@ -738,11 +738,8 @@ msgstr "Su carrito está a punto de caducar."
#: pretix/static/pretixpresale/js/ui/cart.js:62
msgid "The items in your cart are reserved for you for one minute."
msgid_plural "The items in your cart are reserved for you for {num} minutes."
msgstr[0] ""
"Los elementos en su carrito de compras se han reservado durante un minuto."
msgstr[1] ""
"Los elementos en su carrito de compras se han reservado durante {num} "
"minutos."
msgstr[0] "Los artículos de la cesta están reservados durante un minuto."
msgstr[1] "Los artículos de la cesta están reservados durante {num} minutos."
#: pretix/static/pretixpresale/js/ui/cart.js:83
msgid "Your cart has expired."
@@ -766,11 +763,11 @@ msgstr "Renovar reserva"
#: pretix/static/pretixpresale/js/ui/main.js:194
msgid "The organizer keeps %(currency)s %(amount)s"
msgstr "El organizador se queda %(currency)s %(price)s"
msgstr "El organizador retiene %(currency)s %(amount)s"
#: pretix/static/pretixpresale/js/ui/main.js:202
msgid "You get %(currency)s %(amount)s back"
msgstr "Obtienes %(currency)s %(price)s de vuelta"
msgstr "Se le devolverá %(moneda)s %(cantidad)s"
#: pretix/static/pretixpresale/js/ui/main.js:218
msgid "Please enter the amount the organizer can keep."

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
"PO-Revision-Date: 2025-12-15 20:00+0000\n"
"Last-Translator: sandra r <sandrarial@gestiontickets.online>\n"
"PO-Revision-Date: 2026-01-14 00:00+0000\n"
"Last-Translator: Mario Montes <mario@t3chfest.es>\n"
"Language-Team: Galician <https://translate.pretix.eu/projects/pretix/pretix/"
"gl/>\n"
"Language: gl\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.14.3\n"
"X-Generator: Weblate 5.15.1\n"
#: pretix/_base_settings.py:87
msgid "English"
@@ -1149,7 +1149,7 @@ msgstr "Pregunta: {name}"
#: pretix/base/settings.py:3775 pretix/base/settings.py:3828
#: pretix/base/settings.py:3849 pretix/base/settings.py:3871
msgid "Given name"
msgstr "Nombre"
msgstr "Nome"
#: pretix/base/datasync/sourcefields.py:628
#: pretix/base/datasync/sourcefields.py:638 pretix/base/settings.py:3670
@@ -18192,9 +18192,9 @@ msgstr ""
"\"{new_email}\"."
#: pretix/control/logdisplay.py:673
#, fuzzy, python-brace-format
#, python-brace-format
msgid "Your email address {email} has been confirmed."
msgstr "Su carrito ha sido actualizado."
msgstr "Tu email {email} ha sido confirmado."
#: pretix/control/logdisplay.py:685
#, fuzzy, python-brace-format
@@ -24293,7 +24293,7 @@ msgstr "Sí, aprobar la orden"
#: pretix/presale/templates/pretixpresale/event/order.html:483
#: pretix/presale/templates/pretixpresale/event/order_cancel.html:7
msgid "Cancel order"
msgstr "Cancelar a orde"
msgstr "Cancelar o pedido"
#: pretix/control/templates/pretixcontrol/order/cancel.html:12
#: pretix/control/templates/pretixcontrol/order/deny.html:11
@@ -35952,10 +35952,9 @@ msgstr ""
#: pretix/presale/forms/renderers.py:66
#: pretix/presale/templates/pretixpresale/event/fragment_voucher_form.html:14
#, fuzzy
msgctxt "form"
msgid "required"
msgstr "expirado"
msgstr "obrigatorio"
#: pretix/presale/ical.py:87 pretix/presale/ical.py:146
#: pretix/presale/ical.py:182
@@ -37539,14 +37538,13 @@ msgid "A payment of %(total)s is still pending for this order."
msgstr "Un pago de %(total)s aínda está pendente para esta orde."
#: pretix/presale/templates/pretixpresale/event/order.html:97
#, fuzzy, python-format
#, python-format
msgid "Please complete your payment before %(date)s"
msgstr "Por favor complete su pago antes de %(date)s"
msgstr "Por favor complete o seu pago antes de %(date)s"
#: pretix/presale/templates/pretixpresale/event/order.html:108
#, fuzzy
msgid "Re-try payment or choose another payment method"
msgstr "Vuelva a intentar el pago o elija otro método de pago"
msgstr "Volva tentar o pago ou escolla outro método de pago"
#: pretix/presale/templates/pretixpresale/event/order.html:126
#, fuzzy

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
"PO-Revision-Date: 2026-01-05 10:00+0000\n"
"Last-Translator: Yasunobu YesNo Kawaguchi <kawaguti@gmail.com>\n"
"PO-Revision-Date: 2026-01-12 17:00+0000\n"
"Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n"
"Language-Team: Japanese <https://translate.pretix.eu/projects/pretix/pretix/"
"ja/>\n"
"Language: ja\n"
@@ -3831,7 +3831,7 @@ msgstr ""
#: pretix/base/invoicing/peppol.py:164
msgid "The Peppol participant ID is not registered on the Peppol network."
msgstr ""
msgstr "Peppol参加者IDはPeppolネットワークに登録されていません。"
#: pretix/base/invoicing/peppol.py:184
msgid "Peppol participant ID"
@@ -8281,7 +8281,7 @@ msgstr "販売されていない製品が選択されています。"
msgid ""
"Some products can no longer be purchased and have been removed from your "
"cart for the following reason: %s"
msgstr ""
msgstr "一部の製品は購入できなくなり、次の理由でカートから削除されました:%s"
#: pretix/base/services/cart.py:117
msgid ""
@@ -9400,20 +9400,14 @@ msgid "Uncategorized"
msgstr "未分類"
#: pretix/base/services/tax.py:43
#, fuzzy
#| msgid ""
#| "Your VAT ID could not be checked, as the VAT checking service of your "
#| "country is currently not available. We will therefore need to charge VAT "
#| "on your invoice. You can get the tax amount back via the VAT "
#| "reimbursement process."
msgid ""
"Your VAT ID could not be checked, as the VAT checking service of your "
"country is currently not available. We will therefore need to charge you the "
"same tax rate as if you did not enter a VAT ID."
msgstr ""
"お客様のVAT IDは確認できませんでした。お客様の国のVAT確認サービスが現在利用で"
"きないため、請求書にVATを請求する必要があります。VAT払い戻し手続きを通じて税"
"金を返金することができます。"
"あなたの国のVATチェックサービスが現在利用できないため、VAT IDを確認できません"
"でした。したがって、VAT IDを入力しなかった場合と同じ税率を請求する必要があり"
"ます。"
#: pretix/base/services/tax.py:47 pretix/base/services/tax.py:366
#: pretix/base/services/tax.py:393
@@ -9828,23 +9822,17 @@ msgid "Ask for VAT ID"
msgstr "VAT IDを尋ねる"
#: pretix/base/settings.py:632
#, fuzzy, python-brace-format
#| msgid ""
#| "Only works if an invoice address is asked for. VAT ID is never required "
#| "and only requested from business customers in the following countries: "
#| "{countries}"
#, python-brace-format
msgid ""
"Only works if an invoice address is asked for. VAT ID is only requested from "
"business customers in the following countries: {countries}."
msgstr ""
"請求の住所が要求された場合のみ機能します。消費税登録番号やVAT IDは必要な"
"く、以下の国の法人顧客からのみ要求されます:{countries}"
"請求の住所が要求された場合のみ有効です。VAT ID は、{countries} の国の法人の"
"お客様にのみ要求されます。"
#: pretix/base/settings.py:651
#, fuzzy
#| msgid "Require name"
msgid "Require VAT ID in"
msgstr "名前を要求"
msgstr "VAT IDを要求"
#: pretix/base/settings.py:657
msgid ""
@@ -9852,6 +9840,9 @@ msgid ""
"ID in all countries. VAT ID will be required for all business addresses in "
"the selected countries."
msgstr ""
"VAT ID はデフォルトでオプションです。これは、すべての企業に VAT ID が割り当て"
"られているわけではないためです。選択した国のすべてのビジネスアドレスには、"
"VAT IDが必要です。"
#: pretix/base/settings.py:672
msgid "Invoice address explanation"
@@ -13442,11 +13433,9 @@ msgstr ""
"リクエストのために再度有効にしてください。"
#: pretix/base/views/js_helpers.py:41
#, fuzzy
#| msgid "ID"
msgctxt "tax_id_swiss"
msgid "UID"
msgstr "ID"
msgstr "UID"
#. Translators: Only translate to French (IDE) and Italien (IDI), otherwise keep the same
#. Awareness around VAT IDs differes by EU country. For example, in Germany the VAT ID is assigned
@@ -13456,35 +13445,27 @@ msgstr "ID"
#. number (Partita IVA) and also used on domestic transactions. So someone who never purchased something international
#. for their company, might still know the value, if we call it the right way and not just "VAT ID".
#: pretix/base/views/js_helpers.py:49
#, fuzzy
#| msgid "VAT ID"
msgctxt "tax_id_italy"
msgid "VAT ID / P.IVA"
msgstr "消費税登録番号又はVAT ID"
msgstr "VAT ID / P.IVA"
#. Translators: Translate to only "P.IVA" in Italian, keep second part as-is in other languages
#: pretix/base/views/js_helpers.py:50
#, fuzzy
#| msgid "VAT ID"
msgctxt "tax_id_greece"
msgid "VAT ID / TIN"
msgstr "消費税登録番号又はVAT ID"
msgstr "VAT ID / TIN"
#. Translators: Translate to only "ΑΦΜ" in Greek
#: pretix/base/views/js_helpers.py:51
#, fuzzy
#| msgid "VAT ID"
msgctxt "tax_id_spain"
msgid "VAT ID / NIF"
msgstr "消費税登録番号又はVAT ID"
msgstr "VAT ID / NIF"
#. Translators: Translate to only "NIF" in Spanish
#: pretix/base/views/js_helpers.py:52
#, fuzzy
#| msgid "VAT ID"
msgctxt "tax_id_portugal"
msgid "VAT ID / NIF"
msgstr "消費税登録番号又はVAT ID"
msgstr "VAT ID / NIF"
#: pretix/base/views/tasks.py:185
msgid "An unexpected error has occurred, please try again later."
@@ -14021,6 +14002,8 @@ msgid ""
"Formatting is not supported, as some accounting departments process mail "
"automatically and do not handle formatted emails properly."
msgstr ""
"一部の経理部門はメールを自動的に処理し、フォーマットされたメールを適切に処理"
"しないため、フォーマットはサポートされていません。"
#: pretix/control/forms/event.py:1356
msgid ""
@@ -14469,7 +14452,7 @@ msgstr "支払い済み"
#: pretix/control/forms/filter.py:1304
msgctxt "subevent"
msgid "Date doesn't start in selected date range."
msgstr ""
msgstr "日付は選択した日付範囲で開始されません。"
#: pretix/control/forms/filter.py:1360 pretix/control/forms/filter.py:1827
msgid "Shop live and presale running"
@@ -28007,6 +27990,9 @@ msgid ""
"automatically. We recommend that you rename these in your source file to "
"avoid problems during import."
msgstr ""
"CSVファイルの複数の列は同じ名前で、自動的に名前が変更されました。インポート中"
"に問題が発生しないように、ソースファイルでこれらの名前を変更することをお勧め"
"します。"
#: pretix/control/views/modelimport.py:188
msgid "The import was successful."
@@ -29637,7 +29623,7 @@ msgstr ""
#: pretix/plugins/banktransfer/camtimport.py:33
msgid "Empty file or unknown format."
msgstr ""
msgstr "空のファイルまたは不明な形式。"
#: pretix/plugins/banktransfer/payment.py:69
msgid ""
@@ -32132,16 +32118,16 @@ msgid "Przelewy24"
msgstr "Przelewy24"
#: pretix/plugins/stripe/payment.py:417 pretix/plugins/stripe/payment.py:1836
#, fuzzy
#| msgid "Payment by bank transfer"
msgid "Pay by bank"
msgstr "銀行振込による支払い"
msgstr "Pay by bank"
#: pretix/plugins/stripe/payment.py:422
msgid ""
"Currently only available for charges in GBP and customers with UK bank "
"accounts, and in private preview for France and Germany."
msgstr ""
"現在、英国ポンドでの請求と英国の銀行口座を持つ顧客、およびフランスとドイツの"
"プライベートプレビューでのみ利用できます。"
#: pretix/plugins/stripe/payment.py:429 pretix/plugins/stripe/payment.py:1789
msgid "WeChat Pay"
@@ -32446,16 +32432,16 @@ msgstr ""
"いておいてください。"
#: pretix/plugins/stripe/payment.py:1835
#, fuzzy
#| msgid "PayPal via Stripe"
msgid "Pay by bank via Stripe"
msgstr "Stripe経由でPayPal"
msgstr "Stripe経由でPay by bank"
#: pretix/plugins/stripe/payment.py:1841
msgid ""
"Pay by bank allows you to authorize a secure Open Banking payment from your "
"banking app. Currently available only with a UK bank account."
msgstr ""
"Pay by bankを使用すると、銀行アプリから安全なオープンバンキングの支払いを承認"
"できます。現在、英国の銀行口座でのみ利用できます。"
#: pretix/plugins/stripe/payment.py:1861
msgid "PayPal via Stripe"
@@ -32474,22 +32460,16 @@ msgstr ""
"能です。アプリを準備してください。"
#: pretix/plugins/stripe/payment.py:1893
#, fuzzy
#| msgid "giropay via Stripe"
msgid "PromptPay via Stripe"
msgstr "Stripe経由でgiropay"
msgstr "Stripe経由でPromptPay"
#: pretix/plugins/stripe/payment.py:1898
#, fuzzy
#| msgid ""
#| "This payment method is available to MobilePay app users in Denmark and "
#| "Finland. Please have your app ready."
msgid ""
"This payment method is available to PromptPay users in Thailand. Please have "
"your app ready."
msgstr ""
"この支払い方法は、デンマークとフィンランドのMobilePayアプリユーザー利用可能"
"です。アプリを準備してください。"
"この支払い方法は、タイのPromptPayユーザー利用できます。アプリを準備してくだ"
"さい。"
#: pretix/plugins/stripe/payment.py:1917
msgid "TWINT via Stripe"
@@ -32792,22 +32772,16 @@ msgid "Confirm payment: %(code)s"
msgstr "支払いを確認: %(code)s"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca.html:32
#, fuzzy
#| msgid ""
#| "Please scan the barcode below to complete your WeChat payment. Once you "
#| "have completed your payment, you can refresh this page."
msgid ""
"Please scan the QR code below to complete your PromptPay payment. Once you "
"have completed your payment, you can refresh this page."
msgstr ""
"下記のバーコードをスキャンしてWeChat支払いを完了してください。支払いが完了し"
"たら、このページを更新してください。"
"PromptPayの支払いを完了するには、以下のQRコードをスキャンしてください。支払い"
"が完了したら、このページを更新できます。"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca.html:37
#, fuzzy
#| msgid "Create QR code"
msgid "PromptPay QR code"
msgstr "注文番号"
msgstr "PromptPay QRコード"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca_return.html:20
msgid "Confirming your payment…"
@@ -33825,10 +33799,7 @@ msgstr[0] ""
"このカテゴリから%(min_count)s個のオプションを選択する必要があります。"
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:26
#, fuzzy, python-format
#| msgid "You can choose %(max_count)s option from this category."
#| msgid_plural ""
#| "You can choose up to %(max_count)s options from this category."
#, python-format
msgid "You can choose one option from this category."
msgid_plural "You can choose up to %(max_count)s options from this category."
msgstr[0] "このカテゴリから最大 %(max_count)s のオプションを選択できます。"
@@ -35874,6 +35845,8 @@ msgid ""
"Your cart timeout was extended. Please note that some of the prices in your "
"cart changed."
msgstr ""
"カートのタイムアウトが延長されました。カートの価格の一部が変更されましたので"
"ご注意ください。"
#: pretix/presale/views/cart.py:573
msgid "Your cart timeout was extended."

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
"PO-Revision-Date: 2025-12-22 20:00+0000\n"
"PO-Revision-Date: 2026-01-12 17:00+0000\n"
"Last-Translator: Ruud Hendrickx <ruud@leckxicon.eu>\n"
"Language-Team: Dutch (informal) <https://translate.pretix.eu/projects/pretix/"
"pretix/nl_Informal/>\n"
@@ -4008,18 +4008,16 @@ msgstr ""
#: pretix/base/invoicing/peppol.py:164
msgid "The Peppol participant ID is not registered on the Peppol network."
msgstr ""
msgstr "De Peppol-deelnemers-ID is niet geregistreerd op het Peppol-netwerk."
#: pretix/base/invoicing/peppol.py:184
msgid "Peppol participant ID"
msgstr "Peppol-deelnemers-ID"
#: pretix/base/invoicing/peppol.py:200
#, fuzzy
#| msgid "Gift card code"
msgctxt "peppol_invoice"
msgid "Visual copy"
msgstr "Cadeauboncode"
msgstr "Visuele kopie"
#: pretix/base/invoicing/peppol.py:205
msgctxt "peppol_invoice"
@@ -8769,6 +8767,8 @@ msgid ""
"Some products can no longer be purchased and have been removed from your "
"cart for the following reason: %s"
msgstr ""
"Sommige producten kunnen niet meer gekocht worden en zijn om de volgende "
"reden uit je winkelwagen verwijderd: %s"
#: pretix/base/services/cart.py:117
msgid ""
@@ -10037,21 +10037,15 @@ msgid "Uncategorized"
msgstr "Ongecategoriseerd"
#: pretix/base/services/tax.py:43
#, fuzzy
#| msgid ""
#| "Your VAT ID could not be checked, as the VAT checking service of your "
#| "country is currently not available. We will therefore need to charge VAT "
#| "on your invoice. You can get the tax amount back via the VAT "
#| "reimbursement process."
msgid ""
"Your VAT ID could not be checked, as the VAT checking service of your "
"country is currently not available. We will therefore need to charge you the "
"same tax rate as if you did not enter a VAT ID."
msgstr ""
"Je btw-nummer kan niet worden gecontroleerd omdat de btw-controledienst van "
"jouw land momenteel niet beschikbaar is. We zijn daarom genoodzaakt om de "
"btw te factureren. Je kan het belastingbedrag terugkrijgen via het btw-"
"terugbetalingsproces."
"Je btw-nummer kon niet worden gecontroleerd, omdat de btw-controleservice "
"van je land momenteel niet beschikbaar is. We zullen daarom hetzelfde "
"belastingtarief in rekening moeten brengen als wanneer je geen btw-nummer "
"had opgegeven."
#: pretix/base/services/tax.py:47 pretix/base/services/tax.py:366
#: pretix/base/services/tax.py:393
@@ -10506,21 +10500,17 @@ msgid "Ask for VAT ID"
msgstr "Vraag om btw-nummer"
#: pretix/base/settings.py:632
#, fuzzy, python-brace-format
#| msgid ""
#| "Does only work if an invoice address is asked for. VAT ID is not required."
#, python-brace-format
msgid ""
"Only works if an invoice address is asked for. VAT ID is only requested from "
"business customers in the following countries: {countries}."
msgstr ""
"Werkt alleen als een factuuradres wordt gevraagd. Btw-nummer is niet "
"verplicht."
"Werkt alleen als een factuuradres wordt gevraagd. Btw-nummer is alleen "
"vereist voor zakelijke klanten in de volgende landen: {countries}."
#: pretix/base/settings.py:651
#, fuzzy
#| msgid "Require name"
msgid "Require VAT ID in"
msgstr "Naam opgeven verplicht"
msgstr "Btw-nummer verplicht in"
#: pretix/base/settings.py:657
msgid ""
@@ -10528,6 +10518,9 @@ msgid ""
"ID in all countries. VAT ID will be required for all business addresses in "
"the selected countries."
msgstr ""
"Het btw-nummer is standaard optioneel, omdat niet alle bedrijven in alle "
"landen een btw-nummer toegewezen krijgen. Het btw-nummer is vereist voor "
"alle bedrijfsadressen in de geselecteerde landen."
#: pretix/base/settings.py:672
msgid "Invoice address explanation"
@@ -14364,11 +14357,9 @@ msgstr ""
"weer aan, ten minste voor deze site, of voor 'same-origin'-verzoeken."
#: pretix/base/views/js_helpers.py:41
#, fuzzy
#| msgid "ID"
msgctxt "tax_id_swiss"
msgid "UID"
msgstr "ID"
msgstr "UID"
#. Translators: Only translate to French (IDE) and Italien (IDI), otherwise keep the same
#. Awareness around VAT IDs differes by EU country. For example, in Germany the VAT ID is assigned
@@ -14974,6 +14965,8 @@ msgid ""
"Formatting is not supported, as some accounting departments process mail "
"automatically and do not handle formatted emails properly."
msgstr ""
"Opmaak wordt niet ondersteund, omdat sommige boekhoudafdelingen e-mails "
"automatisch verwerken en opgemaakte e-mails niet goed kunnen verwerken."
#: pretix/control/forms/event.py:1356
msgid ""
@@ -14981,7 +14974,7 @@ msgid ""
"the field is empty, the mail will never be sent."
msgstr ""
"Deze e-mail zal dit aantal dagen voor het evenement start worden verstuurd. "
"Als dit veld leeg is zal de mail nooit worden verstuurd."
"Als dit veld leeg is, zal de mail nooit worden verstuurd."
#: pretix/control/forms/event.py:1360
#, fuzzy
@@ -15472,7 +15465,7 @@ msgstr "Betaald"
#: pretix/control/forms/filter.py:1304
msgctxt "subevent"
msgid "Date doesn't start in selected date range."
msgstr ""
msgstr "De datum valt niet binnen de geselecteerde datumrange."
#: pretix/control/forms/filter.py:1360 pretix/control/forms/filter.py:1827
msgid "Shop live and presale running"
@@ -29848,6 +29841,9 @@ msgid ""
"automatically. We recommend that you rename these in your source file to "
"avoid problems during import."
msgstr ""
"Meerdere kolommen van het CSV-bestand hebben dezelfde naam en zijn "
"automatisch hernoemd. We raden aan deze in je bronbestand te hernoemen om "
"problemen tijdens het importeren te voorkomen."
#: pretix/control/views/modelimport.py:188
msgid "The import was successful."
@@ -31611,7 +31607,7 @@ msgstr ""
#: pretix/plugins/banktransfer/camtimport.py:33
msgid "Empty file or unknown format."
msgstr ""
msgstr "Leeg bestand of onbekend format."
#: pretix/plugins/banktransfer/payment.py:69
msgid ""
@@ -34206,6 +34202,9 @@ msgid ""
"generate you API keys with the recommended permission level for optimal "
"usage with pretix."
msgstr ""
"Met de bovenstaande knop installeer je onze Stripe-app op je account en "
"genereer je API-sleutels met het aanbevolen machtigingsniveau voor optimaal "
"gebruik met pretix."
#: pretix/plugins/stripe/payment.py:291
msgid "Secret key"
@@ -34266,6 +34265,8 @@ msgid ""
"Some payment methods might need to be enabled in the settings of your Stripe "
"account before they work properly."
msgstr ""
"Sommige betaalmethoden moeten mogelijk eerst worden ingeschakeld in de "
"instellingen van je Stripe-account voordat ze correct werken."
#: pretix/plugins/stripe/payment.py:350 pretix/plugins/stripe/payment.py:1572
msgid "Alipay"
@@ -34326,16 +34327,16 @@ msgid "Przelewy24"
msgstr "Przelewy24"
#: pretix/plugins/stripe/payment.py:417 pretix/plugins/stripe/payment.py:1836
#, fuzzy
#| msgid "Payment by bank transfer"
msgid "Pay by bank"
msgstr "Betaling via bankoverschrijving"
msgstr "Betaling via bank"
#: pretix/plugins/stripe/payment.py:422
msgid ""
"Currently only available for charges in GBP and customers with UK bank "
"accounts, and in private preview for France and Germany."
msgstr ""
"Momenteel alleen beschikbaar voor betalingen in GBP en klanten met een "
"Britse bankrekening, en in privé-preview voor Frankrijk en Duitsland."
#: pretix/plugins/stripe/payment.py:429 pretix/plugins/stripe/payment.py:1789
msgid "WeChat Pay"
@@ -34630,10 +34631,8 @@ msgid ""
msgstr ""
#: pretix/plugins/stripe/payment.py:1816
#, fuzzy
#| msgid "WeChat Pay via Stripe"
msgid "Revolut Pay via Stripe"
msgstr "WeChat Pay via Stripe"
msgstr "Revolut Pay via Stripe"
#: pretix/plugins/stripe/payment.py:1817
msgid "Revolut Pay"
@@ -34646,28 +34645,24 @@ msgid ""
msgstr ""
#: pretix/plugins/stripe/payment.py:1835
#, fuzzy
#| msgid "Payment via Stripe"
msgid "Pay by bank via Stripe"
msgstr "Betaling via Stripe"
msgstr "Betaling door bank via Stripe"
#: pretix/plugins/stripe/payment.py:1841
msgid ""
"Pay by bank allows you to authorize a secure Open Banking payment from your "
"banking app. Currently available only with a UK bank account."
msgstr ""
"Met Betalen door bank kun je een veilige Open Banking-betaling autoriseren "
"vanuit je bankapp. Momenteel alleen beschikbaar met een Britse bankrekening."
#: pretix/plugins/stripe/payment.py:1861
#, fuzzy
#| msgid "Payment via Stripe"
msgid "PayPal via Stripe"
msgstr "Betaling via Stripe"
msgstr "PayPal via Stripe"
#: pretix/plugins/stripe/payment.py:1869
#, fuzzy
#| msgid "EPS via Stripe"
msgid "Swish via Stripe"
msgstr "EPS via Stripe"
msgstr "Swish via Stripe"
#: pretix/plugins/stripe/payment.py:1874
msgid ""
@@ -34676,22 +34671,20 @@ msgid ""
msgstr ""
#: pretix/plugins/stripe/payment.py:1893
#, fuzzy
#| msgid "giropay via Stripe"
msgid "PromptPay via Stripe"
msgstr "giropay via Stripe"
msgstr "PromptPay via Stripe"
#: pretix/plugins/stripe/payment.py:1898
msgid ""
"This payment method is available to PromptPay users in Thailand. Please have "
"your app ready."
msgstr ""
"Deze betaalmethode is beschikbaar voor PromptPay-gebruikers in Thailand. "
"Zorg ervoor dat je de app bij de hand hebt."
#: pretix/plugins/stripe/payment.py:1917
#, fuzzy
#| msgid "EPS via Stripe"
msgid "TWINT via Stripe"
msgstr "EPS via Stripe"
msgstr "TWINT via Stripe"
#: pretix/plugins/stripe/payment.py:1922
msgid ""
@@ -35010,22 +35003,16 @@ msgid "Confirm payment: %(code)s"
msgstr "Betaling bevestigen: %(code)s"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca.html:32
#, fuzzy
#| msgid ""
#| "Please scan the barcode below to complete your WeChat payment. Once you "
#| "have completed your payment, you can refresh this page."
msgid ""
"Please scan the QR code below to complete your PromptPay payment. Once you "
"have completed your payment, you can refresh this page."
msgstr ""
"Scan de QR-code hieronder om je WeChat-betaling uit te voeren. Als je de "
"betaling hebt afgerond kan je deze pagina verversen."
"Scan de QR-code hieronder om je PromptPay-betaling uit te voeren. Als je de "
"betaling hebt afgerond, kan je deze pagina verversen."
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca.html:37
#, fuzzy
#| msgid "Order code"
msgid "PromptPay QR code"
msgstr "Bestelcode"
msgstr "PromptPay-QR-code"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca_return.html:20
msgid "Confirming your payment…"
@@ -36172,10 +36159,7 @@ msgstr[0] "Je moet precies één optie kiezen uit deze categorie."
msgstr[1] "Je moet %(min_count)s opties kiezen uit deze categorie."
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:26
#, fuzzy, python-format
#| msgid "You can choose at most one option from this category."
#| msgid_plural ""
#| "You can choose up to %(max_count)s options from this category."
#, python-format
msgid "You can choose one option from this category."
msgid_plural "You can choose up to %(max_count)s options from this category."
msgstr[0] "Je kan maximaal één optie kiezen uit deze categorie."
@@ -38526,12 +38510,12 @@ msgid ""
"Your cart timeout was extended. Please note that some of the prices in your "
"cart changed."
msgstr ""
"De time-out van je winkelwagen is verlengd. Merk op dat sommige prijzen in "
"je winkelwagen gewijzigd zijn."
#: pretix/presale/views/cart.py:573
#, fuzzy
#| msgid "Your cart has been updated."
msgid "Your cart timeout was extended."
msgstr "Je winkelwagen is bijgewerkt."
msgstr "De time-out van je winkelwagen is verlengd."
#: pretix/presale/views/cart.py:588
msgid "The products have been successfully added to your cart."

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
"PO-Revision-Date: 2025-11-07 23:00+0000\n"
"Last-Translator: Linnea Thelander <linnea@coeo.events>\n"
"PO-Revision-Date: 2026-01-16 09:22+0000\n"
"Last-Translator: Richard Schreiber <schreiber@rami.io>\n"
"Language-Team: Swedish <https://translate.pretix.eu/projects/pretix/pretix/"
"sv/>\n"
"Language: sv\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.14.2\n"
"X-Generator: Weblate 5.15.2\n"
#: pretix/_base_settings.py:87
msgid "English"
@@ -8993,10 +8993,12 @@ msgstr ""
"exporter."
#: pretix/base/services/invoices.py:116
#, python-brace-format
#, fuzzy, python-brace-format
msgctxt "invoice"
msgid "Please complete your payment before {expire_date}."
msgstr "{expire_date}."
msgstr ""
"Om din betalning inte gick igenom, se till att uppdatera din "
"betalningsinformation innan {expire_date} via knappen nedan."
#: pretix/base/services/invoices.py:128
#, python-brace-format
@@ -35834,7 +35836,7 @@ msgstr "Visa i backend"
#: pretix/presale/templates/pretixpresale/event/order.html:92
#, python-format
msgid "A payment of %(total)s is still pending for this order."
msgstr "En faktura på totalt %(total)s kommer att skickas från Coeo."
msgstr "Tack för din bokning på %(total)s."
#: pretix/presale/templates/pretixpresale/event/order.html:97
#, fuzzy, python-format
@@ -35843,7 +35845,7 @@ msgstr "Tack för din bokning!"
#: pretix/presale/templates/pretixpresale/event/order.html:108
msgid "Re-try payment or choose another payment method"
msgstr "Tack"
msgstr "Uppdatera eller ändra betalningsmetod"
#: pretix/presale/templates/pretixpresale/event/order.html:126
msgid ""

View File

@@ -8,16 +8,16 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
"PO-Revision-Date: 2024-03-30 11:00+0000\n"
"Last-Translator: Thatthep <amaudy@gmail.com>\n"
"Language-Team: Thai <https://translate.pretix.eu/projects/pretix/pretix/th/"
">\n"
"PO-Revision-Date: 2026-01-12 17:00+0000\n"
"Last-Translator: chondaen12 <chondaen12@gmail.com>\n"
"Language-Team: Thai <https://translate.pretix.eu/projects/pretix/pretix/th/>"
"\n"
"Language: th\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.4.3\n"
"X-Generator: Weblate 5.15.1\n"
#: pretix/_base_settings.py:87
msgid "English"
@@ -29,7 +29,7 @@ msgstr "เยอรมัน"
#: pretix/_base_settings.py:89
msgid "German (informal)"
msgstr "เยอรมัน"
msgstr "เยอรมัน (ไม่เป็นทางการ)"
#: pretix/_base_settings.py:90
msgid "Arabic"
@@ -3567,7 +3567,7 @@ msgstr ""
#: pretix/base/invoicing/pdf.py:732 pretix/base/invoicing/pdf.py:740
msgctxt "invoice"
msgid "Description"
msgstr ""
msgstr "คำอธิบาย"
#: pretix/base/invoicing/pdf.py:733 pretix/base/invoicing/pdf.py:741
msgctxt "invoice"
@@ -3577,7 +3577,7 @@ msgstr ""
#: pretix/base/invoicing/pdf.py:734 pretix/base/invoicing/pdf.py:1038
msgctxt "invoice"
msgid "Tax rate"
msgstr ""
msgstr "อัตราภาษี"
#: pretix/base/invoicing/pdf.py:735
msgctxt "invoice"
@@ -3592,7 +3592,7 @@ msgstr ""
#: pretix/base/invoicing/pdf.py:742
msgctxt "invoice"
msgid "Amount"
msgstr ""
msgstr "จำนวน"
#: pretix/base/invoicing/pdf.py:869
#, python-brace-format
@@ -3624,12 +3624,12 @@ msgstr ""
#: pretix/base/invoicing/pdf.py:979
msgctxt "invoice"
msgid "Paid by gift card"
msgstr ""
msgstr "จ่ายโดยบัตรของขวัญ"
#: pretix/base/invoicing/pdf.py:984
msgctxt "invoice"
msgid "Remaining amount"
msgstr ""
msgstr "จำนวนคงเหลือ"
#: pretix/base/invoicing/pdf.py:1008
#, python-brace-format
@@ -3640,7 +3640,7 @@ msgstr ""
#: pretix/base/invoicing/pdf.py:1039
msgctxt "invoice"
msgid "Net value"
msgstr ""
msgstr "ยอดสุทธิ"
#: pretix/base/invoicing/pdf.py:1040
msgctxt "invoice"
@@ -3650,7 +3650,7 @@ msgstr ""
#: pretix/base/invoicing/pdf.py:1041
msgctxt "invoice"
msgid "Tax"
msgstr ""
msgstr "ภาษี"
#: pretix/base/invoicing/pdf.py:1071
msgctxt "invoice"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
"PO-Revision-Date: 2025-12-22 20:00+0000\n"
"PO-Revision-Date: 2026-01-12 17:00+0000\n"
"Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n"
"Language-Team: Chinese (Traditional Han script) <https://translate.pretix.eu/"
"projects/pretix/pretix/zh_Hant/>\n"
@@ -288,39 +288,28 @@ msgid "The bundled item must not have bundles on its own."
msgstr "捆綁商品不得單獨捆綁。"
#: pretix/api/serializers/item.py:235
#, fuzzy
#| msgid "The payment is too late to be accepted."
msgid "The program start must not be empty."
msgstr "付款太晚無法接受。"
msgstr "程式啟動不能為空。"
#: pretix/api/serializers/item.py:239
#, fuzzy
#| msgid "The payment is too late to be accepted."
msgid "The program end must not be empty."
msgstr "付款太晚無法接受。"
msgstr "程式結束不能為空。"
#: pretix/api/serializers/item.py:242 pretix/base/models/items.py:2321
#, fuzzy
#| msgid "The maximum date must not be before the minimum value."
msgid "The program end must not be before the program start."
msgstr "最大日期不得早於最小值。"
msgstr "程式不能在程式開始之前結束。"
#: pretix/api/serializers/item.py:247 pretix/base/models/items.py:2315
#, fuzzy
#| msgid "You can not select a subevent if your event is not an event series."
msgid "You cannot use program times on an event series."
msgstr "如果你的活動不是活動系列,則無法選擇子活動。"
msgstr "您不能在事件系列中使用程式時間。"
#: pretix/api/serializers/item.py:337
#, fuzzy
#| msgid ""
#| "Updating add-ons, bundles, or variations via PATCH/PUT is not supported. "
#| "Please use the dedicated nested endpoint."
msgid ""
"Updating add-ons, bundles, program times or variations via PATCH/PUT is not "
"supported. Please use the dedicated nested endpoint."
msgstr ""
"不支持通過 PATCH/PUT 更新附加件、捆綁包或變體。 請使用專用的嵌套端點。"
"不支援透過PATCH/PUT更新附加件、捆綁包、程式時間或變體。 請使用專用的巢狀端"
"點。"
#: pretix/api/serializers/item.py:345
msgid "Only admission products can currently be personalized."
@@ -570,10 +559,8 @@ msgid "Event series date deleted"
msgstr "活動系列日期已刪除"
#: pretix/api/webhooks.py:375
#, fuzzy
#| msgid "Product name"
msgid "Product changed"
msgstr "商品名稱"
msgstr "產品已更改"
#: pretix/api/webhooks.py:376
msgid ""
@@ -614,16 +601,12 @@ msgid "Waiting list entry received voucher"
msgstr "候補名單條目收到憑證"
#: pretix/api/webhooks.py:413
#, fuzzy
#| msgid "Voucher code"
msgid "Voucher added"
msgstr "優惠券代碼"
msgstr "添加了優惠券"
#: pretix/api/webhooks.py:417
#, fuzzy
#| msgid "Voucher assigned"
msgid "Voucher changed"
msgstr "已分配的優惠券"
msgstr "優惠券已更改"
#: pretix/api/webhooks.py:418
msgid ""

View File

@@ -271,7 +271,8 @@ class BankTransfer(BasePaymentProvider):
'request': request,
'event': self.event,
'settings': self.settings,
'code': self._code(order) if order else None,
'code': self._code(order, force=False) if order else None,
'order': order,
'details': self.settings.get('bank_details', as_type=LazyI18nString),
}
return template.render(ctx)
@@ -295,7 +296,7 @@ class BankTransfer(BasePaymentProvider):
md_nl2br = " \n"
if self.settings.get('bank_details_type') == 'sepa':
bankdetails = (
(_("Reference"), self._code(order)),
(_("Reference"), self._code(order, force=True)),
(_("Amount"), money_filter(payment.amount, self.event.currency)),
(_("Account holder"), self.settings.get('bank_details_sepa_name')),
(_("IBAN"), ibanformat(self.settings.get('bank_details_sepa_iban'))),
@@ -304,7 +305,7 @@ class BankTransfer(BasePaymentProvider):
)
else:
bankdetails = (
(_("Reference"), self._code(order)),
(_("Reference"), self._code(order, force=True)),
(_("Amount"), money_filter(payment.amount, self.event.currency)),
)
t += md_nl2br.join([f"**{k}:** {v}" for k, v in bankdetails])
@@ -317,7 +318,7 @@ class BankTransfer(BasePaymentProvider):
template = get_template('pretixplugins/banktransfer/pending.html')
ctx = {
'event': self.event,
'code': self._code(payment.order),
'code': self._code(payment.order, force=True),
'order': payment.order,
'amount': payment.amount,
'payment_info': payment.info_data,
@@ -345,16 +346,25 @@ class BankTransfer(BasePaymentProvider):
def _render_control_info(self, request, order, info_data, **extra_context):
template = get_template('pretixplugins/banktransfer/control.html')
ctx = {'request': request, 'event': self.event,
'code': self._code(order),
'code': self._code(order, force=True),
'payment_info': info_data, 'order': order,
**extra_context}
return template.render(ctx)
def _code(self, order):
def _code(self, order, force=False):
prefix = self.settings.get('prefix', default='')
li = order.invoices.last()
invoice_number = li.number if self.settings.get('include_invoice_number', as_type=bool) and li else ''
invoice_will_be_generated = (
not li and
self.settings.get('include_invoice_number', as_type=bool) and
order.event.settings.get('invoice_generate') == 'paid' and
self.requires_invoice_immediately
)
if invoice_will_be_generated and not force:
return None
code = " ".join((prefix, order.full_code, invoice_number)).strip(" ")
if self.settings.get('omit_hyphen', as_type=bool):

View File

@@ -24,7 +24,13 @@
{{ details | rich_text }}
{% if not code %}</div>{% endif %}
{% if not code %}
{% if not code and order %}
<p>
<strong>
{% trans "We will assign you a personal reference code in the next step." %}
</strong>
</p>
{% elif not code %}
<p>
<strong>
{% trans "We will assign you a personal reference code to use after you completed the order." %}

View File

@@ -45,10 +45,19 @@
{% endif %}
<p class="help-block">
<small>
{% blocktrans trimmed %}
Only fully paid orders are counted.
Orders paid in multiple payments are shown with the date of their last payment.
{% endblocktrans %}
{% if request.GET.subevent %}
{% blocktrans trimmed %}
Only fully paid orders are counted.
Orders paid in multiple payments are shown with the date of their last payment.
Revenue excludes all fees, including cancellation fees.
{% endblocktrans %}
{% else %}
{% blocktrans trimmed %}
Only fully paid orders are counted.
Orders paid in multiple payments are shown with the date of their last payment.
Revenue includes all fees, including cancellation fees from cancelled orders.
{% endblocktrans %}
{% endif %}
</small>
</p>
</div>
@@ -59,6 +68,14 @@
</div>
<div class="panel-body">
<div id="obp_chart" class="chart"></div>
<p class="help-block">
<small>
{% blocktrans trimmed %}
Placed orders include all orders (pending, paid, cancelled, and expired);
paid orders include only paid orders and exclude all cancelled orders.
{% endblocktrans %}
</small>
</p>
</div>
</div>
{% if seats %}

View File

@@ -128,7 +128,7 @@ class IndexView(EventPermissionRequiredMixin, ChartContainingView, TemplateView)
# Orders by product
ctx['obp_data'] = cache.get('statistics_obp_data' + ckey)
if not ctx['obp_data']:
opqs = OrderPosition.objects
opqs = OrderPosition.all
if subevent:
opqs = opqs.filter(subevent=subevent)
num_ordered = {
@@ -141,7 +141,7 @@ class IndexView(EventPermissionRequiredMixin, ChartContainingView, TemplateView)
num_paid = {
p['item']: p['cnt']
for p in (opqs
.filter(order__event=self.request.event, order__status=Order.STATUS_PAID)
.filter(order__event=self.request.event, order__status=Order.STATUS_PAID, canceled=False)
.values('item')
.annotate(cnt=Count('id')).order_by())
}

View File

@@ -42,6 +42,7 @@ import os
import re
from collections import OrderedDict, defaultdict
from decimal import Decimal
from urllib.parse import quote
from django import forms
from django.conf import settings
@@ -103,13 +104,55 @@ logger = logging.getLogger(__name__)
class OrderDetailMixin(NoSearchIndexViewMixin):
def _allow_anonymous_access(self):
return not (self.request.organizer.settings.customer_accounts and
self.request.organizer.settings.customer_accounts_require_login_for_order_access)
def verify_order_access(self):
o = self.order
if o is None:
raise Http404(_('Unknown order code or not authorized to access this order.'))
if o is False:
login_url = eventreverse(self.request.organizer, 'presale:organizer.customer.login', kwargs={})
if hasattr(self.request, "event_domain") and self.request.event_domain:
next_url = quote(self.request.scheme + "://" + self.request.get_host() + self.request.get_full_path())
return redirect_to_url(f'{login_url}?next={next_url}&request_cross_domain_customer_auth=true')
else:
next_url = quote(self.request.get_full_path())
return redirect_to_url(f'{login_url}?next={next_url}')
return None
@cached_property
def order(self):
"""
Returns the order object when access is permitted, returns `False` when the
order exists but requires authentication, and returns `None` when the order
does not exist or access is denied entirely.
"""
try:
return self.request.event.orders.filter().select_related('event').get_with_secret_check(
order = self.request.event.orders.filter().select_related('event').get_with_secret_check(
code=self.kwargs['order'], received_secret=self.kwargs['secret'], tag=None,
)
if has_event_access_permission(self.request, 'can_view_orders'):
return order
if order.customer is None or not order.customer.is_verified or self._allow_anonymous_access():
return order
if not self.request.customer:
return False
if order.customer_id == self.request.customer.pk:
return order
return None
except Order.DoesNotExist:
return None
@@ -119,6 +162,13 @@ class OrderDetailMixin(NoSearchIndexViewMixin):
'secret': self.order.secret
})
def dispatch(self, request, *args, **kwargs):
resp = self.verify_order_access()
if resp:
return resp
return super().dispatch(request, *args, **kwargs)
class OrderPositionDetailMixin(NoSearchIndexViewMixin):
@cached_property
@@ -157,8 +207,6 @@ class OrderPositionDetailMixin(NoSearchIndexViewMixin):
@method_decorator(xframe_options_exempt, 'dispatch')
class OrderOpen(EventViewMixin, OrderDetailMixin, View):
def get(self, request, *args, **kwargs):
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
if self.order.check_email_confirm_secret(kwargs.get('hash')) and not self.order.email_known_to_work:
self.order.log_action('pretix.event.order.contact.confirmed')
self.order.email_known_to_work = True
@@ -239,8 +287,6 @@ class OrderDetails(EventViewMixin, OrderDetailMixin, CartMixin, TicketPageMixin,
def get(self, request, *args, **kwargs):
self.kwargs = kwargs
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
if self.order.status == Order.STATUS_PENDING:
payment_to_complete = self.order.payments.filter(state=OrderPayment.PAYMENT_STATE_CREATED, process_initiated=False).first()
if payment_to_complete:
@@ -360,8 +406,11 @@ class OrderPaymentStart(EventViewMixin, OrderDetailMixin, TemplateView):
def dispatch(self, request, *args, **kwargs):
self.request = request
self.request.pci_dss_payment_page = True
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
resp = self.verify_order_access()
if resp:
return resp
if (self.order.status not in (Order.STATUS_PENDING, Order.STATUS_EXPIRED)
or self.payment.state != OrderPayment.PAYMENT_STATE_CREATED
or not self.payment.payment_provider.is_enabled
@@ -428,8 +477,11 @@ class OrderPaymentConfirm(EventViewMixin, OrderDetailMixin, TemplateView):
def dispatch(self, request, *args, **kwargs):
self.request = request
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
resp = self.verify_order_access()
if resp:
return resp
if self.payment.state != OrderPayment.PAYMENT_STATE_CREATED or self.order._can_be_paid() is not True:
messages.error(request, _('The payment for this order cannot be continued.'))
return redirect(self.get_order_url())
@@ -495,8 +547,11 @@ class OrderPaymentComplete(EventViewMixin, OrderDetailMixin, View):
def dispatch(self, request, *args, **kwargs):
self.request = request
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
resp = self.verify_order_access()
if resp:
return resp
if self.payment.state != OrderPayment.PAYMENT_STATE_CREATED or self.order._can_be_paid() is not True:
messages.error(request, _('The payment for this order cannot be continued.'))
return redirect(self.get_order_url())
@@ -541,8 +596,11 @@ class OrderPayChangeMethod(EventViewMixin, OrderDetailMixin, TemplateView):
def dispatch(self, request, *args, **kwargs):
self.request = request
self.request.pci_dss_payment_page = True
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
resp = self.verify_order_access()
if resp:
return resp
if self.order.status not in (Order.STATUS_PENDING, Order.STATUS_EXPIRED) or self.order._can_be_paid() is not True:
messages.error(request, _('The payment method for this order cannot be changed.'))
return redirect(self.get_order_url())
@@ -727,8 +785,6 @@ class OrderInvoiceCreate(EventViewMixin, OrderDetailMixin, View):
def dispatch(self, request, *args, **kwargs):
self.request = request
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
return super().dispatch(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
@@ -860,8 +916,11 @@ class OrderModify(EventViewMixin, OrderDetailMixin, OrderQuestionsViewMixin, Tem
def dispatch(self, request, *args, **kwargs):
self.request = request
self.kwargs = kwargs
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
resp = self.verify_order_access()
if resp:
return resp
if not self.order.can_modify_answers:
messages.error(request, _('You cannot modify this order'))
return redirect(self.get_order_url())
@@ -947,8 +1006,11 @@ class OrderCancel(EventViewMixin, OrderDetailMixin, TemplateView):
def dispatch(self, request, *args, **kwargs):
self.request = request
self.kwargs = kwargs
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
resp = self.verify_order_access()
if resp:
return resp
if not self.order.user_cancel_allowed:
messages.error(request, _('You cannot cancel this order.'))
return redirect(self.get_order_url())
@@ -995,14 +1057,7 @@ class OrderCancelDo(EventViewMixin, OrderDetailMixin, AsyncAction, View):
def get_error_url(self):
return self.get_order_url()
def get(self, request, *args, **kwargs):
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
return super().get(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
if not self.order.user_cancel_allowed:
messages.error(request, _('You cannot cancel this order.'))
return redirect(self.get_order_url())
@@ -1293,9 +1348,6 @@ class OrderPositionDownload(OrderDownloadMixin, EventViewMixin, OrderPositionDet
class InvoiceDownload(EventViewMixin, OrderDetailMixin, View):
def get(self, request, *args, **kwargs):
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
try:
invoice = Invoice.objects.get(
event=self.request.event,
@@ -1688,8 +1740,11 @@ class OrderChange(OrderChangeMixin, EventViewMixin, OrderDetailMixin, TemplateVi
def dispatch(self, request, *args, **kwargs):
self.request = request
self.kwargs = kwargs
if not self.order:
raise Http404(_('Unknown order code or not authorized to access this order.'))
resp = self.verify_order_access()
if resp:
return resp
if not self.order.user_change_allowed:
messages.error(request, _('You cannot change this order.'))
return redirect(self.get_order_url())

View File

@@ -932,12 +932,6 @@ def test_search(token_client, organizer, event, clist, clist_all, item, other_it
assert resp.status_code == 200
assert [p1] == resp.data['results']
with django_assert_max_num_queries(25):
resp = token_client.get(
'/api/v1/organizers/{}/checkinrpc/search/?list={}&search=z3fsn8jyu&expand=item'.format(organizer.slug, clist_all.pk))
assert resp.status_code == 200
assert resp.data['results'][0]['item']['name']
@pytest.mark.django_db
def test_search_no_list(token_client, organizer, event, clist, clist_all, item, other_item, order):

View File

@@ -2611,3 +2611,11 @@ def test_approve_cancellation_request(client, env):
doc = BeautifulSoup(response.content.decode(), "lxml")
assert doc.select('input[name=refund-new-giftcard]')[0]['value'] == '10.00'
assert not env[2].cancellation_requests.exists()
@pytest.mark.django_db
def test_view_as_user(client, env):
client.login(email='dummy@dummy.dummy', password='dummy')
response = client.get('/%s/%s/order/%s/%s/' % (env[0].organizer.slug, env[0].slug, env[2].code, env[2].secret))
assert response.status_code == 200
assert env[2].code in response.content.decode()

View File

@@ -1738,3 +1738,222 @@ class OrdersTest(BaseOrdersTest):
self.order.secret, a.pk, match.group(1))
)
assert response.status_code == 404
def test_require_login_for_order_access_disabled_unauth(self):
self.orga.settings.customer_accounts = True
with scopes_disabled():
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
customer.set_password("foo")
customer.save()
self.order.customer = customer
self.order.save()
self.orga.settings.customer_accounts_require_login_for_order_access = False
response = self.client.get(
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
)
assert response.status_code == 200
doc = BeautifulSoup(response.content.decode(), "lxml")
assert len(doc.select(".cart-row")) > 0
assert "pending" in doc.select(".order-details")[0].text.lower()
assert "Peter" in response.content.decode()
assert "Lukas" not in response.content.decode()
response = self.client.get(
'/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
self.ticket_pos.positionid, self.ticket_pos.web_secret)
)
assert response.status_code == 200
doc = BeautifulSoup(response.content.decode(), "lxml")
assert len(doc.select(".cart-row")) > 0
assert "pending" in doc.select(".order-details")[0].text.lower()
assert "Peter" in response.content.decode()
assert "Lukas" not in response.content.decode()
def test_require_login_for_order_access_enabled_unauth(self):
self.orga.settings.customer_accounts = True
with scopes_disabled():
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
customer.set_password("foo")
customer.save()
self.order.customer = customer
self.order.save()
self.orga.settings.customer_accounts_require_login_for_order_access = True
response = self.client.get(
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
)
assert response.status_code == 302
response = self.client.get(
'/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
self.ticket_pos.positionid, self.ticket_pos.web_secret)
)
assert response.status_code == 200
doc = BeautifulSoup(response.content.decode(), "lxml")
assert len(doc.select(".cart-row")) > 0
assert "pending" in doc.select(".order-details")[0].text.lower()
assert "Peter" in response.content.decode()
assert "Lukas" not in response.content.decode()
def test_require_login_for_order_access_disabled_auth(self):
self.orga.settings.customer_accounts = True
with scopes_disabled():
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
customer.set_password("foo")
customer.save()
self.order.customer = customer
self.order.save()
self.orga.settings.customer_accounts_require_login_for_order_access = False
response = self.client.post('/%s/account/login' % (self.orga.slug), {
'email': 'john@example.org',
'password': 'foo',
})
assert response.status_code == 302
response = self.client.get(
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
)
assert response.status_code == 200
doc = BeautifulSoup(response.content.decode(), "lxml")
assert len(doc.select(".cart-row")) > 0
assert "pending" in doc.select(".order-details")[0].text.lower()
assert "Peter" in response.content.decode()
assert "Lukas" not in response.content.decode()
response = self.client.get(
'/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
self.ticket_pos.positionid, self.ticket_pos.web_secret)
)
assert response.status_code == 200
doc = BeautifulSoup(response.content.decode(), "lxml")
assert len(doc.select(".cart-row")) > 0
assert "pending" in doc.select(".order-details")[0].text.lower()
assert "Peter" in response.content.decode()
assert "Lukas" not in response.content.decode()
def test_require_login_for_order_access_enabled_auth(self):
self.orga.settings.customer_accounts = True
with scopes_disabled():
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
customer.set_password("foo")
customer.save()
self.order.customer = customer
self.order.save()
self.orga.settings.customer_accounts_require_login_for_order_access = True
response = self.client.post('/%s/account/login' % (self.orga.slug), {
'email': 'john@example.org',
'password': 'foo',
})
assert response.status_code == 302
response = self.client.get(
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
)
assert response.status_code == 200
doc = BeautifulSoup(response.content.decode(), "lxml")
assert len(doc.select(".cart-row")) > 0
assert "pending" in doc.select(".order-details")[0].text.lower()
assert "Peter" in response.content.decode()
assert "Lukas" not in response.content.decode()
response = self.client.get(
'/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
self.ticket_pos.positionid, self.ticket_pos.web_secret)
)
assert response.status_code == 200
doc = BeautifulSoup(response.content.decode(), "lxml")
assert len(doc.select(".cart-row")) > 0
assert "pending" in doc.select(".order-details")[0].text.lower()
assert "Peter" in response.content.decode()
assert "Lukas" not in response.content.decode()
def test_require_login_for_order_access_accounts_disabled(self):
self.orga.settings.customer_accounts = True
with scopes_disabled():
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
customer.set_password("foo")
customer.save()
self.order.customer = customer
self.order.save()
self.orga.settings.customer_accounts = False
self.orga.settings.customer_accounts_require_login_for_order_access = True
response = self.client.get(
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
)
assert response.status_code == 200
doc = BeautifulSoup(response.content.decode(), "lxml")
assert len(doc.select(".cart-row")) > 0
assert "pending" in doc.select(".order-details")[0].text.lower()
assert "Peter" in response.content.decode()
assert "Lukas" not in response.content.decode()
def test_require_login_for_order_access_enabled_wrong_customer(self):
self.orga.settings.customer_accounts = True
with scopes_disabled():
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
customer.set_password("foo")
customer.save()
self.order.customer = customer
self.order.save()
with scopes_disabled():
customer = self.orga.customers.create(email='jill@example.org', is_verified=True)
customer.set_password("bar")
customer.save()
self.orga.settings.customer_accounts_require_login_for_order_access = True
response = self.client.post('/%s/account/login' % (self.orga.slug), {
'email': 'jill@example.org',
'password': 'bar',
})
assert response.status_code == 302
response = self.client.get(
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
)
assert response.status_code == 404
def test_require_login_for_order_access_enabled_unverified_account(self):
self.orga.settings.customer_accounts = True
with scopes_disabled():
customer = self.orga.customers.create(email='john@example.org', is_verified=False)
customer.set_password("foo")
customer.save()
self.order.customer = customer
self.order.save()
self.orga.settings.customer_accounts_require_login_for_order_access = True
response = self.client.get(
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
)
assert response.status_code == 200
doc = BeautifulSoup(response.content.decode(), "lxml")
assert len(doc.select(".cart-row")) > 0
assert "pending" in doc.select(".order-details")[0].text.lower()
assert "Peter" in response.content.decode()
assert "Lukas" not in response.content.decode()