Compare commits

...
Author SHA1 Message Date
Raphael Michel 1df04d2131 Add tests 2026-09-02 12:30:29 +02:00
Raphael Michel 464bec8b4e Payment step: Allow to postpone payment choice on some sales channels 2026-09-02 12:07:05 +02:00
Richard Schreiber 58a58eff83 Widget: fix show taxline for 0 or 0.00 tax-rate (#6502) 2026-09-01 13:19:32 +02:00
Martin Gross a84a02c298 Vite: Add dev CORS (#6511) 2026-09-01 11:22:19 +02:00
Martin Gross 4390403b9a Add label-overrides to contact_form_fields_overrides and question_form_fields_overrides (Z#23244154) (#6504) 2026-09-01 10:21:20 +02:00
Lukas Bockstaller 9d53cf840b PayPal: validate that the sale has any captures before marking paid (#6498)
* validate that the sale has any captures before marking paid

* code style
2026-09-01 10:16:51 +02:00
luelista 023f9104ef Fix customer password reset rate limit (#6501) 2026-08-31 16:48:48 +02:00
Lukas Bockstaller e6572344ca CI: add tracing for e2e tests during failure (#6491)
* collect and upload traces on failure

* include deps for pw install
2026-08-31 12:52:06 +02:00
Raphael Michel 2e8e6a6b07 SBOM creation and upload (#6499)
* Build and upload SBOM

* Merge SBOMs

* Use official cli

* Remove matrix

* Merge SBOMs to array

* Use newer sbom-submit

* debug

* Remove debug

* Explicitly setup node

* Add npm location

* Add test

* REmove test call
2026-08-25 15:28:15 +02:00
dependabot[bot] 19cd0a7f43 Update protobuf requirement from ==7.35.* to ==7.36.*
Updates the requirements on [protobuf](https://github.com/protocolbuffers/protobuf) to permit the latest version.
- [Release notes](https://github.com/protocolbuffers/protobuf/releases)
- [Commits](https://github.com/protocolbuffers/protobuf/commits)

---
updated-dependencies:
- dependency-name: protobuf
  dependency-version: 7.36.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-25 14:37:23 +02:00
CVZ-es aa583a291f Translations: Update Spanish
Currently translated at 100.0% (6419 of 6419 strings)

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

powered by weblate
2026-08-25 14:33:41 +02:00
CVZ-es 1414c22eb6 Translations: Update French
Currently translated at 100.0% (6419 of 6419 strings)

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

powered by weblate
2026-08-25 14:33:41 +02:00
Raphael Michel 0a6b8c0493 Translations: Update German (informal) (de_Informal)
Currently translated at 100.0% (6419 of 6419 strings)

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

powered by weblate
2026-08-25 14:33:41 +02:00
Raphael Michel 4b4a301e6e Translations: Update German
Currently translated at 100.0% (6419 of 6419 strings)

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

powered by weblate
2026-08-25 14:33:41 +02:00
24 changed files with 606 additions and 359 deletions
+43
View File
@@ -0,0 +1,43 @@
name: SBOM
on:
push:
branches: [ master, sbom ]
tags: [ 'v.*' ]
permissions:
contents: read # to fetch code (actions/checkout)
env:
FORCE_COLOR: 1
jobs:
test:
runs-on: ubuntu-22.04
name: Submission
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
- name: Use Node.js
uses: actions/setup-node@v7
with:
node-version: '24.x'
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install system dependencies
run: sudo apt update && sudo apt install -y gettext unzip
- name: Install Python dependencies
run: pip3 install -U "prisma-sbom-submit[python]"
- name: Create SBOM
run: NPM=$(which npm) prisma-sbom-submit collect . sbom.json
- name: Submit SBOM
run: prisma-sbom-submit upload --server https://prisma.pretix.com sbom.json
env:
PRISMA_UPLOAD_TOKEN: ${{ secrets.PRISMA_UPLOAD_TOKEN }}
+19 -2
View File
@@ -123,7 +123,24 @@ jobs:
working-directory: ./src
run: make all compress
- name: Install Playwright browsers
run: playwright install
run: playwright install --with-deps
- name: Run E2E tests
working-directory: ./src
run: PRETIX_CONFIG_FILE=tests/ci_postgres.cfg py.test tests/e2e/ -v --maxfail=10
run: PRETIX_CONFIG_FILE=tests/ci_postgres.cfg py.test tests/e2e/ -v --maxfail=10 --tracing=retain-on-failure
- uses: actions/upload-artifact@v4
if: ${{ !cancelled() }}
with:
name: playwright-traces
path: test-results/
- name: Log trace instructions
if: steps.check-traces.outputs.found == 'true'
run: |
{
echo "## 🎭 Playwright traces available"
echo ""
echo "Some tests failed or retried and produced traces."
echo ""
echo "1. Download the **playwright-traces-${{ github.run_id }}** artifact from this run (link in the **Summary** tab, under Artifacts)."
echo "2. Unzip it."
echo "3. Go to https://trace.playwright.dev and drag \`trace.zip\` into the page — or run \`npx playwright show-trace trace.zip\` locally."
} >> "$GITHUB_STEP_SUMMARY"
+1 -1
View File
@@ -79,7 +79,7 @@ dependencies = [
"phonenumberslite==9.0.*",
"Pillow==12.3.*",
"pretix-plugin-build",
"protobuf==7.35.*",
"protobuf==7.36.*",
"psycopg2-binary",
"pycountry",
"pycparser==3.0",
+7 -40
View File
@@ -626,47 +626,14 @@ class Order(LockModel, LoggedModel):
self.save(update_fields=['last_modified'])
def set_expires(self, now_dt=None, subevents=None):
now_dt = now_dt or now()
tz = ZoneInfo(self.event.settings.timezone)
from pretix.base.services.payment import compute_payment_deadline
sales_channel_suffix = "_" + self.sales_channel.identifier.replace(".", "_")
if not (mode := self.event.settings.get(f'payment_term_mode{sales_channel_suffix}')):
mode = self.event.settings.get('payment_term_mode')
sales_channel_suffix = ""
if mode == 'days':
exp_by_date = now_dt.astimezone(tz) + timedelta(days=self.event.settings.get(f'payment_term_days{sales_channel_suffix}', as_type=int))
exp_by_date = exp_by_date.astimezone(tz).replace(hour=23, minute=59, second=59, microsecond=0)
if self.event.settings.get('payment_term_weekdays'):
if exp_by_date.weekday() == 5:
exp_by_date += timedelta(days=2)
elif exp_by_date.weekday() == 6:
exp_by_date += timedelta(days=1)
elif mode == 'minutes':
exp_by_date = now_dt.astimezone(tz) + timedelta(minutes=self.event.settings.get(f'payment_term_minutes{sales_channel_suffix}', as_type=int))
else:
raise ValueError("'payment_term_mode' has an invalid value '{}'.".format(mode))
self.expires = exp_by_date
term_last = self.event.settings.get('payment_term_last', as_type=RelativeDateWrapper)
if term_last:
if self.event.has_subevents and subevents:
terms = [
term_last.datetime(se).date()
for se in subevents
]
if not terms:
return
term_last = min(terms)
else:
term_last = term_last.datetime(self.event).date()
term_last = make_aware(datetime.combine(
term_last,
time(hour=23, minute=59, second=59)
), tz)
if term_last < self.expires:
self.expires = term_last
self.expires = compute_payment_deadline(
event=self.event,
sales_channel=self.sales_channel,
now_dt=now_dt,
subevents=subevents,
)
@cached_property
def tax_total(self):
+18 -3
View File
@@ -961,7 +961,7 @@ def _check_positions(event: Event, now_dt: datetime, time_machine_now_dt: dateti
def _apply_rounding_and_fees(positions: List[CartPosition], payment_requests: List[dict], address: InvoiceAddress,
meta_info: dict, event: Event, require_approval=False):
meta_info: dict, event: Event, sales_channel: SalesChannel, require_approval=False):
fees = []
# Pre-rounding, pre-fee total is used for fee calculation
total = sum([c.gross_price_before_rounding for c in positions])
@@ -1021,7 +1021,14 @@ def _apply_rounding_and_fees(positions: List[CartPosition], payment_requests: Li
payments_assigned += to_pay
p['payment_amount'] = to_pay
if total != payments_assigned and not require_approval:
allow_postponed_payment = (
require_approval or
(
sales_channel.identifier in event.settings.payment_choice_postpone_allowed_channels and not payment_requests
)
)
if total != payments_assigned and not allow_postponed_payment:
raise OrderError(_("The selected payment methods do not cover the total balance."))
return fees
@@ -1043,7 +1050,15 @@ def _create_order(event: Event, *, email: str, positions: List[CartPosition], no
# Final calculation of fees, also performs final rounding
try:
fees = _apply_rounding_and_fees(positions, payment_requests, address, meta_info, event, require_approval=require_approval)
fees = _apply_rounding_and_fees(
positions,
payment_requests,
address,
meta_info,
event,
sales_channel=sales_channel,
require_approval=require_approval
)
except TaxRule.SaleNotAllowed:
raise OrderError(error_messages['country_blocked'])
+76
View File
@@ -0,0 +1,76 @@
#
# 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 datetime import datetime, time, timedelta
from zoneinfo import ZoneInfo
from django.utils.timezone import make_aware, now
from pretix.base.models import Event, SalesChannel
from pretix.base.reldate import RelativeDateWrapper
def compute_payment_deadline(event: Event, sales_channel: SalesChannel, now_dt=None, subevents=None) -> datetime:
now_dt = now_dt or now()
tz = ZoneInfo(event.settings.timezone)
sales_channel_suffix = "_" + sales_channel.identifier.replace(".", "_")
if not (mode := event.settings.get(f'payment_term_mode{sales_channel_suffix}')):
mode = event.settings.get('payment_term_mode')
sales_channel_suffix = ""
if mode == 'days':
exp_by_date = now_dt.astimezone(tz) + timedelta(
days=event.settings.get(f'payment_term_days{sales_channel_suffix}', as_type=int))
exp_by_date = exp_by_date.astimezone(tz).replace(hour=23, minute=59, second=59, microsecond=0)
if event.settings.get('payment_term_weekdays'):
if exp_by_date.weekday() == 5:
exp_by_date += timedelta(days=2)
elif exp_by_date.weekday() == 6:
exp_by_date += timedelta(days=1)
elif mode == 'minutes':
exp_by_date = now_dt.astimezone(tz) + timedelta(
minutes=event.settings.get(f'payment_term_minutes{sales_channel_suffix}', as_type=int))
else:
raise ValueError("'payment_term_mode' has an invalid value '{}'.".format(mode))
expires = exp_by_date
term_last = event.settings.get('payment_term_last', as_type=RelativeDateWrapper)
if term_last:
if event.has_subevents and subevents:
terms = [
term_last.datetime(se).date()
for se in subevents
]
if not terms:
return expires
term_last = min(terms)
else:
term_last = term_last.datetime(event).date()
term_last = make_aware(datetime.combine(
term_last,
time(hour=23, minute=59, second=59)
), tz)
if term_last < expires:
return term_last
return expires
+13
View File
@@ -1159,6 +1159,19 @@ DEFAULTS = {
"configured above."),
)
},
'payment_choice_postpone_allowed_channels': {
'default': [],
'type': list,
'form_class': forms.MultipleChoiceField,
'form_kwargs': dict(
label=_('Allow postponed payment choice for sales channels'),
help_text=_("If postponed payment is allowed on a sales channel, customers can complete their order without "
"selecting a payment method. This is useful whenever orders are not created by the same "
"person who is making the payment."),
widget=forms.CheckboxSelectMultiple,
choices=[],
)
},
'presale_start_show_date': {
'default': 'True',
'type': bool,
+2
View File
@@ -135,6 +135,8 @@ class BaseQuestionsViewMixin:
question_field.initial = getattr(question_field, 'initial', None) or src['initial']
if 'validators' in src:
question_field.validators += src['validators']
if 'label' in src:
question_field.label = src['label']
if len(form.fields) > 0:
formlist.append(form)
+8 -1
View File
@@ -855,14 +855,21 @@ class PaymentSettingsForm(EventSettingsValidationMixin, SettingsForm):
'payment_term_accept_late',
'payment_pending_hidden',
'payment_explanation',
'payment_choice_postpone_allowed_channels',
'tax_rule_payment',
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
channels = list(self.obj.organizer.sales_channels.all())
self.fields['payment_choice_postpone_allowed_channels'].choices = [
(c.identifier, c.label) for c in channels
if c.type_instance.payment_restrictions_supported
]
self.term_channel_fields = {}
for c in self.obj.organizer.sales_channels.all():
for c in channels:
if c.type_instance.payment_restrictions_supported and c.identifier != "web":
# At the moment, it seems sufficient to allow this for the same channel types as other payment settings
# We can always introduce more flags later if needed
@@ -109,6 +109,7 @@
{% bootstrap_form_errors form layout="control" %}
{% bootstrap_field form.tax_rule_payment layout="control" %}
{% bootstrap_field form.payment_explanation layout="control" %}
{% bootstrap_field form.payment_choice_postpone_allowed_channels layout="control" %}
</fieldset>
</div>
{% if "event.settings.payment:write" in request.eventpermset %}
+3 -10
View File
@@ -5,10 +5,10 @@ msgstr ""
"Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-24 15:35+0000\n"
"PO-Revision-Date: 2026-08-24 15:31+0000\n"
"PO-Revision-Date: 2026-08-25 00:00+0000\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/de/"
">\n"
"Language-Team: German <https://translate.pretix.eu/projects/pretix/pretix/"
"de/>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -31805,13 +31805,6 @@ msgid "Allow further payments during compliance hold"
msgstr "Erlaube weitere Zahlungsversuche während PayPal eine Zahlung überprüft"
#: pretix/plugins/paypal2/payment.py
#, fuzzy
#| msgid ""
#| "PayPals fraud prevention might block processing of individual payments "
#| "for a considerable amount of time. The payment is marked as \"pending\" "
#| "during this time window. You can allow your customers to start another "
#| "payment attempts during that window. This might result in them being "
#| "charged twice if theoriginal payment is approved."
msgid ""
"PayPals fraud prevention might block processing of individual payments for a "
"considerable amount of time. The payment is marked as \"pending\" during "
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-24 15:35+0000\n"
"PO-Revision-Date: 2026-08-24 15:31+0000\n"
"PO-Revision-Date: 2026-08-25 00:00+0000\n"
"Last-Translator: Raphael Michel <michel@rami.io>\n"
"Language-Team: German (informal) <https://translate.pretix.eu/projects/"
"pretix/pretix/de_Informal/>\n"
@@ -31761,13 +31761,6 @@ msgid "Allow further payments during compliance hold"
msgstr "Erlaube weitere Zahlungsversuche während PayPal eine Zahlung überprüft"
#: pretix/plugins/paypal2/payment.py
#, fuzzy
#| msgid ""
#| "PayPals fraud prevention might block processing of individual payments "
#| "for a considerable amount of time. The payment is marked as \"pending\" "
#| "during this time window. You can allow your customers to start another "
#| "payment attempts during that window. This might result in them being "
#| "charged twice if theoriginal payment is approved."
msgid ""
"PayPals fraud prevention might block processing of individual payments for a "
"considerable amount of time. The payment is marked as \"pending\" during "
+111 -176
View File
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-24 15:35+0000\n"
"PO-Revision-Date: 2026-07-08 16:00+0000\n"
"PO-Revision-Date: 2026-08-25 00:00+0000\n"
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix/"
"es/>\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 2026.6.1\n"
"X-Generator: Weblate 2026.8.1\n"
#: pretix/_base_settings.py
msgid "English"
@@ -93,7 +93,7 @@ msgstr "Hebreo"
#: pretix/_base_settings.py
msgid "Hungarian"
msgstr ""
msgstr "Húngaro"
#: pretix/_base_settings.py
msgid "Indonesian"
@@ -439,10 +439,8 @@ msgid "You cannot exchange a medium for a medium."
msgstr "No se puede cambiar un medio por otro."
#: pretix/api/views/checkin.py
#, fuzzy
#| msgid "Product does not support medium exchange."
msgid "You cannot simulate a medium exchange."
msgstr "Este producto no admite el cambio de medio."
msgstr "No se puede simular un intercambio de medio."
#: pretix/api/views/oauth.py pretix/control/logdisplay.py
#, python-brace-format
@@ -1401,10 +1399,8 @@ msgid "Membership type"
msgstr "Tipo de suscripción"
#: pretix/base/exporters/customers.py
#, fuzzy
#| msgid "Purchase time"
msgid "Purchase ticket"
msgstr "Hora de compra"
msgstr "Comprar entrada"
#: pretix/base/exporters/customers.py pretix/base/exporters/orderlist.py
#: pretix/base/exporters/waitinglist.py pretix/base/forms/questions.py
@@ -1421,8 +1417,6 @@ msgid "Start date"
msgstr "Fecha de inicio"
#: pretix/base/exporters/customers.py
#, fuzzy
#| msgid "Start time from"
msgid "Start time"
msgstr "Hora de inicio"
@@ -1437,10 +1431,8 @@ msgid "End date"
msgstr "Fecha final"
#: pretix/base/exporters/customers.py
#, fuzzy
#| msgid "End: %(time)s"
msgid "End time"
msgstr "Fin: %(time)s"
msgstr "Hora de finalización"
#: pretix/base/exporters/dekodi.py pretix/base/exporters/invoices.py
msgctxt "export_category"
@@ -4687,16 +4679,13 @@ msgid "This event is remote or partially remote."
msgstr "Este evento es remoto o parcialmente remoto."
#: pretix/base/models/event.py
#, fuzzy
#| msgid ""
#| "This will be used to let users know if the event is in a different "
#| "timezone and lets us calculate users local times."
msgid ""
"This will be used to let users know if the event is in a different timezone, "
"and to let us calculate the local time of a user."
msgstr ""
"Esto se utilizará para que los usuarios sepan si el evento se celebra en una "
"zona horaria diferente y nos permite calcular la hora local de los usuarios."
"Esto servirá para informar a los usuarios de si el evento se celebra en una "
"zona horaria diferente y para que podamos calcular la hora local de cada "
"usuario."
#: pretix/base/models/event.py pretix/base/models/organizer.py
#: pretix/control/navigation.py
@@ -5823,7 +5812,7 @@ msgstr "Código de país (ISO 3166-1 alfa-2)"
#: pretix/base/models/items.py
msgid "Asked on"
msgstr ""
msgstr "Preguntado el"
#: pretix/base/models/items.py pretix/base/models/organizer.py
msgid ""
@@ -7523,9 +7512,6 @@ msgid "The payment for this invoice has already been received."
msgstr "El pago de esta factura ya se ha recibido."
#: pretix/base/payment.py
#, fuzzy
#| msgid ""
#| "This payment is already being processed and can not be canceled any more."
msgid ""
"This payment is already being processed and cannot be canceled any more."
msgstr "Este pago ya se está procesando y ya no se puede cancelar."
@@ -7652,15 +7638,12 @@ msgid "This gift card was used in the meantime. Please try again."
msgstr "Mientras tanto, esta tarjeta de regalo se utilizó. Inténtalo de nuevo."
#: pretix/base/payment.py
#, fuzzy
#| msgid ""
#| "This payment provider does not exist or the respective plugin is disabled."
msgid ""
"This payment provider exists for historical purposes only and is no longer "
"usable."
msgstr ""
"Este proveedor de pago no existe o el plugin correspondiente está "
"desactivado."
"Este proveedor de pagos se mantiene únicamente con fines históricos y ya no "
"se puede utilizar."
#: pretix/base/pdf.py
msgid "Ticket code (barcode content)"
@@ -8302,16 +8285,12 @@ msgid "Presale end"
msgstr "Fin de la preventa"
#: pretix/base/reldate.py
#, fuzzy
#| msgid "Order email"
msgid "Order creation"
msgstr "Correo electrónico del pedido"
msgstr "Creación de pedidos"
#: pretix/base/reldate.py
#, fuzzy
#| msgid "Order expired"
msgid "Order expiry"
msgstr "Pedido caducado"
msgstr "Caducidad del pedido"
#: pretix/base/reldate.py
msgid "before"
@@ -8340,22 +8319,22 @@ msgstr "No fijado"
#: pretix/base/reldate.py
#, python-brace-format
msgid "A relative date cannot be expressed as \"before\" for \"{}\""
msgstr ""
msgstr "Una fecha relativa no puede expresarse como «antes de» para «{}»"
#: pretix/base/reldate.py
#, python-brace-format
msgid "A relative date cannot be expressed as \"after\" for \"{}\""
msgstr ""
msgstr "Una fecha relativa no puede expresarse como «después de» para «{}»"
#: pretix/base/reldate.py
#, python-brace-format
msgid "A relative time cannot be expressed as \"before\" for \"{}\""
msgstr ""
msgstr "Un tiempo relativo no puede expresarse como «antes de» para «{}»"
#: pretix/base/reldate.py
#, python-brace-format
msgid "A relative time cannot be expressed as \"after\" for \"{}\""
msgstr ""
msgstr "Un tiempo relativo no puede expresarse como «después de» para «{}»"
#: pretix/base/secrets.py
msgid "Random (default, works with all pretix apps)"
@@ -9597,16 +9576,12 @@ msgstr ""
"una tarjeta regalo."
#: pretix/base/services/orders.py
#, fuzzy
#| msgid ""
#| "You cannot change the price of a position that has been used to issue a "
#| "gift card."
msgid ""
"You cannot change the ticket secret of a position that has been used to "
"issue a gift card."
msgstr ""
"No se puede cambiar el precio de una posición que se ha usado para entregar "
"una tarjeta regalo."
"No se puede modificar el código secreto de un ticket correspondiente a una "
"posición que se haya utilizado para emitir una tarjeta regalo."
#: pretix/base/services/orders.py
#, python-brace-format
@@ -10385,12 +10360,12 @@ msgstr ""
#: pretix/base/settings.py
msgid "No dates match your criteria."
msgstr ""
msgstr "No hay fechas que se ajusten a tus criterios."
#: pretix/base/settings.py
msgctxt "subevents"
msgid "Text for empty date results"
msgstr ""
msgstr "Texto para los resultados con fechas vacías"
#: pretix/base/settings.py
msgctxt "subevents"
@@ -10401,6 +10376,11 @@ msgid ""
"touch with you to arrange further dates. We do not recommend more than one "
"or two sentences."
msgstr ""
"Este texto aparecerá si el calendario o la lista de fechas están vacíos, por "
"ejemplo, porque un mes no contiene ninguna fecha o porque el filtro "
"seleccionado por el usuario no arroja ningún resultado. Puedes aprovecharlo "
"para indicar cómo ponerse en contacto contigo para concertar otras citas. No "
"recomendamos que superen una o dos frases."
#: pretix/base/settings.py
msgid "Guidance text"
@@ -14360,28 +14340,20 @@ msgstr ""
"año en el que se emite la tarjeta de regalo."
#: pretix/control/forms/event.py
#, fuzzy
#| msgid "Payment date"
msgid "Payment term"
msgstr "Fecha de pago"
msgstr "Condiciones de pago"
#: pretix/control/forms/event.py
#, fuzzy
#| msgid "(Same as above)"
msgid "same as above"
msgstr "(Lo mismo que arriba)"
msgstr "igual que arriba"
#: pretix/control/forms/event.py
#, fuzzy
#| msgid "Payment term in days"
msgid "different payment term in days"
msgstr "Plazo de pago en días"
msgstr "plazo de pago diferente en días"
#: pretix/control/forms/event.py
#, fuzzy
#| msgid "Payment term in minutes"
msgid "different payment term in minutes"
msgstr "Plazo de pago en minutos"
msgstr "plazo de pago diferente en minutos"
#: pretix/control/forms/event.py
msgid "Prices including tax"
@@ -15136,7 +15108,7 @@ msgstr "Fecha final"
#: pretix/control/forms/filter.py
msgid "Start time from"
msgstr "Hora de inicio"
msgstr "Hora de inicio a partir de"
#: pretix/control/forms/filter.py
msgid "Start time until"
@@ -15396,10 +15368,8 @@ msgid "Source"
msgstr "Fuente"
#: pretix/control/forms/filter.py
#, fuzzy
#| msgid "All vouchers"
msgid "All sources"
msgstr "Todos los vales de compra"
msgstr "Todas las fuentes"
#: pretix/control/forms/filter.py
msgid "Team actions"
@@ -15410,16 +15380,12 @@ msgid "Customer actions"
msgstr "Acciones de los clientes"
#: pretix/control/forms/filter.py
#, fuzzy
#| msgid "Device status"
msgid "Device actions"
msgstr "Estado de los dispositivos"
msgstr "Acciones del dispositivo"
#: pretix/control/forms/filter.py
#, fuzzy
#| msgid "Order email"
msgid "User email"
msgstr "Correo electrónico del pedido"
msgstr "Correo electrónico del usuario"
#: pretix/control/forms/filter.py pretix/control/navigation.py
msgid "All users"
@@ -16941,40 +16907,33 @@ msgid ""
"because at least one of the selected vouchers has already been redeemed "
"%(max_redeemed)s times."
msgstr ""
"No puedes reducir el número máximo de canjes a %(max_usages)s, ya que al "
"menos uno de los vales seleccionados ya se ha canjeado %(max_redeemed)s "
"veces."
#: pretix/control/forms/vouchers.py
#, fuzzy
#| msgid ""
#| "You cannot create a voucher that blocks quota as the selected product or "
#| "quota is currently sold out or completely reserved."
msgid ""
"You cannot create a voucher that allows selection of a quota but has no date "
"selected."
msgstr ""
"No se puede crear un vale de compra que bloquee la cuota ya que el producto "
"seleccionado o la cuota está agotada o completamente reservada."
"No se puede crear un comprobante que permita seleccionar una cuota pero en "
"el que no se haya seleccionado ninguna fecha."
#: pretix/control/forms/vouchers.py
#, fuzzy
#| msgid "The selected product does not allow to select a seat."
msgid "The selected quota does not match the selected subevent."
msgstr "El producto seleccionado no permite seleccionar una butaca."
msgstr "La cuota seleccionada no coincide con el subevento seleccionado."
#: pretix/control/forms/vouchers.py
#, fuzzy
#| msgid ""
#| "There is not enough quota available on quota \"{}\" to perform the "
#| "operation."
msgid "There is no sufficient quota available to perform this change."
msgstr ""
"No hay suficiente cuota disponible en la cuota \"{}\" para realizar esta "
"operación."
msgstr "No hay cuota suficiente disponible para realizar este cambio."
#: pretix/control/forms/vouchers.py
msgid ""
"Changing the maximum number of usages in bulk is not supported if any of the "
"selected vouchers is assigned a seat."
msgstr ""
"No es posible modificar de forma masiva el número máximo de usos si a alguno "
"de los vales seleccionados se le ha asignado una plaza."
#: pretix/control/forms/vouchers.py
msgctxt "subevent"
@@ -16982,18 +16941,24 @@ msgid ""
"Changing the date in bulk is not supported if any of the selected vouchers "
"is assigned a seat."
msgstr ""
"No es posible modificar la fecha de forma masiva si a alguno de los "
"comprobantes seleccionados se le ha asignado una plaza."
#: pretix/control/forms/vouchers.py
msgid ""
"Changing the product to a quota is not supported if any of the selected "
"vouchers is assigned a seat."
msgstr ""
"No es posible cambiar el producto a una cuota si a alguno de los vales "
"seleccionados se le ha asignado una plaza."
#: pretix/control/forms/vouchers.py
msgid ""
"This change cannot be completed because not all assigned seats of the "
"vouchers are still available"
msgstr ""
"No es posible completar este cambio porque no todos los asientos asignados "
"de los vales siguen estando disponibles"
#: pretix/control/forms/vouchers.py
msgid "Codes"
@@ -20448,34 +20413,24 @@ msgstr ""
"¡Genial!"
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
#, fuzzy
#| msgid "Your new SPF record could look like this:"
msgid "Your new DKIM record should be set up as a CNAME record like this:"
msgstr "El nuevo registro SPF podría tener el siguiente aspecto:"
msgstr ""
"El nuevo registro DKIM debe configurarse como un registro CNAME de la "
"siguiente manera:"
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
#, fuzzy
#| msgid ""
#| "We found an SPF record on your domain that includes this system. Great!"
msgid "We found a DKIM record on your domain for this system. Great!"
msgstr ""
"Hemos encontrado un registro SPF en su dominio que incluye este sistema. "
"¡Genial!"
"Hemos encontrado un registro DKIM en tu dominio para este sistema. ¡Genial!"
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
#, fuzzy
#| msgid "Your new SPF record could look like this:"
msgid "Your new DMARC record could look like this:"
msgstr "El nuevo registro SPF podría tener el siguiente aspecto:"
msgstr "El nuevo registro DMARC podría tener este aspecto:"
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
#, fuzzy
#| msgid ""
#| "We found an SPF record on your domain that includes this system. Great!"
msgid "We found a DMARC record on your domain for this system. Great!"
msgstr ""
"Hemos encontrado un registro SPF en su dominio que incluye este sistema. "
"¡Genial!"
"Hemos encontrado un registro DMARC en tu dominio para este sistema. ¡Genial!"
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
msgid "Verification"
@@ -22186,10 +22141,8 @@ msgid "The quick brown fox jumps over the lazy dog."
msgstr "El veloz zorro marrón salta sobre el perro perezoso."
#: pretix/control/templates/pretixcontrol/fragment_log_filter_form.html
#, fuzzy
#| msgid "Specific seat"
msgid "Specific object selected"
msgstr "Butaca especifica"
msgstr "Se ha seleccionado un objeto concreto"
#: pretix/control/templates/pretixcontrol/fragment_quota_box.html
#: pretix/control/templates/pretixcontrol/fragment_quota_box_paid.html
@@ -23262,28 +23215,24 @@ msgstr ""
"sus usuarios acerca de las necesidades dietéticas."
#: pretix/control/templates/pretixcontrol/items/questions.html
#, fuzzy
#| msgid "Create a new question"
msgid "Create a new per-ticket question"
msgstr "Crear una nueva pregunta"
msgstr "Crear una nueva pregunta por ticket"
#: pretix/control/templates/pretixcontrol/items/questions.html
#, fuzzy
#| msgid "Create a new question"
msgid "Create a new order-level question"
msgstr "Crear una nueva pregunta"
msgstr "Crear una nueva pregunta a nivel de pedido"
#: pretix/control/templates/pretixcontrol/items/questions.html
#, fuzzy
#| msgid "Delete question"
msgid "Per-ticket questions"
msgstr "Borrar pregunta"
msgstr "Preguntas por entrada"
#: pretix/control/templates/pretixcontrol/items/questions.html
msgid ""
"These questions are asked for every ticket, so possibly multiple times in "
"the same order."
msgstr ""
"Estas preguntas se formulan para cada entrada, por lo que es posible que se "
"repitan varias veces en el mismo pedido."
#: pretix/control/templates/pretixcontrol/items/questions.html
msgid "Create a new question"
@@ -23302,28 +23251,28 @@ msgid "All personalized products"
msgstr "Todos los productos personalizados"
#: pretix/control/templates/pretixcontrol/items/questions.html
#, fuzzy
#| msgid "Include questions"
msgid "Per-order questions"
msgstr "Incluir preguntas"
msgstr "Preguntas por pedido"
#: pretix/control/templates/pretixcontrol/items/questions.html
msgid ""
"This functionality is in active development and expected to change "
"significantly over the coming months."
msgstr ""
"Esta funcionalidad se encuentra en fase de desarrollo activo y se prevé que "
"sufra cambios significativos en los próximos meses."
#: pretix/control/templates/pretixcontrol/items/questions.html
msgid ""
"Per-order questions are currently not supported and will not be displayed in "
"pretixPOS."
msgstr ""
"Actualmente no se admiten las preguntas por pedido y no se mostrarán en "
"pretixPOS."
#: pretix/control/templates/pretixcontrol/items/questions.html
#, fuzzy
#| msgid "The question has been reordered."
msgid "These questions are asked once per order."
msgstr "La pregunta ha sido reordenada."
msgstr "Estas preguntas se formulan una vez por pedido."
#: pretix/control/templates/pretixcontrol/items/quota.html
#: pretix/control/templates/pretixcontrol/items/quota_edit.html
@@ -23855,6 +23804,8 @@ msgid ""
"Ticket secrets of order positions that have been used to issue a gift card "
"can not be changed. Only the link will be changed in this case."
msgstr ""
"Los datos de los pedidos que se han utilizado para emitir una tarjeta regalo "
"no se pueden modificar. En este caso, solo se modificará el enlace."
#: pretix/control/templates/pretixcontrol/order/change.html
msgid ""
@@ -23930,10 +23881,8 @@ msgstr "(opcional)"
#: pretix/presale/templates/pretixpresale/event/checkout_confirm.html
#: pretix/presale/templates/pretixpresale/event/checkout_questions.html
#: pretix/presale/templates/pretixpresale/event/order_modify.html
#, fuzzy
#| msgid "Additional information"
msgid "Additional order information"
msgstr "Información adicional"
msgstr "Información adicional sobre el pedido"
#: pretix/control/templates/pretixcontrol/order/delete.html
msgid "Delete order"
@@ -25635,14 +25584,13 @@ msgid "Hardware model"
msgstr "Modelo del Hardware"
#: pretix/control/templates/pretixcontrol/organizers/devices.html
#, fuzzy, python-format
#| msgid "Begin: %(time)s"
#, python-format
msgid "Last seen: %(time)s"
msgstr "Inicio: %(time)s"
msgstr "Última conexión: %(time)s"
#: pretix/control/templates/pretixcontrol/organizers/devices.html
msgid "No recent contact"
msgstr ""
msgstr "No ha habido contacto reciente"
#: pretix/control/templates/pretixcontrol/organizers/devices.html
msgid "Not yet initialized"
@@ -27991,10 +27939,8 @@ msgstr ""
"producto!"
#: pretix/control/templates/pretixcontrol/vouchers/bulk_edit.html
#, fuzzy
#| msgid "Create multiple vouchers"
msgid "Change multiple vouchers"
msgstr "Crear múltiples vales de compra"
msgstr "Modificar varios vales"
#: pretix/control/templates/pretixcontrol/vouchers/delete.html
#: pretix/control/templates/pretixcontrol/vouchers/detail.html
@@ -28405,6 +28351,9 @@ msgid ""
"team. If you want to add a different user or create a new account, log out "
"and click the invitation link again."
msgstr ""
"No puedes aceptar la invitación para «{}», ya que ya formas parte de este "
"equipo. Si quieres añadir a otro usuario o crear una nueva cuenta, cierra la "
"sesión y vuelve a hacer clic en el enlace de invitación."
#: pretix/control/views/auth.py
#, python-brace-format
@@ -29088,13 +29037,6 @@ msgstr ""
"SPF."
#: pretix/control/views/mailsetup.py
#, fuzzy
#| msgid ""
#| "We could not find an SPF record set for the domain you are trying to use. "
#| "This means that there is a very high change most of the emails will be "
#| "rejected or marked as spam. We strongly recommend setting an SPF record "
#| "on the domain. You can do so through the DNS settings at the provider you "
#| "registered your domain with."
msgid ""
"We could not find a CNAME record pointing to our DKIM key for domain you are "
"trying to use. This means that there is a very high change most of the "
@@ -29102,53 +29044,35 @@ msgid ""
"DKIM through a CNAME record. You can do so through the DNS settings at the "
"provider you registered your domain with."
msgstr ""
"No se pudo encontrar un registro SPF configurado para el dominio que está "
"intentando usar. Esto significa que existe una alta probabilidad de que la "
"mayoría de los correos electrónicos sean rechazados o marcados como spam. "
"Recomendamos encarecidamente configurar un registro SPF en el dominio. Puede "
"hacerlo a través de la configuración de DNS en el proveedor con el que "
"registró su dominio."
"No hemos podido encontrar un registro CNAME que apunte a nuestra clave DKIM "
"para el dominio que estás intentando utilizar. Esto significa que hay una "
"probabilidad muy alta de que la mayoría de los correos electrónicos sean "
"rechazados o marcados como spam. Te recomendamos encarecidamente que "
"configures DKIM mediante un registro CNAME. Puedes hacerlo a través de la "
"configuración de DNS del proveedor con el que registraste tu dominio."
#: pretix/control/views/mailsetup.py
#, fuzzy
#| msgid ""
#| "We found an SPF record set for the domain you are trying to use, but it "
#| "does not include this system's email server. This means that there is a "
#| "very high chance most of the emails will be rejected or marked as spam. "
#| "You should update the DNS settings of your domain to include this system "
#| "in the SPF record."
msgid ""
"We found a CNAME record for a DKIM key, but it is not pointing to the right "
"location. This means that there is a very high chance most of the emails "
"will be rejected or marked as spam. You should update the DNS settings of "
"your domain."
msgstr ""
"Hemos encontrado un registro SPF configurado para el dominio que está "
"intentando utilizar, pero no incluye el servidor de correo electrónico del "
"mismo sistema. Esto significa que es muy probable que la mayoría de los "
"correos electrónicos sean rechazados o marcados como spam. Debe actualizar "
"la configuración DNS de su dominio para incluir este sistema en el registro "
"SPF."
"Hemos encontrado un registro CNAME para una clave DKIM, pero no apunta a la "
"ubicación correcta. Esto significa que hay muchas posibilidades de que la "
"mayoría de los correos electrónicos sean rechazados o marcados como spam. "
"Deberías actualizar la configuración DNS de tu dominio."
#: pretix/control/views/mailsetup.py
#, fuzzy
#| msgid ""
#| "We found an SPF record set for the domain you are trying to use, but it "
#| "does not include this system's email server. This means that there is a "
#| "very high chance most of the emails will be rejected or marked as spam. "
#| "You should update the DNS settings of your domain to include this system "
#| "in the SPF record."
msgid ""
"We did not find a DMARC record for your domain. This means that there is a "
"very high chance most of the emails will be rejected or marked as spam. You "
"should update the DNS settings of your domain."
msgstr ""
"Hemos encontrado un registro SPF configurado para el dominio que está "
"intentando utilizar, pero no incluye el servidor de correo electrónico del "
"mismo sistema. Esto significa que es muy probable que la mayoría de los "
"correos electrónicos sean rechazados o marcados como spam. Debe actualizar "
"la configuración DNS de su dominio para incluir este sistema en el registro "
"SPF."
"No hemos encontrado ningún registro DMARC para tu dominio. Esto significa "
"que hay muchas posibilidades de que la mayoría de los correos electrónicos "
"sean rechazados o marcados como spam. Deberías actualizar la configuración "
"DNS de tu dominio."
#: pretix/control/views/mailsetup.py
msgid "The verification code was incorrect, please try again."
@@ -31901,6 +31825,7 @@ msgstr ""
#: pretix/plugins/paypal2/payment.py
msgid "Allow further payments during compliance hold"
msgstr ""
"Permitir que se realicen más pagos durante la suspensión por incumplimiento"
#: pretix/plugins/paypal2/payment.py
msgid ""
@@ -31910,16 +31835,24 @@ msgid ""
"attempts during that window. This might result in them being charged twice "
"if the original payment is approved."
msgstr ""
"El sistema de prevención de fraudes de PayPal podría bloquear la tramitación "
"de pagos individuales durante un periodo de tiempo considerable. Durante ese "
"intervalo, el pago aparece como «pendiente». Puedes permitir que tus "
"clientes realicen nuevos intentos de pago durante ese intervalo. Esto podría "
"dar lugar a que se les cobre dos veces si se aprueba el pago original."
#: pretix/plugins/paypal2/payment.py
msgid "Timeout further payment attempts"
msgstr ""
msgstr "Tiempo de espera para nuevos intentos de pago"
#: pretix/plugins/paypal2/payment.py
msgid ""
"Time duration in minutes after which another payment attempt is possible, "
"while the last payment is still under investigation."
msgstr ""
"Tiempo, expresado en minutos, transcurrido tras el cual es posible realizar "
"otro intento de pago, mientras el último pago sigue siendo objeto de "
"investigación."
#: pretix/plugins/paypal2/payment.py
msgid "-- Automatic --"
@@ -32188,6 +32121,11 @@ msgid ""
"twice in case PayPal allows your initial payment attempt. Please contact us "
"to resolve this case."
msgstr ""
"PayPal está procesando tu pago. Este proceso está tardando más de lo "
"habitual. Puedes esperar a que PayPal confirme el pago o intentar volver a "
"pagar con este u otro método de pago. Esto podría dar lugar a que se te "
"cobre dos veces en caso de que PayPal acepte tu primer intento de pago. "
"Ponte en contacto con nosotros para resolver este asunto."
#: pretix/plugins/paypal2/views.py
msgid ""
@@ -32439,24 +32377,21 @@ msgid "Base redirection URLs"
msgstr "URL de redirección de base"
#: pretix/plugins/returnurl/views.py
#, fuzzy
#| msgid ""
#| "Redirection will only be allowed to URLs that start with one of these "
#| "prefixes. Enter one or more allowed URL prefix per line. URL prefixes "
#| "must include a slash after the hostname."
msgid ""
"Redirection will only be allowed to URLs that start with one of these "
"prefixes. Enter one allowed URL prefix per line. URL prefixes must include a "
"slash after the hostname."
msgstr ""
"La redirección sólo se permitirá a las URL que empiecen por uno de estos "
"prefijos. Introduzca uno o más prefijos de URL permitidos por línea. Los "
"Solo se permitirá la redirección a direcciones URL que empiecen por uno de "
"estos prefijos. Introduce un prefijo de URL permitido por línea. Los "
"prefijos de URL deben incluir una barra después del nombre de host."
#: pretix/plugins/returnurl/views.py
msgid ""
"All values must be URLs that include at last one slash after the hostname."
msgstr ""
"Todos los valores deben ser direcciones URL que incluyan al menos una barra "
"después del nombre de host."
#: pretix/plugins/sendmail/apps.py
msgid "Send out emails to all your customers or specific groups of customers."
+77 -110
View File
@@ -4,10 +4,10 @@ msgstr ""
"Project-Id-Version: 1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-24 15:35+0000\n"
"PO-Revision-Date: 2026-08-11 17:00+0000\n"
"Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n"
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix/fr/"
">\n"
"PO-Revision-Date: 2026-08-25 00:00+0000\n"
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix/"
"fr/>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -89,7 +89,7 @@ msgstr "Hébreu"
#: pretix/_base_settings.py
msgid "Hungarian"
msgstr ""
msgstr "Hongrois"
#: pretix/_base_settings.py
msgid "Indonesian"
@@ -438,10 +438,8 @@ msgid "You cannot exchange a medium for a medium."
msgstr "Il n'est pas possible d'échanger un support contre un autre support."
#: pretix/api/views/checkin.py
#, fuzzy
#| msgid "Product does not support medium exchange."
msgid "You cannot simulate a medium exchange."
msgstr "Ce produit ne permet pas de changer de support."
msgstr "l n'est pas possible de simuler un échange de support."
#: pretix/api/views/oauth.py pretix/control/logdisplay.py
#, python-brace-format
@@ -5833,7 +5831,7 @@ msgstr "Code pays (ISO 3166-1 alpha-2)"
#: pretix/base/models/items.py
msgid "Asked on"
msgstr ""
msgstr "Question posée le"
#: pretix/base/models/items.py pretix/base/models/organizer.py
msgid ""
@@ -7555,9 +7553,6 @@ msgid "The payment for this invoice has already been received."
msgstr "Le paiement de cette facture a déjà été reçu."
#: pretix/base/payment.py
#, fuzzy
#| msgid ""
#| "This payment is already being processed and can not be canceled any more."
msgid ""
"This payment is already being processed and cannot be canceled any more."
msgstr ""
@@ -8340,16 +8335,12 @@ msgid "Presale end"
msgstr "Fin de la prévente"
#: pretix/base/reldate.py
#, fuzzy
#| msgid "Order email"
msgid "Order creation"
msgstr "E-mail de la commande"
msgstr "Création d'une commande"
#: pretix/base/reldate.py
#, fuzzy
#| msgid "Order expired"
msgid "Order expiry"
msgstr "Commande expirée"
msgstr "Expiration de la commande"
#: pretix/base/reldate.py
msgid "before"
@@ -8378,22 +8369,22 @@ msgstr "Non réglé"
#: pretix/base/reldate.py
#, python-brace-format
msgid "A relative date cannot be expressed as \"before\" for \"{}\""
msgstr ""
msgstr "Une date relative ne peut pas être exprimée par « avant » pour « {} »"
#: pretix/base/reldate.py
#, python-brace-format
msgid "A relative date cannot be expressed as \"after\" for \"{}\""
msgstr ""
msgstr "Une date relative ne peut pas être exprimée par « après » pour « {} »"
#: pretix/base/reldate.py
#, python-brace-format
msgid "A relative time cannot be expressed as \"before\" for \"{}\""
msgstr ""
msgstr "Une durée relative ne peut pas être exprimée par « avant » pour « {} »"
#: pretix/base/reldate.py
#, python-brace-format
msgid "A relative time cannot be expressed as \"after\" for \"{}\""
msgstr ""
msgstr "Un temps relatif ne peut pas être exprimé par « après » pour « {} »"
#: pretix/base/secrets.py
msgid "Random (default, works with all pretix apps)"
@@ -10430,12 +10421,12 @@ msgstr ""
#: pretix/base/settings.py
msgid "No dates match your criteria."
msgstr ""
msgstr "Aucune date ne correspond à vos critères."
#: pretix/base/settings.py
msgctxt "subevents"
msgid "Text for empty date results"
msgstr ""
msgstr "Texte à afficher lorsque les résultats ne contiennent aucune date"
#: pretix/base/settings.py
msgctxt "subevents"
@@ -10446,6 +10437,11 @@ msgid ""
"touch with you to arrange further dates. We do not recommend more than one "
"or two sentences."
msgstr ""
"Ce texte s'affichera si le calendrier ou la liste des dates est vide, par "
"exemple parce qu'un mois ne comporte aucune date ou qu'un filtre sélectionné "
"par l'utilisateur ne donne aucun résultat. Vous pouvez en profiter pour "
"indiquer comment vous contacter afin de convenir d'autres dates. Nous vous "
"recommandons de ne pas dépasser une ou deux phrases."
#: pretix/base/settings.py
msgid "Guidance text"
@@ -14479,28 +14475,20 @@ msgstr ""
"plus lannée d’émission de la carte-cadeau."
#: pretix/control/forms/event.py
#, fuzzy
#| msgid "Payment date"
msgid "Payment term"
msgstr "Date de paiement"
msgstr "Conditions de paiement"
#: pretix/control/forms/event.py
#, fuzzy
#| msgid "(Same as above)"
msgid "same as above"
msgstr "(identique à ce qui précède)"
msgstr "idem que ci-dessus"
#: pretix/control/forms/event.py
#, fuzzy
#| msgid "Payment term in days"
msgid "different payment term in days"
msgstr "Délai de paiement en jours"
msgstr "délai de paiement différent en jours"
#: pretix/control/forms/event.py
#, fuzzy
#| msgid "Payment term in minutes"
msgid "different payment term in minutes"
msgstr "Délai de paiement en minutes"
msgstr "durée de paiement différente en minutes"
#: pretix/control/forms/event.py
msgid "Prices including tax"
@@ -20577,26 +20565,20 @@ msgstr ""
"CNAME comme ceci :"
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
#, fuzzy
#| msgid ""
#| "We found an SPF record on your domain that includes this system. Great!"
msgid "We found a DKIM record on your domain for this system. Great!"
msgstr ""
"Nous avons trouvé un enregistrement SPF sur votre domaine qui inclut ce "
"système. Super !"
"Nous avons trouvé un enregistrement DKIM sur votre domaine pour ce système. "
"Parfait!"
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
msgid "Your new DMARC record could look like this:"
msgstr "Votre nouvel enregistrement DMARC pourrait ressembler à ceci :"
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
#, fuzzy
#| msgid ""
#| "We found an SPF record on your domain that includes this system. Great!"
msgid "We found a DMARC record on your domain for this system. Great!"
msgstr ""
"Nous avons trouvé un enregistrement SPF sur votre domaine qui inclut ce "
"système. Super !"
"Nous avons trouvé un enregistrement DMARC sur votre domaine pour ce système. "
"Parfait!"
#: pretix/control/templates/pretixcontrol/email_setup_simple.html
msgid "Verification"
@@ -23407,28 +23389,24 @@ msgstr ""
"besoins alimentaires."
#: pretix/control/templates/pretixcontrol/items/questions.html
#, fuzzy
#| msgid "Create a new question"
msgid "Create a new per-ticket question"
msgstr "Créer une nouvelle question"
msgstr "Créer une nouvelle question spécifique à chaque ticket"
#: pretix/control/templates/pretixcontrol/items/questions.html
#, fuzzy
#| msgid "Create a new question"
msgid "Create a new order-level question"
msgstr "Créer une nouvelle question"
msgstr "Créer une nouvelle question au niveau de la commande"
#: pretix/control/templates/pretixcontrol/items/questions.html
#, fuzzy
#| msgid "Delete question"
msgid "Per-ticket questions"
msgstr "Supprimer la question"
msgstr "Questions relatives à chaque billet"
#: pretix/control/templates/pretixcontrol/items/questions.html
msgid ""
"These questions are asked for every ticket, so possibly multiple times in "
"the same order."
msgstr ""
"Ces questions sont posées pour chaque billet, et peuvent donc être posées "
"plusieurs fois au cours d'une même commande."
#: pretix/control/templates/pretixcontrol/items/questions.html
msgid "Create a new question"
@@ -23447,28 +23425,28 @@ msgid "All personalized products"
msgstr "Tous les produits personnalisés"
#: pretix/control/templates/pretixcontrol/items/questions.html
#, fuzzy
#| msgid "Include questions"
msgid "Per-order questions"
msgstr "Inclure des questions"
msgstr "Questions relatives à chaque commande"
#: pretix/control/templates/pretixcontrol/items/questions.html
msgid ""
"This functionality is in active development and expected to change "
"significantly over the coming months."
msgstr ""
"Cette fonctionnalité est en cours de développement et devrait évoluer "
"considérablement au cours des prochains mois."
#: pretix/control/templates/pretixcontrol/items/questions.html
msgid ""
"Per-order questions are currently not supported and will not be displayed in "
"pretixPOS."
msgstr ""
"Les questions spécifiques à chaque commande ne sont actuellement pas prises "
"en charge et n'apparaîtront pas dans pretixPOS."
#: pretix/control/templates/pretixcontrol/items/questions.html
#, fuzzy
#| msgid "The question has been reordered."
msgid "These questions are asked once per order."
msgstr "La question a été réordonnée."
msgstr "Ces questions sont posées une fois par commande."
#: pretix/control/templates/pretixcontrol/items/quota.html
#: pretix/control/templates/pretixcontrol/items/quota_edit.html
@@ -24080,10 +24058,8 @@ msgstr "(optionnel)"
#: pretix/presale/templates/pretixpresale/event/checkout_confirm.html
#: pretix/presale/templates/pretixpresale/event/checkout_questions.html
#: pretix/presale/templates/pretixpresale/event/order_modify.html
#, fuzzy
#| msgid "Additional information"
msgid "Additional order information"
msgstr "Informations complémentaires"
msgstr "Informations complémentaires sur la commande"
#: pretix/control/templates/pretixcontrol/order/delete.html
msgid "Delete order"
@@ -25799,14 +25775,13 @@ msgid "Hardware model"
msgstr "Modèle de matériel"
#: pretix/control/templates/pretixcontrol/organizers/devices.html
#, fuzzy, python-format
#| msgid "Begin: %(time)s"
#, python-format
msgid "Last seen: %(time)s"
msgstr "Début : %(time)s"
msgstr "Dernière connexion : %(time)s"
#: pretix/control/templates/pretixcontrol/organizers/devices.html
msgid "No recent contact"
msgstr ""
msgstr "Aucun contact récent"
#: pretix/control/templates/pretixcontrol/organizers/devices.html
msgid "Not yet initialized"
@@ -29286,13 +29261,6 @@ msgstr ""
"l'enregistrement SPF."
#: pretix/control/views/mailsetup.py
#, fuzzy
#| msgid ""
#| "We could not find an SPF record set for the domain you are trying to use. "
#| "This means that there is a very high change most of the emails will be "
#| "rejected or marked as spam. We strongly recommend setting an SPF record "
#| "on the domain. You can do so through the DNS settings at the provider you "
#| "registered your domain with."
msgid ""
"We could not find a CNAME record pointing to our DKIM key for domain you are "
"trying to use. This means that there is a very high change most of the "
@@ -29300,53 +29268,35 @@ msgid ""
"DKIM through a CNAME record. You can do so through the DNS settings at the "
"provider you registered your domain with."
msgstr ""
"Nous n'avons pas trouvé d'enregistrement SPF pour le domaine que vous "
"essayez d'utiliser. Cela signifie qu'il y a de fortes chances que la plupart "
"des e-mails soient rejetés ou marqués comme spam. Nous vous recommandons "
"vivement de configurer un enregistrement SPF sur le domaine. Vous pouvez le "
"faire via les paramètres DNS chez le fournisseur auprès duquel vous avez "
"enregistré votre domaine."
"Nous n'avons pas trouvé d'enregistrement CNAME pointant vers notre clé DKIM "
"pour le domaine que vous essayez d'utiliser. Cela signifie qu'il y a de très "
"fortes chances que la plupart des e-mails soient rejetés ou marqués comme "
"spam. Nous vous recommandons vivement de configurer DKIM à l'aide d'un "
"enregistrement CNAME. Vous pouvez le faire via les paramètres DNS chez le "
"fournisseur auprès duquel vous avez enregistré votre domaine."
#: pretix/control/views/mailsetup.py
#, fuzzy
#| msgid ""
#| "We found an SPF record set for the domain you are trying to use, but it "
#| "does not include this system's email server. This means that there is a "
#| "very high chance most of the emails will be rejected or marked as spam. "
#| "You should update the DNS settings of your domain to include this system "
#| "in the SPF record."
msgid ""
"We found a CNAME record for a DKIM key, but it is not pointing to the right "
"location. This means that there is a very high chance most of the emails "
"will be rejected or marked as spam. You should update the DNS settings of "
"your domain."
msgstr ""
"Nous avons trouvé un enregistrement SPF défini pour le domaine que vous "
"essayez d'utiliser, mais il n'inclut pas le serveur de messagerie de ce "
"système. Cela signifie qu'il y a de fortes chances que la plupart des e-"
"mails soient rejetés ou marqués comme spam. Vous devez mettre à jour les "
"paramètres DNS de votre domaine afin d'inclure ce système dans "
"l'enregistrement SPF."
"Nous avons détecté un enregistrement CNAME associé à une clé DKIM, mais "
"celui-ci ne pointe pas vers la bonne adresse. Cela signifie qu'il y a de "
"très fortes chances que la plupart de vos e-mails soient rejetés ou classés "
"comme spam. Vous devez mettre à jour les paramètres DNS de votre domaine."
#: pretix/control/views/mailsetup.py
#, fuzzy
#| msgid ""
#| "We found an SPF record set for the domain you are trying to use, but it "
#| "does not include this system's email server. This means that there is a "
#| "very high chance most of the emails will be rejected or marked as spam. "
#| "You should update the DNS settings of your domain to include this system "
#| "in the SPF record."
msgid ""
"We did not find a DMARC record for your domain. This means that there is a "
"very high chance most of the emails will be rejected or marked as spam. You "
"should update the DNS settings of your domain."
msgstr ""
"Nous avons trouvé un enregistrement SPF défini pour le domaine que vous "
"essayez d'utiliser, mais il n'inclut pas le serveur de messagerie de ce "
"système. Cela signifie qu'il y a de fortes chances que la plupart des e-"
"mails soient rejetés ou marqués comme spam. Vous devez mettre à jour les "
"paramètres DNS de votre domaine afin d'inclure ce système dans "
"l'enregistrement SPF."
"Nous n'avons pas trouvé d'enregistrement DMARC pour votre domaine. Cela "
"signifie qu'il y a de très fortes chances que la plupart de vos e-mails "
"soient rejetés ou marqués comme spam. Vous devriez mettre à jour les "
"paramètres DNS de votre domaine."
#: pretix/control/views/mailsetup.py
msgid "The verification code was incorrect, please try again."
@@ -32032,8 +31982,8 @@ msgid ""
"We're waiting for an answer from PayPal regarding your payment. Please "
"contact us, if this takes more than a few hours."
msgstr ""
"Nous attendons une réponse de PayPal concernant votre paiement. Veuillez "
"nous contacter, si cela prend plus de quelques heures."
"Nous attendons une réponse de PayPal concernant votre paiement. N'hésitez "
"pas à nous contacter si cela prend plus de quelques heures."
#: pretix/plugins/paypal/views.py pretix/plugins/paypal2/views.py
msgid "Invalid response from PayPal received."
@@ -32131,6 +32081,8 @@ msgstr ""
#: pretix/plugins/paypal2/payment.py
msgid "Allow further payments during compliance hold"
msgstr ""
"Autoriser la poursuite des paiements pendant la période de suspension pour "
"non-conformité"
#: pretix/plugins/paypal2/payment.py
msgid ""
@@ -32140,16 +32092,25 @@ msgid ""
"attempts during that window. This might result in them being charged twice "
"if the original payment is approved."
msgstr ""
"Le système de prévention des fraudes de PayPal peut bloquer le traitement de "
"certains paiements pendant une durée considérable. Pendant cette période, le "
"paiement est marqué comme « en attente ». Vous pouvez autoriser vos clients "
"à effectuer de nouvelles tentatives de paiement pendant cette période. Cela "
"peut entraîner un double prélèvement si le paiement initial est finalement "
"approuvé."
#: pretix/plugins/paypal2/payment.py
msgid "Timeout further payment attempts"
msgstr ""
msgstr "Délai d'expiration des tentatives de paiement supplémentaires"
#: pretix/plugins/paypal2/payment.py
msgid ""
"Time duration in minutes after which another payment attempt is possible, "
"while the last payment is still under investigation."
msgstr ""
"Durée en minutes à l'issue de laquelle une nouvelle tentative de paiement "
"est possible, alors que le dernier paiement fait toujours l'objet d'une "
"enquête."
#: pretix/plugins/paypal2/payment.py
msgid "-- Automatic --"
@@ -32427,6 +32388,12 @@ msgid ""
"twice in case PayPal allows your initial payment attempt. Please contact us "
"to resolve this case."
msgstr ""
"Votre paiement est en cours de traitement par PayPal. Cette opération prend "
"plus de temps que d'habitude. Vous pouvez attendre que PayPal valide le "
"paiement ou essayer de payer à nouveau en utilisant ce moyen de paiement ou "
"un autre. Cela pourrait entraîner un double prélèvement si PayPal autorise "
"votre première tentative de paiement. Veuillez nous contacter pour résoudre "
"ce problème."
#: pretix/plugins/paypal2/views.py
msgid ""
+3 -1
View File
@@ -494,6 +494,7 @@ def webhook(request, *args, **kwargs):
elif payment.state in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED,
OrderPayment.PAYMENT_STATE_CANCELED, OrderPayment.PAYMENT_STATE_FAILED):
if sale['status'] == 'COMPLETED':
any_captures = False
all_captures_completed = True
any_pending_review = False
any_failed = None
@@ -505,6 +506,7 @@ def webhook(request, *args, **kwargs):
except ReferencedPayPalObject.MultipleObjectsReturned:
pass
any_captures = True
if capture['status'] in ('COMPLETED', 'REFUNDED', 'PARTIALLY_REFUNDED'):
pass
elif capture['status'] in ("DECLINED", "FAILED"):
@@ -516,7 +518,7 @@ def webhook(request, *args, **kwargs):
any_pending_review = True
else:
raise ValueError("Unknown paypal capture state: {}".format(capture['status']))
if all_captures_completed:
if any_captures and all_captures_completed:
try:
payment.confirm()
prov.log_payment_duration(payment)
+31
View File
@@ -35,6 +35,7 @@ import copy
import inspect
import uuid
from collections import defaultdict
from datetime import time
from decimal import Decimal
from django import forms
@@ -52,6 +53,7 @@ from django.shortcuts import redirect
from django.utils import translation
from django.utils.functional import cached_property
from django.utils.html import conditional_escape
from django.utils.timezone import now
from django.utils.translation import (
get_language, gettext_lazy as _, pgettext_lazy,
)
@@ -71,6 +73,7 @@ from pretix.base.services.cart import (
from pretix.base.services.cross_selling import CrossSellingService
from pretix.base.services.memberships import validate_memberships_in_order
from pretix.base.services.orders import perform_order
from pretix.base.services.payment import compute_payment_deadline
from pretix.base.services.pricing import get_price
from pretix.base.services.tasks import EventTask
from pretix.base.settings import PERSON_NAME_SCHEMES
@@ -840,6 +843,8 @@ class QuestionsStep(CartQuestionsViewMixin, CartMixin, TemplateFlowStep):
f.fields[fname].disabled = val['disabled']
if 'validators' in val and fname in f.fields:
f.fields[fname].validators += val['validators']
if 'label' in val and fname in f.fields:
f.fields[fname].label = val['label']
return f
@@ -944,6 +949,8 @@ class QuestionsStep(CartQuestionsViewMixin, CartMixin, TemplateFlowStep):
f.fields[fname].disabled = val['disabled']
if 'validators' in val and fname in f.fields:
f.fields[fname].validators += val['validators']
if 'label' in val and fname in f.fields:
f.fields[fname].label = val['label']
return f
@@ -1340,6 +1347,11 @@ class PaymentStep(CartMixin, TemplateFlowStep):
self.request = request
self.request.pci_dss_payment_page = True
if "postpone" in request.POST and self._allow_postpone:
self.cart_session['payments_postpone'] = True
self.cart_session['payments'] = []
return redirect_to_url(self.get_next_url(request))
if "remove_payment" in request.POST:
self._remove_payment(request.POST["remove_payment"])
return redirect_to_url(self.get_step_url(request))
@@ -1436,12 +1448,31 @@ class PaymentStep(CartMixin, TemplateFlowStep):
ctx['selected'] = self.single_use_payment['provider']
else:
ctx['selected'] = ''
ctx['allow_postpone'] = self._allow_postpone
if self._allow_postpone:
now_dt = now()
ctx['payment_deadline'] = compute_payment_deadline(
event=self.request.event,
sales_channel=self.request.sales_channel,
subevents={p.subevent for p in ctx['cart']['raw']},
now_dt=now_dt,
)
if ctx['payment_deadline'].time() != time(hour=23, minute=59, second=59):
ctx['payment_deadline_minutes'] = int((ctx['payment_deadline'] - now_dt).total_seconds() // 60)
return ctx
@cached_property
def _allow_postpone(self):
return self.request.sales_channel.identifier in self.request.event.settings.payment_choice_postpone_allowed_channels
def _is_allowed(self, prov, request):
return prov.is_allowed(request, total=self._total_order_value)
def is_completed(self, request, warn=False):
if self.cart_session.get('payments_postpone') and self._allow_postpone:
return True
if not self.cart_session.get('payments'):
if warn:
messages.error(request, _('Please select a payment method to proceed.'))
+1 -1
View File
@@ -334,7 +334,7 @@ class ResetPasswordForm(forms.Form):
def clean_email(self):
if 'email' not in self.cleaned_data:
return
if rate_limit("customer_pwreset_check", max_num=10, expire_time=600):
if rate_limit("customer_pwreset_check", include_ip_from_request=self.request, max_num=10, expire_time=600):
raise forms.ValidationError(
self.error_messages['rate_limit'],
code='rate_limit',
+4 -4
View File
@@ -233,7 +233,7 @@ Arguments: ``request``, ``order``
This signal allows you to override fields of the contact form that is presented during checkout
and by default only asks for the email address. It is also being used for the invoice address
form. You are supposed to return a dictionary of dictionaries with globally unique keys. The
value-dictionary should contain one or more of the following keys: ``initial``, ``disabled``,
value-dictionary should contain one or more of the following keys: ``label``, ``initial``, ``disabled``,
``validators``. The key of the dictionary should be the name of the form field.
As with all event plugin signals, the ``sender`` keyword argument will contain the event. A ``request``
@@ -264,9 +264,9 @@ Arguments: ``position``, ``request``
This signal allows you to override fields of the questions form that is presented during checkout
and by default only asks for the questions configured in the backend. You are supposed to return a
dictionary of dictionaries with globally unique keys. The value-dictionary should contain one or
more of the following keys: ``initial``, ``disabled``, ``validators``. The key of the dictionary
should be the form field name for system fields (e.g. ``company``), or the question's ``identifier``
for user-defined questions.
more of the following keys: ``label``, ``initial``, ``disabled``, ``validators``. The key of the
dictionary should be the form field name for system fields (e.g. ``company``), or the question's
``identifier`` for user-defined questions.
The ``position`` keyword argument will contain a ``CartPosition`` or ``OrderPosition`` object.
@@ -128,6 +128,32 @@
{% endif %}
</div>
{% endif %}
{% if allow_postpone %}
<div class="panel panel-default">
<div class="panel-body row">
<div class="col-md-9 col-xs-12">
{% trans "Not sure yet? You can complete your order first and then select a payment method later." %}
<br>
<span class="text-muted">
{% if payment_deadline_minutes %}
{% blocktrans trimmed with minutes=payment_deadline_minutes %}
Your payment needs to be completed within {{ minutes }} minutes.
{% endblocktrans %}
{% else %}
{% blocktrans trimmed with deadline=payment_deadline|date:"SHORT_DATE_FORMAT" %}
Your payment needs to be completed by {{ deadline }}.
{% endblocktrans %}
{% endif %}
</span>
</div>
<div class="col-md-3 col-xs-12 text-right flip">
<button name="postpone" value="on" class="btn btn-primary">
{% trans "Proceed without selection" %}
</button>
</div>
</div>
</div>
{% endif %}
<div class="row checkout-button-row">
<div class="col-md-4 col-sm-6">
<a class="btn btn-block btn-default btn-lg"
@@ -345,7 +345,7 @@ Vue.component('pricebox', {
+ ' :min="display_price_nonlocalized" :value="suggested_price_nonlocalized" :name="field_name"'
+ ' step="any" v-bind:aria-labelledby="aria_labelledby" v-bind:aria-describedby="price_desc_id">'
+ '</div>'
+ '<small class="pretix-widget-pricebox-tax" :id="price_desc_id" v-if="price.rate != \'0\' && price.gross != \'0.00\'">'
+ '<small class="pretix-widget-pricebox-tax" :id="price_desc_id" v-if="show_taxline">'
+ '{{ taxline }}'
+ '</small>'
+ '</div>'),
@@ -422,6 +422,10 @@ Vue.component('pricebox', {
return '<span class="pretix-widget-pricebox-currency">' + this.$root.currency + "</span> " + this.display_price;
}
},
show_taxline: function () {
// rate can either be "0.00" or "0" => parseFloat to check
return Number.parseFloat(this.price.rate) && Number.parseFloat(this.price.gross);
},
taxline: function () {
if (this.$root.display_net_prices) {
if (this.price.includes_mixed_tax_rate) {
@@ -86,7 +86,8 @@ const taxline = computed(() => {
}
})
const showTaxline = computed(() => props.price.rate !== '0' && props.price.gross !== '0.00')
// rate can either be "0.00" or "0" => parseFloat to check
const showTaxline = computed(() => Number.parseFloat(props.price.rate) && Number.parseFloat(props.price.gross))
</script>
<template lang="pug">
.pretix-widget-pricebox
+118
View File
@@ -299,6 +299,30 @@ def get_test_order_review_pending():
'method': 'GET'}]}
def get_test_empty_captures():
return {'id': '806440346Y391300T',
'intent': 'CAPTURE',
'status': 'COMPLETED',
'purchase_units': [{'reference_id': 'default',
'amount': {'currency_code': 'EUR', 'value': '43.59'},
'payee': {'email_address': 'dummy-facilitator@dummy.dummy',
'merchant_id': 'G6R2B9YXADKWW'},
'description': 'Order JWJGC for PayPal v2',
'custom_id': 'Order PAYPALV2-JWJGC',
'soft_descriptor': 'MARTINFACIL',
'payments': {'captures': []}
}],
'payer': {'name': {'given_name': 'test', 'surname': 'buyer'},
'email_address': 'dummy@dummy.dummy',
'payer_id': 'Q739JNKWH67HE',
'address': {'country_code': 'DE'}},
'create_time': '2022-04-28T11:59:59Z',
'update_time': '2022-04-28T12:00:22Z',
'links': [{'href': 'https://api.sandbox.paypal.com/v2/checkout/orders/806440346Y391300T',
'rel': 'self',
'method': 'GET'}]}
class Object():
pass
@@ -456,6 +480,100 @@ def test_webhook_all_good(env, client, monkeypatch):
assert order.status == Order.STATUS_PAID
@pytest.mark.django_db
def test_webhook_empty_captures(env, client, monkeypatch):
order = env[1]
with scopes_disabled():
p = order.payments.first()
p.state = OrderPayment.PAYMENT_STATE_PENDING
p.save()
order.status = Order.STATUS_PENDING
order.save()
pp_order = Result(get_test_empty_captures())
monkeypatch.setattr("paypalcheckoutsdk.orders.OrdersGetRequest", lambda *args: pp_order)
monkeypatch.setattr("pretix.plugins.paypal2.payment.PaypalMethod.init_api", init_api)
with scopes_disabled():
ReferencedPayPalObject.objects.create(order=order, payment=order.payments.first(),
reference="806440346Y391300T")
client.post('/_paypal/webhook/', json.dumps(
{
"id": "WH-4T867178D0574904F-7TT11736YU643990P",
"create_time": "2022-04-28T12:00:37.077Z",
"resource_type": "checkout-order",
"event_type": "CHECKOUT.ORDER.COMPLETED",
"summary": "Checkout Order Completed",
"resource": {
"update_time": "2022-04-28T12:00:22Z",
"create_time": "2022-04-28T11:59:59Z",
"purchase_units": [
{
"reference_id": "default",
"amount": {
"currency_code": "EUR",
"value": "43.59"
},
"payee": {
"email_address": "dummy-facilitator@dummy.dummy",
"merchant_id": "G6R2B9YXADKWW"
},
"description": "Order JWJGC for PayPal v2",
"custom_id": "Order PAYPALV2-JWJGC",
"soft_descriptor": "MARTINFACIL",
"payments": {
"captures": []
}
}
],
"links": [
{
"href": "https://api.sandbox.paypal.com/v2/checkout/orders/806440346Y391300T",
"rel": "self",
"method": "GET"
}
],
"id": "806440346Y391300T",
"intent": "CAPTURE",
"payer": {
"name": {
"given_name": "test",
"surname": "buyer"
},
"email_address": "dummy@dummy.dummy",
"payer_id": "Q739JNKWH67HE",
"address": {
"country_code": "DE"
}
},
"status": "COMPLETED"
},
"status": "SUCCESS",
"links": [
{
"href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-4T867178D0574904F-7TT11736YU643990P",
"rel": "self",
"method": "GET",
"encType": "application/json"
},
{
"href": "https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-4T867178D0574904F-7TT11736YU643990P/resend",
"rel": "resend",
"method": "POST",
"encType": "application/json"
}
],
"event_version": "1.0",
"resource_version": "2.0"
}
), content_type='application_json')
order = env[1]
order.refresh_from_db()
assert order.status == Order.STATUS_PENDING
@pytest.mark.django_db
def test_webhook_mark_paid(env, client, monkeypatch):
order = env[1]
+33
View File
@@ -2372,6 +2372,39 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
assert p2.fee.value == Decimal("0.46")
assert o.total == Decimal("25.76")
def test_payment_postpone_not_allowed(self):
self.event.settings.set('payment_banktransfer__enabled', True)
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
price=23, expires=now() + timedelta(minutes=10)
)
response = self.client.post('/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug), {
'postpone': 'on',
}, follow=False)
assert 'Please select' in response.content.decode()
def test_payment_postpone_allowed(self):
self.event.settings.set('payment_banktransfer__enabled', True)
self.event.settings.payment_choice_postpone_allowed_channels = ['web']
with scopes_disabled():
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
price=23, expires=now() + timedelta(minutes=10)
)
response = self.client.post('/%s/%s/checkout/payment/' % (self.orga.slug, self.event.slug), {
'postpone': 'on',
}, follow=True)
self.assertRedirects(response, '/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug),
target_status_code=200)
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
doc = BeautifulSoup(response.content.decode(), "lxml")
self.assertEqual(len(doc.select(".thank-you")), 1)
with scopes_disabled():
o = Order.objects.last()
assert not o.payments.exists()
def test_premature_confirm(self):
response = self.client.get('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
self.assertRedirects(response, '/%s/%s/?require_cookie=true' % (self.orga.slug, self.event.slug),
+3
View File
@@ -31,6 +31,9 @@ export default defineConfig({
// Allow serving source files from sibling plugin directories
allow: ['src', ...pluginDirs],
},
cors: {
origin: /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\]|[^:]+\.pretix\.(dev|work))(?::\d+)?$/
},
},
build: {
manifest: true,