mirror of
https://github.com/pretix/pretix.git
synced 2026-01-17 23:32:26 +00:00
Compare commits
1 Commits
master
...
fix-roundi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
433ba66519 |
@@ -1601,7 +1601,7 @@ class OrderCreateSerializer(I18nAwareModelSerializer):
|
||||
order.sales_channel,
|
||||
[
|
||||
(cp.item_id, cp.subevent_id, cp.subevent.date_from if cp.subevent_id else None, cp.price,
|
||||
cp.addon_to, cp.is_bundled, pos._voucher_discount)
|
||||
bool(cp.addon_to), cp.is_bundled, pos._voucher_discount)
|
||||
for cp in order_positions
|
||||
]
|
||||
)
|
||||
|
||||
@@ -443,7 +443,6 @@ class OrganizerSettingsSerializer(SettingsSerializer):
|
||||
'customer_accounts',
|
||||
'customer_accounts_native',
|
||||
'customer_accounts_link_by_email',
|
||||
'customer_accounts_require_login_for_order_access',
|
||||
'invoice_regenerate_allowed',
|
||||
'contact_mail',
|
||||
'imprint_url',
|
||||
|
||||
@@ -34,13 +34,14 @@
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
from asgiref.local import Local
|
||||
from babel import localedata
|
||||
from django.conf import settings
|
||||
from django.utils import translation
|
||||
from django.utils.formats import date_format, number_format
|
||||
from django.utils.translation import gettext
|
||||
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
|
||||
from i18nfield.fields import ( # noqa
|
||||
I18nCharField, I18nTextarea, I18nTextField, I18nTextInput,
|
||||
)
|
||||
@@ -50,9 +51,6 @@ from i18nfield.strings import LazyI18nString # noqa
|
||||
from i18nfield.utils import I18nJSONEncoder # noqa
|
||||
|
||||
|
||||
_active_region = Local()
|
||||
|
||||
|
||||
class LazyDate:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
@@ -88,8 +86,6 @@ class LazyCurrencyNumber:
|
||||
return self.__str__()
|
||||
|
||||
def __str__(self):
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
|
||||
return money_filter(self.value, self.currency)
|
||||
|
||||
|
||||
@@ -109,41 +105,14 @@ ALLOWED_LANGUAGES = dict(settings.LANGUAGES)
|
||||
|
||||
|
||||
def get_babel_locale():
|
||||
# Babel, and therefore also django-phonenumberfield, do not support our custom locales such das de_Informal
|
||||
# Also, this returns best-effort region information for number formatting etc
|
||||
current_language = translation.get_language()
|
||||
current_region = getattr(_active_region, "value", None)
|
||||
|
||||
# Babel only accepts locales that exist on the system. We try combinations in the following order:
|
||||
# language-languageversion-region
|
||||
# language-region
|
||||
# language-languageversion
|
||||
# language
|
||||
# fallback to system default
|
||||
# fallback to english
|
||||
|
||||
try_locales = []
|
||||
if current_language:
|
||||
if "-" in current_language:
|
||||
lng_parts = current_language.split("-")
|
||||
if current_region:
|
||||
try_locales.append(f"{lng_parts[0]}_{lng_parts[1].title()}_{current_region.upper()}")
|
||||
try_locales.append(f"{lng_parts[0]}_{current_region.upper()}")
|
||||
try_locales.append(f"{lng_parts[0]}_{lng_parts[1].upper()}")
|
||||
try_locales.append(f"{lng_parts[0]}_{lng_parts[1].title()}")
|
||||
try_locales.append(f"{lng_parts[0]}")
|
||||
else:
|
||||
if current_region:
|
||||
try_locales.append(f"{current_language}_{current_region.upper()}")
|
||||
try_locales.append(f"{current_language}")
|
||||
|
||||
try_locales.append(settings.LANGUAGE_CODE)
|
||||
|
||||
for locale in try_locales:
|
||||
if localedata.exists(locale):
|
||||
return locale
|
||||
|
||||
return "en"
|
||||
babel_locale = 'en'
|
||||
# Babel, and therefore django-phonenumberfield, do not support our custom locales such das de_Informal
|
||||
if translation.get_language():
|
||||
if localedata.exists(translation.get_language()):
|
||||
babel_locale = translation.get_language()
|
||||
elif localedata.exists(translation.get_language()[:2]):
|
||||
babel_locale = translation.get_language()[:2]
|
||||
return babel_locale
|
||||
|
||||
|
||||
def get_language_without_region(lng=None):
|
||||
@@ -163,10 +132,6 @@ def get_language_without_region(lng=None):
|
||||
return lng
|
||||
|
||||
|
||||
def set_region(region):
|
||||
_active_region.value = region
|
||||
|
||||
|
||||
@contextmanager
|
||||
def language(lng, region=None):
|
||||
"""
|
||||
@@ -178,18 +143,15 @@ def language(lng, region=None):
|
||||
formatting. If you pass a ``lng`` that already contains a region, e.g. ``pt-br``, the ``region``
|
||||
attribute will be ignored.
|
||||
"""
|
||||
lng_before = translation.get_language()
|
||||
region_before = getattr(_active_region, "value", None)
|
||||
_lng = translation.get_language()
|
||||
lng = lng or settings.LANGUAGE_CODE
|
||||
if '-' not in lng and region:
|
||||
lng += '-' + region.lower()
|
||||
translation.activate(lng)
|
||||
_active_region.value = region
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
translation.activate(lng_before)
|
||||
_active_region.value = region_before
|
||||
translation.activate(_lng)
|
||||
|
||||
|
||||
class LazyLocaleException(Exception):
|
||||
|
||||
@@ -64,7 +64,7 @@ class PeppolIdValidator:
|
||||
"0020": "[0-9]{9}",
|
||||
"0201": "[0-9a-zA-Z]{6}",
|
||||
"0204": "[0-9]{2,12}(-[0-9A-Z]{0,30})?-[0-9]{2}",
|
||||
"0208": "[01][0-9]{9}",
|
||||
"0208": "0[0-9]{9}",
|
||||
"0209": ".*",
|
||||
"0210": "[A-Z0-9]+",
|
||||
"0211": "IT[0-9]{11}",
|
||||
|
||||
@@ -35,7 +35,7 @@ from django.utils.translation.trans_real import (
|
||||
parse_accept_lang_header,
|
||||
)
|
||||
|
||||
from pretix.base.i18n import get_language_without_region, set_region
|
||||
from pretix.base.i18n import get_language_without_region
|
||||
from pretix.base.settings import global_settings_object
|
||||
from pretix.multidomain.urlreverse import (
|
||||
get_event_domain, get_organizer_domain,
|
||||
@@ -92,14 +92,10 @@ class LocaleMiddleware(MiddlewareMixin):
|
||||
)
|
||||
if '-' not in language and settings_holder.settings.region:
|
||||
language += '-' + settings_holder.settings.region
|
||||
if settings_holder.settings.region:
|
||||
set_region(settings_holder.settings.region)
|
||||
else:
|
||||
gs = global_settings_object(request)
|
||||
if '-' not in language and gs.settings.region:
|
||||
language += '-' + gs.settings.region
|
||||
if gs.settings.region:
|
||||
set_region(gs.settings.region)
|
||||
|
||||
translation.activate(language)
|
||||
request.LANGUAGE_CODE = get_language_without_region()
|
||||
|
||||
@@ -37,7 +37,7 @@ from pretix.base.decimal import round_decimal
|
||||
from pretix.base.models.base import LoggedModel
|
||||
|
||||
PositionInfo = namedtuple('PositionInfo',
|
||||
['item_id', 'subevent_id', 'subevent_date_from', 'line_price_gross', 'addon_to',
|
||||
['item_id', 'subevent_id', 'subevent_date_from', 'line_price_gross', 'is_addon_to',
|
||||
'voucher_discount'])
|
||||
|
||||
|
||||
@@ -279,42 +279,6 @@ class Discount(LoggedModel):
|
||||
for idx in condition_idx_group:
|
||||
collect_potential_discounts[idx] = [(self, inf, -1, subevent_id)]
|
||||
|
||||
def _addon_idx(self, positions, idx):
|
||||
"""
|
||||
If we have the following cart:
|
||||
|
||||
- Main product
|
||||
- 10x Addon product 5€
|
||||
- Main product
|
||||
- 10x Addon product 5€
|
||||
|
||||
And we have a discount rule that grants "every 10th product is free", people tend to expect
|
||||
|
||||
- Main product
|
||||
- 9x Addon product 5€
|
||||
- 1x Addon product free
|
||||
- Main product
|
||||
- 9x Addon product 5€
|
||||
- 1x Addon product free
|
||||
|
||||
And get confused if they get
|
||||
|
||||
- Main product
|
||||
- 8x Addon product 5€
|
||||
- 2x Addon product free
|
||||
- Main product
|
||||
- 10x Addon product 5€
|
||||
|
||||
Even if the result is the same. Therefore, we sort positions in the cart not only by price, but also by their
|
||||
relative index within their addon group. This is only a heuristic and there are *still* scenarios where the more
|
||||
unexpected version happens, e.g. if prices are different. We need to accept this as long as discounts work on
|
||||
cart level and not on addon-group level, but this simple sorting reduces the number of support issues by making
|
||||
the weird case less likely.
|
||||
"""
|
||||
if not positions[idx].addon_to:
|
||||
return 0
|
||||
return len([1 for i, p in positions.items() if i < idx and p.addon_to == positions[idx].addon_to])
|
||||
|
||||
def _apply_min_count(self, positions, condition_idx_group, benefit_idx_group, result, collect_potential_discounts, subevent_id):
|
||||
if len(condition_idx_group) < self.condition_min_count:
|
||||
return
|
||||
@@ -324,8 +288,8 @@ class Discount(LoggedModel):
|
||||
|
||||
if self.benefit_only_apply_to_cheapest_n_matches:
|
||||
# sort by line_price
|
||||
condition_idx_group = sorted(condition_idx_group, key=lambda idx: (positions[idx].line_price_gross, self._addon_idx(positions, idx), -idx))
|
||||
benefit_idx_group = sorted(benefit_idx_group, key=lambda idx: (positions[idx].line_price_gross, self._addon_idx(positions, idx), -idx))
|
||||
condition_idx_group = sorted(condition_idx_group, key=lambda idx: (positions[idx].line_price_gross, -idx))
|
||||
benefit_idx_group = sorted(benefit_idx_group, key=lambda idx: (positions[idx].line_price_gross, -idx))
|
||||
|
||||
# Prevent over-consuming of items, i.e. if our discount is "buy 2, get 1 free", we only
|
||||
# want to match multiples of 3
|
||||
@@ -470,7 +434,7 @@ class Discount(LoggedModel):
|
||||
for idx, p in positions.items():
|
||||
subevent_to_idx[p.subevent_id].append(idx)
|
||||
for v in subevent_to_idx.values():
|
||||
v.sort(key=lambda idx: (positions[idx].line_price_gross, self._addon_idx(positions, idx)))
|
||||
v.sort(key=lambda idx: positions[idx].line_price_gross)
|
||||
subevent_order = sorted(list(subevent_to_idx.keys()), key=lambda s: len(subevent_to_idx[s]), reverse=True)
|
||||
|
||||
# Build groups of exactly condition_min_count distinct subevents
|
||||
@@ -494,7 +458,7 @@ class Discount(LoggedModel):
|
||||
|
||||
# Sort the list by prices, then pick one. For "buy 2 get 1 free" we apply a "pick 1 from the start
|
||||
# and 2 from the end" scheme to optimize price distribution among groups
|
||||
candidates = sorted(candidates, key=lambda idx: (positions[idx].line_price_gross, self._addon_idx(positions, idx)))
|
||||
candidates = sorted(candidates, key=lambda idx: positions[idx].line_price_gross)
|
||||
if len(current_group) < (self.benefit_only_apply_to_cheapest_n_matches or 0):
|
||||
candidate = candidates[0]
|
||||
else:
|
||||
|
||||
@@ -141,9 +141,8 @@ class LogEntry(models.Model):
|
||||
|
||||
log_entry_type, meta = log_entry_types.get(action_type=self.action_type)
|
||||
if log_entry_type:
|
||||
sender = self.event if self.event else self.organizer
|
||||
link_info = log_entry_type.get_object_link_info(self)
|
||||
if is_app_active(sender, meta['plugin']):
|
||||
if is_app_active(self.event, meta['plugin']):
|
||||
return make_link(link_info, log_entry_type.object_link_wrapper)
|
||||
else:
|
||||
return make_link(link_info, log_entry_type.object_link_wrapper, is_active=False,
|
||||
|
||||
@@ -35,7 +35,6 @@ from pretix.base.email import get_email_context
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.models import User, Voucher
|
||||
from pretix.base.services.mail import SendMailException, mail, render_mail
|
||||
from pretix.helpers import OF_SELF
|
||||
|
||||
from ...helpers.format import format_map
|
||||
from ...helpers.names import build_name
|
||||
@@ -186,47 +185,44 @@ class WaitingListEntry(LoggedModel):
|
||||
if not free_seats:
|
||||
raise WaitingListException(_('No seat with this product is currently available.'))
|
||||
|
||||
if self.voucher:
|
||||
raise WaitingListException(_('A voucher has already been sent to this person.'))
|
||||
if '@' not in self.email:
|
||||
raise WaitingListException(_('This entry is anonymized and can no longer be used.'))
|
||||
|
||||
with transaction.atomic():
|
||||
locked_wle = WaitingListEntry.objects.select_for_update(of=OF_SELF).get(pk=self.pk)
|
||||
if locked_wle.voucher:
|
||||
raise WaitingListException(_('A voucher has already been sent to this person.'))
|
||||
e = locked_wle.email
|
||||
if locked_wle.name:
|
||||
e += ' / ' + locked_wle.name
|
||||
e = self.email
|
||||
if self.name:
|
||||
e += ' / ' + self.name
|
||||
v = Voucher.objects.create(
|
||||
event=locked_wle.event,
|
||||
event=self.event,
|
||||
max_usages=1,
|
||||
valid_until=now() + timedelta(hours=locked_wle.event.settings.waiting_list_hours),
|
||||
item=locked_wle.item,
|
||||
variation=locked_wle.variation,
|
||||
valid_until=now() + timedelta(hours=self.event.settings.waiting_list_hours),
|
||||
item=self.item,
|
||||
variation=self.variation,
|
||||
tag='waiting-list',
|
||||
comment=_('Automatically created from waiting list entry for {email}').format(
|
||||
email=e
|
||||
),
|
||||
block_quota=True,
|
||||
subevent=locked_wle.subevent,
|
||||
subevent=self.subevent,
|
||||
)
|
||||
v.log_action('pretix.voucher.added', {
|
||||
'item': locked_wle.item.pk,
|
||||
'variation': locked_wle.variation.pk if locked_wle.variation else None,
|
||||
'item': self.item.pk,
|
||||
'variation': self.variation.pk if self.variation else None,
|
||||
'tag': 'waiting-list',
|
||||
'block_quota': True,
|
||||
'valid_until': v.valid_until.isoformat(),
|
||||
'max_usages': 1,
|
||||
'subevent': locked_wle.subevent.pk if locked_wle.subevent else None,
|
||||
'subevent': self.subevent.pk if self.subevent else None,
|
||||
'source': 'waitinglist',
|
||||
}, user=user, auth=auth)
|
||||
v.log_action('pretix.voucher.added.waitinglist', {
|
||||
'email': locked_wle.email,
|
||||
'waitinglistentry': locked_wle.pk,
|
||||
'email': self.email,
|
||||
'waitinglistentry': self.pk,
|
||||
}, user=user, auth=auth)
|
||||
locked_wle.voucher = v
|
||||
locked_wle.save()
|
||||
|
||||
self.refresh_from_db()
|
||||
self.voucher = v
|
||||
self.save()
|
||||
|
||||
with language(self.locale, self.event.settings.region):
|
||||
self.send_mail(
|
||||
|
||||
@@ -1528,7 +1528,7 @@ class CartManager:
|
||||
self._sales_channel.identifier,
|
||||
[
|
||||
(cp.item_id, cp.subevent_id, cp.subevent.date_from if cp.subevent_id else None, cp.line_price_gross,
|
||||
cp.addon_to, cp.is_bundled, cp.listed_price - cp.price_after_voucher)
|
||||
bool(cp.addon_to), cp.is_bundled, cp.listed_price - cp.price_after_voucher)
|
||||
for cp in positions
|
||||
]
|
||||
)
|
||||
|
||||
@@ -121,7 +121,7 @@ class CrossSellingService:
|
||||
self.sales_channel,
|
||||
[
|
||||
(cp.item_id, cp.subevent_id, cp.subevent.date_from if cp.subevent_id else None, cp.line_price_gross,
|
||||
cp.addon_to, cp.is_bundled,
|
||||
bool(cp.addon_to), cp.is_bundled,
|
||||
cp.listed_price - cp.price_after_voucher)
|
||||
for cp in self.cartpositions
|
||||
],
|
||||
|
||||
@@ -914,7 +914,7 @@ def _check_positions(event: Event, now_dt: datetime, time_machine_now_dt: dateti
|
||||
sales_channel.identifier,
|
||||
[
|
||||
(cp.item_id, cp.subevent_id, cp.subevent.date_from if cp.subevent_id else None, cp.line_price_gross,
|
||||
cp.addon_to, cp.is_bundled, cp.listed_price - cp.price_after_voucher)
|
||||
bool(cp.addon_to), cp.is_bundled, cp.listed_price - cp.price_after_voucher)
|
||||
for cp in sorted_positions
|
||||
]
|
||||
)
|
||||
|
||||
@@ -174,9 +174,7 @@ def apply_discounts(event: Event, sales_channel: Union[str, SalesChannel],
|
||||
|
||||
:param event: Event the cart belongs to
|
||||
:param sales_channel: Sales channel the cart was created with
|
||||
:param positions: Tuple of the form ``(item_id, subevent_id, subevent_date_from, line_price_gross, addon_to_id, is_bundled, voucher_discount)``
|
||||
``addon_to_id`` does not have to be the proper ID, any identifier is okay, even ``True``/``False`` are accepted, but
|
||||
a better result may be given if addons to the same main product have the same distinct value.
|
||||
:param positions: Tuple of the form ``(item_id, subevent_id, subevent_date_from, line_price_gross, is_addon_to, is_bundled, voucher_discount)``
|
||||
:param collect_potential_discounts: If a `defaultdict(list)` is supplied, all discounts that could be applied to the cart
|
||||
based on the "consumed" items, but lack matching "benefitting" items will be collected therein.
|
||||
The dict will contain a mapping from index in the `positions` list of the item that could be consumed, to a list
|
||||
@@ -198,9 +196,9 @@ def apply_discounts(event: Event, sales_channel: Union[str, SalesChannel],
|
||||
).prefetch_related('condition_limit_products', 'benefit_limit_products').order_by('position', 'pk')
|
||||
for discount in discount_qs:
|
||||
result = discount.apply({
|
||||
idx: PositionInfo(item_id, subevent_id, subevent_date_from, line_price_gross, addon_to, voucher_discount)
|
||||
idx: PositionInfo(item_id, subevent_id, subevent_date_from, line_price_gross, is_addon_to, voucher_discount)
|
||||
for
|
||||
idx, (item_id, subevent_id, subevent_date_from, line_price_gross, addon_to, is_bundled, voucher_discount)
|
||||
idx, (item_id, subevent_id, subevent_date_from, line_price_gross, is_addon_to, is_bundled, voucher_discount)
|
||||
in enumerate(positions)
|
||||
if not is_bundled and idx not in new_prices
|
||||
}, collect_potential_discounts)
|
||||
|
||||
@@ -180,19 +180,6 @@ DEFAULTS = {
|
||||
widget=forms.CheckboxInput(attrs={'data-display-dependency': '#id_settings-customer_accounts'}),
|
||||
)
|
||||
},
|
||||
'customer_accounts_require_login_for_order_access': {
|
||||
'default': 'False',
|
||||
'type': bool,
|
||||
'form_class': forms.BooleanField,
|
||||
'serializer_class': serializers.BooleanField,
|
||||
'form_kwargs': dict(
|
||||
label=_("Require login to access order confirmation pages"),
|
||||
help_text=_("If enabled, users who were logged in at the time of purchase must also log in to access their order information. "
|
||||
"If a customer account is created while placing an order, the restriction only becomes active after the customer "
|
||||
"account is activated."),
|
||||
widget=forms.CheckboxInput(attrs={'data-display-dependency': '#id_settings-customer_accounts'}),
|
||||
)
|
||||
},
|
||||
'customer_accounts_link_by_email': {
|
||||
'default': 'False',
|
||||
'type': bool,
|
||||
|
||||
@@ -26,8 +26,7 @@ from babel.numbers import format_currency
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.template.defaultfilters import floatformat
|
||||
|
||||
from pretix.base.i18n import get_babel_locale
|
||||
from django.utils import translation
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@@ -60,10 +59,13 @@ def money_filter(value: Decimal, arg='', hide_currency=False):
|
||||
if hide_currency:
|
||||
return floatformat(value, f"{places}g")
|
||||
|
||||
try:
|
||||
locale = Locale(get_babel_locale())
|
||||
except UnknownLocaleError:
|
||||
locale = "en"
|
||||
locale_parts = translation.get_language().split("-", 1)
|
||||
locale = locale_parts[0]
|
||||
if len(locale_parts) > 1 and len(locale_parts[1]) == 2:
|
||||
try:
|
||||
locale = Locale(locale_parts[0], locale_parts[1].upper())
|
||||
except UnknownLocaleError:
|
||||
pass
|
||||
|
||||
try:
|
||||
return format_currency(value, arg, locale=locale)
|
||||
|
||||
@@ -474,7 +474,6 @@ class OrganizerSettingsForm(SettingsForm):
|
||||
'customer_accounts',
|
||||
'customer_accounts_native',
|
||||
'customer_accounts_link_by_email',
|
||||
'customer_accounts_require_login_for_order_access',
|
||||
'invoice_regenerate_allowed',
|
||||
'contact_mail',
|
||||
'imprint_url',
|
||||
|
||||
@@ -132,7 +132,6 @@
|
||||
<legend>{% trans "Customer accounts" %}</legend>
|
||||
{% bootstrap_field sform.customer_accounts layout="control" %}
|
||||
{% bootstrap_field sform.customer_accounts_native layout="control" %}
|
||||
{% bootstrap_field sform.customer_accounts_require_login_for_order_access layout="control" %}
|
||||
{% bootstrap_field sform.customer_accounts_link_by_email layout="control" %}
|
||||
{% bootstrap_field sform.name_scheme layout="control" %}
|
||||
{% bootstrap_field sform.name_scheme_titles layout="control" %}
|
||||
|
||||
@@ -188,8 +188,6 @@ class LicenseCheckView(StaffMemberRequiredMixin, FormView):
|
||||
return None, None
|
||||
try:
|
||||
for k, v in pkg.metadata.items():
|
||||
if k == "License-Expression":
|
||||
license = v
|
||||
if k == "License":
|
||||
license = v
|
||||
if k == "Home-page":
|
||||
|
||||
@@ -2583,7 +2583,7 @@ class LogView(OrganizerPermissionRequiredMixin, PaginationMixin, ListView):
|
||||
def get_queryset(self):
|
||||
# technically, we'd also need to sort by pk since this is a paginated list, but in this case we just can't
|
||||
# bear the performance cost
|
||||
qs = self.request.organizer.logentry_set.filter(event=None).select_related(
|
||||
qs = self.request.organizer.all_logentries().select_related(
|
||||
'user', 'content_type', 'api_token', 'oauth_application', 'device'
|
||||
).order_by('-datetime')
|
||||
qs = qs.exclude(action_type__in=OVERVIEW_BANLIST)
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
|
||||
"PO-Revision-Date: 2026-01-14 00:00+0000\n"
|
||||
"Last-Translator: Mario Montes <mario@t3chfest.es>\n"
|
||||
"PO-Revision-Date: 2026-01-06 23:00+0000\n"
|
||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"es/>\n"
|
||||
"Language: es\n"
|
||||
@@ -35588,8 +35588,7 @@ msgstr "El período de preventa para este evento ha terminado."
|
||||
#: pretix/presale/views/widget.py:807
|
||||
#, python-format
|
||||
msgid "The booking period for this event will start on %(date)s at %(time)s."
|
||||
msgstr ""
|
||||
"El periodo de reserva para este evento comenzará el %(date)s a las %(time)s."
|
||||
msgstr "La preventa para este evento comenzará en %(date)s a %(time)s."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/index.html:185
|
||||
#: pretix/presale/templates/pretixpresale/event/seatingplan.html:23
|
||||
@@ -36852,11 +36851,11 @@ msgstr ""
|
||||
|
||||
#: pretix/presale/views/cart.py:520
|
||||
msgid "Your cart has been updated."
|
||||
msgstr "Su carrito ha sido actualizado."
|
||||
msgstr "Su carrito ha sido actualizada."
|
||||
|
||||
#: pretix/presale/views/cart.py:523 pretix/presale/views/cart.py:549
|
||||
msgid "Your cart is now empty."
|
||||
msgstr "Su carrito está vacio."
|
||||
msgstr "Su carrito ha sido vaciada."
|
||||
|
||||
#: pretix/presale/views/cart.py:570
|
||||
msgid ""
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-01-05 12:13+0000\n"
|
||||
"PO-Revision-Date: 2026-01-14 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-10-22 16:00+0000\n"
|
||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||
"js/es/>\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.15.1\n"
|
||||
"X-Generator: Weblate 5.13.3\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||
@@ -738,8 +738,11 @@ msgstr "Su carrito está a punto de caducar."
|
||||
#: pretix/static/pretixpresale/js/ui/cart.js:62
|
||||
msgid "The items in your cart are reserved for you for one minute."
|
||||
msgid_plural "The items in your cart are reserved for you for {num} minutes."
|
||||
msgstr[0] "Los artículos de la cesta están reservados durante un minuto."
|
||||
msgstr[1] "Los artículos de la cesta están reservados durante {num} minutos."
|
||||
msgstr[0] ""
|
||||
"Los elementos en su carrito de compras se han reservado durante un minuto."
|
||||
msgstr[1] ""
|
||||
"Los elementos en su carrito de compras se han reservado durante {num} "
|
||||
"minutos."
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/cart.js:83
|
||||
msgid "Your cart has expired."
|
||||
@@ -763,11 +766,11 @@ msgstr "Renovar reserva"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:194
|
||||
msgid "The organizer keeps %(currency)s %(amount)s"
|
||||
msgstr "El organizador retiene %(currency)s %(amount)s"
|
||||
msgstr "El organizador se queda %(currency)s %(price)s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:202
|
||||
msgid "You get %(currency)s %(amount)s back"
|
||||
msgstr "Se le devolverá %(moneda)s %(cantidad)s"
|
||||
msgstr "Obtienes %(currency)s %(price)s de vuelta"
|
||||
|
||||
#: pretix/static/pretixpresale/js/ui/main.js:218
|
||||
msgid "Please enter the amount the organizer can keep."
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
|
||||
"PO-Revision-Date: 2026-01-14 00:00+0000\n"
|
||||
"Last-Translator: Mario Montes <mario@t3chfest.es>\n"
|
||||
"PO-Revision-Date: 2025-12-15 20:00+0000\n"
|
||||
"Last-Translator: sandra r <sandrarial@gestiontickets.online>\n"
|
||||
"Language-Team: Galician <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"gl/>\n"
|
||||
"Language: gl\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.15.1\n"
|
||||
"X-Generator: Weblate 5.14.3\n"
|
||||
|
||||
#: pretix/_base_settings.py:87
|
||||
msgid "English"
|
||||
@@ -1149,7 +1149,7 @@ msgstr "Pregunta: {name}"
|
||||
#: pretix/base/settings.py:3775 pretix/base/settings.py:3828
|
||||
#: pretix/base/settings.py:3849 pretix/base/settings.py:3871
|
||||
msgid "Given name"
|
||||
msgstr "Nome"
|
||||
msgstr "Nombre"
|
||||
|
||||
#: pretix/base/datasync/sourcefields.py:628
|
||||
#: pretix/base/datasync/sourcefields.py:638 pretix/base/settings.py:3670
|
||||
@@ -18192,9 +18192,9 @@ msgstr ""
|
||||
"\"{new_email}\"."
|
||||
|
||||
#: pretix/control/logdisplay.py:673
|
||||
#, python-brace-format
|
||||
#, fuzzy, python-brace-format
|
||||
msgid "Your email address {email} has been confirmed."
|
||||
msgstr "Tu email {email} ha sido confirmado."
|
||||
msgstr "Su carrito ha sido actualizado."
|
||||
|
||||
#: pretix/control/logdisplay.py:685
|
||||
#, fuzzy, python-brace-format
|
||||
@@ -24293,7 +24293,7 @@ msgstr "Sí, aprobar la orden"
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:483
|
||||
#: pretix/presale/templates/pretixpresale/event/order_cancel.html:7
|
||||
msgid "Cancel order"
|
||||
msgstr "Cancelar o pedido"
|
||||
msgstr "Cancelar a orde"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/order/cancel.html:12
|
||||
#: pretix/control/templates/pretixcontrol/order/deny.html:11
|
||||
@@ -35952,9 +35952,10 @@ msgstr ""
|
||||
|
||||
#: pretix/presale/forms/renderers.py:66
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_voucher_form.html:14
|
||||
#, fuzzy
|
||||
msgctxt "form"
|
||||
msgid "required"
|
||||
msgstr "obrigatorio"
|
||||
msgstr "expirado"
|
||||
|
||||
#: pretix/presale/ical.py:87 pretix/presale/ical.py:146
|
||||
#: pretix/presale/ical.py:182
|
||||
@@ -37538,13 +37539,14 @@ msgid "A payment of %(total)s is still pending for this order."
|
||||
msgstr "Un pago de %(total)s aínda está pendente para esta orde."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:97
|
||||
#, python-format
|
||||
#, fuzzy, python-format
|
||||
msgid "Please complete your payment before %(date)s"
|
||||
msgstr "Por favor complete o seu pago antes de %(date)s"
|
||||
msgstr "Por favor complete su pago antes de %(date)s"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:108
|
||||
#, fuzzy
|
||||
msgid "Re-try payment or choose another payment method"
|
||||
msgstr "Volva tentar o pago ou escolla outro método de pago"
|
||||
msgstr "Vuelva a intentar el pago o elija otro método de pago"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:126
|
||||
#, fuzzy
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
|
||||
"PO-Revision-Date: 2026-01-12 17:00+0000\n"
|
||||
"Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n"
|
||||
"PO-Revision-Date: 2026-01-05 10:00+0000\n"
|
||||
"Last-Translator: Yasunobu YesNo Kawaguchi <kawaguti@gmail.com>\n"
|
||||
"Language-Team: Japanese <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"ja/>\n"
|
||||
"Language: ja\n"
|
||||
@@ -3831,7 +3831,7 @@ msgstr ""
|
||||
|
||||
#: pretix/base/invoicing/peppol.py:164
|
||||
msgid "The Peppol participant ID is not registered on the Peppol network."
|
||||
msgstr "Peppol参加者IDはPeppolネットワークに登録されていません。"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/invoicing/peppol.py:184
|
||||
msgid "Peppol participant ID"
|
||||
@@ -8281,7 +8281,7 @@ msgstr "販売されていない製品が選択されています。"
|
||||
msgid ""
|
||||
"Some products can no longer be purchased and have been removed from your "
|
||||
"cart for the following reason: %s"
|
||||
msgstr "一部の製品は購入できなくなり、次の理由でカートから削除されました:%s"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/services/cart.py:117
|
||||
msgid ""
|
||||
@@ -9400,14 +9400,20 @@ msgid "Uncategorized"
|
||||
msgstr "未分類"
|
||||
|
||||
#: pretix/base/services/tax.py:43
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Your VAT ID could not be checked, as the VAT checking service of your "
|
||||
#| "country is currently not available. We will therefore need to charge VAT "
|
||||
#| "on your invoice. You can get the tax amount back via the VAT "
|
||||
#| "reimbursement process."
|
||||
msgid ""
|
||||
"Your VAT ID could not be checked, as the VAT checking service of your "
|
||||
"country is currently not available. We will therefore need to charge you the "
|
||||
"same tax rate as if you did not enter a VAT ID."
|
||||
msgstr ""
|
||||
"あなたの国のVATチェックサービスが現在利用できないため、VAT IDを確認できません"
|
||||
"でした。したがって、VAT IDを入力しなかった場合と同じ税率を請求する必要があり"
|
||||
"ます。"
|
||||
"お客様のVAT IDは確認できませんでした。お客様の国のVAT確認サービスが現在利用で"
|
||||
"きないため、請求書にVATを請求する必要があります。VAT払い戻し手続きを通じて税"
|
||||
"金を返金することができます。"
|
||||
|
||||
#: pretix/base/services/tax.py:47 pretix/base/services/tax.py:366
|
||||
#: pretix/base/services/tax.py:393
|
||||
@@ -9822,17 +9828,23 @@ msgid "Ask for VAT ID"
|
||||
msgstr "VAT IDを尋ねる"
|
||||
|
||||
#: pretix/base/settings.py:632
|
||||
#, python-brace-format
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid ""
|
||||
#| "Only works if an invoice address is asked for. VAT ID is never required "
|
||||
#| "and only requested from business customers in the following countries: "
|
||||
#| "{countries}"
|
||||
msgid ""
|
||||
"Only works if an invoice address is asked for. VAT ID is only requested from "
|
||||
"business customers in the following countries: {countries}."
|
||||
msgstr ""
|
||||
"請求書の住所が要求された場合のみ有効です。VAT ID は、{countries} の国の法人の"
|
||||
"お客様にのみ要求されます。"
|
||||
"請求先の住所が要求された場合のみ機能します。消費税登録番号やVAT IDは必要な"
|
||||
"く、以下の国の法人顧客からのみ要求されます:{countries}"
|
||||
|
||||
#: pretix/base/settings.py:651
|
||||
#, fuzzy
|
||||
#| msgid "Require name"
|
||||
msgid "Require VAT ID in"
|
||||
msgstr "VAT IDを要求"
|
||||
msgstr "名前を要求"
|
||||
|
||||
#: pretix/base/settings.py:657
|
||||
msgid ""
|
||||
@@ -9840,9 +9852,6 @@ msgid ""
|
||||
"ID in all countries. VAT ID will be required for all business addresses in "
|
||||
"the selected countries."
|
||||
msgstr ""
|
||||
"VAT ID はデフォルトでオプションです。これは、すべての企業に VAT ID が割り当て"
|
||||
"られているわけではないためです。選択した国のすべてのビジネスアドレスには、"
|
||||
"VAT IDが必要です。"
|
||||
|
||||
#: pretix/base/settings.py:672
|
||||
msgid "Invoice address explanation"
|
||||
@@ -13433,9 +13442,11 @@ msgstr ""
|
||||
"リクエストのために再度有効にしてください。"
|
||||
|
||||
#: pretix/base/views/js_helpers.py:41
|
||||
#, fuzzy
|
||||
#| msgid "ID"
|
||||
msgctxt "tax_id_swiss"
|
||||
msgid "UID"
|
||||
msgstr "UID"
|
||||
msgstr "ID"
|
||||
|
||||
#. Translators: Only translate to French (IDE) and Italien (IDI), otherwise keep the same
|
||||
#. Awareness around VAT IDs differes by EU country. For example, in Germany the VAT ID is assigned
|
||||
@@ -13445,27 +13456,35 @@ msgstr "UID"
|
||||
#. number (Partita IVA) and also used on domestic transactions. So someone who never purchased something international
|
||||
#. for their company, might still know the value, if we call it the right way and not just "VAT ID".
|
||||
#: pretix/base/views/js_helpers.py:49
|
||||
#, fuzzy
|
||||
#| msgid "VAT ID"
|
||||
msgctxt "tax_id_italy"
|
||||
msgid "VAT ID / P.IVA"
|
||||
msgstr "VAT ID / P.IVA"
|
||||
msgstr "消費税登録番号又はVAT ID"
|
||||
|
||||
#. Translators: Translate to only "P.IVA" in Italian, keep second part as-is in other languages
|
||||
#: pretix/base/views/js_helpers.py:50
|
||||
#, fuzzy
|
||||
#| msgid "VAT ID"
|
||||
msgctxt "tax_id_greece"
|
||||
msgid "VAT ID / TIN"
|
||||
msgstr "VAT ID / TIN"
|
||||
msgstr "消費税登録番号又はVAT ID"
|
||||
|
||||
#. Translators: Translate to only "ΑΦΜ" in Greek
|
||||
#: pretix/base/views/js_helpers.py:51
|
||||
#, fuzzy
|
||||
#| msgid "VAT ID"
|
||||
msgctxt "tax_id_spain"
|
||||
msgid "VAT ID / NIF"
|
||||
msgstr "VAT ID / NIF"
|
||||
msgstr "消費税登録番号又はVAT ID"
|
||||
|
||||
#. Translators: Translate to only "NIF" in Spanish
|
||||
#: pretix/base/views/js_helpers.py:52
|
||||
#, fuzzy
|
||||
#| msgid "VAT ID"
|
||||
msgctxt "tax_id_portugal"
|
||||
msgid "VAT ID / NIF"
|
||||
msgstr "VAT ID / NIF"
|
||||
msgstr "消費税登録番号又はVAT ID"
|
||||
|
||||
#: pretix/base/views/tasks.py:185
|
||||
msgid "An unexpected error has occurred, please try again later."
|
||||
@@ -14002,8 +14021,6 @@ msgid ""
|
||||
"Formatting is not supported, as some accounting departments process mail "
|
||||
"automatically and do not handle formatted emails properly."
|
||||
msgstr ""
|
||||
"一部の経理部門はメールを自動的に処理し、フォーマットされたメールを適切に処理"
|
||||
"しないため、フォーマットはサポートされていません。"
|
||||
|
||||
#: pretix/control/forms/event.py:1356
|
||||
msgid ""
|
||||
@@ -14452,7 +14469,7 @@ msgstr "支払い済み"
|
||||
#: pretix/control/forms/filter.py:1304
|
||||
msgctxt "subevent"
|
||||
msgid "Date doesn't start in selected date range."
|
||||
msgstr "日付は選択した日付範囲で開始されません。"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py:1360 pretix/control/forms/filter.py:1827
|
||||
msgid "Shop live and presale running"
|
||||
@@ -27990,9 +28007,6 @@ msgid ""
|
||||
"automatically. We recommend that you rename these in your source file to "
|
||||
"avoid problems during import."
|
||||
msgstr ""
|
||||
"CSVファイルの複数の列は同じ名前で、自動的に名前が変更されました。インポート中"
|
||||
"に問題が発生しないように、ソースファイルでこれらの名前を変更することをお勧め"
|
||||
"します。"
|
||||
|
||||
#: pretix/control/views/modelimport.py:188
|
||||
msgid "The import was successful."
|
||||
@@ -29623,7 +29637,7 @@ msgstr ""
|
||||
|
||||
#: pretix/plugins/banktransfer/camtimport.py:33
|
||||
msgid "Empty file or unknown format."
|
||||
msgstr "空のファイルまたは不明な形式。"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/banktransfer/payment.py:69
|
||||
msgid ""
|
||||
@@ -32118,16 +32132,16 @@ msgid "Przelewy24"
|
||||
msgstr "Przelewy24"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:417 pretix/plugins/stripe/payment.py:1836
|
||||
#, fuzzy
|
||||
#| msgid "Payment by bank transfer"
|
||||
msgid "Pay by bank"
|
||||
msgstr "Pay by bank"
|
||||
msgstr "銀行振込による支払い"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:422
|
||||
msgid ""
|
||||
"Currently only available for charges in GBP and customers with UK bank "
|
||||
"accounts, and in private preview for France and Germany."
|
||||
msgstr ""
|
||||
"現在、英国ポンドでの請求と英国の銀行口座を持つ顧客、およびフランスとドイツの"
|
||||
"プライベートプレビューでのみ利用できます。"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:429 pretix/plugins/stripe/payment.py:1789
|
||||
msgid "WeChat Pay"
|
||||
@@ -32432,16 +32446,16 @@ msgstr ""
|
||||
"いておいてください。"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1835
|
||||
#, fuzzy
|
||||
#| msgid "PayPal via Stripe"
|
||||
msgid "Pay by bank via Stripe"
|
||||
msgstr "Stripe経由でPay by bank"
|
||||
msgstr "Stripe経由でPayPal"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1841
|
||||
msgid ""
|
||||
"Pay by bank allows you to authorize a secure Open Banking payment from your "
|
||||
"banking app. Currently available only with a UK bank account."
|
||||
msgstr ""
|
||||
"Pay by bankを使用すると、銀行アプリから安全なオープンバンキングの支払いを承認"
|
||||
"できます。現在、英国の銀行口座でのみ利用できます。"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1861
|
||||
msgid "PayPal via Stripe"
|
||||
@@ -32460,16 +32474,22 @@ msgstr ""
|
||||
"能です。アプリを準備してください。"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1893
|
||||
#, fuzzy
|
||||
#| msgid "giropay via Stripe"
|
||||
msgid "PromptPay via Stripe"
|
||||
msgstr "Stripe経由でPromptPay"
|
||||
msgstr "Stripe経由でgiropay"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1898
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "This payment method is available to MobilePay app users in Denmark and "
|
||||
#| "Finland. Please have your app ready."
|
||||
msgid ""
|
||||
"This payment method is available to PromptPay users in Thailand. Please have "
|
||||
"your app ready."
|
||||
msgstr ""
|
||||
"この支払い方法は、タイのPromptPayユーザーが利用できます。アプリを準備してくだ"
|
||||
"さい。"
|
||||
"この支払い方法は、デンマークとフィンランドのMobilePayアプリユーザーに利用可能"
|
||||
"です。アプリを準備してください。"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1917
|
||||
msgid "TWINT via Stripe"
|
||||
@@ -32772,16 +32792,22 @@ msgid "Confirm payment: %(code)s"
|
||||
msgstr "支払いを確認: %(code)s"
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca.html:32
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Please scan the barcode below to complete your WeChat payment. Once you "
|
||||
#| "have completed your payment, you can refresh this page."
|
||||
msgid ""
|
||||
"Please scan the QR code below to complete your PromptPay payment. Once you "
|
||||
"have completed your payment, you can refresh this page."
|
||||
msgstr ""
|
||||
"PromptPayの支払いを完了するには、以下のQRコードをスキャンしてください。支払い"
|
||||
"が完了したら、このページを更新できます。"
|
||||
"下記のバーコードをスキャンしてWeChat支払いを完了してください。支払いが完了し"
|
||||
"たら、このページを更新してください。"
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca.html:37
|
||||
#, fuzzy
|
||||
#| msgid "Create QR code"
|
||||
msgid "PromptPay QR code"
|
||||
msgstr "PromptPay QRコード"
|
||||
msgstr "注文番号"
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca_return.html:20
|
||||
msgid "Confirming your payment…"
|
||||
@@ -33799,7 +33825,10 @@ msgstr[0] ""
|
||||
"このカテゴリから%(min_count)s個のオプションを選択する必要があります。"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:26
|
||||
#, python-format
|
||||
#, fuzzy, python-format
|
||||
#| msgid "You can choose %(max_count)s option from this category."
|
||||
#| msgid_plural ""
|
||||
#| "You can choose up to %(max_count)s options from this category."
|
||||
msgid "You can choose one option from this category."
|
||||
msgid_plural "You can choose up to %(max_count)s options from this category."
|
||||
msgstr[0] "このカテゴリから最大 %(max_count)s のオプションを選択できます。"
|
||||
@@ -35845,8 +35874,6 @@ msgid ""
|
||||
"Your cart timeout was extended. Please note that some of the prices in your "
|
||||
"cart changed."
|
||||
msgstr ""
|
||||
"カートのタイムアウトが延長されました。カートの価格の一部が変更されましたので"
|
||||
"ご注意ください。"
|
||||
|
||||
#: pretix/presale/views/cart.py:573
|
||||
msgid "Your cart timeout was extended."
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
|
||||
"PO-Revision-Date: 2026-01-12 17:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-22 20:00+0000\n"
|
||||
"Last-Translator: Ruud Hendrickx <ruud@leckxicon.eu>\n"
|
||||
"Language-Team: Dutch (informal) <https://translate.pretix.eu/projects/pretix/"
|
||||
"pretix/nl_Informal/>\n"
|
||||
@@ -4008,16 +4008,18 @@ msgstr ""
|
||||
|
||||
#: pretix/base/invoicing/peppol.py:164
|
||||
msgid "The Peppol participant ID is not registered on the Peppol network."
|
||||
msgstr "De Peppol-deelnemers-ID is niet geregistreerd op het Peppol-netwerk."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/invoicing/peppol.py:184
|
||||
msgid "Peppol participant ID"
|
||||
msgstr "Peppol-deelnemers-ID"
|
||||
|
||||
#: pretix/base/invoicing/peppol.py:200
|
||||
#, fuzzy
|
||||
#| msgid "Gift card code"
|
||||
msgctxt "peppol_invoice"
|
||||
msgid "Visual copy"
|
||||
msgstr "Visuele kopie"
|
||||
msgstr "Cadeauboncode"
|
||||
|
||||
#: pretix/base/invoicing/peppol.py:205
|
||||
msgctxt "peppol_invoice"
|
||||
@@ -8767,8 +8769,6 @@ msgid ""
|
||||
"Some products can no longer be purchased and have been removed from your "
|
||||
"cart for the following reason: %s"
|
||||
msgstr ""
|
||||
"Sommige producten kunnen niet meer gekocht worden en zijn om de volgende "
|
||||
"reden uit je winkelwagen verwijderd: %s"
|
||||
|
||||
#: pretix/base/services/cart.py:117
|
||||
msgid ""
|
||||
@@ -10037,15 +10037,21 @@ msgid "Uncategorized"
|
||||
msgstr "Ongecategoriseerd"
|
||||
|
||||
#: pretix/base/services/tax.py:43
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Your VAT ID could not be checked, as the VAT checking service of your "
|
||||
#| "country is currently not available. We will therefore need to charge VAT "
|
||||
#| "on your invoice. You can get the tax amount back via the VAT "
|
||||
#| "reimbursement process."
|
||||
msgid ""
|
||||
"Your VAT ID could not be checked, as the VAT checking service of your "
|
||||
"country is currently not available. We will therefore need to charge you the "
|
||||
"same tax rate as if you did not enter a VAT ID."
|
||||
msgstr ""
|
||||
"Je btw-nummer kon niet worden gecontroleerd, omdat de btw-controleservice "
|
||||
"van je land momenteel niet beschikbaar is. We zullen daarom hetzelfde "
|
||||
"belastingtarief in rekening moeten brengen als wanneer je geen btw-nummer "
|
||||
"had opgegeven."
|
||||
"Je btw-nummer kan niet worden gecontroleerd omdat de btw-controledienst van "
|
||||
"jouw land momenteel niet beschikbaar is. We zijn daarom genoodzaakt om de "
|
||||
"btw te factureren. Je kan het belastingbedrag terugkrijgen via het btw-"
|
||||
"terugbetalingsproces."
|
||||
|
||||
#: pretix/base/services/tax.py:47 pretix/base/services/tax.py:366
|
||||
#: pretix/base/services/tax.py:393
|
||||
@@ -10500,17 +10506,21 @@ msgid "Ask for VAT ID"
|
||||
msgstr "Vraag om btw-nummer"
|
||||
|
||||
#: pretix/base/settings.py:632
|
||||
#, python-brace-format
|
||||
#, fuzzy, python-brace-format
|
||||
#| msgid ""
|
||||
#| "Does only work if an invoice address is asked for. VAT ID is not required."
|
||||
msgid ""
|
||||
"Only works if an invoice address is asked for. VAT ID is only requested from "
|
||||
"business customers in the following countries: {countries}."
|
||||
msgstr ""
|
||||
"Werkt alleen als een factuuradres wordt gevraagd. Btw-nummer is alleen "
|
||||
"vereist voor zakelijke klanten in de volgende landen: {countries}."
|
||||
"Werkt alleen als een factuuradres wordt gevraagd. Btw-nummer is niet "
|
||||
"verplicht."
|
||||
|
||||
#: pretix/base/settings.py:651
|
||||
#, fuzzy
|
||||
#| msgid "Require name"
|
||||
msgid "Require VAT ID in"
|
||||
msgstr "Btw-nummer verplicht in"
|
||||
msgstr "Naam opgeven verplicht"
|
||||
|
||||
#: pretix/base/settings.py:657
|
||||
msgid ""
|
||||
@@ -10518,9 +10528,6 @@ msgid ""
|
||||
"ID in all countries. VAT ID will be required for all business addresses in "
|
||||
"the selected countries."
|
||||
msgstr ""
|
||||
"Het btw-nummer is standaard optioneel, omdat niet alle bedrijven in alle "
|
||||
"landen een btw-nummer toegewezen krijgen. Het btw-nummer is vereist voor "
|
||||
"alle bedrijfsadressen in de geselecteerde landen."
|
||||
|
||||
#: pretix/base/settings.py:672
|
||||
msgid "Invoice address explanation"
|
||||
@@ -14357,9 +14364,11 @@ msgstr ""
|
||||
"weer aan, ten minste voor deze site, of voor 'same-origin'-verzoeken."
|
||||
|
||||
#: pretix/base/views/js_helpers.py:41
|
||||
#, fuzzy
|
||||
#| msgid "ID"
|
||||
msgctxt "tax_id_swiss"
|
||||
msgid "UID"
|
||||
msgstr "UID"
|
||||
msgstr "ID"
|
||||
|
||||
#. Translators: Only translate to French (IDE) and Italien (IDI), otherwise keep the same
|
||||
#. Awareness around VAT IDs differes by EU country. For example, in Germany the VAT ID is assigned
|
||||
@@ -14965,8 +14974,6 @@ msgid ""
|
||||
"Formatting is not supported, as some accounting departments process mail "
|
||||
"automatically and do not handle formatted emails properly."
|
||||
msgstr ""
|
||||
"Opmaak wordt niet ondersteund, omdat sommige boekhoudafdelingen e-mails "
|
||||
"automatisch verwerken en opgemaakte e-mails niet goed kunnen verwerken."
|
||||
|
||||
#: pretix/control/forms/event.py:1356
|
||||
msgid ""
|
||||
@@ -14974,7 +14981,7 @@ msgid ""
|
||||
"the field is empty, the mail will never be sent."
|
||||
msgstr ""
|
||||
"Deze e-mail zal dit aantal dagen voor het evenement start worden verstuurd. "
|
||||
"Als dit veld leeg is, zal de mail nooit worden verstuurd."
|
||||
"Als dit veld leeg is zal de mail nooit worden verstuurd."
|
||||
|
||||
#: pretix/control/forms/event.py:1360
|
||||
#, fuzzy
|
||||
@@ -15465,7 +15472,7 @@ msgstr "Betaald"
|
||||
#: pretix/control/forms/filter.py:1304
|
||||
msgctxt "subevent"
|
||||
msgid "Date doesn't start in selected date range."
|
||||
msgstr "De datum valt niet binnen de geselecteerde datumrange."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/control/forms/filter.py:1360 pretix/control/forms/filter.py:1827
|
||||
msgid "Shop live and presale running"
|
||||
@@ -29841,9 +29848,6 @@ msgid ""
|
||||
"automatically. We recommend that you rename these in your source file to "
|
||||
"avoid problems during import."
|
||||
msgstr ""
|
||||
"Meerdere kolommen van het CSV-bestand hebben dezelfde naam en zijn "
|
||||
"automatisch hernoemd. We raden aan deze in je bronbestand te hernoemen om "
|
||||
"problemen tijdens het importeren te voorkomen."
|
||||
|
||||
#: pretix/control/views/modelimport.py:188
|
||||
msgid "The import was successful."
|
||||
@@ -31607,7 +31611,7 @@ msgstr ""
|
||||
|
||||
#: pretix/plugins/banktransfer/camtimport.py:33
|
||||
msgid "Empty file or unknown format."
|
||||
msgstr "Leeg bestand of onbekend format."
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/banktransfer/payment.py:69
|
||||
msgid ""
|
||||
@@ -34202,9 +34206,6 @@ msgid ""
|
||||
"generate you API keys with the recommended permission level for optimal "
|
||||
"usage with pretix."
|
||||
msgstr ""
|
||||
"Met de bovenstaande knop installeer je onze Stripe-app op je account en "
|
||||
"genereer je API-sleutels met het aanbevolen machtigingsniveau voor optimaal "
|
||||
"gebruik met pretix."
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:291
|
||||
msgid "Secret key"
|
||||
@@ -34265,8 +34266,6 @@ msgid ""
|
||||
"Some payment methods might need to be enabled in the settings of your Stripe "
|
||||
"account before they work properly."
|
||||
msgstr ""
|
||||
"Sommige betaalmethoden moeten mogelijk eerst worden ingeschakeld in de "
|
||||
"instellingen van je Stripe-account voordat ze correct werken."
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:350 pretix/plugins/stripe/payment.py:1572
|
||||
msgid "Alipay"
|
||||
@@ -34327,16 +34326,16 @@ msgid "Przelewy24"
|
||||
msgstr "Przelewy24"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:417 pretix/plugins/stripe/payment.py:1836
|
||||
#, fuzzy
|
||||
#| msgid "Payment by bank transfer"
|
||||
msgid "Pay by bank"
|
||||
msgstr "Betaling via bank"
|
||||
msgstr "Betaling via bankoverschrijving"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:422
|
||||
msgid ""
|
||||
"Currently only available for charges in GBP and customers with UK bank "
|
||||
"accounts, and in private preview for France and Germany."
|
||||
msgstr ""
|
||||
"Momenteel alleen beschikbaar voor betalingen in GBP en klanten met een "
|
||||
"Britse bankrekening, en in privé-preview voor Frankrijk en Duitsland."
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:429 pretix/plugins/stripe/payment.py:1789
|
||||
msgid "WeChat Pay"
|
||||
@@ -34631,8 +34630,10 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1816
|
||||
#, fuzzy
|
||||
#| msgid "WeChat Pay via Stripe"
|
||||
msgid "Revolut Pay via Stripe"
|
||||
msgstr "Revolut Pay via Stripe"
|
||||
msgstr "WeChat Pay via Stripe"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1817
|
||||
msgid "Revolut Pay"
|
||||
@@ -34645,24 +34646,28 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1835
|
||||
#, fuzzy
|
||||
#| msgid "Payment via Stripe"
|
||||
msgid "Pay by bank via Stripe"
|
||||
msgstr "Betaling door bank via Stripe"
|
||||
msgstr "Betaling via Stripe"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1841
|
||||
msgid ""
|
||||
"Pay by bank allows you to authorize a secure Open Banking payment from your "
|
||||
"banking app. Currently available only with a UK bank account."
|
||||
msgstr ""
|
||||
"Met ‘Betalen door bank’ kun je een veilige Open Banking-betaling autoriseren "
|
||||
"vanuit je bankapp. Momenteel alleen beschikbaar met een Britse bankrekening."
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1861
|
||||
#, fuzzy
|
||||
#| msgid "Payment via Stripe"
|
||||
msgid "PayPal via Stripe"
|
||||
msgstr "PayPal via Stripe"
|
||||
msgstr "Betaling via Stripe"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1869
|
||||
#, fuzzy
|
||||
#| msgid "EPS via Stripe"
|
||||
msgid "Swish via Stripe"
|
||||
msgstr "Swish via Stripe"
|
||||
msgstr "EPS via Stripe"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1874
|
||||
msgid ""
|
||||
@@ -34671,20 +34676,22 @@ msgid ""
|
||||
msgstr ""
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1893
|
||||
#, fuzzy
|
||||
#| msgid "giropay via Stripe"
|
||||
msgid "PromptPay via Stripe"
|
||||
msgstr "PromptPay via Stripe"
|
||||
msgstr "giropay via Stripe"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1898
|
||||
msgid ""
|
||||
"This payment method is available to PromptPay users in Thailand. Please have "
|
||||
"your app ready."
|
||||
msgstr ""
|
||||
"Deze betaalmethode is beschikbaar voor PromptPay-gebruikers in Thailand. "
|
||||
"Zorg ervoor dat je de app bij de hand hebt."
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1917
|
||||
#, fuzzy
|
||||
#| msgid "EPS via Stripe"
|
||||
msgid "TWINT via Stripe"
|
||||
msgstr "TWINT via Stripe"
|
||||
msgstr "EPS via Stripe"
|
||||
|
||||
#: pretix/plugins/stripe/payment.py:1922
|
||||
msgid ""
|
||||
@@ -35003,16 +35010,22 @@ msgid "Confirm payment: %(code)s"
|
||||
msgstr "Betaling bevestigen: %(code)s"
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca.html:32
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Please scan the barcode below to complete your WeChat payment. Once you "
|
||||
#| "have completed your payment, you can refresh this page."
|
||||
msgid ""
|
||||
"Please scan the QR code below to complete your PromptPay payment. Once you "
|
||||
"have completed your payment, you can refresh this page."
|
||||
msgstr ""
|
||||
"Scan de QR-code hieronder om je PromptPay-betaling uit te voeren. Als je de "
|
||||
"betaling hebt afgerond, kan je deze pagina verversen."
|
||||
"Scan de QR-code hieronder om je WeChat-betaling uit te voeren. Als je de "
|
||||
"betaling hebt afgerond kan je deze pagina verversen."
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca.html:37
|
||||
#, fuzzy
|
||||
#| msgid "Order code"
|
||||
msgid "PromptPay QR code"
|
||||
msgstr "PromptPay-QR-code"
|
||||
msgstr "Bestelcode"
|
||||
|
||||
#: pretix/plugins/stripe/templates/pretixplugins/stripe/sca_return.html:20
|
||||
msgid "Confirming your payment…"
|
||||
@@ -36159,7 +36172,10 @@ msgstr[0] "Je moet precies één optie kiezen uit deze categorie."
|
||||
msgstr[1] "Je moet %(min_count)s opties kiezen uit deze categorie."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:26
|
||||
#, python-format
|
||||
#, fuzzy, python-format
|
||||
#| msgid "You can choose at most one option from this category."
|
||||
#| msgid_plural ""
|
||||
#| "You can choose up to %(max_count)s options from this category."
|
||||
msgid "You can choose one option from this category."
|
||||
msgid_plural "You can choose up to %(max_count)s options from this category."
|
||||
msgstr[0] "Je kan maximaal één optie kiezen uit deze categorie."
|
||||
@@ -38510,12 +38526,12 @@ msgid ""
|
||||
"Your cart timeout was extended. Please note that some of the prices in your "
|
||||
"cart changed."
|
||||
msgstr ""
|
||||
"De time-out van je winkelwagen is verlengd. Merk op dat sommige prijzen in "
|
||||
"je winkelwagen gewijzigd zijn."
|
||||
|
||||
#: pretix/presale/views/cart.py:573
|
||||
#, fuzzy
|
||||
#| msgid "Your cart has been updated."
|
||||
msgid "Your cart timeout was extended."
|
||||
msgstr "De time-out van je winkelwagen is verlengd."
|
||||
msgstr "Je winkelwagen is bijgewerkt."
|
||||
|
||||
#: pretix/presale/views/cart.py:588
|
||||
msgid "The products have been successfully added to your cart."
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
|
||||
"PO-Revision-Date: 2026-01-16 09:22+0000\n"
|
||||
"Last-Translator: Richard Schreiber <schreiber@rami.io>\n"
|
||||
"PO-Revision-Date: 2025-11-07 23:00+0000\n"
|
||||
"Last-Translator: Linnea Thelander <linnea@coeo.events>\n"
|
||||
"Language-Team: Swedish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"sv/>\n"
|
||||
"Language: sv\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.15.2\n"
|
||||
"X-Generator: Weblate 5.14.2\n"
|
||||
|
||||
#: pretix/_base_settings.py:87
|
||||
msgid "English"
|
||||
@@ -8993,12 +8993,10 @@ msgstr ""
|
||||
"exporter."
|
||||
|
||||
#: pretix/base/services/invoices.py:116
|
||||
#, fuzzy, python-brace-format
|
||||
#, python-brace-format
|
||||
msgctxt "invoice"
|
||||
msgid "Please complete your payment before {expire_date}."
|
||||
msgstr ""
|
||||
"Om din betalning inte gick igenom, se till att uppdatera din "
|
||||
"betalningsinformation innan {expire_date} via knappen nedan."
|
||||
msgstr "{expire_date}."
|
||||
|
||||
#: pretix/base/services/invoices.py:128
|
||||
#, python-brace-format
|
||||
@@ -35836,7 +35834,7 @@ msgstr "Visa i backend"
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:92
|
||||
#, python-format
|
||||
msgid "A payment of %(total)s is still pending for this order."
|
||||
msgstr "Tack för din bokning på %(total)s."
|
||||
msgstr "En faktura på totalt %(total)s kommer att skickas från Coeo."
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:97
|
||||
#, fuzzy, python-format
|
||||
@@ -35845,7 +35843,7 @@ msgstr "Tack för din bokning!"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:108
|
||||
msgid "Re-try payment or choose another payment method"
|
||||
msgstr "Uppdatera eller ändra betalningsmetod"
|
||||
msgstr "Tack"
|
||||
|
||||
#: pretix/presale/templates/pretixpresale/event/order.html:126
|
||||
msgid ""
|
||||
|
||||
@@ -8,16 +8,16 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
|
||||
"PO-Revision-Date: 2026-01-12 17:00+0000\n"
|
||||
"Last-Translator: chondaen12 <chondaen12@gmail.com>\n"
|
||||
"Language-Team: Thai <https://translate.pretix.eu/projects/pretix/pretix/th/>"
|
||||
"\n"
|
||||
"PO-Revision-Date: 2024-03-30 11:00+0000\n"
|
||||
"Last-Translator: Thatthep <amaudy@gmail.com>\n"
|
||||
"Language-Team: Thai <https://translate.pretix.eu/projects/pretix/pretix/th/"
|
||||
">\n"
|
||||
"Language: th\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"X-Generator: Weblate 5.15.1\n"
|
||||
"X-Generator: Weblate 5.4.3\n"
|
||||
|
||||
#: pretix/_base_settings.py:87
|
||||
msgid "English"
|
||||
@@ -29,7 +29,7 @@ msgstr "เยอรมัน"
|
||||
|
||||
#: pretix/_base_settings.py:89
|
||||
msgid "German (informal)"
|
||||
msgstr "เยอรมัน (ไม่เป็นทางการ)"
|
||||
msgstr "เยอรมัน"
|
||||
|
||||
#: pretix/_base_settings.py:90
|
||||
msgid "Arabic"
|
||||
@@ -3567,7 +3567,7 @@ msgstr ""
|
||||
#: pretix/base/invoicing/pdf.py:732 pretix/base/invoicing/pdf.py:740
|
||||
msgctxt "invoice"
|
||||
msgid "Description"
|
||||
msgstr "คำอธิบาย"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/invoicing/pdf.py:733 pretix/base/invoicing/pdf.py:741
|
||||
msgctxt "invoice"
|
||||
@@ -3577,7 +3577,7 @@ msgstr ""
|
||||
#: pretix/base/invoicing/pdf.py:734 pretix/base/invoicing/pdf.py:1038
|
||||
msgctxt "invoice"
|
||||
msgid "Tax rate"
|
||||
msgstr "อัตราภาษี"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/invoicing/pdf.py:735
|
||||
msgctxt "invoice"
|
||||
@@ -3592,7 +3592,7 @@ msgstr ""
|
||||
#: pretix/base/invoicing/pdf.py:742
|
||||
msgctxt "invoice"
|
||||
msgid "Amount"
|
||||
msgstr "จำนวน"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/invoicing/pdf.py:869
|
||||
#, python-brace-format
|
||||
@@ -3624,12 +3624,12 @@ msgstr ""
|
||||
#: pretix/base/invoicing/pdf.py:979
|
||||
msgctxt "invoice"
|
||||
msgid "Paid by gift card"
|
||||
msgstr "จ่ายโดยบัตรของขวัญ"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/invoicing/pdf.py:984
|
||||
msgctxt "invoice"
|
||||
msgid "Remaining amount"
|
||||
msgstr "จำนวนคงเหลือ"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/invoicing/pdf.py:1008
|
||||
#, python-brace-format
|
||||
@@ -3640,7 +3640,7 @@ msgstr ""
|
||||
#: pretix/base/invoicing/pdf.py:1039
|
||||
msgctxt "invoice"
|
||||
msgid "Net value"
|
||||
msgstr "ยอดสุทธิ"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/invoicing/pdf.py:1040
|
||||
msgctxt "invoice"
|
||||
@@ -3650,7 +3650,7 @@ msgstr ""
|
||||
#: pretix/base/invoicing/pdf.py:1041
|
||||
msgctxt "invoice"
|
||||
msgid "Tax"
|
||||
msgstr "ภาษี"
|
||||
msgstr ""
|
||||
|
||||
#: pretix/base/invoicing/pdf.py:1071
|
||||
msgctxt "invoice"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-01-05 12:12+0000\n"
|
||||
"PO-Revision-Date: 2026-01-12 17:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-22 20:00+0000\n"
|
||||
"Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n"
|
||||
"Language-Team: Chinese (Traditional Han script) <https://translate.pretix.eu/"
|
||||
"projects/pretix/pretix/zh_Hant/>\n"
|
||||
@@ -288,28 +288,39 @@ msgid "The bundled item must not have bundles on its own."
|
||||
msgstr "捆綁商品不得單獨捆綁。"
|
||||
|
||||
#: pretix/api/serializers/item.py:235
|
||||
#, fuzzy
|
||||
#| msgid "The payment is too late to be accepted."
|
||||
msgid "The program start must not be empty."
|
||||
msgstr "程式啟動不能為空。"
|
||||
msgstr "付款太晚無法接受。"
|
||||
|
||||
#: pretix/api/serializers/item.py:239
|
||||
#, fuzzy
|
||||
#| msgid "The payment is too late to be accepted."
|
||||
msgid "The program end must not be empty."
|
||||
msgstr "程式結束不能為空。"
|
||||
msgstr "付款太晚無法接受。"
|
||||
|
||||
#: pretix/api/serializers/item.py:242 pretix/base/models/items.py:2321
|
||||
#, fuzzy
|
||||
#| msgid "The maximum date must not be before the minimum value."
|
||||
msgid "The program end must not be before the program start."
|
||||
msgstr "程式不能在程式開始之前結束。"
|
||||
msgstr "最大日期不得早於最小值。"
|
||||
|
||||
#: pretix/api/serializers/item.py:247 pretix/base/models/items.py:2315
|
||||
#, fuzzy
|
||||
#| msgid "You can not select a subevent if your event is not an event series."
|
||||
msgid "You cannot use program times on an event series."
|
||||
msgstr "您不能在事件系列中使用程式時間。"
|
||||
msgstr "如果你的活動不是活動系列,則無法選擇子活動。"
|
||||
|
||||
#: pretix/api/serializers/item.py:337
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Updating add-ons, bundles, or variations via PATCH/PUT is not supported. "
|
||||
#| "Please use the dedicated nested endpoint."
|
||||
msgid ""
|
||||
"Updating add-ons, bundles, program times or variations via PATCH/PUT is not "
|
||||
"supported. Please use the dedicated nested endpoint."
|
||||
msgstr ""
|
||||
"不支援透過PATCH/PUT更新附加元件、捆綁包、程式時間或變體。 請使用專用的巢狀端"
|
||||
"點。"
|
||||
"不支持通過 PATCH/PUT 更新附加組件、捆綁包或變體。 請使用專用的嵌套端點。"
|
||||
|
||||
#: pretix/api/serializers/item.py:345
|
||||
msgid "Only admission products can currently be personalized."
|
||||
@@ -559,8 +570,10 @@ msgid "Event series date deleted"
|
||||
msgstr "活動系列日期已刪除"
|
||||
|
||||
#: pretix/api/webhooks.py:375
|
||||
#, fuzzy
|
||||
#| msgid "Product name"
|
||||
msgid "Product changed"
|
||||
msgstr "產品已更改"
|
||||
msgstr "商品名稱"
|
||||
|
||||
#: pretix/api/webhooks.py:376
|
||||
msgid ""
|
||||
@@ -601,12 +614,16 @@ msgid "Waiting list entry received voucher"
|
||||
msgstr "候補名單條目收到憑證"
|
||||
|
||||
#: pretix/api/webhooks.py:413
|
||||
#, fuzzy
|
||||
#| msgid "Voucher code"
|
||||
msgid "Voucher added"
|
||||
msgstr "添加了優惠券"
|
||||
msgstr "優惠券代碼"
|
||||
|
||||
#: pretix/api/webhooks.py:417
|
||||
#, fuzzy
|
||||
#| msgid "Voucher assigned"
|
||||
msgid "Voucher changed"
|
||||
msgstr "優惠券已更改"
|
||||
msgstr "已分配的優惠券"
|
||||
|
||||
#: pretix/api/webhooks.py:418
|
||||
msgid ""
|
||||
|
||||
@@ -271,8 +271,7 @@ class BankTransfer(BasePaymentProvider):
|
||||
'request': request,
|
||||
'event': self.event,
|
||||
'settings': self.settings,
|
||||
'code': self._code(order, force=False) if order else None,
|
||||
'order': order,
|
||||
'code': self._code(order) if order else None,
|
||||
'details': self.settings.get('bank_details', as_type=LazyI18nString),
|
||||
}
|
||||
return template.render(ctx)
|
||||
@@ -296,7 +295,7 @@ class BankTransfer(BasePaymentProvider):
|
||||
md_nl2br = " \n"
|
||||
if self.settings.get('bank_details_type') == 'sepa':
|
||||
bankdetails = (
|
||||
(_("Reference"), self._code(order, force=True)),
|
||||
(_("Reference"), self._code(order)),
|
||||
(_("Amount"), money_filter(payment.amount, self.event.currency)),
|
||||
(_("Account holder"), self.settings.get('bank_details_sepa_name')),
|
||||
(_("IBAN"), ibanformat(self.settings.get('bank_details_sepa_iban'))),
|
||||
@@ -305,7 +304,7 @@ class BankTransfer(BasePaymentProvider):
|
||||
)
|
||||
else:
|
||||
bankdetails = (
|
||||
(_("Reference"), self._code(order, force=True)),
|
||||
(_("Reference"), self._code(order)),
|
||||
(_("Amount"), money_filter(payment.amount, self.event.currency)),
|
||||
)
|
||||
t += md_nl2br.join([f"**{k}:** {v}" for k, v in bankdetails])
|
||||
@@ -318,7 +317,7 @@ class BankTransfer(BasePaymentProvider):
|
||||
template = get_template('pretixplugins/banktransfer/pending.html')
|
||||
ctx = {
|
||||
'event': self.event,
|
||||
'code': self._code(payment.order, force=True),
|
||||
'code': self._code(payment.order),
|
||||
'order': payment.order,
|
||||
'amount': payment.amount,
|
||||
'payment_info': payment.info_data,
|
||||
@@ -346,25 +345,16 @@ class BankTransfer(BasePaymentProvider):
|
||||
def _render_control_info(self, request, order, info_data, **extra_context):
|
||||
template = get_template('pretixplugins/banktransfer/control.html')
|
||||
ctx = {'request': request, 'event': self.event,
|
||||
'code': self._code(order, force=True),
|
||||
'code': self._code(order),
|
||||
'payment_info': info_data, 'order': order,
|
||||
**extra_context}
|
||||
return template.render(ctx)
|
||||
|
||||
def _code(self, order, force=False):
|
||||
def _code(self, order):
|
||||
prefix = self.settings.get('prefix', default='')
|
||||
li = order.invoices.last()
|
||||
invoice_number = li.number if self.settings.get('include_invoice_number', as_type=bool) and li else ''
|
||||
|
||||
invoice_will_be_generated = (
|
||||
not li and
|
||||
self.settings.get('include_invoice_number', as_type=bool) and
|
||||
order.event.settings.get('invoice_generate') == 'paid' and
|
||||
self.requires_invoice_immediately
|
||||
)
|
||||
if invoice_will_be_generated and not force:
|
||||
return None
|
||||
|
||||
code = " ".join((prefix, order.full_code, invoice_number)).strip(" ")
|
||||
|
||||
if self.settings.get('omit_hyphen', as_type=bool):
|
||||
|
||||
@@ -24,13 +24,7 @@
|
||||
{{ details | rich_text }}
|
||||
{% if not code %}</div>{% endif %}
|
||||
|
||||
{% if not code and order %}
|
||||
<p>
|
||||
<strong>
|
||||
{% trans "We will assign you a personal reference code in the next step." %}
|
||||
</strong>
|
||||
</p>
|
||||
{% elif not code %}
|
||||
{% if not code %}
|
||||
<p>
|
||||
<strong>
|
||||
{% trans "We will assign you a personal reference code to use after you completed the order." %}
|
||||
|
||||
@@ -19,30 +19,6 @@ $(function () {
|
||||
fillOpacity: 0.3,
|
||||
behaveLikeLine: true
|
||||
});
|
||||
new Morris.Area({
|
||||
element: 'abd_chart',
|
||||
data: JSON.parse($("#abd-data").html()),
|
||||
xkey: 'date',
|
||||
ykeys: ['ordered', 'paid'],
|
||||
labels: [gettext('Attendees (ordered)'), gettext('Attendees (paid)')],
|
||||
lineColors: ['#3b1c4a', '#50a167'],
|
||||
smooth: false,
|
||||
resize: true,
|
||||
fillOpacity: 0.3,
|
||||
behaveLikeLine: true
|
||||
});
|
||||
new Morris.Area({
|
||||
element: 'abt_chart',
|
||||
data: JSON.parse($("#abt-data").html()),
|
||||
xkey: 'date',
|
||||
ykeys: ['ordered', 'paid'],
|
||||
labels: [gettext('Attendees (ordered)'), gettext('Attendees (paid)')],
|
||||
lineColors: ['#3b1c4a', '#50a167'],
|
||||
smooth: false,
|
||||
resize: true,
|
||||
fillOpacity: 0.3,
|
||||
behaveLikeLine: true
|
||||
});
|
||||
new Morris.Area({
|
||||
element: 'rev_chart',
|
||||
data: JSON.parse($("#rev-data").html()),
|
||||
|
||||
@@ -24,48 +24,6 @@
|
||||
<small>
|
||||
{% blocktrans trimmed %}
|
||||
Orders paid in multiple payments are shown with the date of their last payment.
|
||||
Placed orders include all orders (pending, paid, cancelled, and expired);
|
||||
paid orders include only paid orders and exclude all cancelled orders.
|
||||
{% endblocktrans %}
|
||||
</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "Attendees by day" %}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="abd_chart" class="chart"></div>
|
||||
<p class="help-block">
|
||||
<small>
|
||||
{% blocktrans trimmed %}
|
||||
Attendees in orders paid in multiple instalments are shown using the date of the
|
||||
final payment. Order dates reflect when the order was first placed; attendees added
|
||||
later via additional order positions still use the original order date. Attendees in
|
||||
placed orders include those from all order states (pending, paid, cancelled, and
|
||||
expired); attendees in paid orders include only those from paid orders and exclude
|
||||
those from cancelled orders.
|
||||
{% endblocktrans %}
|
||||
</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{% trans "Attendees by time" %}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="abt_chart" class="chart"></div>
|
||||
<p class="help-block">
|
||||
<small>
|
||||
{% blocktrans trimmed %}
|
||||
Attendees in orders paid in multiple instalments are shown using the date of the
|
||||
final payment. Order dates reflect when the order was first placed; attendees added
|
||||
later via additional order positions still use the original order date. Attendees in
|
||||
placed orders include those from all order states (pending, paid, cancelled, and
|
||||
expired); attendees in paid orders include only those from paid orders and exclude
|
||||
those from cancelled orders.
|
||||
{% endblocktrans %}
|
||||
</small>
|
||||
</p>
|
||||
@@ -87,19 +45,10 @@
|
||||
{% endif %}
|
||||
<p class="help-block">
|
||||
<small>
|
||||
{% if request.GET.subevent %}
|
||||
{% blocktrans trimmed %}
|
||||
Only fully paid orders are counted.
|
||||
Orders paid in multiple payments are shown with the date of their last payment.
|
||||
Revenue excludes all fees, including cancellation fees.
|
||||
{% endblocktrans %}
|
||||
{% else %}
|
||||
{% blocktrans trimmed %}
|
||||
Only fully paid orders are counted.
|
||||
Orders paid in multiple payments are shown with the date of their last payment.
|
||||
Revenue includes all fees, including cancellation fees from cancelled orders.
|
||||
{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% blocktrans trimmed %}
|
||||
Only fully paid orders are counted.
|
||||
Orders paid in multiple payments are shown with the date of their last payment.
|
||||
{% endblocktrans %}
|
||||
</small>
|
||||
</p>
|
||||
</div>
|
||||
@@ -110,14 +59,6 @@
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div id="obp_chart" class="chart"></div>
|
||||
<p class="help-block">
|
||||
<small>
|
||||
{% blocktrans trimmed %}
|
||||
Placed orders include all orders (pending, paid, cancelled, and expired);
|
||||
paid orders include only paid orders and exclude all cancelled orders.
|
||||
{% endblocktrans %}
|
||||
</small>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% if seats %}
|
||||
@@ -217,8 +158,6 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
<script type="application/json" id="obd-data">{{ obd_data|escapejson }}</script>
|
||||
<script type="application/json" id="abd-data">{{ abd_data|escapejson }}</script>
|
||||
<script type="application/json" id="abt-data">{{ abt_data|escapejson }}</script>
|
||||
<script type="application/json" id="rev-data">{{ rev_data|escapejson }}</script>
|
||||
<script type="application/json" id="obp-data">{{ obp_data|escapejson }}</script>
|
||||
<script type="application/text" id="currency">{{ request.event.currency }}</script>
|
||||
|
||||
@@ -103,10 +103,7 @@ class IndexView(EventPermissionRequiredMixin, ChartContainingView, TemplateView)
|
||||
day = o['datetime'].astimezone(tz).date()
|
||||
ordered_by_day[day] = ordered_by_day.get(day, 0) + 1
|
||||
paid_by_day = {}
|
||||
for o in oqs.filter(
|
||||
event=self.request.event, payment_date__isnull=False,
|
||||
status=Order.STATUS_PAID, all_positions__canceled=False
|
||||
).distinct().values('payment_date'):
|
||||
for o in oqs.filter(event=self.request.event, payment_date__isnull=False).values('payment_date'):
|
||||
day = o['payment_date'].astimezone(tz).date()
|
||||
paid_by_day[day] = paid_by_day.get(day, 0) + 1
|
||||
|
||||
@@ -128,56 +125,10 @@ class IndexView(EventPermissionRequiredMixin, ChartContainingView, TemplateView)
|
||||
ctx['obd_data'] = json.dumps(data)
|
||||
cache.set('statistics_obd_data' + ckey, ctx['obd_data'])
|
||||
|
||||
# Attendees by day/time
|
||||
ctx['abd_data'] = cache.get('statistics_abd_data' + ckey)
|
||||
ctx['abt_data'] = cache.get('statistics_abt_data' + ckey)
|
||||
if not ctx['abd_data'] or not ctx['abt_data']:
|
||||
opqs = OrderPosition.all.filter(order__event=self.request.event, item__admission=True).annotate(
|
||||
payment_date=Subquery(op_date, output_field=DateTimeField())
|
||||
)
|
||||
if subevent:
|
||||
opqs = opqs.filter(subevent=subevent)
|
||||
|
||||
ordered_by_day = {}
|
||||
for p in opqs.values('order__datetime'):
|
||||
day = p['order__datetime'].astimezone(tz).date()
|
||||
ordered_by_day[day] = ordered_by_day.get(day, 0) + 1
|
||||
|
||||
paid_by_day = {}
|
||||
for p in opqs.filter(payment_date__isnull=False, canceled=False, order__status=Order.STATUS_PAID).values('payment_date'):
|
||||
day = p['payment_date'].astimezone(tz).date()
|
||||
paid_by_day[day] = paid_by_day.get(day, 0) + 1
|
||||
|
||||
day_data = []
|
||||
time_data = []
|
||||
for d in dateutil.rrule.rrule(
|
||||
dateutil.rrule.DAILY,
|
||||
dtstart=min(ordered_by_day.keys()) if ordered_by_day else datetime.date.today(),
|
||||
until=max(
|
||||
max(ordered_by_day.keys() if paid_by_day else [datetime.date.today()]),
|
||||
max(paid_by_day.keys() if paid_by_day else [datetime.date(1970, 1, 1)])
|
||||
)):
|
||||
d = d.date()
|
||||
day_data.append({
|
||||
'date': d.strftime('%Y-%m-%d'),
|
||||
'ordered': ordered_by_day.get(d, 0),
|
||||
'paid': paid_by_day.get(d, 0)
|
||||
})
|
||||
time_data.append({
|
||||
'date': d.strftime('%Y-%m-%d'),
|
||||
'ordered': (time_data[-1]["ordered"] if time_data else 0) + ordered_by_day.get(d, 0),
|
||||
'paid': (time_data[-1]["paid"] if time_data else 0) + paid_by_day.get(d, 0)
|
||||
})
|
||||
|
||||
ctx['abd_data'] = json.dumps(day_data)
|
||||
ctx['abt_data'] = json.dumps(time_data)
|
||||
cache.set('statistics_abd_data' + ckey, ctx['abd_data'])
|
||||
cache.set('statistics_abt_data' + ckey, ctx['abt_data'])
|
||||
|
||||
# Orders by product
|
||||
ctx['obp_data'] = cache.get('statistics_obp_data' + ckey)
|
||||
if not ctx['obp_data']:
|
||||
opqs = OrderPosition.all
|
||||
opqs = OrderPosition.objects
|
||||
if subevent:
|
||||
opqs = opqs.filter(subevent=subevent)
|
||||
num_ordered = {
|
||||
@@ -190,7 +141,7 @@ class IndexView(EventPermissionRequiredMixin, ChartContainingView, TemplateView)
|
||||
num_paid = {
|
||||
p['item']: p['cnt']
|
||||
for p in (opqs
|
||||
.filter(order__event=self.request.event, order__status=Order.STATUS_PAID, canceled=False)
|
||||
.filter(order__event=self.request.event, order__status=Order.STATUS_PAID)
|
||||
.values('item')
|
||||
.annotate(cnt=Count('id')).order_by())
|
||||
}
|
||||
|
||||
@@ -313,12 +313,12 @@
|
||||
<input type="hidden" name="variation_{{ line.item.id }}_{{ line.variation.id }}"
|
||||
value="1" />
|
||||
<input type="hidden" name="price_{{ line.item.id }}_{{ line.variation.id }}"
|
||||
value="{% if event.settings.display_net_prices %}{{ line.price_for_input_net }}{% else %}{{ line.price_for_input }}{% endif %}" />
|
||||
value="{% if event.settings.display_net_prices %}{{ line.bundle_sum_net }}{% else %}{{ line.bundle_sum }}{% endif %}" />
|
||||
{% else %}
|
||||
<input type="hidden" name="item_{{ line.item.id }}"
|
||||
value="1" />
|
||||
<input type="hidden" name="price_{{ line.item.id }}"
|
||||
value="{% if event.settings.display_net_prices %}{{ line.price_for_input_net }}{% else %}{{ line.price_for_input }}{% endif %}" />
|
||||
value="{% if event.settings.display_net_prices %}{{ line.bundle_sum_net }}{% else %}{{ line.bundle_sum }}{% endif %}" />
|
||||
{% endif %}
|
||||
<button class="btn btn-mini btn-link {% if line.seat %}btn-invisible{% endif %}" title="{% blocktrans with item=line.item.name %}Add one more {{item}} to your cart{% endblocktrans %}" {% if line.seat %}disabled{% endif %}>
|
||||
<i class="fa fa-plus" aria-hidden="true"></i>
|
||||
|
||||
@@ -48,7 +48,7 @@ from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from pretix.base.i18n import get_language_without_region, set_region
|
||||
from pretix.base.i18n import get_language_without_region
|
||||
from pretix.base.middleware import get_supported_language
|
||||
from pretix.base.models import (
|
||||
CartPosition, Customer, InvoiceAddress, ItemAddOn, OrderFee, Question,
|
||||
@@ -209,8 +209,6 @@ class CartMixin:
|
||||
pos.valid_from,
|
||||
pos.valid_until,
|
||||
pos.used_membership_id,
|
||||
pos.gross_price_before_rounding,
|
||||
pos.tax_value_before_rounding,
|
||||
)
|
||||
|
||||
positions = []
|
||||
@@ -224,8 +222,8 @@ class CartMixin:
|
||||
if not hasattr(group, 'tax_rule'):
|
||||
group.tax_rule = group.item.tax_rule
|
||||
|
||||
group.price_for_input = group.gross_price_before_rounding + sum(a.gross_price_before_rounding for a in has_addons[group.pk])
|
||||
group.price_for_input_net = group.net_price_before_rounding + sum(a.net_price_before_rounding for a in has_addons[group.pk])
|
||||
group.bundle_sum = group.price + sum(a.price for a in has_addons[group.pk])
|
||||
group.bundle_sum_net = group.net_price + sum(a.net_price for a in has_addons[group.pk])
|
||||
|
||||
if answers:
|
||||
group.cache_answers(all=False)
|
||||
@@ -544,7 +542,6 @@ def iframe_entry_view_wrapper(view_func):
|
||||
region = request.event.settings.region
|
||||
if '-' not in lng and region:
|
||||
lng += '-' + region.lower()
|
||||
set_region(region)
|
||||
|
||||
# with language() is not good enough here – we really need to take the role of LocaleMiddleware and modify
|
||||
# global state, because template rendering might be happening lazily.
|
||||
|
||||
@@ -42,7 +42,6 @@ import os
|
||||
import re
|
||||
from collections import OrderedDict, defaultdict
|
||||
from decimal import Decimal
|
||||
from urllib.parse import quote
|
||||
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
@@ -104,55 +103,13 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OrderDetailMixin(NoSearchIndexViewMixin):
|
||||
def _allow_anonymous_access(self):
|
||||
return not (self.request.organizer.settings.customer_accounts and
|
||||
self.request.organizer.settings.customer_accounts_require_login_for_order_access)
|
||||
|
||||
def verify_order_access(self):
|
||||
o = self.order
|
||||
|
||||
if o is None:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
|
||||
if o is False:
|
||||
login_url = eventreverse(self.request.organizer, 'presale:organizer.customer.login', kwargs={})
|
||||
|
||||
if hasattr(self.request, "event_domain") and self.request.event_domain:
|
||||
next_url = quote(self.request.scheme + "://" + self.request.get_host() + self.request.get_full_path())
|
||||
return redirect_to_url(f'{login_url}?next={next_url}&request_cross_domain_customer_auth=true')
|
||||
|
||||
else:
|
||||
next_url = quote(self.request.get_full_path())
|
||||
return redirect_to_url(f'{login_url}?next={next_url}')
|
||||
|
||||
return None
|
||||
|
||||
@cached_property
|
||||
def order(self):
|
||||
"""
|
||||
Returns the order object when access is permitted, returns `False` when the
|
||||
order exists but requires authentication, and returns `None` when the order
|
||||
does not exist or access is denied entirely.
|
||||
"""
|
||||
try:
|
||||
order = self.request.event.orders.filter().select_related('event').get_with_secret_check(
|
||||
return self.request.event.orders.filter().select_related('event').get_with_secret_check(
|
||||
code=self.kwargs['order'], received_secret=self.kwargs['secret'], tag=None,
|
||||
)
|
||||
|
||||
if has_event_access_permission(self.request, 'can_view_orders'):
|
||||
return order
|
||||
|
||||
if order.customer is None or not order.customer.is_verified or self._allow_anonymous_access():
|
||||
return order
|
||||
|
||||
if not self.request.customer:
|
||||
return False
|
||||
|
||||
if order.customer_id == self.request.customer.pk:
|
||||
return order
|
||||
|
||||
return None
|
||||
|
||||
except Order.DoesNotExist:
|
||||
return None
|
||||
|
||||
@@ -162,13 +119,6 @@ class OrderDetailMixin(NoSearchIndexViewMixin):
|
||||
'secret': self.order.secret
|
||||
})
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
resp = self.verify_order_access()
|
||||
if resp:
|
||||
return resp
|
||||
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
|
||||
class OrderPositionDetailMixin(NoSearchIndexViewMixin):
|
||||
@cached_property
|
||||
@@ -207,6 +157,8 @@ class OrderPositionDetailMixin(NoSearchIndexViewMixin):
|
||||
@method_decorator(xframe_options_exempt, 'dispatch')
|
||||
class OrderOpen(EventViewMixin, OrderDetailMixin, View):
|
||||
def get(self, request, *args, **kwargs):
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
if self.order.check_email_confirm_secret(kwargs.get('hash')) and not self.order.email_known_to_work:
|
||||
self.order.log_action('pretix.event.order.contact.confirmed')
|
||||
self.order.email_known_to_work = True
|
||||
@@ -287,6 +239,8 @@ class OrderDetails(EventViewMixin, OrderDetailMixin, CartMixin, TicketPageMixin,
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.kwargs = kwargs
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
if self.order.status == Order.STATUS_PENDING:
|
||||
payment_to_complete = self.order.payments.filter(state=OrderPayment.PAYMENT_STATE_CREATED, process_initiated=False).first()
|
||||
if payment_to_complete:
|
||||
@@ -406,11 +360,8 @@ class OrderPaymentStart(EventViewMixin, OrderDetailMixin, TemplateView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
self.request.pci_dss_payment_page = True
|
||||
|
||||
resp = self.verify_order_access()
|
||||
if resp:
|
||||
return resp
|
||||
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
if (self.order.status not in (Order.STATUS_PENDING, Order.STATUS_EXPIRED)
|
||||
or self.payment.state != OrderPayment.PAYMENT_STATE_CREATED
|
||||
or not self.payment.payment_provider.is_enabled
|
||||
@@ -477,11 +428,8 @@ class OrderPaymentConfirm(EventViewMixin, OrderDetailMixin, TemplateView):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
|
||||
resp = self.verify_order_access()
|
||||
if resp:
|
||||
return resp
|
||||
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
if self.payment.state != OrderPayment.PAYMENT_STATE_CREATED or self.order._can_be_paid() is not True:
|
||||
messages.error(request, _('The payment for this order cannot be continued.'))
|
||||
return redirect(self.get_order_url())
|
||||
@@ -547,11 +495,8 @@ class OrderPaymentComplete(EventViewMixin, OrderDetailMixin, View):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
|
||||
resp = self.verify_order_access()
|
||||
if resp:
|
||||
return resp
|
||||
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
if self.payment.state != OrderPayment.PAYMENT_STATE_CREATED or self.order._can_be_paid() is not True:
|
||||
messages.error(request, _('The payment for this order cannot be continued.'))
|
||||
return redirect(self.get_order_url())
|
||||
@@ -596,11 +541,8 @@ class OrderPayChangeMethod(EventViewMixin, OrderDetailMixin, TemplateView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
self.request.pci_dss_payment_page = True
|
||||
|
||||
resp = self.verify_order_access()
|
||||
if resp:
|
||||
return resp
|
||||
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
if self.order.status not in (Order.STATUS_PENDING, Order.STATUS_EXPIRED) or self.order._can_be_paid() is not True:
|
||||
messages.error(request, _('The payment method for this order cannot be changed.'))
|
||||
return redirect(self.get_order_url())
|
||||
@@ -785,6 +727,8 @@ class OrderInvoiceCreate(EventViewMixin, OrderDetailMixin, View):
|
||||
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
return super().dispatch(request, *args, **kwargs)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
@@ -916,11 +860,8 @@ class OrderModify(EventViewMixin, OrderDetailMixin, OrderQuestionsViewMixin, Tem
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
self.kwargs = kwargs
|
||||
|
||||
resp = self.verify_order_access()
|
||||
if resp:
|
||||
return resp
|
||||
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
if not self.order.can_modify_answers:
|
||||
messages.error(request, _('You cannot modify this order'))
|
||||
return redirect(self.get_order_url())
|
||||
@@ -1006,11 +947,8 @@ class OrderCancel(EventViewMixin, OrderDetailMixin, TemplateView):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
self.kwargs = kwargs
|
||||
|
||||
resp = self.verify_order_access()
|
||||
if resp:
|
||||
return resp
|
||||
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
if not self.order.user_cancel_allowed:
|
||||
messages.error(request, _('You cannot cancel this order.'))
|
||||
return redirect(self.get_order_url())
|
||||
@@ -1057,7 +995,14 @@ class OrderCancelDo(EventViewMixin, OrderDetailMixin, AsyncAction, View):
|
||||
def get_error_url(self):
|
||||
return self.get_order_url()
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
if not self.order.user_cancel_allowed:
|
||||
messages.error(request, _('You cannot cancel this order.'))
|
||||
return redirect(self.get_order_url())
|
||||
@@ -1348,6 +1293,9 @@ class OrderPositionDownload(OrderDownloadMixin, EventViewMixin, OrderPositionDet
|
||||
class InvoiceDownload(EventViewMixin, OrderDetailMixin, View):
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
|
||||
try:
|
||||
invoice = Invoice.objects.get(
|
||||
event=self.request.event,
|
||||
@@ -1740,11 +1688,8 @@ class OrderChange(OrderChangeMixin, EventViewMixin, OrderDetailMixin, TemplateVi
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.request = request
|
||||
self.kwargs = kwargs
|
||||
|
||||
resp = self.verify_order_access()
|
||||
if resp:
|
||||
return resp
|
||||
|
||||
if not self.order:
|
||||
raise Http404(_('Unknown order code or not authorized to access this order.'))
|
||||
if not self.order.user_change_allowed:
|
||||
messages.error(request, _('You cannot change this order.'))
|
||||
return redirect(self.get_order_url())
|
||||
|
||||
@@ -781,39 +781,6 @@ testcases_single_rule = [
|
||||
)
|
||||
),
|
||||
|
||||
# Distribute discounts somewhat equally over addon groups
|
||||
(
|
||||
(
|
||||
Discount(
|
||||
condition_min_count=3,
|
||||
benefit_discount_matching_percent=20,
|
||||
condition_apply_to_addons=True,
|
||||
benefit_only_apply_to_cheapest_n_matches=1,
|
||||
condition_ignore_voucher_discounted=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
(2, 1, now(), Decimal('0.00'), None, False, Decimal('10.00')), # Main product
|
||||
(1, 1, now(), Decimal('100.00'), 1, False, Decimal('0.00')),
|
||||
(1, 1, now(), Decimal('100.00'), 1, False, Decimal('0.00')),
|
||||
(1, 1, now(), Decimal('100.00'), 1, False, Decimal('0.00')),
|
||||
(2, 1, now(), Decimal('0.00'), None, False, Decimal('10.00')), # Main product
|
||||
(1, 1, now(), Decimal('100.00'), 2, False, Decimal('0.00')),
|
||||
(1, 1, now(), Decimal('100.00'), 2, False, Decimal('0.00')),
|
||||
(1, 1, now(), Decimal('100.00'), 2, False, Decimal('0.00')),
|
||||
),
|
||||
(
|
||||
Decimal('0.00'),
|
||||
Decimal('100.00'),
|
||||
Decimal('100.00'),
|
||||
Decimal('80.00'),
|
||||
Decimal('0.00'),
|
||||
Decimal('100.00'),
|
||||
Decimal('100.00'),
|
||||
Decimal('80.00'),
|
||||
)
|
||||
),
|
||||
|
||||
# Ignore bundled
|
||||
(
|
||||
(
|
||||
|
||||
@@ -68,6 +68,9 @@ def test_urlreplace_replace_parameter():
|
||||
|
||||
("en", Decimal("1023"), "JPY", "¥1,023"),
|
||||
|
||||
("pt-pt", Decimal("10.00"), "EUR", "10,00" + NBSP + "€"),
|
||||
("pt-br", Decimal("10.00"), "EUR", "€" + NBSP + "10,00"),
|
||||
|
||||
# unknown currency
|
||||
("de", Decimal("1234.56"), "FOO", "1.234,56" + NBSP + "FOO"),
|
||||
("de", Decimal("1234.567"), "FOO", "1.234,57" + NBSP + "FOO"),
|
||||
|
||||
@@ -2611,11 +2611,3 @@ def test_approve_cancellation_request(client, env):
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert doc.select('input[name=refund-new-giftcard]')[0]['value'] == '10.00'
|
||||
assert not env[2].cancellation_requests.exists()
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_view_as_user(client, env):
|
||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||
response = client.get('/%s/%s/order/%s/%s/' % (env[0].organizer.slug, env[0].slug, env[2].code, env[2].secret))
|
||||
assert response.status_code == 200
|
||||
assert env[2].code in response.content.decode()
|
||||
|
||||
@@ -19,12 +19,9 @@
|
||||
# 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 pytest
|
||||
from django.utils.translation import get_language
|
||||
|
||||
from pretix.base.i18n import (
|
||||
get_babel_locale, get_language_without_region, language,
|
||||
)
|
||||
from pretix.base.i18n import get_language_without_region, language
|
||||
from pretix.helpers.i18n import get_javascript_format, get_moment_locale
|
||||
|
||||
|
||||
@@ -45,26 +42,22 @@ def test_get_locale():
|
||||
assert get_moment_locale('en-CA') == 'en-ca'
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
["lng_in", "region_in", "lng_out", "lng_without_region_out", "babel_out"],
|
||||
[
|
||||
("en", None, "en", "en", "en"),
|
||||
("en-us", None, "en-us", "en", "en_US"),
|
||||
("en", "US", "en-us", "en", "en_US"),
|
||||
("de", None, "de", "de", "de"),
|
||||
("de", "US", "de-us", "de", "de"),
|
||||
("de", "DE", "de-de", "de", "de_DE"),
|
||||
("de-informal", "DE", "de-informal", "de-informal", "de_DE"),
|
||||
("de-informal", "CH", "de-informal", "de-informal", "de_CH"),
|
||||
("pt-pt", "PT", "pt-pt", "pt-pt", "pt_PT"),
|
||||
("es", "MX", "es-mx", "es", "es_MX"),
|
||||
("es-419", "MX", "es-419", "es-419", "es_MX"),
|
||||
("zh-hans", "CN", "zh-hans", "zh-hans", "zh_Hans_CN"),
|
||||
("zh-hant", "TW", "zh-hant", "zh-hant", "zh_Hant_TW"),
|
||||
],
|
||||
)
|
||||
def test_set_region(lng_in, region_in, lng_out, lng_without_region_out, babel_out):
|
||||
with language(lng_in, region_in):
|
||||
assert get_language() == lng_out
|
||||
assert get_language_without_region() == lng_without_region_out
|
||||
assert str(get_babel_locale()) == babel_out
|
||||
def test_set_region():
|
||||
with language('de'):
|
||||
assert get_language() == 'de'
|
||||
assert get_language_without_region() == 'de'
|
||||
with language('de', 'US'):
|
||||
assert get_language() == 'de-us'
|
||||
assert get_language_without_region() == 'de'
|
||||
with language('de', 'DE'):
|
||||
assert get_language() == 'de-de'
|
||||
assert get_language_without_region() == 'de'
|
||||
with language('de-informal', 'DE'):
|
||||
assert get_language() == 'de-informal'
|
||||
assert get_language_without_region() == 'de-informal'
|
||||
with language('pt', 'PT'):
|
||||
assert get_language() == 'pt-pt'
|
||||
assert get_language_without_region() == 'pt-pt'
|
||||
with language('pt-pt', 'BR'):
|
||||
assert get_language() == 'pt-pt'
|
||||
assert get_language_without_region() == 'pt-pt'
|
||||
|
||||
@@ -1738,222 +1738,3 @@ class OrdersTest(BaseOrdersTest):
|
||||
self.order.secret, a.pk, match.group(1))
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_require_login_for_order_access_disabled_unauth(self):
|
||||
self.orga.settings.customer_accounts = True
|
||||
|
||||
with scopes_disabled():
|
||||
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
|
||||
customer.set_password("foo")
|
||||
customer.save()
|
||||
|
||||
self.order.customer = customer
|
||||
self.order.save()
|
||||
|
||||
self.orga.settings.customer_accounts_require_login_for_order_access = False
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert len(doc.select(".cart-row")) > 0
|
||||
assert "pending" in doc.select(".order-details")[0].text.lower()
|
||||
assert "Peter" in response.content.decode()
|
||||
assert "Lukas" not in response.content.decode()
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.ticket_pos.positionid, self.ticket_pos.web_secret)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert len(doc.select(".cart-row")) > 0
|
||||
assert "pending" in doc.select(".order-details")[0].text.lower()
|
||||
assert "Peter" in response.content.decode()
|
||||
assert "Lukas" not in response.content.decode()
|
||||
|
||||
def test_require_login_for_order_access_enabled_unauth(self):
|
||||
self.orga.settings.customer_accounts = True
|
||||
|
||||
with scopes_disabled():
|
||||
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
|
||||
customer.set_password("foo")
|
||||
customer.save()
|
||||
|
||||
self.order.customer = customer
|
||||
self.order.save()
|
||||
|
||||
self.orga.settings.customer_accounts_require_login_for_order_access = True
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
||||
)
|
||||
assert response.status_code == 302
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.ticket_pos.positionid, self.ticket_pos.web_secret)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert len(doc.select(".cart-row")) > 0
|
||||
assert "pending" in doc.select(".order-details")[0].text.lower()
|
||||
assert "Peter" in response.content.decode()
|
||||
assert "Lukas" not in response.content.decode()
|
||||
|
||||
def test_require_login_for_order_access_disabled_auth(self):
|
||||
self.orga.settings.customer_accounts = True
|
||||
|
||||
with scopes_disabled():
|
||||
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
|
||||
customer.set_password("foo")
|
||||
customer.save()
|
||||
|
||||
self.order.customer = customer
|
||||
self.order.save()
|
||||
|
||||
self.orga.settings.customer_accounts_require_login_for_order_access = False
|
||||
|
||||
response = self.client.post('/%s/account/login' % (self.orga.slug), {
|
||||
'email': 'john@example.org',
|
||||
'password': 'foo',
|
||||
})
|
||||
assert response.status_code == 302
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert len(doc.select(".cart-row")) > 0
|
||||
assert "pending" in doc.select(".order-details")[0].text.lower()
|
||||
assert "Peter" in response.content.decode()
|
||||
assert "Lukas" not in response.content.decode()
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.ticket_pos.positionid, self.ticket_pos.web_secret)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert len(doc.select(".cart-row")) > 0
|
||||
assert "pending" in doc.select(".order-details")[0].text.lower()
|
||||
assert "Peter" in response.content.decode()
|
||||
assert "Lukas" not in response.content.decode()
|
||||
|
||||
def test_require_login_for_order_access_enabled_auth(self):
|
||||
self.orga.settings.customer_accounts = True
|
||||
|
||||
with scopes_disabled():
|
||||
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
|
||||
customer.set_password("foo")
|
||||
customer.save()
|
||||
|
||||
self.order.customer = customer
|
||||
self.order.save()
|
||||
|
||||
self.orga.settings.customer_accounts_require_login_for_order_access = True
|
||||
|
||||
response = self.client.post('/%s/account/login' % (self.orga.slug), {
|
||||
'email': 'john@example.org',
|
||||
'password': 'foo',
|
||||
})
|
||||
assert response.status_code == 302
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert len(doc.select(".cart-row")) > 0
|
||||
assert "pending" in doc.select(".order-details")[0].text.lower()
|
||||
assert "Peter" in response.content.decode()
|
||||
assert "Lukas" not in response.content.decode()
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/ticket/%s/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code,
|
||||
self.ticket_pos.positionid, self.ticket_pos.web_secret)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert len(doc.select(".cart-row")) > 0
|
||||
assert "pending" in doc.select(".order-details")[0].text.lower()
|
||||
assert "Peter" in response.content.decode()
|
||||
assert "Lukas" not in response.content.decode()
|
||||
|
||||
def test_require_login_for_order_access_accounts_disabled(self):
|
||||
self.orga.settings.customer_accounts = True
|
||||
|
||||
with scopes_disabled():
|
||||
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
|
||||
customer.set_password("foo")
|
||||
customer.save()
|
||||
|
||||
self.order.customer = customer
|
||||
self.order.save()
|
||||
|
||||
self.orga.settings.customer_accounts = False
|
||||
self.orga.settings.customer_accounts_require_login_for_order_access = True
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert len(doc.select(".cart-row")) > 0
|
||||
assert "pending" in doc.select(".order-details")[0].text.lower()
|
||||
assert "Peter" in response.content.decode()
|
||||
assert "Lukas" not in response.content.decode()
|
||||
|
||||
def test_require_login_for_order_access_enabled_wrong_customer(self):
|
||||
self.orga.settings.customer_accounts = True
|
||||
|
||||
with scopes_disabled():
|
||||
customer = self.orga.customers.create(email='john@example.org', is_verified=True)
|
||||
customer.set_password("foo")
|
||||
customer.save()
|
||||
|
||||
self.order.customer = customer
|
||||
self.order.save()
|
||||
|
||||
with scopes_disabled():
|
||||
customer = self.orga.customers.create(email='jill@example.org', is_verified=True)
|
||||
customer.set_password("bar")
|
||||
customer.save()
|
||||
|
||||
self.orga.settings.customer_accounts_require_login_for_order_access = True
|
||||
|
||||
response = self.client.post('/%s/account/login' % (self.orga.slug), {
|
||||
'email': 'jill@example.org',
|
||||
'password': 'bar',
|
||||
})
|
||||
assert response.status_code == 302
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
||||
)
|
||||
assert response.status_code == 404
|
||||
|
||||
def test_require_login_for_order_access_enabled_unverified_account(self):
|
||||
self.orga.settings.customer_accounts = True
|
||||
|
||||
with scopes_disabled():
|
||||
customer = self.orga.customers.create(email='john@example.org', is_verified=False)
|
||||
customer.set_password("foo")
|
||||
customer.save()
|
||||
|
||||
self.order.customer = customer
|
||||
self.order.save()
|
||||
|
||||
self.orga.settings.customer_accounts_require_login_for_order_access = True
|
||||
|
||||
response = self.client.get(
|
||||
'/%s/%s/order/%s/%s/' % (self.orga.slug, self.event.slug, self.order.code, self.order.secret)
|
||||
)
|
||||
assert response.status_code == 200
|
||||
doc = BeautifulSoup(response.content.decode(), "lxml")
|
||||
assert len(doc.select(".cart-row")) > 0
|
||||
assert "pending" in doc.select(".order-details")[0].text.lower()
|
||||
assert "Peter" in response.content.decode()
|
||||
assert "Lukas" not in response.content.decode()
|
||||
|
||||
Reference in New Issue
Block a user