Compare commits

..

1 Commits

Author SHA1 Message Date
Phin Wolkwitz
efd5ca5e25 Update django to 5.2, initial fixes 2025-12-04 14:45:28 +01:00
19 changed files with 336 additions and 399 deletions

View File

@@ -3,7 +3,7 @@ name = "pretix"
dynamic = ["version"]
description = "Reinventing presales, one ticket at a time"
readme = "README.rst"
requires-python = ">=3.9"
requires-python = ">=3.10"
license = {file = "LICENSE"}
keywords = ["tickets", "web", "shop", "ecommerce"]
authors = [
@@ -22,7 +22,7 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.2",
]
dependencies = [
@@ -36,7 +36,7 @@ dependencies = [
"css-inline==0.18.*",
"defusedcsv>=1.1.0",
"dnspython==2.*",
"Django[argon2]==4.2.*,>=4.2.26",
"Django[argon2]==5.2.*",
"django-bootstrap3==25.2",
"django-compressor==4.5.1",
"django-countries==7.6.*",

View File

@@ -60,23 +60,25 @@ def _populate_app_cache():
def get_defining_app(o):
# If sentry packed this in a wrapper, unpack that
if "sentry" in o.__module__:
module = getattr(o, "__module__", None)
if module and "sentry" in module:
o = o.__wrapped__
if hasattr(o, "__mocked_app"):
return o.__mocked_app
# Find the Django application this belongs to
searchpath = o.__module__
searchpath = module or getattr(o.__class__, "__module__", None) or ""
# Core modules are always active
if any(searchpath.startswith(cm) for cm in settings.CORE_MODULES):
if searchpath and any(searchpath.startswith(cm) for cm in settings.CORE_MODULES):
return 'CORE'
if not app_cache:
_populate_app_cache()
while True:
app = None
while searchpath:
app = app_cache.get(searchpath)
if "." not in searchpath or app:
break
@@ -157,7 +159,11 @@ class PluginSignal(Generic[T], django.dispatch.Signal):
if not app_cache:
_populate_app_cache()
for receiver in self._sorted_receivers(sender):
for receiver in self._sorted_receivers(sender)[0]:
if self._is_receiver_active(sender, receiver):
response = receiver(signal=self, sender=sender, **named)
responses.append((receiver, response))
for receiver in self._sorted_receivers(sender)[1]:
if self._is_receiver_active(sender, receiver):
response = receiver(signal=self, sender=sender, **named)
responses.append((receiver, response))
@@ -179,7 +185,11 @@ class PluginSignal(Generic[T], django.dispatch.Signal):
if not app_cache:
_populate_app_cache()
for receiver in self._sorted_receivers(sender):
for receiver in self._sorted_receivers(sender)[0]:
if self._is_receiver_active(sender, receiver):
named[chain_kwarg_name] = response
response = receiver(signal=self, sender=sender, **named)
for receiver in self._sorted_receivers(sender)[1]:
if self._is_receiver_active(sender, receiver):
named[chain_kwarg_name] = response
response = receiver(signal=self, sender=sender, **named)
@@ -204,7 +214,15 @@ class PluginSignal(Generic[T], django.dispatch.Signal):
if not app_cache:
_populate_app_cache()
for receiver in self._sorted_receivers(sender):
for receiver in self._sorted_receivers(sender)[0]:
if self._is_receiver_active(sender, receiver):
try:
response = receiver(signal=self, sender=sender, **named)
except Exception as err:
responses.append((receiver, err))
else:
responses.append((receiver, response))
for receiver in self._sorted_receivers(sender)[1]:
if self._is_receiver_active(sender, receiver):
try:
response = receiver(signal=self, sender=sender, **named)
@@ -215,16 +233,33 @@ class PluginSignal(Generic[T], django.dispatch.Signal):
return responses
def _sorted_receivers(self, sender):
orig_list = self._live_receivers(sender)
sorted_list = sorted(
orig_list,
orig_list_sync = self._live_receivers(sender)[0]
# todo: _live_receivers changed return value from [] to [], []
orig_list_async = self._live_receivers(sender)[1]
def _receiver_module(receiver):
return getattr(receiver, "__module__", receiver.__class__.__module__)
def _receiver_name(receiver):
return getattr(receiver, "__name__", receiver.__class__.__name__)
sorted_list_sync = sorted(
orig_list_sync,
key=lambda receiver: (
0 if any(receiver.__module__.startswith(m) for m in settings.CORE_MODULES) else 1,
receiver.__module__,
receiver.__name__,
0 if any(_receiver_module(receiver).startswith(m) for m in settings.CORE_MODULES) else 1,
_receiver_module(receiver),
_receiver_name(receiver),
)
)
return sorted_list
sorted_list_async = sorted(
orig_list_async,
key=lambda receiver: (
0 if any(_receiver_module(receiver).startswith(m) for m in settings.CORE_MODULES) else 1,
_receiver_module(receiver),
_receiver_name(receiver),
)
)
return sorted_list_sync, sorted_list_async
class EventPluginSignal(PluginSignal[Event]):

View File

@@ -974,7 +974,7 @@ class EventCancelForm(FormPlaceholderMixin, forms.Form):
self._set_field_placeholders('send_subject', ['event_or_subevent', 'refund_amount', 'position_or_address',
'order', 'event'])
self._set_field_placeholders('send_message', ['event_or_subevent', 'refund_amount', 'position_or_address',
'order', 'event'], rich=True)
'order', 'event'])
self.fields['send_waitinglist_subject'] = I18nFormField(
label=_("Subject"),
required=True,
@@ -998,7 +998,7 @@ class EventCancelForm(FormPlaceholderMixin, forms.Form):
))
)
self._set_field_placeholders('send_waitinglist_subject', ['event_or_subevent', 'event'])
self._set_field_placeholders('send_waitinglist_message', ['event_or_subevent', 'event'], rich=True)
self._set_field_placeholders('send_waitinglist_message', ['event_or_subevent', 'event'])
if self.event.has_subevents:
self.fields['subevent'].queryset = self.event.subevents.all()

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-27 13:57+0000\n"
"PO-Revision-Date: 2025-12-04 18:00+0000\n"
"PO-Revision-Date: 2025-12-03 23:00+0000\n"
"Last-Translator: sandra r <sandrarial@gestiontickets.online>\n"
"Language-Team: Galician <https://translate.pretix.eu/projects/pretix/pretix/"
"gl/>\n"
@@ -713,7 +713,7 @@ msgid "Your password must contain both numeric and alphabetic characters."
msgstr "O teu contrasinal debe conter caracteres numéricos e alfabéticos."
#: pretix/base/auth.py:202 pretix/base/auth.py:212
#, python-format
#, fuzzy, python-format
msgid "Your password may not be the same as your previous password."
msgid_plural ""
"Your password may not be the same as one of your %(history_length)s previous "
@@ -721,7 +721,7 @@ msgid_plural ""
msgstr[0] "O teu contrasinal non sexa o mesmo que o teu contrasinal anterior."
msgstr[1] ""
"O teu contrasinal non sexa o mesmo que un dos teus contrasinais anteriores "
"de %(history_length)s."
"de %(history_length)."
#: pretix/base/channels.py:168
msgid "Online shop"
@@ -3329,48 +3329,42 @@ msgid ""
"Upload a valid image. The file you uploaded was either not an image or a "
"corrupted image."
msgstr ""
"Carga unha imaxe válida. O ficheiro que cargaches ou non era unha imaxe ou "
"estaba danado."
#: pretix/base/forms/questions.py:653 pretix/base/forms/questions.py:662
msgid ""
"If you keep this empty, the ticket will be valid starting at the time of "
"purchase."
msgstr ""
"Se o deixas baleiro, o billete será válido a partir do momento da compra."
#: pretix/base/forms/questions.py:709 pretix/base/forms/questions.py:1102
#, fuzzy
msgid "Street and Number"
msgstr "Rúa e Número"
msgstr "Calle y número"
#: pretix/base/forms/questions.py:1166
msgid ""
"Optional, but depending on the country you reside in we might need to charge "
"you additional taxes if you do not enter it."
msgstr ""
"Opcional, pero dependendo do país no que residas, pode que teñamos que "
"cobrarche impostos adicionais se non o introduces."
#: pretix/base/forms/questions.py:1168 pretix/base/forms/questions.py:1174
msgid "If you are registered in Switzerland, you can enter your UID instead."
msgstr ""
"Se estás rexistrado/a en Suíza, podes introducir o teu UID no seu lugar."
#: pretix/base/forms/questions.py:1172
msgid ""
"Optional, but it might be required for you to claim tax benefits on your "
"invoice depending on your and the sellers country of residence."
msgstr ""
"Opcional, pero pode ser necesario para que solicites beneficios fiscais na "
"túa factura dependendo do teu país de residencia e do vendedor."
#: pretix/base/forms/questions.py:1181
#, fuzzy
msgid "No invoice requested"
msgstr "Non se solicitou factura"
msgstr "Tarifa de cancelación"
#: pretix/base/forms/questions.py:1183
msgid "Invoice transmission method"
msgstr "Método de transmisión de facturas"
msgstr ""
#: pretix/base/forms/questions.py:1329
msgid "You need to provide a company name."
@@ -3385,101 +3379,111 @@ msgid ""
"If you enter an invoice address, you also need to select an invoice "
"transmission method."
msgstr ""
"Se introduces un enderezo de facturación, tamén debes seleccionar un método "
"de transmisión da factura."
#: pretix/base/forms/questions.py:1385
#, fuzzy
msgid ""
"The selected transmission type is not available in your country or for your "
"type of address."
msgstr ""
"O tipo de transmisión seleccionado non está dispoñible no seu país nin para "
"o seu tipo de enderezo."
msgstr "El producto seleccionado no está activo o no tiene precio fijo."
#: pretix/base/forms/questions.py:1394
msgid ""
"The selected type of invoice transmission requires a field that is currently "
"not available, please reach out to the organizer."
msgstr ""
"O tipo de transmisión de factura seleccionado require un campo que non está "
"dispoñible actualmente. Ponte en contacto co organizador."
#: pretix/base/forms/questions.py:1398
msgid "This field is required for the selected type of invoice transmission."
msgstr ""
"Este campo é obrigatorio para o tipo de transmisión de factura seleccionado."
#: pretix/base/forms/user.py:54 pretix/control/forms/organizer.py:458
#: pretix/control/forms/users.py:58
#, fuzzy
msgid "Default timezone"
msgstr "Fuso horario predeterminado"
msgstr "Zona horaria predefinida"
#: pretix/base/forms/user.py:55 pretix/control/forms/users.py:59
#, fuzzy
msgid ""
"Only used for views that are not bound to an event. For all event views, the "
"event timezone is used instead."
msgstr ""
"Só se usa para vistas que non están vinculadas a un evento. Para todas as "
"vistas de eventos, úsase o fuso horario do evento."
"Sólo se utiliza para vistas que no están vinculadas a un evento. Para todas "
"las vistas de eventos, se utiliza la zona horaria de eventos."
#: pretix/base/forms/user.py:77
#, fuzzy
#| msgid "Attendee email address"
msgid "Change email address"
msgstr "Cambiar enderezo de correo electrónico"
msgstr "Correo electrónico do participante"
#: pretix/base/forms/user.py:83
msgid "Device name"
msgstr "Nombre do dispositivo"
#: pretix/base/forms/user.py:84
#, fuzzy
msgid "Device type"
msgstr "Tipo de dispositivo"
#: pretix/base/forms/user.py:85
#, fuzzy
msgid "Smartphone with the Authenticator application"
msgstr "Teléfono intelixente coa aplicación Authenticator"
msgstr "Celular con aplicación de autenticación"
#: pretix/base/forms/user.py:86
#, fuzzy
msgid "WebAuthn-compatible hardware token (e.g. Yubikey)"
msgstr "Token de hardware compatible con WebAuthn (por exemplo, Yubikey)"
msgstr "Hardware compatible con token WebAuthn (p. ej. Yubikey)"
#: pretix/base/forms/user.py:92 pretix/presale/forms/customer.py:383
#: pretix/presale/forms/customer.py:456
#, fuzzy
msgid "The current password you entered was not correct."
msgstr "O contrasinal actual que introduciches non era correcto."
msgstr "La contraseña actual que ingresó no es correcta."
#: pretix/base/forms/user.py:95
msgid "Please choose a password different to your current one."
msgstr "Escolle un contrasinal diferente ao teu actual."
msgstr ""
#: pretix/base/forms/user.py:105 pretix/presale/forms/customer.py:392
#: pretix/presale/forms/customer.py:461
#, fuzzy
msgid "Your current password"
msgstr "O teu contrasinal actual"
msgstr "Su contraseña actual"
#: pretix/base/forms/user.py:111 pretix/control/forms/users.py:50
#: pretix/presale/forms/customer.py:397
#, fuzzy
msgid "New password"
msgstr "New password"
msgstr "Nueva contraseña"
#: pretix/base/forms/user.py:117 pretix/control/forms/users.py:54
#, fuzzy
msgid "Repeat new password"
msgstr "Repita o novo contrasinal"
msgstr "Repetir la nueva contraseña"
#: pretix/base/forms/user.py:176 pretix/control/forms/users.py:43
#, fuzzy
msgid ""
"There already is an account associated with this email address. Please "
"choose a different one."
msgstr ""
"Xa existe unha conta asociada a este enderezo de correo electrónico. Escolle "
"unha diferente."
"Ya existe una cuenta asociada a este correo electrónico. Por favor, escoja "
"otro."
#: pretix/base/forms/user.py:179
#, fuzzy
#| msgid "Email address"
msgid "Old email address"
msgstr "Enderezo de correo electrónico antigo"
msgstr "Correo electrónico"
#: pretix/base/forms/user.py:180
#, fuzzy
#| msgid "Email address"
msgid "New email address"
msgstr "Novo enderezo de correo electrónico"
msgstr "Correo electrónico"
#: pretix/base/forms/validators.py:51
msgid ""
@@ -3488,32 +3492,29 @@ msgid ""
"up. Please note: to use literal \"{\" or \"}\", you need to double them as "
"\"{{\" and \"}}\"."
msgstr ""
"Hai un erro coa sintaxe dos marcadores de posición. Comproba que as "
"corchetes de apertura \"{\" e de peche \"}\" dos marcadores de posición "
"coincidan. Ten en conta que para usar \"{\" ou \"}\" literal, debes "
"duplicalos como \"{{\" e \"}}\"."
#: pretix/base/forms/validators.py:72 pretix/control/views/event.py:870
#, python-format
#, fuzzy, python-format
msgid "Invalid placeholder: {%(value)s}"
msgstr "Marcador de posición non válido: {%(value)s}"
msgstr "Persona(s) interesada(s) inválida(s): %(value)s"
#: pretix/base/forms/widgets.py:68
#, python-format
#, fuzzy, python-format
msgid "Sample: %s"
msgstr "Mostra: %s"
msgstr "Ciudad de ejemplo"
#: pretix/base/forms/widgets.py:71
#, python-brace-format
msgid "Available placeholders: {list}"
msgstr "Marcadores de posición dispoñibles: {list}"
msgstr ""
#: pretix/base/forms/widgets.py:214 pretix/base/models/items.py:1655
#: pretix/plugins/checkinlists/exporters.py:757
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_create.html:40
#: pretix/plugins/sendmail/templates/pretixplugins/sendmail/rule_update.html:54
#, fuzzy
msgid "Time"
msgstr "Tempo"
msgstr "Hora"
#: pretix/base/forms/widgets.py:234 pretix/base/forms/widgets.py:239
msgid "Business or institutional customer"
@@ -3526,49 +3527,53 @@ msgstr "Cliente individual"
#: pretix/base/invoicing/email.py:50
msgid "Email invoice directly to accounting department"
msgstr ""
"Enviar factura por correo electrónico directamente ao departamento de "
"contabilidade"
#: pretix/base/invoicing/email.py:51
#, fuzzy
#| msgid "Please enter the same email address twice."
msgid ""
"If not selected, the invoice will be sent to you using the email address "
"listed above."
msgstr ""
"Se non se selecciona, a factura enviaraseche usando o enderezo de correo "
"electrónico indicado anteriormente."
msgstr "Introduce o mesmo enderezo de correo electrónico dúas veces."
#: pretix/base/invoicing/email.py:55
#, fuzzy
#| msgid "Email address verified"
msgid "Email address for invoice"
msgstr "Enderezo de correo electrónico para factura"
msgstr "Correo electrónico verificado"
#: pretix/base/invoicing/email.py:91
#, fuzzy
msgid "PDF via email"
msgstr "PDF por correo electrónico"
msgstr "Vista previa del correo electrónico"
#: pretix/base/invoicing/national.py:37
msgctxt "italian_invoice"
msgid "Italian Exchange System (SdI)"
msgstr "Sistema de intercambio italiano (SdI)"
msgstr ""
#: pretix/base/invoicing/national.py:38
msgctxt "italian_invoice"
msgid "Exchange System (SdI)"
msgstr "Sistema de intercambio (SdI)"
msgstr ""
#: pretix/base/invoicing/national.py:49
#, fuzzy
#| msgid "Gift card code"
msgctxt "italian_invoice"
msgid "Fiscal code"
msgstr "Código fiscal"
msgstr "Código da tarxeta de regalo"
#: pretix/base/invoicing/national.py:53
msgctxt "italian_invoice"
msgid "Address for certified electronic mail"
msgstr "Enderezo para correo electrónico certificado"
msgstr ""
#: pretix/base/invoicing/national.py:57
#, fuzzy
msgctxt "italian_invoice"
msgid "Recipient code"
msgstr "Código do destinatario"
msgstr "Destinatario"
#: pretix/base/invoicing/national.py:81
msgctxt "italian_invoice"
@@ -3578,68 +3583,75 @@ msgid ""
"in accordance with the procedures and terms set forth in No. 89757/2018 of "
"April 30, 2018, issued by the Director of the Revenue Agency."
msgstr ""
"Este documento PDF é unha copia visual da factura e non constitúe unha "
"factura para efectos do IVE. A factura emítese en formato XML, transmitida "
"de acordo cos procedementos e termos establecidos no Regulamento n.º 89757/"
"2018, do 30 de abril de 2018, emitido polo Director da Axencia Tributaria."
#: pretix/base/invoicing/pdf.py:143
#, python-format
#, fuzzy, python-format
msgctxt "invoice"
msgid "Page %d of %d"
msgstr "Páxina %d de %d"
msgstr "Página %d de %d"
#: pretix/base/invoicing/pdf.py:384
#, fuzzy
msgctxt "invoice"
msgid "Classic renderer (pretix 1.0)"
msgstr "Renderizador clásico (pretix 1.0)"
msgstr "Versión clásica (pretix 1.0)"
#: pretix/base/invoicing/pdf.py:428
#, fuzzy
msgctxt "invoice"
msgid "Invoice from"
msgstr "Factura dende"
msgstr "Factura de"
#: pretix/base/invoicing/pdf.py:434
#, fuzzy
msgctxt "invoice"
msgid "Invoice to"
msgstr "Factura ata"
msgstr "Factura para"
#: pretix/base/invoicing/pdf.py:471 pretix/base/invoicing/pdf.py:1222
#, fuzzy
msgctxt "invoice"
msgid "Order code"
msgstr "Código de pedido"
msgstr "Código de la orden"
#: pretix/base/invoicing/pdf.py:480 pretix/base/invoicing/pdf.py:1235
#, fuzzy
msgctxt "invoice"
msgid "Cancellation number"
msgstr "Número de cancelación"
#: pretix/base/invoicing/pdf.py:486 pretix/base/invoicing/pdf.py:1237
#, fuzzy
msgctxt "invoice"
msgid "Original invoice"
msgstr "Factura orixinal"
msgstr "Factura original"
#: pretix/base/invoicing/pdf.py:491 pretix/base/invoicing/pdf.py:1242
#, fuzzy
msgctxt "invoice"
msgid "Invoice number"
msgstr "Número de factura"
#: pretix/base/invoicing/pdf.py:499 pretix/base/invoicing/pdf.py:1257
#, fuzzy
msgctxt "invoice"
msgid "Cancellation date"
msgstr "Data de cancelación"
msgstr "Fecha de cancelación"
#: pretix/base/invoicing/pdf.py:505
#, fuzzy
msgctxt "invoice"
msgid "Original invoice date"
msgstr "Data orixinal da factura"
msgstr "Fecha original de la factura"
#: pretix/base/invoicing/pdf.py:512 pretix/base/invoicing/pdf.py:1259
#, fuzzy
msgctxt "invoice"
msgid "Invoice date"
msgstr "Data da factura"
msgstr "Fecha de la factura"
#: pretix/base/invoicing/pdf.py:528
#, fuzzy
msgctxt "invoice"
msgid "Event"
msgstr "Evento"
@@ -3655,7 +3667,7 @@ msgstr ""
" ata {to_date}"
#: pretix/base/invoicing/pdf.py:609 pretix/base/services/mail.py:512
#, python-brace-format
#, fuzzy, python-brace-format
msgctxt "invoice"
msgid "Invoice {num}"
msgstr "Factura {num}"
@@ -3667,21 +3679,25 @@ msgid "Customer reference: {reference}"
msgstr "Referencia do cliente: {reference}"
#: pretix/base/invoicing/pdf.py:669
#, fuzzy
msgctxt "invoice"
msgid "Customer VAT ID"
msgstr "CIF do cliente"
msgstr "Cliente VAT ID"
#: pretix/base/invoicing/pdf.py:676
#, fuzzy
msgctxt "invoice"
msgid "Beneficiary"
msgstr "Beneficiario"
#: pretix/base/invoicing/pdf.py:709
#, fuzzy
msgctxt "invoice"
msgid "Tax Invoice"
msgstr "Factura fiscal"
msgstr "Impuesto de la factura"
#: pretix/base/invoicing/pdf.py:710
#, fuzzy
msgctxt "invoice"
msgid "Invoice"
msgstr "Factura"
@@ -3690,6 +3706,7 @@ msgstr "Factura"
#: pretix/control/templates/pretixcontrol/order/index.html:272
#: pretix/control/templates/pretixcontrol/order/mail_history.html:70
#: pretix/presale/templates/pretixpresale/event/order.html:244
#, fuzzy
msgctxt "invoice"
msgid "Cancellation"
msgstr "Cancelación"
@@ -3707,133 +3724,145 @@ msgid "Qty"
msgstr "Cant."
#: pretix/base/invoicing/pdf.py:735 pretix/base/invoicing/pdf.py:1039
#, fuzzy
msgctxt "invoice"
msgid "Tax rate"
msgstr "Tipo impositivo"
msgstr "Tasa de impuestos"
#: pretix/base/invoicing/pdf.py:736
#, fuzzy
msgctxt "invoice"
msgid "Net"
msgstr "Neto"
#: pretix/base/invoicing/pdf.py:737
#, fuzzy
msgctxt "invoice"
msgid "Gross"
msgstr "Bruto"
#: pretix/base/invoicing/pdf.py:743
#, fuzzy
msgctxt "invoice"
msgid "Amount"
msgstr "Cantidade"
msgstr "Monto"
#: pretix/base/invoicing/pdf.py:870
#, python-brace-format
msgctxt "invoice"
msgid "Single price: {net_price} net / {gross_price} gross"
msgstr "Prezo único: {net_price} neto / {gross_price} bruto"
msgstr ""
#: pretix/base/invoicing/pdf.py:901
#, python-brace-format
#, fuzzy, python-brace-format
msgctxt "invoice"
msgid "Single price: {price}"
msgstr "Prezo único: {price}"
msgstr "Precio original"
#: pretix/base/invoicing/pdf.py:944 pretix/base/invoicing/pdf.py:949
#, fuzzy
msgctxt "invoice"
msgid "Invoice total"
msgstr "Total da factura"
msgstr "Total de la factura"
#: pretix/base/invoicing/pdf.py:958
#, fuzzy
msgctxt "invoice"
msgid "Received payments"
msgstr "Pagos recibidos"
#: pretix/base/invoicing/pdf.py:963
#, fuzzy
msgctxt "invoice"
msgid "Outstanding payments"
msgstr "Pagos pendentes"
msgstr "Pagos no válidos"
#: pretix/base/invoicing/pdf.py:980
#, fuzzy
msgctxt "invoice"
msgid "Paid by gift card"
msgstr "Pago con tarxeta regalo"
msgstr "Tarjeta de crédito"
#: pretix/base/invoicing/pdf.py:985
#, fuzzy
msgctxt "invoice"
msgid "Remaining amount"
msgstr "Cantidade restante"
msgstr "Monto pendiente"
#: pretix/base/invoicing/pdf.py:1009
#, python-brace-format
#, fuzzy, python-brace-format
msgctxt "invoice"
msgid "Invoice period: {daterange}"
msgstr "Período de facturación: {daterange}"
msgstr "Rango de fechas de evento"
#: pretix/base/invoicing/pdf.py:1040
#, fuzzy
msgctxt "invoice"
msgid "Net value"
msgstr "Valor neto"
#: pretix/base/invoicing/pdf.py:1041
#, fuzzy
msgctxt "invoice"
msgid "Gross value"
msgstr "Valor bruto"
#: pretix/base/invoicing/pdf.py:1042
#, fuzzy
msgctxt "invoice"
msgid "Tax"
msgstr "Imposto"
msgstr "Impuesto"
#: pretix/base/invoicing/pdf.py:1072
#, fuzzy
msgctxt "invoice"
msgid "Included taxes"
msgstr "Impostos incluídos"
msgstr "Impuestos incluidos"
#: pretix/base/invoicing/pdf.py:1100
#, python-brace-format
#, fuzzy, python-brace-format
msgctxt "invoice"
msgid ""
"Using the conversion rate of 1:{rate} as published by the {authority} on "
"{date}, this corresponds to:"
msgstr ""
"Usando a taxa de conversión de 1:{rate} tal e como a publicou {authority} o "
"{date}, isto corresponde a:"
"Utilizando el tipo de conversión de 1:{rate} publicado por el Banco Central "
"Europeo el {date}, esto corresponde a:"
#: pretix/base/invoicing/pdf.py:1115
#, python-brace-format
#, fuzzy, python-brace-format
msgctxt "invoice"
msgid ""
"Using the conversion rate of 1:{rate} as published by the {authority} on "
"{date}, the invoice total corresponds to {total}."
msgstr ""
"Usando a taxa de conversión de 1:{rate} publicada pola {authority} o {date}, "
"o total da factura corresponde a {total}."
"Utilizando el tipo de conversión de 1:{rate} publicado por el Banco Central "
"Europeo el {date}, el total de la factura corresponde a {total}."
#: pretix/base/invoicing/pdf.py:1129
msgid "Default invoice renderer (European-style letter)"
msgstr "Renderizador de facturas predeterminado (carta de estilo europeo)"
msgstr ""
#: pretix/base/invoicing/pdf.py:1218
#, fuzzy
msgctxt "invoice"
msgid "(Please quote at all times.)"
msgstr "(Por favor, cite en todo momento.)"
msgstr "Por favor, seleccione una cuota."
#: pretix/base/invoicing/pdf.py:1265
msgid "Simplified invoice renderer"
msgstr "Renderizador de facturas simplificado"
msgstr ""
#: pretix/base/invoicing/pdf.py:1284
#, python-brace-format
#, fuzzy, python-brace-format
msgctxt "invoice"
msgid "Event date: {date_range}"
msgstr "Data do evento: {date_range}"
msgstr "Rango de fechas de evento"
#: pretix/base/invoicing/peppol.py:128
msgid ""
"A Peppol participant ID always starts with a prefix, followed by a colon (:)."
msgstr ""
"Un ID de participante de Peppol sempre comeza cun prefixo, seguido de dous "
"puntos (:)."
#: pretix/base/invoicing/peppol.py:132
#, python-format
@@ -3841,8 +3870,6 @@ msgid ""
"The Peppol participant ID prefix %(number)s is not known to our system. "
"Please reach out to us if you are sure this ID is correct."
msgstr ""
"O noso sistema descoñece o prefixo do ID de participante de Peppol %(number)"
"s. Ponte en contacto connosco se estás seguro de que este ID é correcto."
#: pretix/base/invoicing/peppol.py:136
#, python-format
@@ -3850,18 +3877,17 @@ msgid ""
"The Peppol participant ID does not match the validation rules for the prefix "
"%(number)s. Please reach out to us if you are sure this ID is correct."
msgstr ""
"O ID de participante de Peppol non coincide coas regras de validación para o "
"prefixo %(number)s. Ponte en contacto connosco se estás seguro de que este "
"ID é correcto."
#: pretix/base/invoicing/peppol.py:156
msgid "Peppol participant ID"
msgstr "Identificación de participante de Peppol"
msgstr ""
#: pretix/base/invoicing/peppol.py:170
#, fuzzy
#| msgid "Gift card code"
msgctxt "peppol_invoice"
msgid "Visual copy"
msgstr "Copia visual"
msgstr "Código da tarxeta de regalo"
#: pretix/base/invoicing/peppol.py:175
msgctxt "peppol_invoice"
@@ -3870,30 +3896,27 @@ msgid ""
"invoice for VAT purposes. The original invoice is issued in XML format and "
"transmitted through the Peppol network."
msgstr ""
"Este documento PDF é unha copia visual da factura e non constitúe unha "
"factura para efectos do IVE. A factura orixinal emítese en formato XML e "
"transmítese a través da rede Peppol."
#: pretix/base/logentrytype_registry.py:43
msgid ""
"The relevant plugin is currently not active. To activate it, click here to "
"go to the plugin settings."
msgstr ""
"O plugin relevante non está activo actualmente. Para activalo, fai clic aquí "
"para ir á configuración do plugin."
#: pretix/base/logentrytype_registry.py:53
#, fuzzy
msgid "The relevant plugin is currently not active."
msgstr "O plugin relevante non está activo actualmente."
msgstr "La taquilla seleccionada no está disponible en este momento."
#: pretix/base/logentrytypes.py:49
#, fuzzy
msgid "(deleted)"
msgstr "(eliminado)"
msgstr "Eliminar"
#: pretix/base/logentrytypes.py:78
#, python-brace-format
#, fuzzy, python-brace-format
msgid "Order {val}"
msgstr "Orde {val}"
msgstr "Orden {val}"
#: pretix/base/logentrytypes.py:90
#, fuzzy, python-brace-format

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-27 13:57+0000\n"
"PO-Revision-Date: 2025-12-04 18:00+0000\n"
"PO-Revision-Date: 2025-09-10 05:00+0000\n"
"Last-Translator: Renne Rocha <renne@rocha.dev.br>\n"
"Language-Team: Portuguese (Brazil) <https://translate.pretix.eu/projects/"
"pretix/pretix/pt_BR/>\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.13.2\n"
#: pretix/_base_settings.py:87
msgid "English"
@@ -3286,8 +3286,10 @@ msgid "Repeat password"
msgstr "Repita a senha"
#: pretix/base/forms/auth.py:220 pretix/base/forms/user.py:99
#, fuzzy
#| msgid "Email address"
msgid "Your email address"
msgstr "Seu endereço de e-mail"
msgstr "Endereço de email"
#: pretix/base/forms/auth.py:327 pretix/control/forms/orders.py:1041
#: pretix/control/templates/pretixcontrol/shredder/download.html:53
@@ -3431,8 +3433,10 @@ msgstr ""
"as exibições de eventos, o fuso horário do evento é usado."
#: pretix/base/forms/user.py:77
#, fuzzy
#| msgid "Attendee email address"
msgid "Change email address"
msgstr "Alterar endereço de e-mail"
msgstr "Email do participante"
#: pretix/base/forms/user.py:83
msgid "Device name"
@@ -3482,12 +3486,16 @@ msgstr ""
"um diferente."
#: pretix/base/forms/user.py:179
#, fuzzy
#| msgid "Email address"
msgid "Old email address"
msgstr "Endereço de e-mail antigo"
msgstr "Endereço de email"
#: pretix/base/forms/user.py:180
#, fuzzy
#| msgid "Email address"
msgid "New email address"
msgstr "Endereço de e-mail novo"
msgstr "Endereço de email"
#: pretix/base/forms/validators.py:51
msgid ""
@@ -3532,17 +3540,22 @@ msgid "Individual customer"
msgstr "Cliente pessoa física"
#: pretix/base/invoicing/email.py:50
#, fuzzy
#| msgid ""
#| "To send the invoice directly to your accounting department, please enter "
#| "their email address:"
msgid "Email invoice directly to accounting department"
msgstr ""
"Enviar e-mail com a fatura diretamente para departamento de contabilidade"
"Para enviar a fatura diretamente ao seu departamento de contabilidade, "
"insira o endereço de e-mail:"
#: pretix/base/invoicing/email.py:51
#, fuzzy
#| msgid "The invoice was sent to the designated email address."
msgid ""
"If not selected, the invoice will be sent to you using the email address "
"listed above."
msgstr ""
"Se não selecionado, a fatura será enviada para o endereço de e-mail listado "
"a seguir."
msgstr "A fatura foi enviada para o endereço de e-mail designado."
#: pretix/base/invoicing/email.py:55
msgid "Email address for invoice"
@@ -3765,10 +3778,12 @@ msgid "Remaining amount"
msgstr "Valor restante"
#: pretix/base/invoicing/pdf.py:1009
#, python-brace-format
#, fuzzy, python-brace-format
#| msgctxt "invoice"
#| msgid "Event date: {date_range}"
msgctxt "invoice"
msgid "Invoice period: {daterange}"
msgstr "Período da fatura: {daterange}"
msgstr "Data do evento: {date_range}"
#: pretix/base/invoicing/pdf.py:1040
msgctxt "invoice"
@@ -3853,9 +3868,12 @@ msgid "Peppol participant ID"
msgstr ""
#: pretix/base/invoicing/peppol.py:170
#, fuzzy
#| msgctxt "italian_invoice"
#| msgid "Fiscal code"
msgctxt "peppol_invoice"
msgid "Visual copy"
msgstr "Cópia visual"
msgstr "Código fiscal"
#: pretix/base/invoicing/peppol.py:175
msgctxt "peppol_invoice"
@@ -4339,8 +4357,10 @@ msgid ""
msgstr ""
#: pretix/base/models/auth.py:392
#, fuzzy
#| msgid "Confirmation code"
msgid "pretix confirmation code"
msgstr "código de confirmação do pretix"
msgstr "Código de confirmação"
#: pretix/base/models/auth.py:435
#: pretix/control/templates/pretixcontrol/auth/forgot.html:7
@@ -6278,6 +6298,9 @@ msgstr ""
"insira um valor possível por linha."
#: pretix/base/models/items.py:2310
#, fuzzy
#| msgctxt "timeframe"
#| msgid "Start"
msgid "Start"
msgstr "Início"
@@ -7889,8 +7912,10 @@ msgid "123.45 EUR"
msgstr "123.45 BRL"
#: pretix/base/pdf.py:166
#, fuzzy
#| msgid "Price including add-ons"
msgid "Price including bundled products"
msgstr "Preços incluindo produtos empacotados"
msgstr "Preço incluindo complementos"
#: pretix/base/pdf.py:175
#, fuzzy
@@ -9853,8 +9878,10 @@ msgid "Require a phone number per order"
msgstr "Exigir um número de telefone por pedido"
#: pretix/base/settings.py:482
#, fuzzy
#| msgid "including all taxes"
msgid "Rounding of taxes"
msgstr "Arredondamento dos impostos"
msgstr "incluindo todos os impostos"
#: pretix/base/settings.py:486
msgid ""
@@ -10397,12 +10424,18 @@ msgid "Automatic, but prefer invoice date over event date"
msgstr ""
#: pretix/base/settings.py:1142 pretix/base/settings.py:1153
#, fuzzy
#| msgctxt "invoice"
#| msgid "Invoice date"
msgid "Invoice date"
msgstr "Data da fatura"
#: pretix/base/settings.py:1146
#, fuzzy
#| msgctxt "subevent"
#| msgid "Date ordering"
msgid "Date of service"
msgstr "Data do serviço"
msgstr "Ordenação de datas"
#: pretix/base/settings.py:1155
msgid ""
@@ -12133,7 +12166,17 @@ msgid "Invoice {invoice_number}"
msgstr "Fatura {invoice_number}"
#: pretix/base/settings.py:2789
#, python-brace-format
#, fuzzy, python-brace-format
#| msgid ""
#| "Hello,\n"
#| "\n"
#| "somebody requested a list of your orders for {event}.\n"
#| "The list is as follows:\n"
#| "\n"
#| "{orders}\n"
#| "\n"
#| "Best regards, \n"
#| "Your {event} team"
msgid ""
"Hello,\n"
"\n"
@@ -12146,12 +12189,12 @@ msgid ""
msgstr ""
"Olá,\n"
"\n"
"Em anexo você encontrará uma nova fatura para o pedido {code} para {event}. "
"Este pedido foi feito por {order_email}.\n"
"Segue anexo uma nova fatura para o pedido {code} para {evento} . Este pedido "
"foi feito por {order_email}.\n"
"\n"
"Atenciosamente, \n"
"\n"
"Organização {event}"
"Equipe organizadora de {event}"
#: pretix/base/settings.py:2807 pretix/base/settings.py:2823
#, python-brace-format
@@ -13980,16 +14023,21 @@ msgstr ""
"que o cartão-presente é emitido."
#: pretix/control/forms/event.py:813
#, fuzzy
#| msgid "including all taxes"
msgid "Prices including tax"
msgstr "Preços incluindo impostos"
msgstr "incluindo todos os impostos"
#: pretix/control/forms/event.py:814
msgid "Recommended if you sell tickets at least partly to consumers."
msgstr ""
#: pretix/control/forms/event.py:818
#, fuzzy
#| msgctxt "reporting_timeframe"
#| msgid "All future (excluding today)"
msgid "Prices excluding tax"
msgstr "Preços excluindo impostos"
msgstr "Todos os futuros (excluindo hoje)"
#: pretix/control/forms/event.py:819
msgid "Recommended only if you sell tickets primarily to business customers."
@@ -17362,9 +17410,10 @@ msgstr ""
"O endereço de e-mail foi alterado de \"{old_email}\" para \"{new_email}\"."
#: pretix/control/logdisplay.py:673
#, python-brace-format
#, fuzzy, python-brace-format
#| msgid "Your email address has been updated."
msgid "Your email address {email} has been confirmed."
msgstr "Seu endereço de e-mail {email} foi confirmado."
msgstr "Seu endereço de email foi atualizado."
#: pretix/control/logdisplay.py:685
#, python-brace-format
@@ -19641,20 +19690,6 @@ msgid ""
"Best regards,\n"
"Your pretix team\n"
msgstr ""
"Olá,\n"
"\n"
"%(reason)s\n"
"\n"
" %(code)s\n"
"\n"
"Por favor, nunca forneça este código para outra pessoa. Nosso time de "
"suporte nunca irá solicitar este código.\n"
"\n"
"Se você não solicitou este código, por favor entre em contato conosco "
"imediatamente.\n"
"\n"
"Atenciosamente,\n"
"Time pretix\n"
#: pretix/control/templates/pretixcontrol/email/email_setup.txt:1
#, python-format
@@ -21279,8 +21314,10 @@ msgid "with custom rules"
msgstr "Regras personalizadas"
#: pretix/control/templates/pretixcontrol/event/tax.html:110
#, fuzzy
#| msgid "Base settings"
msgid "Tax settings"
msgstr "Configurações de impostos"
msgstr "Configurações base"
#: pretix/control/templates/pretixcontrol/event/tax_delete.html:4
#: pretix/control/templates/pretixcontrol/event/tax_delete.html:6
@@ -26107,7 +26144,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/shredder/download.html:29
msgid "Download data"
msgstr "Baixar dados"
msgstr ""
#: pretix/control/templates/pretixcontrol/shredder/download.html:34
msgid "Step 2: Confirm deletion"
@@ -26438,7 +26475,7 @@ msgstr "Adicionar um dispositivo de autenticação de dois fatores"
#: pretix/control/templates/pretixcontrol/user/2fa_confirm_totp.html:8
msgid "To set up this device, please follow the following steps:"
msgstr "Para configurar este dispositivo, por favor siga os passos a seguir:"
msgstr ""
#: pretix/control/templates/pretixcontrol/user/2fa_confirm_totp.html:12
msgid "Download the Google Authenticator application to your phone:"
@@ -26864,11 +26901,11 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html:6
msgid "Session notes"
msgstr "Notas de sessão"
msgstr ""
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html:17
msgid "Audit log"
msgstr "Log de auditoria"
msgstr ""
#: pretix/control/templates/pretixcontrol/user/staff_session_edit.html:30
msgid "Method"
@@ -27912,7 +27949,7 @@ msgstr ""
#: pretix/control/views/item.py:237
msgid "The selected category has been deleted."
msgstr "A categoria selecionada foi excluída"
msgstr ""
#: pretix/control/views/item.py:322
msgid "The new category has been created."
@@ -29837,7 +29874,7 @@ msgstr ""
#: pretix/plugins/banktransfer/payment.py:239
msgid "Please fill out your bank account details."
msgstr "Por favor, preencha os detalhes da sua conta bancária."
msgstr ""
#: pretix/plugins/banktransfer/payment.py:243
msgid "Please enter your bank account details."
@@ -30138,7 +30175,7 @@ msgstr ""
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/pending.html:122
msgid "Scan the QR code with your banking app"
msgstr "Escanear o QR Code com o seu aplicativo bancário"
msgstr ""
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/refund_export.html:5
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/refund_export.html:7
@@ -30709,8 +30746,6 @@ msgid ""
"We're waiting for an answer from PayPal regarding your payment. Please "
"contact us, if this takes more than a few hours."
msgstr ""
"Estamos aguardando por informações do PayPal referentes ao seu pagamento. "
"Por favor, entre em contato conosco se isso demorar mais que algumas horas."
#: pretix/plugins/paypal/templates/pretixplugins/paypal/redirect.html:17
#: pretix/plugins/paypal2/templates/pretixplugins/paypal2/redirect.html:17
@@ -33335,17 +33370,19 @@ msgstr "Organizador: {organizer}"
#: pretix/presale/ical.py:139
#, python-brace-format
msgid "{event} - {item}"
msgstr "{event} - {item}"
msgstr ""
#: pretix/presale/ical.py:147
#, python-brace-format
#, fuzzy, python-brace-format
#| msgid "Start date"
msgid "Start: {datetime}"
msgstr "Início: {datetime}"
msgstr "Data inicial"
#: pretix/presale/ical.py:150
#, python-brace-format
#, fuzzy, python-brace-format
#| msgid "Admission: {datetime}"
msgid "End: {datetime}"
msgstr "Término: {datetime}"
msgstr "Admissão: {datetime}"
#: pretix/presale/templates/pretixpresale/base.html:44
#, fuzzy
@@ -35595,8 +35632,10 @@ msgid "The following gift cards are available in your customer account:"
msgstr ""
#: pretix/presale/templates/pretixpresale/giftcard/checkout.html:24
#, fuzzy
#| msgid "Issued gift cards"
msgid "Use gift card"
msgstr "Usar cartão-presente"
msgstr "Cartões-presente emitidos"
#: pretix/presale/templates/pretixpresale/giftcard/checkout_confirm.html:4
#, python-format
@@ -35715,9 +35754,10 @@ msgid "Expired since %(date)s"
msgstr "Expirado desde"
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html:46
#, python-format
#, fuzzy, python-format
#| msgid "Valid until %(datetime)s"
msgid "Valid until %(date)s"
msgstr "Válido até %(date)s"
msgstr "Válido até %(datetime)s"
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html:66
#, fuzzy
@@ -36247,8 +36287,10 @@ msgid "The selected date does not exist in this event series."
msgstr "A data selecionada não existe nesta série de eventos."
#: pretix/presale/views/widget.py:412
#, fuzzy
#| msgid "The selected seat \"{seat}\" is not available."
msgid "The selected date is not available."
msgstr "A data selecionada não está disponível."
msgstr "O assento selecionado \"{seat}\" não está disponível."
#: pretix/presale/views/widget.py:476
#, python-format

View File

@@ -41,20 +41,15 @@ for app in apps.get_app_configs():
if hasattr(app, 'PretixPluginMeta'):
if importlib.util.find_spec(app.name + '.urls'):
urlmod = importlib.import_module(app.name + '.urls')
single_plugin_patterns = []
if hasattr(urlmod, 'event_patterns'):
patterns = plugin_event_urls(urlmod.event_patterns, plugin=app.name)
single_plugin_patterns.append(
re_path(r'^(?P<event>[^/]+)/', include(patterns))
)
if hasattr(urlmod, 'organizer_patterns'):
single_plugin_patterns += plugin_event_urls(urlmod.organizer_patterns, plugin=app.name)
if single_plugin_patterns:
raw_plugin_patterns.append(
re_path(r'', include((single_plugin_patterns, app.label)))
re_path(r'^(?P<event>[^/]+)/', include((patterns, app.label)))
)
if hasattr(urlmod, 'organizer_patterns'):
patterns = plugin_event_urls(urlmod.organizer_patterns, plugin=app.name)
raw_plugin_patterns.append(
re_path(r'', include((patterns, app.label)))
)
plugin_patterns = [

View File

@@ -42,20 +42,15 @@ for app in apps.get_app_configs():
if hasattr(app, 'PretixPluginMeta'):
if importlib.util.find_spec(app.name + '.urls'):
urlmod = importlib.import_module(app.name + '.urls')
single_plugin_patterns = []
if hasattr(urlmod, 'organizer_patterns'):
single_plugin_patterns += plugin_event_urls(urlmod.organizer_patterns, plugin=app.name)
if hasattr(urlmod, 'event_patterns'):
plugin_event_patterns = plugin_event_urls(urlmod.event_patterns, plugin=app.name)
single_plugin_patterns.append(
re_path(r'^(?P<event>[^/]+)/', include(plugin_event_patterns))
)
if single_plugin_patterns:
patterns = plugin_event_urls(urlmod.event_patterns, plugin=app.name)
raw_plugin_patterns.append(
re_path(r'', include((single_plugin_patterns, app.label)))
re_path(r'^(?P<event>[^/]+)/', include((patterns, app.label)))
)
if hasattr(urlmod, 'organizer_patterns'):
patterns = plugin_event_urls(urlmod.organizer_patterns, plugin=app.name)
raw_plugin_patterns.append(
re_path(r'', include((patterns, app.label)))
)
plugin_patterns = [

View File

@@ -34,10 +34,8 @@
import json
import logging
import operator
import re
from decimal import Decimal
from functools import reduce
import dateutil.parser
from celery.exceptions import MaxRetriesExceededError
@@ -119,26 +117,20 @@ def _find_order_for_code(base_qs, code):
pass
def _find_order_for_invoice_id(base_qs, prefixes, number):
def _find_order_for_invoice_id(base_qs, prefix, number):
try:
# Working with __iregex here is an experiment, if this turns out to be too slow in production
# we might need to switch to a different approach.
r = [
Q(
prefix__istartswith=prefix, # redundant, but hopefully makes it a little faster
full_invoice_no__iregex=prefix + r'[\- ]*0*' + number
)
for prefix in set(prefixes)
]
return base_qs.select_related('order').get(
reduce(operator.or_, r)
prefix__istartswith=prefix, # redundant, but hopefully makes it a little faster
full_invoice_no__iregex=prefix + r'[\- ]*0*' + number
).order
except (Invoice.DoesNotExist, Invoice.MultipleObjectsReturned):
pass
@transaction.atomic
def _handle_transaction(trans: BankTransaction, matches: tuple, regex_match_to_slug, event: Event = None, organizer: Organizer = None):
def _handle_transaction(trans: BankTransaction, matches: tuple, event: Event = None, organizer: Organizer = None):
orders = []
if event:
for slug, code in matches:
@@ -147,19 +139,18 @@ def _handle_transaction(trans: BankTransaction, matches: tuple, regex_match_to_s
if order.code not in {o.code for o in orders}:
orders.append(order)
else:
order = _find_order_for_invoice_id(Invoice.objects.filter(event=event), (slug, regex_match_to_slug.get(slug, slug)), code)
order = _find_order_for_invoice_id(Invoice.objects.filter(event=event), slug, code)
if order and order.code not in {o.code for o in orders}:
orders.append(order)
else:
qs = Order.objects.filter(event__organizer=organizer)
for slug, code in matches:
original_slug = regex_match_to_slug.get(slug, slug)
order = _find_order_for_code(qs.filter(Q(event__slug__iexact=slug) | Q(event__slug__iexact=original_slug)), code)
order = _find_order_for_code(qs.filter(event__slug__iexact=slug), code)
if order:
if order.code not in {o.code for o in orders}:
orders.append(order)
else:
order = _find_order_for_invoice_id(Invoice.objects.filter(event__organizer=organizer), (slug, original_slug), code)
order = _find_order_for_invoice_id(Invoice.objects.filter(event__organizer=organizer), slug, code)
if order and order.code not in {o.code for o in orders}:
orders.append(order)
@@ -375,37 +366,22 @@ def process_banktransfers(self, job: int, data: list) -> None:
transactions = _get_unknown_transactions(job, data, **job.owner_kwargs)
# Match order codes
regex_match_to_slug = {}
code_len_agg = Order.objects.filter(event__organizer=job.organizer).annotate(
clen=Length('code')
).aggregate(min=Min('clen'), max=Max('clen'))
if job.event:
prefixes = {job.event.slug.upper(), job.event.slug.upper().replace("-", "")}
if "-" in job.event.slug:
regex_match_to_slug[job.event.slug.upper().replace("-", "")] = job.event.slug
prefixes = {job.event.slug.upper()}
else:
prefixes = set()
for e in job.organizer.events.all():
prefixes.add(e.slug.upper())
if "-" in e.slug:
prefixes.add(e.slug.upper().replace("-", ""))
regex_match_to_slug[e.slug.upper().replace("-", "")] = e.slug
prefixes = {e.slug.upper() for e in job.organizer.events.all()}
# Match invoice numbers
inr_len_agg = Invoice.objects.filter(event__organizer=job.organizer).annotate(
clen=Length('invoice_no')
).aggregate(min=Min('clen'), max=Max('clen'))
if job.event:
invoice_prefixes = Invoice.objects.filter(event=job.event)
prefixes |= {p.rstrip(' -') for p in Invoice.objects.filter(event=job.event).distinct().values_list('prefix', flat=True)}
else:
invoice_prefixes = Invoice.objects.filter(event__organizer=job.organizer)
for p in invoice_prefixes.order_by().distinct().values_list('prefix', flat=True):
prefix = p.rstrip(" -")
prefixes.add(prefix)
if "-" in prefix:
prefix_nodash = prefix.replace("-", "")
prefixes.add(prefix_nodash)
regex_match_to_slug[prefix_nodash] = prefix
prefixes |= {p.rstrip(' -') for p in Invoice.objects.filter(event__organizer=job.organizer).distinct().values_list('prefix', flat=True)}
pattern = re.compile(
"(%s)[ \\-_]*([A-Z0-9]{%s,%s})" % (
@@ -433,9 +409,9 @@ def process_banktransfers(self, job: int, data: list) -> None:
if matches:
if job.event:
_handle_transaction(trans, matches, regex_match_to_slug, event=job.event)
_handle_transaction(trans, matches, event=job.event)
else:
_handle_transaction(trans, matches, regex_match_to_slug, organizer=job.organizer)
_handle_transaction(trans, matches, organizer=job.organizer)
else:
trans.state = BankTransaction.STATE_NOMATCH
trans.save()

View File

@@ -137,7 +137,7 @@ logger = logging.getLogger('pretix.plugins.stripe')
# Real-time payments
# - Swish: ✓
# - PayNow: ✗
# - PromptPay:
# - PromptPay:
# - Pix: ✗
#
# Vouchers
@@ -428,14 +428,6 @@ class StripeSettingsHolder(BasePaymentProvider):
'before they work properly.'),
required=False,
)),
('method_promptpay',
forms.BooleanField(
label='PromptPay',
disabled=self.event.currency != 'THB',
help_text=_('Some payment methods might need to be enabled in the settings of your Stripe account '
'before they work properly.'),
required=False,
)),
('method_swish',
forms.BooleanField(
label=_('Swish'),
@@ -1850,30 +1842,6 @@ class StripeSwish(StripeRedirectMethod):
}
class StripePromptPay(StripeRedirectMethod):
identifier = 'stripe_promptpay'
verbose_name = _('PromptPay via Stripe')
public_name = 'PromptPay'
method = 'promptpay'
confirmation_method = 'automatic'
explanation = _(
'This payment method is available to PromptPay users in Thailand. Please have your app ready.'
)
def is_allowed(self, request: HttpRequest, total: Decimal=None) -> bool:
return super().is_allowed(request, total) and request.event.currency == "THB"
def _payment_intent_kwargs(self, request, payment):
return {
"payment_method_data": {
"type": "promptpay",
"billing_details": {
"email": payment.order.email,
},
},
}
class StripeTwint(StripeRedirectMethod):
identifier = 'stripe_twint'
verbose_name = _('TWINT via Stripe')

View File

@@ -47,16 +47,15 @@ def register_payment_provider(sender, **kwargs):
from .payment import (
StripeAffirm, StripeAlipay, StripeBancontact, StripeCC, StripeEPS,
StripeGiropay, StripeIdeal, StripeKlarna, StripeMobilePay,
StripeMultibanco, StripePayPal, StripePromptPay, StripePrzelewy24,
StripeRevolutPay, StripeSEPADirectDebit, StripeSettingsHolder,
StripeSofort, StripeSwish, StripeTwint, StripeWeChatPay,
StripeMultibanco, StripePayPal, StripePrzelewy24, StripeRevolutPay,
StripeSEPADirectDebit, StripeSettingsHolder, StripeSofort, StripeSwish,
StripeTwint, StripeWeChatPay,
)
return [
StripeSettingsHolder, StripeCC, StripeGiropay, StripeIdeal, StripeAlipay, StripeBancontact,
StripeSofort, StripeEPS, StripeMultibanco, StripePrzelewy24, StripePromptPay, StripeRevolutPay,
StripeWeChatPay, StripeSEPADirectDebit, StripeAffirm, StripeKlarna, StripePayPal, StripeSwish,
StripeTwint, StripeMobilePay
StripeSofort, StripeEPS, StripeMultibanco, StripePrzelewy24, StripeRevolutPay, StripeWeChatPay,
StripeSEPADirectDebit, StripeAffirm, StripeKlarna, StripePayPal, StripeSwish, StripeTwint, StripeMobilePay
]

View File

@@ -79,9 +79,3 @@
.vcenter {
margin: auto;
}
.stripe-qr-code {
max-width: 80%;
width: 200px;
height: auto;
}

View File

@@ -325,8 +325,6 @@ $(function () {
} else if ($("#stripe_payment_intent_next_action_redirect_url").length) {
let payment_intent_next_action_redirect_url = $.trim($("#stripe_payment_intent_next_action_redirect_url").html());
pretixstripe.handlePaymentRedirectAction(payment_intent_next_action_redirect_url);
} else if ($.trim($("#stripe_payment_intent_action_type").html()) === "promptpay_display_qr_code") {
waitingDialog.hide();
} else if ($.trim($("#stripe_payment_intent_action_type").html()) === "wechat_pay_display_qr_code") {
let payment_intent_client_secret = $.trim($("#stripe_payment_intent_client_secret").html());
pretixstripe.handleWechatAction(payment_intent_client_secret);

View File

@@ -27,21 +27,9 @@
<div class="stripe-errors sr-only panel-body">
</div>
{% if payment_intent_promptpay_image_url %}
<div class="panel-body">
<p>{% blocktrans trimmed %}
Please scan the QR code below to complete your PromptPay payment.
Once you have completed your payment, you can refresh this page.
{% endblocktrans %}</p>
<div class="text-center">
<img src="{{ payment_intent_promptpay_image_url }}" alt="{% trans 'PromptPay QR code' %}"
class="stripe-qr-code" />
</div>
</div>
{% else %}
<div class="panel-body embed-responsive embed-responsive-sca" id="scacontainer">
</div>
{% endif %}
<div class="panel-body embed-responsive embed-responsive-sca" id="scacontainer">
</div>
</div>
<div class="row checkout-button-row">
<div class="col-md-4">

View File

@@ -595,7 +595,7 @@ class ScaView(StripeOrderView, View):
if intent.status == 'requires_action' and intent.next_action.type in [
'use_stripe_sdk', 'redirect_to_url', 'alipay_handle_redirect', 'wechat_pay_display_qr_code',
'swish_handle_redirect_or_display_qr_code', 'multibanco_display_details', 'promptpay_display_qr_code',
'swish_handle_redirect_or_display_qr_code', 'multibanco_display_details',
]:
ctx = {
'order': self.order,
@@ -613,8 +613,6 @@ class ScaView(StripeOrderView, View):
elif intent.next_action.type == 'multibanco_display_details':
ctx['payment_intent_next_action_redirect_url'] = intent.next_action.multibanco_display_details['hosted_voucher_url']
ctx['payment_intent_redirect_action_handling'] = 'iframe'
elif intent.next_action.type == 'promptpay_display_qr_code':
ctx['payment_intent_promptpay_image_url'] = intent.next_action.promptpay_display_qr_code['image_url_svg']
r = render(request, 'pretixplugins/stripe/sca.html', ctx)
r._csp_ignore = True

View File

@@ -49,7 +49,7 @@ from django.views.decorators.cache import cache_page
from django.views.decorators.gzip import gzip_page
from django.views.decorators.http import condition
from django.views.i18n import (
JavaScriptCatalog, get_formats, js_catalog_template,
JavaScriptCatalog, get_formats, builtin_template_path,
)
from lxml import html
@@ -168,7 +168,8 @@ def generate_widget_js(version, lang):
'September', 'October', 'November', 'December'
)
catalog = dict((k, v) for k, v in catalog.items() if k.startswith('widget\u0004') or k in str_wl)
template = Engine().from_string(js_catalog_template)
with builtin_template_path("i18n_catalog.js").open(encoding="utf-8") as fh:
template = Engine().from_string(fh.read())
context = Context({
'catalog_str': indent(json.dumps(
catalog, sort_keys=True, indent=2)) if catalog else None,

View File

@@ -530,6 +530,7 @@ X_FRAME_OPTIONS = 'DENY'
# URL settings
ROOT_URLCONF = 'pretix.multidomain.maindomain_urlconf'
FORMS_URLFIELD_ASSUME_HTTPS = True # transitional for django 6.0
WSGI_APPLICATION = 'pretix.wsgi.application'

View File

@@ -45,8 +45,6 @@ def env():
def test_event_main_domain_front_page(env):
assert eventreverse(env[1], 'presale:event.index') == '/mrmcd/2015/'
assert eventreverse(env[0], 'presale:organizer.index') == '/mrmcd/'
assert eventreverse(env[1], 'plugins:testdummy:view') == '/mrmcd/2015/testdummy'
assert eventreverse(env[0], 'plugins:testdummy:view') == '/mrmcd/testdummy'
@pytest.mark.django_db
@@ -54,16 +52,12 @@ def test_event_custom_domain_kwargs(env):
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
KnownDomain.objects.create(domainname='barfoo', organizer=env[0], event=env[1])
assert eventreverse(env[1], 'presale:event.checkout', {'step': 'payment'}) == 'http://barfoo/checkout/payment/'
assert eventreverse(env[0], 'plugins:testdummy:view') == 'http://foobar/testdummy'
assert eventreverse(env[1], 'plugins:testdummy:view') == 'http://barfoo/testdummy'
@pytest.mark.django_db
def test_event_org_domain_kwargs(env):
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
assert eventreverse(env[1], 'presale:event.checkout', {'step': 'payment'}) == 'http://foobar/2015/checkout/payment/'
assert eventreverse(env[0], 'plugins:testdummy:view') == 'http://foobar/testdummy'
assert eventreverse(env[1], 'plugins:testdummy:view') == 'http://foobar/2015/testdummy'
@pytest.mark.django_db
@@ -71,13 +65,9 @@ def test_event_org_alt_domain_kwargs(env):
KnownDomain.objects.create(domainname='foobar', organizer=env[0])
d = KnownDomain.objects.create(domainname='altfoo', organizer=env[0], mode=KnownDomain.MODE_ORG_ALT_DOMAIN)
assert eventreverse(env[1], 'presale:event.checkout', {'step': 'payment'}) == 'http://foobar/2015/checkout/payment/'
assert eventreverse(env[1], 'plugins:testdummy:view') == 'http://foobar/2015/testdummy'
d.event_assignments.create(event=env[1])
with scopes_disabled():
event = Event.objects.get(pk=env[1].pk)
assert eventreverse(event, 'presale:event.checkout', {'step': 'payment'}) == 'http://altfoo/2015/checkout/payment/'
assert eventreverse(env[0], 'plugins:testdummy:view') == 'http://foobar/testdummy'
assert eventreverse(event, 'plugins:testdummy:view') == 'http://altfoo/2015/testdummy'
assert eventreverse(Event.objects.get(pk=env[1].pk), 'presale:event.checkout', {'step': 'payment'}) == 'http://altfoo/2015/checkout/payment/'
@pytest.mark.django_db

View File

@@ -385,20 +385,6 @@ def test_mark_paid_organizer_dash_in_slug(env, orga_job):
assert env[2].status == Order.STATUS_PAID
@pytest.mark.django_db
def test_mark_paid_organizer_dash_in_slug_missing(env, orga_job):
env[0].slug = "foo-bar"
env[0].save()
process_banktransfers(orga_job, [{
'payer': 'Karla Kundin',
'reference': 'Bestellung FOOBAR1234S',
'date': '2016-01-26',
'amount': '23.00'
}])
env[2].refresh_from_db()
assert env[2].status == Order.STATUS_PAID
@pytest.mark.django_db
def test_mark_paid_organizer_varying_order_code_length(env, orga_job):
env[2].code = "123412341234"

View File

@@ -1,52 +0,0 @@
#
# 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.http import HttpResponse
from django.urls import path
def view(request):
return HttpResponse("")
urlpatterns = [
path(
"testdummy",
view,
name="view",
),
]
organizer_patterns = [
path(
"testdummy",
view,
name="view",
),
]
event_patterns = [
path(
"testdummy",
view,
name="view",
),
]