mirror of
https://github.com/pretix/pretix.git
synced 2025-12-06 21:42:49 +00:00
Compare commits
20 Commits
a11y-fix-w
...
dialog-bac
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5aa8b6c329 | ||
|
|
a84beef269 | ||
|
|
7c59ec51ca | ||
|
|
bf47da521c | ||
|
|
e3b74249c9 | ||
|
|
1791a63f87 | ||
|
|
f931362bc5 | ||
|
|
a836dc1588 | ||
|
|
8b6685dd89 | ||
|
|
7463e41be8 | ||
|
|
31b2a9026d | ||
|
|
1d49d7cbf7 | ||
|
|
30570fe287 | ||
|
|
00508dea99 | ||
|
|
6be4e2bd7b | ||
|
|
b014446399 | ||
|
|
5053d4db6b | ||
|
|
ae2cc7a04a | ||
|
|
d49141c05d | ||
|
|
0bbb136d67 |
@@ -101,6 +101,7 @@ ALL_LANGUAGES = [
|
||||
('fi', _('Finnish')),
|
||||
('gl', _('Galician')),
|
||||
('el', _('Greek')),
|
||||
('he', _('Hebrew')),
|
||||
('id', _('Indonesian')),
|
||||
('it', _('Italian')),
|
||||
('ja', _('Japanese')),
|
||||
@@ -122,7 +123,7 @@ LANGUAGES_OFFICIAL = {
|
||||
}
|
||||
LANGUAGES_RTL = {
|
||||
# When adding more right-to-left languages, also update pretix/static/pretixbase/scss/_rtl.scss
|
||||
'ar', 'hw'
|
||||
'ar', 'he'
|
||||
}
|
||||
LANGUAGES_INCUBATING = {
|
||||
'pt-br', 'gl',
|
||||
|
||||
18
src/pretix/base/migrations/0280_cartposition_max_extend.py
Normal file
18
src/pretix/base/migrations/0280_cartposition_max_extend.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.2.20 on 2025-05-14 14:58
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0279_discount_event_date_from_discount_event_date_until'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='cartposition',
|
||||
name='max_extend',
|
||||
field=models.DateTimeField(null=True),
|
||||
),
|
||||
]
|
||||
@@ -3098,7 +3098,10 @@ class CartPosition(AbstractPosition):
|
||||
verbose_name=_("Expiration date"),
|
||||
db_index=True
|
||||
)
|
||||
|
||||
max_extend = models.DateTimeField(
|
||||
verbose_name=_("Limit for extending expiration date"),
|
||||
null=True
|
||||
)
|
||||
tax_rate = models.DecimalField(
|
||||
max_digits=7, decimal_places=2, default=Decimal('0.00'),
|
||||
verbose_name=_('Tax rate')
|
||||
|
||||
@@ -45,6 +45,7 @@ from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import DatabaseError, transaction
|
||||
from django.db.models import Count, Exists, IntegerField, OuterRef, Q, Value
|
||||
from django.db.models.aggregates import Min
|
||||
from django.dispatch import receiver
|
||||
from django.utils.timezone import make_aware, now
|
||||
from django.utils.translation import (
|
||||
@@ -275,7 +276,10 @@ class CartManager:
|
||||
}
|
||||
|
||||
def __init__(self, event: Event, cart_id: str, sales_channel: SalesChannel,
|
||||
invoice_address: InvoiceAddress=None, widget_data=None, expiry=None):
|
||||
invoice_address: InvoiceAddress=None, widget_data=None, reservation_time: timedelta=None):
|
||||
"""
|
||||
Creates a new CartManager for an event.
|
||||
"""
|
||||
self.event = event
|
||||
self.cart_id = cart_id
|
||||
self.real_now_dt = now()
|
||||
@@ -286,11 +290,17 @@ class CartManager:
|
||||
self._subevents_cache = {}
|
||||
self._variations_cache = {}
|
||||
self._seated_cache = {}
|
||||
self._expiry = None
|
||||
self._explicit_expiry = expiry
|
||||
self.invoice_address = invoice_address
|
||||
self._widget_data = widget_data or {}
|
||||
self._sales_channel = sales_channel
|
||||
self.num_extended_positions = 0
|
||||
|
||||
if reservation_time:
|
||||
self._reservation_time = reservation_time
|
||||
else:
|
||||
self._reservation_time = timedelta(minutes=self.event.settings.get('reservation_time', as_type=int))
|
||||
self._expiry = self.real_now_dt + self._reservation_time
|
||||
self._max_expiry_extend = self.real_now_dt + (self._reservation_time * 11)
|
||||
|
||||
@property
|
||||
def positions(self):
|
||||
@@ -305,14 +315,6 @@ class CartManager:
|
||||
self._seated_cache[item, subevent] = item.seat_category_mappings.filter(subevent=subevent).exists()
|
||||
return self._seated_cache[item, subevent]
|
||||
|
||||
def _calculate_expiry(self):
|
||||
if self._explicit_expiry:
|
||||
self._expiry = self._explicit_expiry
|
||||
else:
|
||||
self._expiry = self.real_now_dt + timedelta(
|
||||
minutes=self.event.settings.get('reservation_time', as_type=int)
|
||||
)
|
||||
|
||||
def _check_presale_dates(self):
|
||||
if self.event.presale_start and time_machine_now(self.real_now_dt) < self.event.presale_start:
|
||||
raise CartError(error_messages['not_started'])
|
||||
@@ -329,9 +331,27 @@ class CartManager:
|
||||
raise CartError(error_messages['payment_ended'])
|
||||
|
||||
def _extend_expiry_of_valid_existing_positions(self):
|
||||
# real_now_dt is initialized at CartManager instantiation, so it's slightly in the past. Add a small
|
||||
# delta to reduce risk of extending already expired CartPositions.
|
||||
padded_now_dt = self.real_now_dt + timedelta(seconds=5)
|
||||
|
||||
# Make sure we do not extend past the max_extend timestamp, allowing users to extend their valid positions up
|
||||
# to 11 times the reservation time. If we add new positions to the cart while valid positions exist, the new
|
||||
# positions' reservation will also be limited to max_extend of the oldest position.
|
||||
# Only after all positions expire, an ExtendOperation may reset max_extend to another 11x reservation_time.
|
||||
max_extend_existing = self.positions.filter(expires__gt=padded_now_dt).aggregate(m=Min('max_extend'))['m']
|
||||
if max_extend_existing:
|
||||
self._expiry = min(self._expiry, max_extend_existing)
|
||||
self._max_expiry_extend = max_extend_existing
|
||||
|
||||
# Extend this user's cart session to ensure all items in the cart expire at the same time
|
||||
# We can extend the reservation of items which are not yet expired without risk
|
||||
self.positions.filter(expires__gt=self.real_now_dt).update(expires=self._expiry)
|
||||
if self._expiry > padded_now_dt:
|
||||
self.num_extended_positions += self.positions.filter(
|
||||
expires__gt=padded_now_dt, expires__lt=self._expiry,
|
||||
).update(
|
||||
expires=self._expiry,
|
||||
)
|
||||
|
||||
def _delete_out_of_timeframe(self):
|
||||
err = None
|
||||
@@ -1246,6 +1266,7 @@ class CartManager:
|
||||
item=op.item,
|
||||
variation=op.variation,
|
||||
expires=self._expiry,
|
||||
max_extend=self._max_expiry_extend,
|
||||
cart_id=self.cart_id,
|
||||
voucher=op.voucher,
|
||||
addon_to=op.addon_to if op.addon_to else None,
|
||||
@@ -1294,7 +1315,9 @@ class CartManager:
|
||||
event=self.event,
|
||||
item=b.item,
|
||||
variation=b.variation,
|
||||
expires=self._expiry, cart_id=self.cart_id,
|
||||
expires=self._expiry,
|
||||
max_extend=self._max_expiry_extend,
|
||||
cart_id=self.cart_id,
|
||||
voucher=None,
|
||||
addon_to=cp,
|
||||
subevent=b.subevent,
|
||||
@@ -1321,12 +1344,14 @@ class CartManager:
|
||||
op.position.delete()
|
||||
elif available_count == 1:
|
||||
op.position.expires = self._expiry
|
||||
op.position.max_extend = self._max_expiry_extend
|
||||
op.position.listed_price = op.listed_price
|
||||
op.position.price_after_voucher = op.price_after_voucher
|
||||
# op.position.price will be updated by recompute_final_prices_and_taxes()
|
||||
if op.position.pk not in deleted_positions:
|
||||
try:
|
||||
op.position.save(force_update=True, update_fields=['expires', 'listed_price', 'price_after_voucher'])
|
||||
op.position.save(force_update=True, update_fields=['expires', 'max_extend', 'listed_price', 'price_after_voucher'])
|
||||
self.num_extended_positions += 1
|
||||
except DatabaseError:
|
||||
# Best effort... The position might have been deleted in the meantime!
|
||||
pass
|
||||
@@ -1416,14 +1441,11 @@ class CartManager:
|
||||
def commit(self):
|
||||
self._check_presale_dates()
|
||||
self._check_max_cart_size()
|
||||
self._calculate_expiry()
|
||||
|
||||
err = self._delete_out_of_timeframe()
|
||||
err = self.extend_expired_positions() or err
|
||||
err = err or self._check_min_per_voucher()
|
||||
|
||||
self.real_now_dt = now()
|
||||
|
||||
self._extend_expiry_of_valid_existing_positions()
|
||||
err = self._perform_operations() or err
|
||||
self.recompute_final_prices_and_taxes()
|
||||
@@ -1632,6 +1654,31 @@ def clear_cart(self, event: Event, cart_id: str=None, locale='en', sales_channel
|
||||
raise CartError(error_messages['busy'])
|
||||
|
||||
|
||||
@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
|
||||
def extend_cart_reservation(self, event: Event, cart_id: str=None, locale='en', sales_channel='web', override_now_dt: datetime=None) -> None:
|
||||
"""
|
||||
Resets the expiry time of a cart to the configured reservation time of this event.
|
||||
Limited to 11x the reservation time.
|
||||
|
||||
:param event: The event ID in question
|
||||
:param cart_id: The cart ID of the cart to modify
|
||||
"""
|
||||
with language(locale), time_machine_now_assigned(override_now_dt):
|
||||
try:
|
||||
sales_channel = event.organizer.sales_channels.get(identifier=sales_channel)
|
||||
except SalesChannel.DoesNotExist:
|
||||
raise CartError("Invalid sales channel.")
|
||||
try:
|
||||
try:
|
||||
cm = CartManager(event=event, cart_id=cart_id, sales_channel=sales_channel)
|
||||
cm.commit()
|
||||
return cm.num_extended_positions
|
||||
except LockTimeoutException:
|
||||
self.retry()
|
||||
except (MaxRetriesExceededError, LockTimeoutException):
|
||||
raise CartError(error_messages['busy'])
|
||||
|
||||
|
||||
@app.task(base=ProfiledEventTask, bind=True, max_retries=5, default_retry_delay=1, throws=(CartError,))
|
||||
def set_cart_addons(self, event: Event, addons: List[dict], add_to_cart_items: List[dict], cart_id: str=None, locale='en',
|
||||
invoice_address: int=None, sales_channel='web', override_now_dt: datetime=None) -> None:
|
||||
|
||||
60
src/pretix/base/templatetags/dialog.py
Normal file
60
src/pretix/base/templatetags/dialog.py
Normal file
@@ -0,0 +1,60 @@
|
||||
#
|
||||
# This file is part of pretix (Community Edition).
|
||||
#
|
||||
# Copyright (C) 2014-2020 Raphael Michel and contributors
|
||||
# Copyright (C) 2020-2021 rami.io GmbH and contributors
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
|
||||
# Public License as published by the Free Software Foundation in version 3 of the License.
|
||||
#
|
||||
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
|
||||
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
|
||||
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
|
||||
# this file, see <https://pretix.eu/about/en/license>.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
||||
# details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
from django import template
|
||||
from django.utils.html import format_html
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from django.utils.translation import gettext_lazy as _ # NOQA
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def dialog(html_id, label, description, *args, **kwargs):
|
||||
format_kwargs = {
|
||||
"id": html_id,
|
||||
"label": label,
|
||||
"description": description,
|
||||
"icon": format_html('<div class="modal-card-icon"><span class="fa fa-{}" aria-hidden="true"></span></div>', kwargs["icon"]) if "icon" in kwargs else "",
|
||||
"alert": mark_safe('role="alertdialog"') if kwargs.get("alert", "False") != "False" else "",
|
||||
}
|
||||
result = """
|
||||
<dialog {alert}
|
||||
id="{id}"
|
||||
aria-labelledby="{id}-label"
|
||||
aria-describedby="{id}-description">
|
||||
<form method="dialog" class="modal-card form-horizontal">
|
||||
{icon}
|
||||
<div class="modal-card-content">
|
||||
<h2 id="{id}-label">{label}</h2>
|
||||
<p id="{id}-description">{description}</p>
|
||||
"""
|
||||
return format_html(result, **format_kwargs)
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def enddialog(*args, **kwargs):
|
||||
return mark_safe("""
|
||||
</div>
|
||||
</form>
|
||||
</dialog>
|
||||
""")
|
||||
@@ -8,16 +8,16 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-28 11:06+0000\n"
|
||||
"PO-Revision-Date: 2025-02-19 17:00+0000\n"
|
||||
"Last-Translator: Petr Čermák <pcermak@live.com>\n"
|
||||
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix/cs/"
|
||||
">\n"
|
||||
"PO-Revision-Date: 2025-05-16 17:00+0000\n"
|
||||
"Last-Translator: David <davemachala@gmail.com>\n"
|
||||
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix/cs/>"
|
||||
"\n"
|
||||
"Language: cs\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.10\n"
|
||||
"X-Generator: Weblate 5.11.4\n"
|
||||
|
||||
#: pretix/_base_settings.py:87
|
||||
msgid "English"
|
||||
@@ -57,7 +57,7 @@ msgstr "Čeština"
|
||||
|
||||
#: pretix/_base_settings.py:96
|
||||
msgid "Croatian"
|
||||
msgstr ""
|
||||
msgstr "Chorvatština"
|
||||
|
||||
#: pretix/_base_settings.py:97
|
||||
msgid "Danish"
|
||||
@@ -2971,12 +2971,9 @@ msgid "Repeat password"
|
||||
msgstr "Opakovat heslo"
|
||||
|
||||
#: pretix/base/forms/questions.py:134 pretix/base/forms/questions.py:256
|
||||
#, fuzzy
|
||||
#| msgctxt "subevent"
|
||||
#| msgid "No date was specified."
|
||||
msgctxt "name_salutation"
|
||||
msgid "not specified"
|
||||
msgstr "Nebylo uvedeno žádné datum."
|
||||
msgstr "neuvedeno"
|
||||
|
||||
#: pretix/base/forms/questions.py:219
|
||||
msgid "Please do not use special characters in names."
|
||||
@@ -4227,20 +4224,14 @@ msgstr ""
|
||||
"automatická sleva poskytnuta i nadále."
|
||||
|
||||
#: pretix/base/models/discount.py:177
|
||||
#, fuzzy
|
||||
#| msgctxt "subevent"
|
||||
#| msgid "All dates starting before"
|
||||
msgctxt "subevent"
|
||||
msgid "Available for dates starting from"
|
||||
msgstr "Všechny termíny začínající před"
|
||||
msgstr "Dostupné pro termíny začínající od"
|
||||
|
||||
#: pretix/base/models/discount.py:182
|
||||
#, fuzzy
|
||||
#| msgctxt "subevent"
|
||||
#| msgid "All dates starting before"
|
||||
msgctxt "subevent"
|
||||
msgid "Available for dates starting until"
|
||||
msgstr "Všechny termíny začínající před"
|
||||
msgstr "Dostupné pro termíny začínající do"
|
||||
|
||||
#: pretix/base/models/discount.py:214
|
||||
msgid ""
|
||||
@@ -13474,7 +13465,7 @@ msgstr "Schváleno, čeká se na platbu"
|
||||
#: pretix/plugins/reports/exporters.py:380
|
||||
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html:7
|
||||
msgid "Approval pending"
|
||||
msgstr "Čeká se na schválení"
|
||||
msgstr "Čeká na schválení"
|
||||
|
||||
#: pretix/control/forms/filter.py:241
|
||||
#, fuzzy
|
||||
@@ -18849,7 +18840,7 @@ msgstr "Kontrola"
|
||||
#: pretix/control/templates/pretixcontrol/organizers/device_logs.html:50
|
||||
#: pretix/control/templates/pretixcontrol/organizers/logs.html:80
|
||||
msgid "No results"
|
||||
msgstr "Bez výsledků"
|
||||
msgstr "Žádné výsledky"
|
||||
|
||||
#: pretix/control/templates/pretixcontrol/event/mail.html:7
|
||||
#: pretix/control/templates/pretixcontrol/organizers/mail.html:11
|
||||
|
||||
@@ -8,8 +8,8 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-28 11:08+0000\n"
|
||||
"PO-Revision-Date: 2025-02-19 17:00+0000\n"
|
||||
"Last-Translator: Petr Čermák <pcermak@live.com>\n"
|
||||
"PO-Revision-Date: 2025-05-16 17:00+0000\n"
|
||||
"Last-Translator: David <davemachala@gmail.com>\n"
|
||||
"Language-Team: Czech <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||
"cs/>\n"
|
||||
"Language: cs\n"
|
||||
@@ -17,7 +17,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.10\n"
|
||||
"X-Generator: Weblate 5.11.4\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||
@@ -237,11 +237,11 @@ msgstr "Zrušeno"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:46
|
||||
msgid "Confirmed"
|
||||
msgstr ""
|
||||
msgstr "Potvrzeno"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:47
|
||||
msgid "Approval pending"
|
||||
msgstr ""
|
||||
msgstr "Čeká na schválení"
|
||||
|
||||
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:48
|
||||
msgid "Redeemed"
|
||||
@@ -440,7 +440,7 @@ msgstr "je po"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:40
|
||||
msgid "="
|
||||
msgstr ""
|
||||
msgstr "="
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:99
|
||||
msgid "Product"
|
||||
@@ -452,7 +452,7 @@ msgstr "Varianta produktu"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:107
|
||||
msgid "Gate"
|
||||
msgstr ""
|
||||
msgstr "Brána"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:111
|
||||
msgid "Current date and time"
|
||||
@@ -557,12 +557,12 @@ msgstr "Duplikát"
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:193
|
||||
msgctxt "entry_status"
|
||||
msgid "present"
|
||||
msgstr ""
|
||||
msgstr "přítomen"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:194
|
||||
msgctxt "entry_status"
|
||||
msgid "absent"
|
||||
msgstr ""
|
||||
msgstr "nepřítomen"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/editor.js:171
|
||||
msgid "Check-in QR"
|
||||
@@ -692,10 +692,8 @@ msgid "Calculating default price…"
|
||||
msgstr "Výpočet standardní ceny…"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/plugins.js:69
|
||||
#, fuzzy
|
||||
#| msgid "Search results"
|
||||
msgid "No results"
|
||||
msgstr "Vyhledat výsledky"
|
||||
msgstr "Žádné výsledky"
|
||||
|
||||
#: pretix/static/pretixcontrol/js/ui/question.js:42
|
||||
msgid "Others"
|
||||
@@ -764,64 +762,57 @@ msgid "Your local time:"
|
||||
msgstr "Místní čas:"
|
||||
|
||||
#: pretix/static/pretixpresale/js/walletdetection.js:39
|
||||
#, fuzzy
|
||||
#| msgid "Apple Pay"
|
||||
msgid "Google Pay"
|
||||
msgstr "Apple Pay"
|
||||
msgstr "Google Pay"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:16
|
||||
msgctxt "widget"
|
||||
msgid "Quantity"
|
||||
msgstr ""
|
||||
msgstr "Počet"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:17
|
||||
msgctxt "widget"
|
||||
msgid "Decrease quantity"
|
||||
msgstr ""
|
||||
msgstr "Snížit počet"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:18
|
||||
msgctxt "widget"
|
||||
msgid "Increase quantity"
|
||||
msgstr ""
|
||||
msgstr "Zvýšit počet"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:19
|
||||
msgctxt "widget"
|
||||
msgid "Price"
|
||||
msgstr ""
|
||||
msgstr "Cena"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:20
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "Original price: %s"
|
||||
msgstr ""
|
||||
msgstr "Původní cena: %s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:21
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "New price: %s"
|
||||
msgstr ""
|
||||
msgstr "Nová cena: %s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:22
|
||||
#, fuzzy
|
||||
#| msgid "Selected only"
|
||||
msgctxt "widget"
|
||||
msgid "Select"
|
||||
msgstr "Pouze vybrané"
|
||||
msgstr "Vybrat"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:23
|
||||
#, fuzzy, javascript-format
|
||||
#| msgid "Selected only"
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "Select %s"
|
||||
msgstr "Pouze vybrané"
|
||||
msgstr "Vybrat %s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:24
|
||||
#, fuzzy, javascript-format
|
||||
#| msgctxt "widget"
|
||||
#| msgid "See variations"
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "Select variant %s"
|
||||
msgstr "Zobrazit možnosti"
|
||||
msgstr "Vybrat variantu %s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:25
|
||||
msgctxt "widget"
|
||||
@@ -857,7 +848,7 @@ msgstr "od %(currency)s %(price)s"
|
||||
#, javascript-format
|
||||
msgctxt "widget"
|
||||
msgid "Image of %s"
|
||||
msgstr ""
|
||||
msgstr "Obrázek%s"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:32
|
||||
msgctxt "widget"
|
||||
@@ -892,24 +883,19 @@ msgstr "K dispozici pouze s poukazem"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:38
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:41
|
||||
#, fuzzy
|
||||
#| msgid "Payment method unavailable"
|
||||
msgctxt "widget"
|
||||
msgid "Not yet available"
|
||||
msgstr "Způsob platby není k dispozici"
|
||||
msgstr "Zatím není k dispozici"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:39
|
||||
msgctxt "widget"
|
||||
msgid "Not available anymore"
|
||||
msgstr ""
|
||||
msgstr "Již není k dispozici"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:40
|
||||
#, fuzzy
|
||||
#| msgctxt "widget"
|
||||
#| msgid "currently available: %s"
|
||||
msgctxt "widget"
|
||||
msgid "Currently not available"
|
||||
msgstr "aktuálně k dispozici: %s"
|
||||
msgstr "Momentálně není k dispozici."
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:42
|
||||
#, javascript-format
|
||||
@@ -942,12 +928,9 @@ msgid "Open ticket shop"
|
||||
msgstr "Obchod vstupenek otevřit"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:48
|
||||
#, fuzzy
|
||||
#| msgctxt "widget"
|
||||
#| msgid "Resume checkout"
|
||||
msgctxt "widget"
|
||||
msgid "Checkout"
|
||||
msgstr "Obnovit checkout"
|
||||
msgstr "Checkout"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:49
|
||||
msgctxt "widget"
|
||||
@@ -1009,20 +992,14 @@ msgid "Continue"
|
||||
msgstr "Pokračovat"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:61
|
||||
#, fuzzy
|
||||
#| msgctxt "widget"
|
||||
#| msgid "See variations"
|
||||
msgctxt "widget"
|
||||
msgid "Show variants"
|
||||
msgstr "Zobrazit možnosti"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:62
|
||||
#, fuzzy
|
||||
#| msgctxt "widget"
|
||||
#| msgid "See variations"
|
||||
msgctxt "widget"
|
||||
msgid "Hide variants"
|
||||
msgstr "Zobrazit možnosti"
|
||||
msgstr "Skrýt možnosti"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:63
|
||||
msgctxt "widget"
|
||||
@@ -1110,31 +1087,31 @@ msgstr "Ne"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:81
|
||||
msgid "Monday"
|
||||
msgstr ""
|
||||
msgstr "Pondělí"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:82
|
||||
msgid "Tuesday"
|
||||
msgstr ""
|
||||
msgstr "Úterý"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:83
|
||||
msgid "Wednesday"
|
||||
msgstr ""
|
||||
msgstr "Středa"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:84
|
||||
msgid "Thursday"
|
||||
msgstr ""
|
||||
msgstr "Čtvrtek"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:85
|
||||
msgid "Friday"
|
||||
msgstr ""
|
||||
msgstr "Pátek"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:86
|
||||
msgid "Saturday"
|
||||
msgstr ""
|
||||
msgstr "Sobota"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:87
|
||||
msgid "Sunday"
|
||||
msgstr ""
|
||||
msgstr "Neděle"
|
||||
|
||||
#: pretix/static/pretixpresale/js/widget/widget.js:90
|
||||
msgid "January"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-28 11:06+0000\n"
|
||||
"PO-Revision-Date: 2025-04-14 23:00+0000\n"
|
||||
"PO-Revision-Date: 2025-05-17 18:00+0000\n"
|
||||
"Last-Translator: Patrick Chilton <chpatrick@gmail.com>\n"
|
||||
"Language-Team: Hungarian <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||
"hu/>\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.10.4\n"
|
||||
"X-Generator: Weblate 5.11.4\n"
|
||||
|
||||
#: pretix/_base_settings.py:87
|
||||
msgid "English"
|
||||
@@ -14670,7 +14670,7 @@ msgstr "A kiválasztott \"{seat}\" ülés nem elérhető."
|
||||
#: pretix/control/logdisplay.py:406 pretix/control/views/orders.py:1573
|
||||
#: pretix/presale/views/order.py:1047
|
||||
msgid "The order has been canceled."
|
||||
msgstr ""
|
||||
msgstr "A megrendelés sztornózva lett."
|
||||
|
||||
#: pretix/control/logdisplay.py:414
|
||||
#, python-brace-format
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,17 +8,17 @@ msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2025-04-28 11:08+0000\n"
|
||||
"PO-Revision-Date: 2019-08-27 08:00+0000\n"
|
||||
"Last-Translator: Bostjan Marusic <bostjan@brokenbones.si>\n"
|
||||
"Language-Team: Slovenian <https://translate.pretix.eu/projects/pretix/pretix-"
|
||||
"js/sl/>\n"
|
||||
"PO-Revision-Date: 2025-05-16 17:00+0000\n"
|
||||
"Last-Translator: bstramsek <stramsek.borut+pretix-translate@gmail.com>\n"
|
||||
"Language-Team: Slovenian <https://translate.pretix.eu/projects/pretix/"
|
||||
"pretix-js/sl/>\n"
|
||||
"Language: sl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || "
|
||||
"n%100==4 ? 2 : 3;\n"
|
||||
"X-Generator: Weblate 3.5.1\n"
|
||||
"X-Generator: Weblate 5.11.4\n"
|
||||
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||
@@ -32,7 +32,7 @@ msgstr "Komentar:"
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:34
|
||||
msgid "PayPal"
|
||||
msgstr ""
|
||||
msgstr "PayPal"
|
||||
|
||||
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:35
|
||||
msgid "Venmo"
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% load icon %}
|
||||
{% load eventurl %}
|
||||
|
||||
{% if item.current_unavailability_reason == 'require_voucher' %}
|
||||
@@ -21,15 +20,14 @@
|
||||
{% elif avail <= 10 %}
|
||||
<div class="col-md-2 col-sm-3 col-xs-6 availability-box gone">
|
||||
{% if price or original_price %}
|
||||
<strong>{% icon "ban" %} {% trans "SOLD OUT" %}</strong>
|
||||
<strong>{% trans "SOLD OUT" %}</strong>
|
||||
{% else %}
|
||||
<strong>{% icon "ban" %} {% trans "FULLY BOOKED" %}</strong>
|
||||
<strong>{% trans "FULLY BOOKED" %}</strong>
|
||||
{% endif %}
|
||||
</span>
|
||||
{% if allow_waitinglist and item.allow_waitinglist %}
|
||||
<br/>
|
||||
<a href="{% eventurl event "presale:event.waitinglist" cart_namespace=cart_namespace|default_if_none:"" %}?item={{ item.pk }}{% if var %}&var={{ var.pk }}{% endif %}{% if subevent %}&subevent={{ subevent.pk }}{% endif %}" class="btn btn-default btn-xs">
|
||||
{% icon "plus-circle" %}
|
||||
<a href="{% eventurl event "presale:event.waitinglist" cart_namespace=cart_namespace|default_if_none:"" %}?item={{ item.pk }}{% if var %}&var={{ var.pk }}{% endif %}{% if subevent %}&subevent={{ subevent.pk }}{% endif %}">
|
||||
<span class="fa fa-plus-circle" aria-hidden="true"></span>
|
||||
{% trans "Waiting list" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
@@ -492,15 +492,21 @@
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{% if not cart.is_ordered %}
|
||||
<p class="text-muted" id="cart-deadline" data-expires="{{ cart.first_expiry|date:"Y-m-d H:i:sO" }}">
|
||||
{% if cart.minutes_left > 0 or cart.seconds_left > 0 %}
|
||||
{% blocktrans trimmed with minutes=cart.minutes_left %}
|
||||
The items in your cart are reserved for you for {{ minutes }} minutes.
|
||||
{% endblocktrans %}
|
||||
{% else %}
|
||||
{% trans "The items in your cart are no longer reserved for you. You can still complete your order as long as they’re available." %}
|
||||
{% endif %}
|
||||
</p>
|
||||
<form class="text-muted"
|
||||
method="post" data-asynctask action="{% eventurl request.event "presale:event.cart.extend" cart_namespace=cart_namespace %}">
|
||||
{% csrf_token %}
|
||||
<span id="cart-deadline" data-expires="{{ cart.first_expiry|date:"Y-m-d H:i:sO" }}">
|
||||
{% if cart.minutes_left > 0 or cart.seconds_left > 0 %}
|
||||
{% blocktrans trimmed with minutes=cart.minutes_left %}
|
||||
The items in your cart are reserved for you for {{ minutes }} minutes.
|
||||
{% endblocktrans %}
|
||||
{% else %}
|
||||
{% trans "The items in your cart are no longer reserved for you. You can still complete your order as long as they’re available." %}
|
||||
{% endif %}
|
||||
</span>
|
||||
<button class="btn btn-link" type="submit" id="cart-extend-button">
|
||||
<i class="fa fa-refresh" aria-hidden="true"></i> {% trans "Extend" %}</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<p class="sr-only" id="cart-description">{% trans "Overview of your ordered products." %}</p>
|
||||
{% endif %}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% load icon %}
|
||||
{% load l10n %}
|
||||
{% load eventurl %}
|
||||
{% load money %}
|
||||
@@ -83,9 +82,9 @@
|
||||
{% if not event.settings.show_variations_expanded %}
|
||||
{% if item.best_variation_availability <= 10 %}
|
||||
{% if not item.min_price %}
|
||||
<strong class="gone">{% icon "ban" %} {% trans "FULLY BOOKED" %}</strong>
|
||||
<strong class="gone">{% trans "FULLY BOOKED" %}</strong>
|
||||
{% else %}
|
||||
<strong class="gone">{% icon "ban" %} {% trans "SOLD OUT" %}</strong>
|
||||
<strong class="gone">{% trans "SOLD OUT" %}</strong>
|
||||
{% endif %}
|
||||
{% if allow_waitinglist and item.allow_waitinglist %}
|
||||
<br/>
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
{% load thumb %}
|
||||
{% load eventsignal %}
|
||||
{% load rich_text %}
|
||||
{% load icon %}
|
||||
{% load dialog %}
|
||||
|
||||
{% block title %}
|
||||
{% if "year" in request.GET %}
|
||||
@@ -240,6 +242,13 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% if ev.presale_is_running and display_add_to_cart %}
|
||||
{% trans "You didn’t select any ticket." as label_nothing_to_add %}
|
||||
{% trans "Please tick a checkbox or enter a quantity for one of the ticket types to add to the cart." as description_nothing_to_add %}
|
||||
{% dialog "dialog-nothing-to-add" label_nothing_to_add description_nothing_to_add icon="exclamation-circle" %}
|
||||
<p class="modal-card-confirm"><button class="btn btn-primary">{% trans "OK" %}</button></p>
|
||||
{% enddialog %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</main>
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
{% load rich_text %}
|
||||
{% load safelink %}
|
||||
{% load escapejson %}
|
||||
{% load icon %}
|
||||
{% load dialog %}
|
||||
<div id="ajaxerr">
|
||||
</div>
|
||||
<div id="popupmodal" hidden aria-live="polite">
|
||||
@@ -50,93 +52,74 @@
|
||||
{{ cookie_consent_from_widget|json_script:"cookie-consent-from-widget" }}
|
||||
{% endif %}
|
||||
{% if cookie_providers %}
|
||||
<div id="cookie-consent-modal" aria-live="polite">
|
||||
<div class="modal-card">
|
||||
<div class="modal-card-content">
|
||||
<h3 id="cookie-consent-modal-label"></h3>
|
||||
<div id="cookie-consent-modal-description">
|
||||
<form class="form-horizontal">
|
||||
{% with request.event|default:request.organizer as sh %}
|
||||
<h3>{{ sh.settings.cookie_consent_dialog_title }}</h3>
|
||||
{{ sh.settings.cookie_consent_dialog_text|rich_text }}
|
||||
{% if sh.settings.cookie_consent_dialog_text_secondary %}
|
||||
<div class="text-muted">
|
||||
{{ sh.settings.cookie_consent_dialog_text_secondary|rich_text }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<details id="cookie-consent-details">
|
||||
<summary>
|
||||
<span class="fa fa-fw chevron"></span>
|
||||
{% trans "Adjust settings in detail" %}
|
||||
</summary>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" disabled checked="" aira-describedby="cookie-consent-checkbox-required-description">
|
||||
{% trans "Required cookies" %}
|
||||
</label>
|
||||
</div>
|
||||
<div class="help-block" id="cookie-consent-checkbox-required-description">
|
||||
<p>{% trans "Functional cookies (e.g. shopping cart, login, payment, language preference) and technical cookies (e.g. security purposes)" %}</p>
|
||||
</div>
|
||||
{% for cp in cookie_providers %}
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="{{ cp.identifier }}" aira-describedby="cookie-consent-checkbox-{{ cp.identifier }}-description">
|
||||
{{ cp.provider_name }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="help-block" id="cookie-consent-checkbox-{{ cp.identifier }}-description">
|
||||
<p>
|
||||
{% for c in cp.usage_classes %}
|
||||
{% if forloop.counter0 > 0 %}· {% endif %}
|
||||
{% if c.value == 1 %}
|
||||
{% trans "Functionality" context "cookie_usage" %}
|
||||
{% elif c.value == 2 %}
|
||||
{% trans "Analytics" context "cookie_usage" %}
|
||||
{% elif c.value == 3 %}
|
||||
{% trans "Marketing" context "cookie_usage" %}
|
||||
{% elif c.value == 4 %}
|
||||
{% trans "Social features" context "cookie_usage" %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if cp.privacy_url %}
|
||||
·
|
||||
<a href="{% safelink cp.privacy_url %}" target="_blank">
|
||||
{% trans "Privacy policy" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</details>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<p>
|
||||
<button type="button" class="btn btn-lg btn-block btn-primary" id="cookie-consent-button-no"
|
||||
data-summary-text="{{ sh.settings.cookie_consent_dialog_button_no }}"
|
||||
data-detail-text="{% trans "Save selection" %}">
|
||||
{{ sh.settings.cookie_consent_dialog_button_no }}
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<p>
|
||||
<button type="button" class="btn btn-lg btn-block btn-primary" id="cookie-consent-button-yes">
|
||||
{{ sh.settings.cookie_consent_dialog_button_yes }}
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{% if sh.settings.privacy_url %}
|
||||
<p class="text-center">
|
||||
<a href="{% safelink sh.settings.privacy_url %}" target="_blank" rel="noopener">{% trans "Privacy policy" %}</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
<form>
|
||||
{% with request.event|default:request.organizer as sh %}
|
||||
{% dialog "cookie-consent-modal" sh.settings.cookie_consent_dialog_title sh.settings.cookie_consent_dialog_text|rich_text icon="shield" %}
|
||||
{% if sh.settings.cookie_consent_dialog_text_secondary %}
|
||||
<div class="text-muted">
|
||||
{{ sh.settings.cookie_consent_dialog_text_secondary|rich_text }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<details id="cookie-consent-details">
|
||||
<summary>
|
||||
<span class="fa fa-fw chevron"></span>
|
||||
{% trans "Adjust settings in detail" %}
|
||||
</summary>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" disabled checked="" aira-describedby="cookie-consent-checkbox-required-description">
|
||||
{% trans "Required cookies" %}
|
||||
</label>
|
||||
</div>
|
||||
<div class="help-block" id="cookie-consent-checkbox-required-description">
|
||||
<p>{% trans "Functional cookies (e.g. shopping cart, login, payment, language preference) and technical cookies (e.g. security purposes)" %}</p>
|
||||
</div>
|
||||
{% for cp in cookie_providers %}
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" name="{{ cp.identifier }}" aira-describedby="cookie-consent-checkbox-{{ cp.identifier }}-description">
|
||||
{{ cp.provider_name }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="help-block" id="cookie-consent-checkbox-{{ cp.identifier }}-description">
|
||||
<p>
|
||||
{% for c in cp.usage_classes %}
|
||||
{% if forloop.counter0 > 0 %}· {% endif %}
|
||||
{% if c.value == 1 %}
|
||||
{% trans "Functionality" context "cookie_usage" %}
|
||||
{% elif c.value == 2 %}
|
||||
{% trans "Analytics" context "cookie_usage" %}
|
||||
{% elif c.value == 3 %}
|
||||
{% trans "Marketing" context "cookie_usage" %}
|
||||
{% elif c.value == 4 %}
|
||||
{% trans "Social features" context "cookie_usage" %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if cp.privacy_url %}
|
||||
·
|
||||
<a href="{% safelink cp.privacy_url %}" target="_blank">
|
||||
{% trans "Privacy policy" %}
|
||||
</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</details>
|
||||
<p class="modal-card-confirm modal-card-confirm-spread">
|
||||
<button class="btn btn-lg btn-default" id="cookie-consent-button-no" value="no" autofocus="true"
|
||||
data-summary-text="{{ sh.settings.cookie_consent_dialog_button_no }}"
|
||||
data-detail-text="{% trans "Save selection" %}">
|
||||
{{ sh.settings.cookie_consent_dialog_button_no }}
|
||||
</button>
|
||||
<button class="btn btn-lg btn-primary" id="cookie-consent-button-yes" value="yes">
|
||||
{{ sh.settings.cookie_consent_dialog_button_yes }}
|
||||
</button>
|
||||
</p>
|
||||
{% if sh.settings.privacy_url %}
|
||||
<p class="text-center">
|
||||
<small><a href="{% safelink sh.settings.privacy_url %}" target="_blank" rel="noopener">{% trans "Privacy policy" %}</a></small>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% enddialog %}
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
<div class="event-list full-width-list alternating-rows">
|
||||
{% for e in events %}{% eventurl e "presale:event.index" as url %}
|
||||
<article class="row" aria-labelledby="event-{{ e.pk }}-label" aria-describedby="event-{{ e.pk }}-desc">
|
||||
<h3 class="col-md-4 col-xs-12"><a href="{{ url }}" id="event-{{ e.pk }}-label">{{ e.name }}</a></h3>
|
||||
<h3 class="col-md-4 col-xs-12"><a href="{{ url }}" id="event-{{ e.pk }}-label" class="no-underline">{{ e.name }}</a></h3>
|
||||
<p class="col-md-3 col-xs-12" id="event-{{ e.pk }}-desc">
|
||||
{% if e.settings.show_dates_on_frontpage %}
|
||||
{% if e.has_subevents %}
|
||||
|
||||
@@ -56,6 +56,7 @@ frame_wrapped_urls = [
|
||||
re_path(r'^cart/remove$', pretix.presale.views.cart.CartRemove.as_view(), name='event.cart.remove'),
|
||||
re_path(r'^cart/voucher$', pretix.presale.views.cart.CartApplyVoucher.as_view(), name='event.cart.voucher'),
|
||||
re_path(r'^cart/clear$', pretix.presale.views.cart.CartClear.as_view(), name='event.cart.clear'),
|
||||
re_path(r'^cart/extend$', pretix.presale.views.cart.CartExtendReservation.as_view(), name='event.cart.extend'),
|
||||
re_path(r'^cart/answer/(?P<answer>[^/]+)/$',
|
||||
pretix.presale.views.cart.AnswerDownload.as_view(),
|
||||
name='event.cart.download.answer'),
|
||||
|
||||
@@ -62,7 +62,7 @@ from pretix.base.models import (
|
||||
)
|
||||
from pretix.base.services.cart import (
|
||||
CartError, add_items_to_cart, apply_voucher, clear_cart, error_messages,
|
||||
remove_cart_position,
|
||||
extend_cart_reservation, remove_cart_position,
|
||||
)
|
||||
from pretix.base.timemachine import time_machine_now
|
||||
from pretix.base.views.tasks import AsyncAction
|
||||
@@ -537,6 +537,20 @@ class CartClear(EventViewMixin, CartActionMixin, AsyncAction, View):
|
||||
request.sales_channel.identifier, time_machine_now(default=None))
|
||||
|
||||
|
||||
@method_decorator(allow_frame_if_namespaced, 'dispatch')
|
||||
class CartExtendReservation(EventViewMixin, CartActionMixin, AsyncAction, View):
|
||||
task = extend_cart_reservation
|
||||
known_errortypes = ['CartError']
|
||||
|
||||
def get_success_message(self, value):
|
||||
if value > 0:
|
||||
return _('Your cart timeout was extended.')
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
return self.do(self.request.event.id, get_or_create_cart_id(self.request), translation.get_language(),
|
||||
request.sales_channel.identifier, time_machine_now(default=None))
|
||||
|
||||
|
||||
@method_decorator(allow_cors_if_namespaced, 'dispatch')
|
||||
@method_decorator(allow_frame_if_namespaced, 'dispatch')
|
||||
@method_decorator(iframe_entry_view_wrapper, 'dispatch')
|
||||
|
||||
BIN
src/pretix/static/pretixbase/img/flags/basque.png
Normal file
BIN
src/pretix/static/pretixbase/img/flags/basque.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 587 B |
@@ -49,7 +49,7 @@ html.rtl {
|
||||
}
|
||||
|
||||
input[lang=ar], textarea[lang=ar], div[lang=ar], pre[lang=ar],
|
||||
input[lang=hw], textarea[lang=hw], div[lang=hw], pre[lang=hw] {
|
||||
input[lang=he], textarea[lang=he], div[lang=he], pre[lang=he] {
|
||||
/* Keep list of languages in sync with pretix._base_settings.LANGUAGES_RTL */
|
||||
direction: rtl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,3 +262,95 @@ svg.svg-icon {
|
||||
@include table-row-variant('info', var(--pretix-brand-info-success-lighten-30), var(--pretix-brand-info-success-lighten-25));
|
||||
@include table-row-variant('warning', var(--pretix-brand-warning-lighten-40), var(--pretix-brand-warning-lighten-35));
|
||||
@include table-row-variant('danger', var(--pretix-brand-danger-lighten-30), var(--pretix-brand-danger-lighten-25));
|
||||
|
||||
|
||||
|
||||
|
||||
dialog {
|
||||
border: none;
|
||||
width: 80%;
|
||||
max-width: 43em;
|
||||
padding: 0;
|
||||
box-shadow: 0 7px 14px 0 rgba(78, 50, 92, 0.1),0 3px 6px 0 rgba(0,0,0,.07);
|
||||
background: white;
|
||||
border-radius: $border-radius-large;
|
||||
|
||||
opacity: 0;
|
||||
transition: opacity .5s allow-discrete;
|
||||
|
||||
.modal-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-content: stretch;
|
||||
}
|
||||
.modal-card-icon {
|
||||
background: $brand-primary;
|
||||
font-size: 2em;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 3px;
|
||||
}
|
||||
.modal-card-content {
|
||||
padding: 1.5em;
|
||||
}
|
||||
.modal-card-content>*:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.modal-card-content>*:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.modal-card-confirm {
|
||||
margin-top: 2em;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 1em;
|
||||
align-items: center;
|
||||
}
|
||||
.modal-card-confirm-spread {
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
dialog::backdrop {
|
||||
background-color: rgba(255, 255, 255, .5);
|
||||
opacity: 0;
|
||||
transition: opacity .5s allow-discrete;
|
||||
}
|
||||
dialog[open], dialog[open]::backdrop {
|
||||
opacity: 1;
|
||||
}
|
||||
@starting-style {
|
||||
dialog[open], dialog[open]::backdrop {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: $screen-sm-min) {
|
||||
dialog {
|
||||
.modal-card:has(.modal-card-icon) {
|
||||
flex-direction: row;
|
||||
}
|
||||
.modal-card-content {
|
||||
padding: 2em;
|
||||
}
|
||||
.modal-card-icon {
|
||||
font-size: 4em;
|
||||
padding: 6px 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shake-once {
|
||||
animation: shake .2s;
|
||||
transform: translate3d(0, 0, 0);
|
||||
backface-visibility: hidden;
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0% { transform: skewX(0deg); }
|
||||
20% { transform: skewX(-5deg); }
|
||||
40% { transform: skewX(5deg); }
|
||||
60% { transform: skewX(-5deg); }
|
||||
80% { transform: skewX(5deg); }
|
||||
100% { transform: skewX(0deg); }
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ pre[lang=ht], input[lang=ht], textarea[lang=ht], div[lang=ht] { background-image
|
||||
pre[lang=hu], input[lang=hu], textarea[lang=hu], div[lang=hu] { background-image: url(static('pretixbase/img/flags/hu.png')); }
|
||||
pre[lang=id], input[lang=id], textarea[lang=id], div[lang=id] { background-image: url(static('pretixbase/img/flags/id.png')); }
|
||||
pre[lang=ie], input[lang=ie], textarea[lang=ie], div[lang=ie] { background-image: url(static('pretixbase/img/flags/ie.png')); }
|
||||
pre[lang=il], input[lang=il], textarea[lang=il], div[lang=il] { background-image: url(static('pretixbase/img/flags/il.png')); }
|
||||
pre[lang=he], input[lang=he], textarea[lang=he], div[lang=he] { background-image: url(static('pretixbase/img/flags/il.png')); }
|
||||
pre[lang=in], input[lang=in], textarea[lang=in], div[lang=in] { background-image: url(static('pretixbase/img/flags/in.png')); }
|
||||
pre[lang=io], input[lang=io], textarea[lang=io], div[lang=io] { background-image: url(static('pretixbase/img/flags/io.png')); }
|
||||
pre[lang=iq], input[lang=iq], textarea[lang=iq], div[lang=iq] { background-image: url(static('pretixbase/img/flags/iq.png')); }
|
||||
@@ -306,3 +306,4 @@ pre[lang=za], input[lang=za], textarea[lang=za], div[lang=za] { background-image
|
||||
pre[lang=zm], input[lang=zm], textarea[lang=zm], div[lang=zm] { background-image: url(static('pretixbase/img/flags/zm.png')); }
|
||||
pre[lang=zw], input[lang=zw], textarea[lang=zw], div[lang=zw] { background-image: url(static('pretixbase/img/flags/zw.png')); }
|
||||
pre[lang=en], input[lang=en], textarea[lang=en], div[lang=en] { background-image: url(static('pretixbase/img/flags/gb.png')); }
|
||||
pre[lang=eu], input[lang=eu], textarea[lang=eu], div[lang=eu] { background-image: url(static('pretixbase/img/flags/basque.png')); }
|
||||
|
||||
@@ -55,6 +55,7 @@ var cart = {
|
||||
pad(diff_minutes.toString(), 2) + ':' + pad(diff_seconds.toString(), 2)
|
||||
);
|
||||
}
|
||||
$("#cart-extend-button").toggle(diff_minutes < 3);
|
||||
},
|
||||
|
||||
init: function () {
|
||||
|
||||
@@ -6,7 +6,7 @@ $(function () {
|
||||
var storage_key = $("#cookie-consent-storage-key").text();
|
||||
var widget_consent = $("#cookie-consent-from-widget").text();
|
||||
var consent_checkboxes = $("#cookie-consent-details input[type=checkbox][name]");
|
||||
var consent_modal = $("#cookie-consent-modal");
|
||||
var consent_modal = document.getElementById("cookie-consent-modal");
|
||||
|
||||
function update_consent(consent, sessionOnly) {
|
||||
if (storage_key && window.sessionStorage && sessionOnly) {
|
||||
@@ -108,25 +108,32 @@ $(function () {
|
||||
|
||||
_set_button_text();
|
||||
if (show_dialog) {
|
||||
// We use .css() instead of .show() because of some weird issue that only occurs in Firefox
|
||||
// and only within the widget.
|
||||
consent_modal.css("display", "block");
|
||||
consent_modal.showModal();
|
||||
consent_modal.addEventListener("cancel", function() {
|
||||
// Dialog was initially shown, interpret Escape as „do not consent to new providers“
|
||||
var consent = {};
|
||||
consent_checkboxes.each(function () {
|
||||
consent[this.name] = storage_val[this.name] || false;
|
||||
});
|
||||
update_consent(consent, false);
|
||||
}, {once : true});
|
||||
}
|
||||
|
||||
$("#cookie-consent-button-yes, #cookie-consent-button-no").on("click", function () {
|
||||
consent_modal.hide();
|
||||
consent_modal.addEventListener("close", function () {
|
||||
if (!consent_modal.returnValue) {// ESC, do not save
|
||||
return;
|
||||
}
|
||||
var consent = {};
|
||||
var consent_all = this.id == "cookie-consent-button-yes";
|
||||
var consent_all = consent_modal.returnValue == "yes";
|
||||
consent_checkboxes.each(function () {
|
||||
consent[this.name] = this.checked = consent_all || this.checked;
|
||||
});
|
||||
if (consent_all) _set_button_text();
|
||||
// Always save explicit consent to permanent storage
|
||||
update_consent(consent, false);
|
||||
});
|
||||
consent_checkboxes.on("change", _set_button_text);
|
||||
$("#cookie-consent-reopen").on("click", function (e) {
|
||||
consent_modal.show()
|
||||
consent_modal.showModal()
|
||||
e.preventDefault()
|
||||
return true
|
||||
})
|
||||
|
||||
@@ -390,6 +390,13 @@ $(function () {
|
||||
sessionStorage.removeItem('scrollpos');
|
||||
}
|
||||
|
||||
$("dialog").on("mousedown", function (e) {
|
||||
if (e.target == this) {
|
||||
// dialog has no padding, so this triggers only onclick on backdrop
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
|
||||
$(".accordion-radio").click(function() {
|
||||
var $input = $("input", this);
|
||||
if (!$input.prop("checked")) $input.prop('checked', true).trigger("change");
|
||||
@@ -478,33 +485,21 @@ $(function () {
|
||||
sessionStorage.setItem('scrollpos', window.scrollY);
|
||||
});
|
||||
}
|
||||
var update_cart_form = function () {
|
||||
var is_enabled = $(".product-row input[type=checkbox]:checked, .variations input[type=checkbox]:checked, .product-row input[type=radio]:checked, .variations input[type=radio]:checked").length;
|
||||
if (!is_enabled) {
|
||||
$(".input-item-count").each(function () {
|
||||
if ($(this).val() && $(this).val() !== "0") {
|
||||
is_enabled = true;
|
||||
}
|
||||
});
|
||||
$(".input-seat-selection option").each(function() {
|
||||
if ($(this).val() && $(this).val() !== "" && $(this).prop('selected')) {
|
||||
is_enabled = true;
|
||||
}
|
||||
});
|
||||
$("form:has(#btn-add-to-cart)").on("submit", function(e) {
|
||||
if (
|
||||
(this.classList.contains("has-seating") && this.querySelector("pretix-seating-checkout-button button")) ||
|
||||
this.querySelector("input[type=checkbox]:checked") ||
|
||||
[...this.querySelectorAll(".input-item-count[type=text]")].some(input => input.value && input.value !== "0") // TODO: seating hat noch einen seating-dummy-item-count, das ist Mist!
|
||||
) {
|
||||
// okay, let the submit-event bubble to async-task
|
||||
return;
|
||||
}
|
||||
if (!is_enabled && (!$(".has-seating").length || $("#seating-dummy-item-count").length)) {
|
||||
$("#btn-add-to-cart").prop("disabled", !is_enabled).popover({
|
||||
'content': function () { return gettext("Please enter a quantity for one of the ticket types.") },
|
||||
'placement': 'top',
|
||||
'trigger': 'hover focus'
|
||||
});
|
||||
} else {
|
||||
$("#btn-add-to-cart").prop("disabled", false).popover("destroy")
|
||||
}
|
||||
};
|
||||
update_cart_form();
|
||||
$(".product-row input[type=checkbox], .variations input[type=checkbox], .product-row input[type=radio], .variations input[type=radio], .input-item-count, .input-seat-selection")
|
||||
.on("change mouseup keyup", update_cart_form);
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
document.querySelector("#dialog-nothing-to-add").showModal();
|
||||
});
|
||||
|
||||
$(".table-calendar td.has-events").click(function () {
|
||||
var $grid = $(this).closest("[role='grid']");
|
||||
|
||||
@@ -471,7 +471,7 @@ Vue.component('variation', {
|
||||
// Variation description
|
||||
+ '<div class="pretix-widget-item-info-col">'
|
||||
+ '<div class="pretix-widget-item-title-and-description">'
|
||||
+ '<strong :id="variation_label_id" class="pretix-widget-item-title">{{ variation.value }}</strong>'
|
||||
+ '<strong :id="variation_label_id" class="pretix-widget-item-title" role="heading" v-bind:aria-level="headingLevel">{{ variation.value }}</strong>'
|
||||
+ '<div :id="variation_desc_id" class="pretix-widget-item-description" v-if="variation.description" v-html="variation.description"></div>'
|
||||
+ '<p class="pretix-widget-item-meta" '
|
||||
+ ' v-if="!variation.has_variations && variation.avail[1] !== null && variation.avail[0] === 100">'
|
||||
@@ -500,6 +500,7 @@ Vue.component('variation', {
|
||||
props: {
|
||||
variation: Object,
|
||||
item: Object,
|
||||
category: Object,
|
||||
},
|
||||
computed: {
|
||||
orig_price: function () {
|
||||
@@ -523,6 +524,9 @@ Vue.component('variation', {
|
||||
aria_labelledby: function () {
|
||||
return [this.variation_label_id, this.variation_price_id].join(" ");
|
||||
},
|
||||
headingLevel: function () {
|
||||
return this.category.name ? '5' : '4';
|
||||
},
|
||||
}
|
||||
});
|
||||
Vue.component('item', {
|
||||
@@ -533,12 +537,12 @@ Vue.component('item', {
|
||||
+ '<div class="pretix-widget-item-info-col">'
|
||||
+ '<a :href="item.picture_fullsize" v-if="item.picture" class="pretix-widget-item-picture-link" @click.prevent.stop="lightbox"><img :src="item.picture" class="pretix-widget-item-picture" :alt="picture_alt_text"></a>'
|
||||
+ '<div class="pretix-widget-item-title-and-description">'
|
||||
+ '<a v-if="item.has_variations && show_toggle" :id="item_label_id" class="pretix-widget-item-title" :href="\'#\' + item.id + \'-variants\'"'
|
||||
+ '<a v-if="item.has_variations && show_toggle" :id="item_label_id" role="heading" v-bind:aria-level="headingLevel" class="pretix-widget-item-title" :href="\'#\' + item.id + \'-variants\'"'
|
||||
+ ' @click.prevent.stop="expand"'
|
||||
+ '>'
|
||||
+ '{{ item.name }}'
|
||||
+ '</a>'
|
||||
+ '<strong v-else class="pretix-widget-item-title" :id="item_label_id">{{ item.name }}</strong>'
|
||||
+ '<strong v-else class="pretix-widget-item-title" :id="item_label_id" role="heading" v-bind:aria-level="headingLevel">{{ item.name }}</strong>'
|
||||
+ '<div class="pretix-widget-item-description" :id="item_desc_id" v-if="item.description" v-html="item.description"></div>'
|
||||
+ '<p class="pretix-widget-item-meta" v-if="item.order_min && item.order_min > 1">'
|
||||
+ '<small>{{ min_order_str }}</small>'
|
||||
@@ -572,13 +576,14 @@ Vue.component('item', {
|
||||
|
||||
// Variations
|
||||
+ '<div :class="varClasses" v-if="item.has_variations" :id="item.id + \'-variants\'" ref="variations">'
|
||||
+ '<variation v-for="variation in item.variations" :variation="variation" :item="item" :key="variation.id">'
|
||||
+ '<variation v-for="variation in item.variations" :variation="variation" :item="item" :category="category" :key="variation.id">'
|
||||
+ '</variation>'
|
||||
+ '</div>'
|
||||
|
||||
+ '</div>'),
|
||||
props: {
|
||||
item: Object,
|
||||
category: Object,
|
||||
},
|
||||
data: function () {
|
||||
return {
|
||||
@@ -636,6 +641,9 @@ Vue.component('item', {
|
||||
picture_alt_text: function () {
|
||||
return django.interpolate(strings["image_of"], [this.item.name]);
|
||||
},
|
||||
headingLevel: function () {
|
||||
return this.category.name ? '4' : '3';
|
||||
},
|
||||
item_label_id: function () {
|
||||
return this.$root.html_id + '-item-label-' + this.item.id;
|
||||
},
|
||||
@@ -687,7 +695,7 @@ Vue.component('category', {
|
||||
+ '<div class="pretix-widget-category-description" v-if="category.description" v-html="category.description">'
|
||||
+ '</div>'
|
||||
+ '<div class="pretix-widget-category-items">'
|
||||
+ '<item v-for="item in category.items" :item="item" :key="item.id"></item>'
|
||||
+ '<item v-for="item in category.items" :category="category" :item="item" :key="item.id"></item>'
|
||||
+ '</div>'
|
||||
+ '</div>'),
|
||||
props: {
|
||||
@@ -1002,7 +1010,7 @@ Vue.component('pretix-widget-event-form', {
|
||||
|
||||
// Event name
|
||||
+ '<div class="pretix-widget-event-header" v-if="display_event_info">'
|
||||
+ '<strong>{{ $root.name }}</strong>'
|
||||
+ '<strong role="heading" aria-level="2">{{ $root.name }}</strong>'
|
||||
+ '</div>'
|
||||
|
||||
// Date range
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
text-align: center;
|
||||
|
||||
&.gone, .gone {
|
||||
color: $brand-danger;
|
||||
color: $alert-danger-text;
|
||||
}
|
||||
&.unavailable, .unavailable {
|
||||
color: $alert-warning-text;
|
||||
|
||||
@@ -76,6 +76,7 @@ html {
|
||||
clip: auto;
|
||||
}
|
||||
#skip-to-main {
|
||||
z-index: 9999;
|
||||
/* padding is needed to make focus-outline visible */
|
||||
padding: 8px;
|
||||
background-color: inherit;
|
||||
@@ -156,6 +157,7 @@ button:focus, a:focus, .btn:focus, summary:focus, div:focus,
|
||||
button:active:focus, a:active:focus, .btn:active:focus, summary:active:focus, div:active:focus,
|
||||
button.active:focus, a.active:focus, .btn.active:focus,
|
||||
input:focus, .form-control:focus, .btn-checkbox:has(input:focus),
|
||||
input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus,
|
||||
.input-item-count-group:has(input:focus), .input-group-price:has(input:focus) {
|
||||
outline: 2px solid $link-hover-color;
|
||||
outline-offset: 2px;
|
||||
@@ -289,7 +291,7 @@ body.loading .container {
|
||||
font-size: 120px;
|
||||
color: $brand-primary;
|
||||
}
|
||||
#loadingmodal, #ajaxerr, #cookie-consent-modal, #popupmodal {
|
||||
#loadingmodal, #ajaxerr, #popupmodal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
@@ -359,7 +361,7 @@ body.loading .container {
|
||||
}
|
||||
}
|
||||
@media (max-width: 700px) {
|
||||
#loadingmodal, #ajaxerr, #cookie-consent-modal, #popupmodal {
|
||||
#loadingmodal, #ajaxerr, #popupmodal {
|
||||
.modal-card {
|
||||
margin: 25px auto 0;
|
||||
max-height: calc(100vh - 50px - 20px);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user