Compare commits

..

1 Commits

Author SHA1 Message Date
Raphael Michel
9b7aed9557 Items: Allow plugins to put forms above a formset 2025-09-10 11:06:15 +02:00
18 changed files with 199 additions and 372 deletions

View File

@@ -120,7 +120,7 @@ dev = [
"pytest-cache",
"pytest-cov",
"pytest-django==4.*",
"pytest-mock==3.15.*",
"pytest-mock==3.14.*",
"pytest-sugar",
"pytest-xdist==3.8.*",
"pytest==8.4.*",

View File

@@ -42,7 +42,6 @@ from django.db.models.functions import Cast
from django.utils import timezone
from django.utils.crypto import get_random_string
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _, pgettext
from django_scopes import ScopedManager
@@ -369,22 +368,6 @@ class Invoice(models.Model):
from pretix.base.invoicing.transmission import transmission_types
return transmission_types.get(identifier=self.transmission_type)[0]
def set_transmission_failed(self, provider, data):
self.transmission_status = Invoice.TRANSMISSION_STATUS_FAILED
self.transmission_date = now()
if not self.transmission_provider and provider:
self.transmission_provider = provider
self.save(update_fields=["transmission_status", "transmission_date", "transmission_provider"])
self.order.log_action(
"pretix.event.order.invoice.sending_failed",
data={
"full_invoice_no": self.full_invoice_no,
"transmission_provider": provider,
"transmission_type": self.transmission_type,
"data": data,
}
)
class InvoiceLine(models.Model):
"""

View File

@@ -664,7 +664,20 @@ def transmit_invoice(sender, invoice_id, allow_retransmission=True, **kwargs):
break
if not provider:
invoice.set_transmission_failed(provider=None, data={"reason": "no_provider"})
invoice.transmission_status = Invoice.TRANSMISSION_STATUS_FAILED
invoice.transmission_date = now()
invoice.save(update_fields=["transmission_status", "transmission_date"])
invoice.order.log_action(
"pretix.event.order.invoice.sending_failed",
data={
"full_invoice_no": invoice.full_invoice_no,
"transmission_provider": None,
"transmission_type": invoice.transmission_type,
"data": {
"reason": "no_provider",
},
}
)
return
if invoice.order.testmode and not provider.testmode_supported:
@@ -685,7 +698,18 @@ def transmit_invoice(sender, invoice_id, allow_retransmission=True, **kwargs):
provider.transmit(invoice)
except Exception as e:
logger.exception(f"Transmission of invoice {invoice.pk} failed with exception.")
invoice.set_transmission_failed(provider=provider.identifier, data={
"reason": "exception",
"exception": str(e),
})
invoice.transmission_status = Invoice.TRANSMISSION_STATUS_FAILED
invoice.transmission_date = now()
invoice.save(update_fields=["transmission_status", "transmission_date"])
invoice.order.log_action(
"pretix.event.order.invoice.sending_failed",
data={
"full_invoice_no": invoice.full_invoice_no,
"transmission_provider": None,
"transmission_type": invoice.transmission_type,
"data": {
"reason": "exception",
"exception": str(e),
},
}
)

View File

@@ -495,7 +495,7 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
email = email_filter.send_chained(event, 'message', message=email, order=order, user=user)
invoices_to_mark_transmitted = []
invoices_sent = []
if invoices:
invoices = Invoice.objects.filter(pk__in=invoices)
for inv in invoices:
@@ -516,23 +516,7 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
inv.file.file.read(),
'application/pdf'
)
if inv.transmission_type == "email":
# Mark invoice as sent when it was sent to the requested address *either* at the time of
# invoice creation *or* as of right now.
expected_recipients = [
(inv.invoice_to_transmission_info or {}).get("transmission_email_address")
or inv.order.email,
]
try:
expected_recipients.append(
(inv.order.invoice_address.transmission_info or {}).get("transmission_email_address")
or inv.order.email
)
except InvoiceAddress.DoesNotExist:
pass
if any(t in expected_recipients for t in to):
invoices_to_mark_transmitted.append(inv)
invoices_sent.append(inv)
except:
logger.exception('Could not attach invoice to email')
pass
@@ -605,11 +589,6 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
'invoices': [],
}
)
for i in invoices_to_mark_transmitted:
i.set_transmission_failed(provider="email_pdf", data={
"reason": "exception",
"exception": "SMTP code {}, max retries exceeded".format(e.smtp_code),
})
raise e
logger.exception('Error sending email')
@@ -623,11 +602,6 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
'invoices': [],
}
)
for i in invoices_to_mark_transmitted:
i.set_transmission_failed(provider="email_pdf", data={
"reason": "exception",
"exception": "SMTP code {}".format(e.smtp_code),
})
raise SendMailException('Failed to send an email to {}.'.format(to))
except smtplib.SMTPRecipientsRefused as e:
@@ -659,11 +633,6 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
'invoices': [],
}
)
for i in invoices_to_mark_transmitted:
i.set_transmission_failed(provider="email_pdf", data={
"reason": "exception",
"exception": "SMTP error",
})
raise SendMailException('Failed to send an email to {}.'.format(to))
except Exception as e:
@@ -681,11 +650,6 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
'invoices': [],
}
)
for i in invoices_to_mark_transmitted:
i.set_transmission_failed(provider="email_pdf", data={
"reason": "exception",
"exception": "Internal error",
})
raise e
if log_target:
log_target.log_action(
@@ -697,52 +661,59 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
'invoices': [],
}
)
for i in invoices_to_mark_transmitted:
i.set_transmission_failed(provider="email_pdf", data={
"reason": "exception",
"exception": "Internal error",
})
logger.exception('Error sending email')
raise SendMailException('Failed to send an email to {}.'.format(to))
else:
for i in invoices_to_mark_transmitted:
if i.transmission_status != Invoice.TRANSMISSION_STATUS_COMPLETED:
i.transmission_date = now()
i.transmission_status = Invoice.TRANSMISSION_STATUS_COMPLETED
i.transmission_provider = "email_pdf"
i.transmission_info = {
"sent": [
for i in invoices_sent:
if i.transmission_type == "email":
# Mark invoice as sent when it was sent to the requested address *either* at the time of invoice
# creation *or* as of right now.
expected_recipients = [
(i.invoice_to_transmission_info or {}).get("transmission_email_address") or i.order.email,
]
try:
expected_recipients.append((i.order.invoice_address.transmission_info or {}).get("transmission_email_address") or i.order.email)
except InvoiceAddress.DoesNotExist:
pass
if not any(t in expected_recipients for t in to):
continue
if i.transmission_status != Invoice.TRANSMISSION_STATUS_COMPLETED:
i.transmission_date = now()
i.transmission_status = Invoice.TRANSMISSION_STATUS_COMPLETED
i.transmission_provider = "email_pdf"
i.transmission_info = {
"sent": [
{
"recipients": to,
"datetime": now().isoformat(),
}
]
}
i.save(update_fields=[
"transmission_date", "transmission_provider", "transmission_status",
"transmission_info"
])
elif i.transmission_provider == "email_pdf":
i.transmission_info["sent"].append(
{
"recipients": to,
"datetime": now().isoformat(),
}
]
}
i.save(update_fields=[
"transmission_date", "transmission_provider", "transmission_status",
"transmission_info"
])
elif i.transmission_provider == "email_pdf":
i.transmission_info["sent"].append(
{
"recipients": to,
"datetime": now().isoformat(),
)
i.save(update_fields=[
"transmission_info"
])
i.order.log_action(
"pretix.event.order.invoice.sent",
data={
"full_invoice_no": i.full_invoice_no,
"transmission_provider": "email_pdf",
"transmission_type": "email",
"data": {
"recipients": [to],
},
}
)
i.save(update_fields=[
"transmission_info"
])
i.order.log_action(
"pretix.event.order.invoice.sent",
data={
"full_invoice_no": i.full_invoice_no,
"transmission_provider": "email_pdf",
"transmission_type": "email",
"data": {
"recipients": [to],
},
}
)
def mail_send(*args, **kwargs):

View File

@@ -236,7 +236,7 @@ class VoucherForm(I18nModelForm):
try:
Voucher.clean_max_usages(data, self.instance.redeemed)
except ValidationError as e:
raise ValidationError({"max_usages": e})
raise ValidationError({"max_usages": e.message})
check_quota = Voucher.clean_quota_needs_checking(
data, self.initial_instance_data,
item_changed=data.get('itemvar') != self.initial.get('itemvar'),

View File

@@ -581,7 +581,7 @@ class CoreOrderLogEntryType(OrderLogEntryType):
'The voucher has been set to expire because the recipient removed themselves from the waiting list.'),
'pretix.voucher.changed': _('The voucher has been changed.'),
'pretix.voucher.deleted': _('The voucher has been deleted.'),
'pretix.voucher.added.waitinglist': _('The voucher has been assigned to {email} through the waiting list.'),
'pretix.voucher.added.waitinglist': _('The voucher has been sent to {email} through the waiting list.'),
})
class CoreVoucherLogEntryType(VoucherLogEntryType):
pass

View File

@@ -310,9 +310,13 @@ an instance of a form class that you bind yourself when appropriate. Your form w
as part of the standard validation and rendering cycle and rendered using default bootstrap
styles. It is advisable to set a prefix for your form to avoid clashes with other plugins.
Your forms may also have two special properties: ``template`` with a template that will be
included to render the form, and ``title``, which will be used as a headline. Your template
will be passed a ``form`` variable with your form.
Your forms may also have special properties:
- ``template`` with a template that will be included to render the form. Your template will be passed a ``form``
variable with your form.
- ``title``, which will be used as a headline.
- ``ìs_layouts = True``, if your form should be grouped with the ticket layout settings (mutually exclusive with setting ``title``).
- ``group_with_formset = True``, if your form should be grouped with a formset of the same ``title``
As with all event plugin signals, the ``sender`` keyword argument will contain the event.
"""

View File

@@ -177,6 +177,18 @@
{% for v in formsets.values %}
<fieldset>
<legend>{{ v.title }}</legend>
{% for f in plugin_forms %}
{% if f.group_with_formset and f.title == v.title %}
{% if f.template and not "template" in f.fields %}
{% include f.template with form=f %}
{% else %}
{% bootstrap_form f layout="control" %}
{% endif %}
<hr />
{% endif %}
{% endfor %}
{% include v.template with formset=v %}
</fieldset>
{% endfor %}
@@ -276,7 +288,7 @@
{% endfor %}
</fieldset>
{% for f in plugin_forms %}
{% if not f.is_layouts and f.title %}
{% if not f.is_layouts and not f.group_with_formset and f.title %}
<fieldset>
<legend>{{ f.title }}</legend>
{% if f.template and not "template" in f.fields %}

View File

@@ -64,16 +64,6 @@ def daterange(df, dt, as_html=False):
return format_html(base_format, _date(df, "j."), mark_safe(until.strip()), _date(dt, "j. F Y"))
elif df.year == dt.year:
return format_html(base_format, _date(df, "j. F"), until, _date(dt, "j. F Y"))
elif lng == "en-nz":
if df.year == dt.year and df.month == dt.month and df.day == dt.day:
# Mon, 15 January 2024
return format_html(base_format, _date(df, "D, j F Y"))
elif df.year == dt.year and df.month == dt.month:
# 1 3 January 2024
return format_html(base_format, _date(df, "j"), until, _date(dt, "j F Y"))
elif df.year == dt.year:
# 1 January 3 April 2024
return format_html(base_format, _date(df, "j F"), until, _date(dt, "j F Y"))
elif lng.startswith("en"):
if df.year == dt.year and df.month == dt.month and df.day == dt.day:
return format_html(base_format, _date(df, "D, N jS, Y"))

View File

@@ -1,21 +0,0 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#

View File

@@ -1,50 +0,0 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
# Date according to https://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
# Following NZ government guidance from https://www.digital.govt.nz/standards-and-guidance/design-and-ux/content-design-guidance/writing-style/numbers
DATE_FORMAT = "j F Y" # 12 December 2015
DATETIME_FORMAT = "j F Y, g:ia" # 12 December 2015, 5:30pm
TIME_FORMAT = "g:ia" # 5:30pm
YEAR_MONTH_FORMAT = "F Y" # December 2015
MONTH_DAY_FORMAT = "j F" # 12 December
SHORT_DATE_FORMAT = "j F Y" # same as DATE_FORMAT per guidance
SHORT_DATETIME_FORMAT = "j F Y, g:ia"
WEEKDAY_FORMAT = "l" # Monday
WEEKDAY_DATE_FORMAT = "l, j F Y" # Friday, 23 November 2018
WEEK_FORMAT = "\\W W, o" # ISO week: "W 52, 2024"
WEEK_DAY_FORMAT = "D, j M" # Abbrev weekday and month: "Mon, 5 Feb"
SHORT_MONTH_DAY_FORMAT = "j/n" # Numeric day/month: "5/2"
# Parsing inputs; keep d/m/Y and ISO
DATE_INPUT_FORMATS = [
"%d/%m/%Y",
"%Y-%m-%d",
"%d/%m/%y",
]
TIME_INPUT_FORMATS = [
"%I:%M%p", # 5:30pm
"%H:%M:%S",
"%H:%M:%S.%f",
"%H:%M",
]

View File

@@ -8,20 +8,20 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-08-19 16:35+0000\n"
"PO-Revision-Date: 2025-09-09 04:00+0000\n"
"Last-Translator: Alois Pospíšil <alois.pospisil@gmail.com>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix/cs/>"
"\n"
"PO-Revision-Date: 2025-05-16 17:00+0000\n"
"Last-Translator: David <davemachala@gmail.com>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix/cs/"
">\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Weblate 5.13.2\n"
"X-Generator: Weblate 5.11.4\n"
#: pretix/_base_settings.py:87
msgid "English"
msgstr "AngličDodací adresatina"
msgstr "Angličtina"
#: pretix/_base_settings.py:88
msgid "German"
@@ -145,7 +145,7 @@ msgstr "Španělština"
#: pretix/_base_settings.py:118
msgid "Spanish (Latin America)"
msgstr "uzamčeno (pouze obchody)"
msgstr ""
#: pretix/_base_settings.py:119
msgid "Turkish"
@@ -688,7 +688,7 @@ msgstr "{system} Uživatel"
#: pretix/presale/templates/pretixpresale/event/checkout_customer.html:31
#: pretix/presale/templates/pretixpresale/event/order.html:300
msgid "Email"
msgstr "E-mail"
msgstr "Email"
#: pretix/base/auth.py:157 pretix/base/forms/auth.py:164
#: pretix/base/forms/auth.py:218 pretix/base/models/auth.py:675
@@ -1083,7 +1083,7 @@ msgstr "Krátká forma"
#: pretix/control/templates/pretixcontrol/events/index.html:68
#: pretix/control/templates/pretixcontrol/organizers/detail.html:64
msgid "Event name"
msgstr "Název události"
msgstr "Název akce"
#: pretix/base/datasync/sourcefields.py:446
#: pretix/base/exporters/invoices.py:326
@@ -1107,7 +1107,7 @@ msgstr "Datum ukončení akce"
#: pretix/presale/templates/pretixpresale/event/fragment_voucher_form.html:12
#: pretix/presale/templates/pretixpresale/event/fragment_voucher_form.html:20
msgid "Voucher code"
msgstr "Kód poukazu"
msgstr "Kód poukázky"
#: pretix/base/datasync/sourcefields.py:473 pretix/base/pdf.py:116
msgid "Order code and position number"
@@ -1254,7 +1254,7 @@ msgstr "Nahrání souborů s odpověďmi na otázky"
#: pretix/plugins/reports/exporters.py:662
msgctxt "export_category"
msgid "Order data"
msgstr "Data objednávky"
msgstr "Údaje o objednávce"
#: pretix/base/exporters/answers.py:56
msgid ""
@@ -1414,7 +1414,7 @@ msgstr "Celé jméno"
#: pretix/presale/templates/pretixpresale/event/checkout_customer.html:35
#: pretix/presale/templates/pretixpresale/event/order.html:312
msgid "Name"
msgstr "Název"
msgstr "Jméno"
#: pretix/base/exporters/customers.py:77 pretix/base/models/customers.py:99
msgid "Account active"
@@ -2310,7 +2310,7 @@ msgstr ""
#: pretix/base/exporters/waitinglist.py:115 pretix/control/forms/event.py:1671
#: pretix/control/forms/organizer.py:116
msgid "Event slug"
msgstr "Zkratka události"
msgstr "Odkaz akce"
#: pretix/base/exporters/orderlist.py:262
#: pretix/base/exporters/orderlist.py:452
@@ -2419,7 +2419,7 @@ msgstr "Čísla faktur"
#: pretix/control/forms/filter.py:585
#: pretix/control/templates/pretixcontrol/order/index.html:190
msgid "Sales channel"
msgstr "Prodejní kanál"
msgstr "B2B Kanál"
#: pretix/base/exporters/orderlist.py:286
#: pretix/base/exporters/orderlist.py:630 pretix/base/models/orders.py:277
@@ -2579,12 +2579,12 @@ msgstr "ID sedadla"
#: pretix/base/exporters/orderlist.py:622
#: pretix/plugins/checkinlists/exporters.py:527
msgid "Seat name"
msgstr "Název místa"
msgstr "Název sedadla"
#: pretix/base/exporters/orderlist.py:623
#: pretix/plugins/checkinlists/exporters.py:528
msgid "Seat zone"
msgstr "dd.MM HH:mm"
msgstr "Sedací zóna"
#: pretix/base/exporters/orderlist.py:624
#: pretix/plugins/checkinlists/exporters.py:529
@@ -3568,7 +3568,7 @@ msgstr "Příjemce"
#, python-format
msgctxt "invoice"
msgid "Page %d of %d"
msgstr ""
msgstr "Stránka %d z %d"
#: pretix/base/invoicing/pdf.py:378
msgctxt "invoice"
@@ -4780,7 +4780,7 @@ msgstr ""
#: pretix/base/models/event.py:583 pretix/base/models/organizer.py:89
msgid "The slug may only contain letters, numbers, dots and dashes."
msgstr "Zkratka smí obsahovat pouze písmena, čísla, tečky a pomlčky."
msgstr "Krátká forma může obsahovat pouze písmena, číslice, tečky a pomlčky."
#: pretix/base/models/event.py:600 pretix/base/models/event.py:1495
msgid "Show in lists"
@@ -4837,7 +4837,7 @@ msgstr "Série událostí"
#: pretix/base/models/event.py:652 pretix/base/models/event.py:1544
msgid "Seating plan"
msgstr "Plán míst k sezení"
msgstr "Plán usazení"
#: pretix/base/models/event.py:659 pretix/base/models/items.py:675
msgid "Sell on all sales channels"
@@ -5866,7 +5866,7 @@ msgstr "Upload souborů"
#: pretix/base/models/items.py:1657
#: pretix/control/templates/pretixcontrol/event/settings.html:240
msgid "Date and time"
msgstr "Datum a čas"
msgstr "Datum a hodina"
#: pretix/base/models/items.py:1658
msgid "Country code (ISO 3166-1 alpha-2)"
@@ -6027,7 +6027,7 @@ msgstr ""
#: pretix/base/models/items.py:1961
#: pretix/control/templates/pretixcontrol/items/question.html:90
msgid "Answer"
msgstr ""
msgstr "Odpověď"
#: pretix/base/models/items.py:1985
#, python-brace-format
@@ -6667,6 +6667,7 @@ msgstr "Pozvání do týmu \"{team}\" pro \"{email}\""
#: pretix/base/models/organizer.py:604
#: pretix/control/templates/pretixcontrol/organizers/channels.html:23
#, fuzzy
msgid "Identifier"
msgstr "Identifikátor"
@@ -8002,7 +8003,7 @@ msgstr "Přízemí, řada 3, sedadlo 4"
#: pretix/base/pdf.py:500 pretix/base/pdf.py:506
#: pretix/control/forms/orders.py:344
msgid "General admission"
msgstr "včetně všech daní"
msgstr "Všeobecné vstupné"
#: pretix/base/pdf.py:503
msgid "Seat: zone"
@@ -8174,7 +8175,7 @@ msgstr "Nevybrali jste žádné produkty."
#: pretix/base/services/cart.py:106
msgid "Unknown cart position."
msgstr "Neznámá pozice produktu v košíku."
msgstr "Neznámá pozice produktu ve vozíku."
#: pretix/base/services/cart.py:107
msgctxt "subevent"
@@ -8380,8 +8381,7 @@ msgid ""
"Applying a voucher to the whole cart should not be combined with other "
"operations."
msgstr ""
"Použití poukazu na všechny produkty v košíku by se nemělo kombinovat s "
"jinými operacemi."
"Použití poukazu na celý vozík by se nemělo kombinovat s jinými operacemi."
#: pretix/base/services/cart.py:179
msgid ""
@@ -16471,7 +16471,7 @@ msgstr "Bylo změněno nastavení metody stahování lístků."
#: pretix/control/logdisplay.py:492
msgid "Blocked manually"
msgstr "Ručně blokováno"
msgstr "Ručně zablokováno"
#: pretix/control/logdisplay.py:494
msgid "Blocked because of an API integration"
@@ -26626,7 +26626,7 @@ msgstr ""
#: pretix/plugins/stripe/views.py:682
#: pretix/plugins/ticketoutputpdf/views.py:132
msgid "We could not save your changes. See below for details."
msgstr "Vaše změny se nepodařilo uložit. Podrobnosti najdete níže."
msgstr ""
#: pretix/control/views/checkin.py:420 pretix/control/views/checkin.py:457
msgid "The requested list does not exist."
@@ -30204,7 +30204,7 @@ msgstr "Stránka %d z %d"
#: pretix/plugins/reports/exporters.py:211
#, python-format
msgid "Page %d"
msgstr "Strana %dd"
msgstr "Strana %d"
#: pretix/plugins/reports/exporters.py:213
#, python-format
@@ -31294,7 +31294,7 @@ msgstr "giropay přes Stripe"
#: pretix/plugins/stripe/payment.py:1480
msgid "giropay"
msgstr "Smazat"
msgstr "giropay"
#: pretix/plugins/stripe/payment.py:1483
msgid ""
@@ -31499,37 +31499,37 @@ msgstr ""
#: pretix/plugins/stripe/signals.py:108
#, python-brace-format
msgid "Dispute updated. Reason: {}"
msgstr "Spor aktualizován. Důvod: {}"
msgstr ""
#: pretix/plugins/stripe/signals.py:110
#, python-brace-format
msgid "Dispute closed. Status: {}"
msgstr "Spor uzavřen. Stav: {}"
msgstr ""
#: pretix/plugins/stripe/signals.py:113
#, python-brace-format
msgid "Stripe reported an event: {}"
msgstr "Stripe nahlásil událost: {}"
msgstr ""
#: pretix/plugins/stripe/signals.py:124
msgid "Stripe Connect: Client ID"
msgstr "Stripe Connect: ID klienta"
msgstr ""
#: pretix/plugins/stripe/signals.py:131
msgid "Stripe Connect: Secret key"
msgstr "Stripe Connect: tajný klíč"
msgstr ""
#: pretix/plugins/stripe/signals.py:138
msgid "Stripe Connect: Publishable key"
msgstr "Stripe Connect: veřejný klíč"
msgstr ""
#: pretix/plugins/stripe/signals.py:145
msgid "Stripe Connect: Secret key (test)"
msgstr "Stripe Connect: tajný klíč (test)"
msgstr ""
#: pretix/plugins/stripe/signals.py:152
msgid "Stripe Connect: Publishable key (test)"
msgstr "Stripe Connect: veřejný klíč (test)"
msgstr ""
#: pretix/plugins/stripe/signals.py:178
#: pretix/plugins/stripe/templates/pretixplugins/stripe/oauth_disconnect.html:3
@@ -31556,7 +31556,7 @@ msgstr "Celková částka bude vybrána z vašeho bankovního účtu."
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:18
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sepadirectdebit.html:23
msgid "Banking Institution"
msgstr "bankovní instituce"
msgstr ""
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_confirm.html:20
#: pretix/plugins/stripe/templates/pretixplugins/stripe/checkout_payment_form_sepadirectdebit.html:25
@@ -31635,16 +31635,6 @@ msgid ""
"statement that you can obtain from your bank. You agree to receive "
"notifications for future debits up to 2 days before they occur."
msgstr ""
"Poskytnutím svých platebních údajů a potvrzením této platby opravňujete (A) "
"%(sepa_creditor_name)s a společnost Stripe, našeho poskytovatele platebních "
"služeb a/nebo PPRO, jeho místního poskytovatele služeb, aby vaší bance "
"posílali pokyny k inkasu vašeho účtu a (B) vaši banku, aby váš účet "
"inkasovala v souladu s těmito pokyny. V rámci vašich práv máte nárok na "
"vrácení peněz od své banky podle podmínek vaší smlouvy s bankou. Nárok na "
"vrácení peněz musí být uplatněn do 8 týdnů od data, kdy byl vaš účet "
"zatížen. Vaše práva jsou vysvětlená v prohlášení, které můžete získat od své "
"banky. Souhlasíte s tím, že budete dostávat oznámení o budoucích inkasech až "
"2 dny předtím, než k nim dojde."
#: pretix/plugins/stripe/templates/pretixplugins/stripe/control.html:7
msgid "Charge ID"
@@ -31665,8 +31655,10 @@ msgid "Payer name"
msgstr "Jméno poplatníka"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/control.html:91
#, fuzzy
#| msgid "Payment fee"
msgid "Payment receipt"
msgstr "Potvrzení o platbě"
msgstr "Poplatek za platbu"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/oauth_disconnect.html:12
msgid "Do you really want to disconnect your Stripe account?"
@@ -31677,8 +31669,9 @@ msgid "Disconnect"
msgstr "Odpojit"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/pending.html:6
#, fuzzy
msgid "Payment instructions"
msgstr "Pokyny k platbě"
msgstr "Nastavení platby"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/pending.html:9
msgid ""
@@ -31707,8 +31700,8 @@ msgid ""
"We're waiting for an answer from the payment provider regarding your "
"payment. Please contact us if this takes more than a few days."
msgstr ""
"Čekáme na odpověď od poskytovatele plateb ohledně vaší platby. Pokud to bude "
"trvat déle než několik dní, kontaktujte nás."
"Čekáme na odpověď poskytovatele platební služby ohledně vaší platby. Pokud "
"to bude trvat déle než několik dní, kontaktujte nás prosím."
#: pretix/plugins/stripe/templates/pretixplugins/stripe/pending.html:42
msgid ""
@@ -31738,7 +31731,7 @@ msgstr "Transakci se nepodařilo dokončit z následujícího důvodu:"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca.html:22
#, python-format
msgid "Confirm payment: %(code)s"
msgstr "Potvrdit platbu: %(code)s"
msgstr "Potvrzení platby: %(code)s"
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca_return.html:20
msgid "Confirming your payment…"
@@ -31785,7 +31778,7 @@ msgstr ""
#: pretix/plugins/stripe/views.py:590 pretix/plugins/stripe/views.py:593
msgid "Sorry, there was an error in the payment process."
msgstr "Omlouváme se, při platebním procesu došlo k chybě."
msgstr "Omlouváme se, při plat došlo k chybě."
#: pretix/plugins/ticketoutputpdf/apps.py:44
#: pretix/plugins/ticketoutputpdf/apps.py:47
@@ -32245,9 +32238,10 @@ msgid "No other variations of this product exist."
msgstr "Žádné další varianty tohoto produktu neexistují."
#: pretix/presale/forms/organizer.py:70
#, fuzzy
msgctxt "filter_empty"
msgid "all"
msgstr "Vše"
msgstr "Všechny"
#: pretix/presale/forms/renderers.py:51
msgctxt "form"
@@ -32393,8 +32387,10 @@ msgstr "Informace"
#: pretix/presale/templates/pretixpresale/event/base.html:222
#: pretix/presale/templates/pretixpresale/organizers/base.html:100
#, fuzzy
#| msgid "Contact:"
msgid "Contact"
msgstr "Kontakt"
msgstr "Kontakt:"
#: pretix/presale/templates/pretixpresale/event/base.html:225
#: pretix/presale/templates/pretixpresale/fragment_modals.html:118
@@ -33143,13 +33139,13 @@ msgstr "Pokračujte k platbě"
#: pretix/presale/templates/pretixpresale/event/fragment_cart_box.html:63
msgid "Empty cart"
msgstr "Vyprázdnit košík"
msgstr "Vyprázdnit vozík"
#: pretix/presale/templates/pretixpresale/event/fragment_cart_box.html:68
#: pretix/presale/templates/pretixpresale/event/index.html:248
#: pretix/presale/templates/pretixpresale/event/voucher_form.html:16
msgid "Redeem a voucher"
msgstr "Uplatnit poukaz"
msgstr "Uplatnit poukázku"
#: pretix/presale/templates/pretixpresale/event/fragment_cart_box.html:71
msgid "We're applying this voucher to your cart..."
@@ -33158,7 +33154,7 @@ msgstr "Uplatňujeme tento poukaz ve vašem košíku..."
#: pretix/presale/templates/pretixpresale/event/fragment_cart_box.html:79
#: pretix/presale/templates/pretixpresale/event/fragment_voucher_form.html:27
msgid "Redeem voucher"
msgstr "Uplatnit poukaz"
msgstr "Uplatnění poukázky"
#: pretix/presale/templates/pretixpresale/event/fragment_change_confirm.html:10
msgid "Change summary"
@@ -33704,6 +33700,10 @@ msgstr ""
"vám také zaslali e-mail s odkazem."
#: pretix/presale/templates/pretixpresale/event/order.html:59
#, fuzzy
#| msgid ""
#| "Please save the following link if you want to access your order later. We "
#| "also sent you an email containing the link to the address you specified."
msgid ""
"Please save the following link if you want to access your order later. We "
"also sent you an email to the address you specified containing the link."
@@ -34485,8 +34485,6 @@ msgid ""
"Please tick a checkbox or enter a quantity for one of the ticket types to "
"add to the cart."
msgstr ""
"Zaškrtněte políčko nebo zadejte množství pro jeden z typů vstupenek, které "
"chcete přidat do košíku."
#: pretix/presale/templates/pretixpresale/fragment_week_calendar.html:82
#, python-format
@@ -34605,8 +34603,10 @@ msgid "Change password"
msgstr "Změnit heslo"
#: pretix/presale/templates/pretixpresale/organizers/customer_base.html:41
#, fuzzy
#| msgid "Customer account registration"
msgid "customer account information"
msgstr "informace o zákaznickém účtu"
msgstr "Registrace účtu zákazníka"
#: pretix/presale/templates/pretixpresale/organizers/customer_info.html:6
msgid "Account information"
@@ -34640,8 +34640,10 @@ msgid "transferable"
msgstr "Přenos"
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html:42
#, fuzzy
#| msgid "not answered"
msgid "not transferable"
msgstr "nepřenosné"
msgstr "není odpovězeno"
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html:122
#, fuzzy
@@ -34927,8 +34929,9 @@ msgid "You are not allowed to access time machine mode."
msgstr "Na tuto stránku nemáte přístup."
#: pretix/presale/views/event.py:975
#, fuzzy
msgid "This feature is only available in test mode."
msgstr "Objednávku nesmíte změnit tak, aby vyžadovala vrácení peněz."
msgstr "Tuto dárkovou poukázku lze použít pouze v testovacím režimu."
#: pretix/presale/views/event.py:992
msgid "Time machine disabled!"
@@ -35008,8 +35011,9 @@ msgid "You may not change your order in a way that changes the total price."
msgstr "Objednávku nemůžete změnit tak, aby se změnila celková cena."
#: pretix/presale/views/order.py:1634
#, fuzzy
msgid "You may not change your order in a way that would require a refund."
msgstr "Objednávku nesmíte změnit tak, aby vyžadovala vrácení peněz."
msgstr "Objednávku nesmíte změnit tak, aby se snížila celková cena."
#: pretix/presale/views/order.py:1642
msgid ""
@@ -35020,14 +35024,17 @@ msgstr ""
"objednávku měnit tak, aby se zvýšila celková cena."
#: pretix/presale/views/order.py:1648
#, fuzzy
#| msgid ""
#| "You may not change your order in a way that increases the total price "
#| "since payments are no longer being accepted for this event."
msgid ""
"You may not change your order in a way that requires additional payment "
"while we are processing your current payment. Please check back after your "
"current payment has been accepted."
msgstr ""
"Nemůžete změnit svou objednávku způsobem, který vyžaduje dodatečnou platbu, "
"zatímco zpracováváme vaši aktuální platbu. Vraťte se prosím poté, co bude "
"vaše platba přijata."
"Vzhledem k tomu, že platby za tuto akci již nepřijímáme, nemůžete svou "
"objednávku měnit tak, aby se zvýšila celková cena."
#: pretix/presale/views/order.py:1664 pretix/presale/views/order.py:1695
msgid "You cannot change this order."
@@ -35068,8 +35075,6 @@ msgid ""
"No ticket types are available for the waiting list, have a look at the "
"ticket shop instead."
msgstr ""
"Pro čekací listinu nejsou k dispozici žádné typy vstupenek, podívejte se "
"místo toho do obchodu se vstupenkami."
#: pretix/presale/views/waiting.py:137 pretix/presale/views/waiting.py:161
msgid "Waiting lists are disabled for this event."

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-08-19 16:02+0000\n"
"PO-Revision-Date: 2025-09-08 18:57+0000\n"
"Last-Translator: Alois Pospíšil <alois.pospisil@gmail.com>\n"
"PO-Revision-Date: 2025-05-16 17:00+0000\n"
"Last-Translator: David <davemachala@gmail.com>\n"
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix-js/"
"cs/>\n"
"Language: cs\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
"X-Generator: Weblate 5.13\n"
"X-Generator: Weblate 5.11.4\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
@@ -640,15 +640,19 @@ msgid "Unknown error."
msgstr "Neznámá chyba."
#: pretix/static/pretixcontrol/js/ui/main.js:292
#, fuzzy
#| msgid "Your color has great contrast and is very easy to read!"
msgid "Your color has great contrast and will provide excellent accessibility."
msgstr "Tato barva má velmi dobrý kontrast a je velmi dobře čitelná."
msgstr "Tato barva má velmi dobrý kontrast a je velmi dobře čitelná!"
#: pretix/static/pretixcontrol/js/ui/main.js:296
#, fuzzy
#| msgid "Your color has decent contrast and is probably good-enough to read!"
msgid ""
"Your color has decent contrast and is sufficient for minimum accessibility "
"requirements."
msgstr ""
"Tato barva má slušný kontrast a pravděpodobně je dostatečně dobře čitelná."
"Tato barva má slušný kontrast a pravděpodobně je dostatečně dobře čitelná!"
#: pretix/static/pretixcontrol/js/ui/main.js:300
msgid ""
@@ -731,7 +735,7 @@ msgstr "Nákupní košík vypršel"
#: pretix/static/pretixpresale/js/ui/cart.js:58
#: pretix/static/pretixpresale/js/ui/cart.js:84
msgid "Your cart is about to expire."
msgstr "Nákupní košík brzy vyprší."
msgstr ""
#: pretix/static/pretixpresale/js/ui/cart.js:62
msgid "The items in your cart are reserved for you for one minute."
@@ -744,8 +748,10 @@ msgstr[2] ""
"Produkty v nákupním košíku jsou pro vás rezervovány na dalších {num} minut."
#: pretix/static/pretixpresale/js/ui/cart.js:83
#, fuzzy
#| msgid "Cart expired"
msgid "Your cart has expired."
msgstr "Nákupní košík vypršel."
msgstr "Nákupní košík vypršel"
#: pretix/static/pretixpresale/js/ui/cart.js:86
#, fuzzy
@@ -805,12 +811,12 @@ msgstr "Zvýšit počet"
#: pretix/static/pretixpresale/js/widget/widget.js:19
msgctxt "widget"
msgid "Filter events by"
msgstr "Filtrovat události"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:20
msgctxt "widget"
msgid "Filter"
msgstr "Filtrovat"
msgstr ""
#: pretix/static/pretixpresale/js/widget/widget.js:21
msgctxt "widget"
@@ -927,7 +933,7 @@ msgstr "Již není k dispozici"
#: pretix/static/pretixpresale/js/widget/widget.js:42
msgctxt "widget"
msgid "Currently not available"
msgstr "Momentálně není k dispozici"
msgstr "Momentálně není k dispozici."
#: pretix/static/pretixpresale/js/widget/widget.js:44
#, javascript-format
@@ -962,7 +968,7 @@ msgstr "Obchod vstupenek otevřit"
#: pretix/static/pretixpresale/js/widget/widget.js:50
msgctxt "widget"
msgid "Checkout"
msgstr "Přejít k platbě"
msgstr "Checkout"
#: pretix/static/pretixpresale/js/widget/widget.js:51
msgctxt "widget"
@@ -1084,7 +1090,7 @@ msgstr "Předchozí týden"
#: pretix/static/pretixpresale/js/widget/widget.js:74
msgctxt "widget"
msgid "Open seat selection"
msgstr "Otevřete výběr míst"
msgstr "Otevřete výběr sedadla"
#: pretix/static/pretixpresale/js/widget/widget.js:75
msgctxt "widget"

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-08-19 16:35+0000\n"
"PO-Revision-Date: 2025-09-09 04:00+0000\n"
"PO-Revision-Date: 2025-08-28 23:00+0000\n"
"Last-Translator: Yasunobu YesNo Kawaguchi <kawaguti@gmail.com>\n"
"Language-Team: Japanese <https://translate.pretix.eu/projects/pretix/pretix/"
"ja/>\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.13.2\n"
"X-Generator: Weblate 5.13\n"
#: pretix/_base_settings.py:87
msgid "English"
@@ -1384,7 +1384,7 @@ msgstr "言語"
#: pretix/control/templates/pretixcontrol/organizers/customer.html:72
#: pretix/control/templates/pretixcontrol/organizers/reusable_medium.html:68
msgid "Notes"
msgstr "備考"
msgstr "注記"
#: pretix/base/exporters/customers.py:100
#: pretix/base/exporters/customers.py:101 pretix/base/exporters/events.py:83
@@ -4413,7 +4413,7 @@ msgstr "障害を持つ"
#: pretix/base/models/customers.py:310 pretix/base/models/orders.py:1538
#: pretix/base/models/orders.py:3280 pretix/base/settings.py:1150
msgid "Company name"
msgstr "会社名"
msgstr "企業名"
#: pretix/base/models/customers.py:314 pretix/base/models/orders.py:1542
#: pretix/base/models/orders.py:3287 pretix/base/settings.py:83
@@ -14119,7 +14119,7 @@ msgstr "検索クエリ"
#: pretix/control/templates/pretixcontrol/organizers/giftcard_acceptance_list.html:133
#: pretix/control/templates/pretixcontrol/organizers/reusable_medium.html:39
msgid "active"
msgstr "有効"
msgstr "アクティブ"
#: pretix/control/forms/filter.py:1499
#: pretix/control/templates/pretixcontrol/organizers/customer.html:44
@@ -20414,7 +20414,7 @@ msgstr "理由"
#: pretix/control/templates/pretixcontrol/event/tax_edit.html:137
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:251
msgid "Add a new rule"
msgstr "新しいルールを追加"
msgstr "新しいルールを追加する"
#: pretix/control/templates/pretixcontrol/event/tax_edit.html:153
#: pretix/control/templates/pretixcontrol/organizers/edit.html:391

View File

@@ -48,13 +48,8 @@ function async_task_on_success(data) {
history.replaceState({}, "pretix", async_task_old_url);
}
}
if (!async_task_dont_redirect) {
$(window).one("pageshow", function (e) {
// hide waitingDialog when using browser's history back
waitingDialog.hide();
});
if (!async_task_dont_redirect)
location.href = data.redirect;
}
$(this).trigger('pretix:async-task-success', data);
}

View File

@@ -225,16 +225,6 @@ var form_handlers = function (el) {
};
function setup_basics(el) {
el.find("form").attr("novalidate", true).on("submit", function (e) {
if (!this.checkValidity()) {
var input = this.querySelector(":invalid:not(fieldset)");
(input.labels[0] || input).scrollIntoView();
// only use reportValidity, which usually sets focus on element
// input.focus() opens dropdowns, which is not what we want
input.reportValidity();
e.preventDefault();
}
});
el.find("input[data-toggle=radiocollapse]").change(function () {
$($(this).attr("data-parent")).find(".collapse.in").collapse('hide');
$($(this).attr("data-target")).collapse('show');

View File

@@ -1,31 +0,0 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-2021 rami.io GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
import smtplib
from django.core.mail.backends.locmem import EmailBackend
class FailingEmailBackend(EmailBackend):
def send_messages(self, email_messages):
raise smtplib.SMTPRecipientsRefused({
'recipient@example.org': (450, b'Recipient unknown')
})

View File

@@ -29,7 +29,7 @@ import pytest
from django.conf import settings
from django.core import mail as djmail
from django.db.models import F, Sum
from django.test import TestCase, override_settings
from django.test import TestCase
from django.utils.timezone import make_aware, now
from django_countries.fields import Country
from django_scopes import scope
@@ -811,57 +811,6 @@ def test_mark_invoices_as_sent(event):
assert i.transmission_provider == "email_pdf"
@pytest.mark.django_db(transaction=True)
@override_settings(EMAIL_BACKEND='pretix.testutils.mail.FailingEmailBackend')
def test_mark_invoices_as_failed(event):
djmail.outbox = []
event.settings.invoice_address_asked = True
event.settings.invoice_address_required = True
event.settings.invoice_generate = "True"
event.settings.invoice_email_attachment = True
o1 = Order.objects.create(
code='FOO', event=event, email='dummy@dummy.test',
status=Order.STATUS_PENDING,
datetime=now(), expires=now() - timedelta(days=10),
total=10, locale='en',
sales_channel=event.organizer.sales_channels.get(identifier="web"),
)
ticket = Item.objects.create(event=event, name='Early-bird ticket',
default_price=Decimal('23.00'), admission=True)
OrderPosition.objects.create(
order=o1, item=ticket, variation=None, price=Decimal("23.00"),
attendee_name_parts={'full_name': "Peter"},
positionid=1
)
ia = InvoiceAddress.objects.create(
order=o1,
is_business=True,
country=Country('AT'),
transmission_type="email",
transmission_info={
"transmission_email_address": "invoice@example.org",
}
)
o1.create_transactions()
i = generate_invoice(o1)
assert i.transmission_type == "email"
assert i.transmission_status == Invoice.TRANSMISSION_STATUS_PENDING
assert not i.transmission_provider
# If no other address is there, order address will be accepted
ia.transmission_info = {}
ia.save()
o1.send_mail(
subject=LazyI18nString({"en": "Hey"}),
template=LazyI18nString({"en": "Just wanted to send this invoice"}),
context={},
invoices=[i]
)
i.refresh_from_db()
assert i.transmission_status == Invoice.TRANSMISSION_STATUS_FAILED
assert i.transmission_provider == "email_pdf"
class PaymentReminderTests(TestCase):
def setUp(self):
super().setUp()