forked from CGM_Public/pretix_original
Compare commits
13 Commits
dashboard-
...
fieldset-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4aeab2b017 | ||
|
|
ae29240e58 | ||
|
|
74edf10b04 | ||
|
|
e2e0eca872 | ||
|
|
6132e4a2c4 | ||
|
|
7df7d28518 | ||
|
|
11ab5c5eeb | ||
|
|
d8f3875db0 | ||
|
|
20211d2097 | ||
|
|
d760ad38bf | ||
|
|
69af2cee93 | ||
|
|
6b199a2b9c | ||
|
|
94a64ba53a |
@@ -44,7 +44,7 @@ dependencies = [
|
|||||||
"django-formtools==2.5.1",
|
"django-formtools==2.5.1",
|
||||||
"django-hierarkey==1.2.*",
|
"django-hierarkey==1.2.*",
|
||||||
"django-hijack==3.7.*",
|
"django-hijack==3.7.*",
|
||||||
"django-i18nfield==1.9.*,>=1.9.4",
|
"django-i18nfield==1.9.*,>=1.9.5",
|
||||||
"django-libsass==0.9",
|
"django-libsass==0.9",
|
||||||
"django-localflavor==4.0",
|
"django-localflavor==4.0",
|
||||||
"django-markup",
|
"django-markup",
|
||||||
|
|||||||
@@ -19,57 +19,8 @@
|
|||||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
# 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/>.
|
# <https://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
from django.conf import settings
|
|
||||||
from django.core.validators import URLValidator
|
from django.core.validators import URLValidator
|
||||||
from i18nfield.fields import I18nCharField, I18nTextField
|
from i18nfield.rest_framework import I18nAwareModelSerializer, I18nField
|
||||||
from i18nfield.strings import LazyI18nString
|
|
||||||
from rest_framework.exceptions import ValidationError
|
|
||||||
from rest_framework.fields import Field
|
|
||||||
from rest_framework.serializers import ModelSerializer
|
|
||||||
|
|
||||||
|
|
||||||
class I18nField(Field):
|
|
||||||
def __init__(self, **kwargs):
|
|
||||||
self.allow_blank = kwargs.pop('allow_blank', False)
|
|
||||||
self.trim_whitespace = kwargs.pop('trim_whitespace', True)
|
|
||||||
self.max_length = kwargs.pop('max_length', None)
|
|
||||||
self.min_length = kwargs.pop('min_length', None)
|
|
||||||
super().__init__(**kwargs)
|
|
||||||
|
|
||||||
def to_representation(self, value):
|
|
||||||
if hasattr(value, 'data'):
|
|
||||||
if isinstance(value.data, dict):
|
|
||||||
return value.data
|
|
||||||
elif value.data is None:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return {
|
|
||||||
settings.LANGUAGE_CODE: str(value.data)
|
|
||||||
}
|
|
||||||
elif value is None:
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
return {
|
|
||||||
settings.LANGUAGE_CODE: str(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
|
||||||
if isinstance(data, str):
|
|
||||||
return LazyI18nString(data)
|
|
||||||
elif isinstance(data, dict):
|
|
||||||
if any([k not in dict(settings.LANGUAGES) for k in data.keys()]):
|
|
||||||
raise ValidationError('Invalid languages included.')
|
|
||||||
return LazyI18nString(data)
|
|
||||||
else:
|
|
||||||
raise ValidationError('Invalid data type.')
|
|
||||||
|
|
||||||
|
|
||||||
class I18nAwareModelSerializer(ModelSerializer):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
I18nAwareModelSerializer.serializer_field_mapping[I18nCharField] = I18nField
|
|
||||||
I18nAwareModelSerializer.serializer_field_mapping[I18nTextField] = I18nField
|
|
||||||
|
|
||||||
|
|
||||||
class I18nURLField(I18nField):
|
class I18nURLField(I18nField):
|
||||||
@@ -84,3 +35,10 @@ class I18nURLField(I18nField):
|
|||||||
else:
|
else:
|
||||||
URLValidator()(value.data)
|
URLValidator()(value.data)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"I18nAwareModelSerializer", # for backwards compatibility
|
||||||
|
"I18nField", # for backwards compatibility
|
||||||
|
"I18nURLField",
|
||||||
|
]
|
||||||
|
|||||||
@@ -1419,50 +1419,51 @@ class GiftCardPayment(BasePaymentProvider):
|
|||||||
def payment_refund_supported(self, payment: OrderPayment) -> bool:
|
def payment_refund_supported(self, payment: OrderPayment) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> Union[bool, str, None]:
|
def _add_giftcard_to_cart(self, cs, gc):
|
||||||
from pretix.base.services.cart import add_payment_to_cart
|
from pretix.base.services.cart import add_payment_to_cart_session
|
||||||
|
|
||||||
|
if gc.currency != self.event.currency:
|
||||||
|
raise ValidationError(_("This gift card does not support this currency."))
|
||||||
|
if gc.testmode and not self.event.testmode:
|
||||||
|
raise ValidationError(_("This gift card can only be used in test mode."))
|
||||||
|
if not gc.testmode and self.event.testmode:
|
||||||
|
raise ValidationError(_("Only test gift cards can be used in test mode."))
|
||||||
|
if gc.expires and gc.expires < time_machine_now():
|
||||||
|
raise ValidationError(_("This gift card is no longer valid."))
|
||||||
|
if gc.value <= Decimal("0.00"):
|
||||||
|
raise ValidationError(_("All credit on this gift card has been used."))
|
||||||
|
|
||||||
|
for p in cs.get('payments', []):
|
||||||
|
if p['provider'] == self.identifier and p['info_data']['gift_card'] == gc.pk:
|
||||||
|
raise ValidationError(_("This gift card is already used for your payment."))
|
||||||
|
|
||||||
|
add_payment_to_cart_session(
|
||||||
|
cs,
|
||||||
|
self,
|
||||||
|
max_value=gc.value,
|
||||||
|
info_data={
|
||||||
|
'gift_card': gc.pk,
|
||||||
|
'gift_card_secret': gc.secret,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> Union[bool, str, None]:
|
||||||
for p in get_cart(request):
|
for p in get_cart(request):
|
||||||
if p.item.issue_giftcard:
|
if p.item.issue_giftcard:
|
||||||
messages.error(request, _("You cannot pay with gift cards when buying a gift card."))
|
messages.error(request, _("You cannot pay with gift cards when buying a gift card."))
|
||||||
return
|
return
|
||||||
|
|
||||||
cs = cart_session(request)
|
|
||||||
try:
|
try:
|
||||||
gc = self.event.organizer.accepted_gift_cards.get(
|
gc = self.event.organizer.accepted_gift_cards.get(
|
||||||
secret=request.POST.get("giftcard").strip()
|
secret=request.POST.get("giftcard").strip()
|
||||||
)
|
)
|
||||||
if gc.currency != self.event.currency:
|
cs = cart_session(request)
|
||||||
messages.error(request, _("This gift card does not support this currency."))
|
try:
|
||||||
|
self._add_giftcard_to_cart(cs, gc)
|
||||||
|
return True
|
||||||
|
except ValidationError as e:
|
||||||
|
messages.error(request, str(e.message))
|
||||||
return
|
return
|
||||||
if gc.testmode and not self.event.testmode:
|
|
||||||
messages.error(request, _("This gift card can only be used in test mode."))
|
|
||||||
return
|
|
||||||
if not gc.testmode and self.event.testmode:
|
|
||||||
messages.error(request, _("Only test gift cards can be used in test mode."))
|
|
||||||
return
|
|
||||||
if gc.expires and gc.expires < time_machine_now():
|
|
||||||
messages.error(request, _("This gift card is no longer valid."))
|
|
||||||
return
|
|
||||||
if gc.value <= Decimal("0.00"):
|
|
||||||
messages.error(request, _("All credit on this gift card has been used."))
|
|
||||||
return
|
|
||||||
|
|
||||||
for p in cs.get('payments', []):
|
|
||||||
if p['provider'] == self.identifier and p['info_data']['gift_card'] == gc.pk:
|
|
||||||
messages.error(request, _("This gift card is already used for your payment."))
|
|
||||||
return
|
|
||||||
|
|
||||||
add_payment_to_cart(
|
|
||||||
request,
|
|
||||||
self,
|
|
||||||
max_value=gc.value,
|
|
||||||
info_data={
|
|
||||||
'gift_card': gc.pk,
|
|
||||||
'gift_card_secret': gc.secret,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
return True
|
|
||||||
except GiftCard.DoesNotExist:
|
except GiftCard.DoesNotExist:
|
||||||
if self.event.vouchers.filter(code__iexact=request.POST.get("giftcard")).exists():
|
if self.event.vouchers.filter(code__iexact=request.POST.get("giftcard")).exists():
|
||||||
messages.warning(request, _("You entered a voucher instead of a gift card. Vouchers can only be entered on the first page of the shop below "
|
messages.warning(request, _("You entered a voucher instead of a gift card. Vouchers can only be entered on the first page of the shop below "
|
||||||
|
|||||||
@@ -1426,6 +1426,28 @@ class CartManager:
|
|||||||
raise CartError(err)
|
raise CartError(err)
|
||||||
|
|
||||||
|
|
||||||
|
def add_payment_to_cart_session(cart_session, provider, min_value: Decimal=None, max_value: Decimal=None, info_data: dict=None):
|
||||||
|
"""
|
||||||
|
:param cart_session: The current cart session.
|
||||||
|
:param provider: The instance of your payment provider.
|
||||||
|
:param min_value: The minimum value this payment instrument supports, or ``None`` for unlimited.
|
||||||
|
:param max_value: The maximum value this payment instrument supports, or ``None`` for unlimited. Highly discouraged
|
||||||
|
to use for payment providers which charge a payment fee, as this can be very user-unfriendly if
|
||||||
|
users need a second payment method just for the payment fee of the first method.
|
||||||
|
:param info_data: A dictionary of information that will be passed through to the ``OrderPayment.info_data`` attribute.
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
cart_session.setdefault('payments', [])
|
||||||
|
cart_session['payments'].append({
|
||||||
|
'id': str(uuid.uuid4()),
|
||||||
|
'provider': provider.identifier,
|
||||||
|
'multi_use_supported': provider.multi_use_supported,
|
||||||
|
'min_value': str(min_value) if min_value is not None else None,
|
||||||
|
'max_value': str(max_value) if max_value is not None else None,
|
||||||
|
'info_data': info_data or {},
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
def add_payment_to_cart(request, provider, min_value: Decimal=None, max_value: Decimal=None, info_data: dict=None):
|
def add_payment_to_cart(request, provider, min_value: Decimal=None, max_value: Decimal=None, info_data: dict=None):
|
||||||
"""
|
"""
|
||||||
:param request: The current HTTP request context.
|
:param request: The current HTTP request context.
|
||||||
@@ -1440,16 +1462,7 @@ def add_payment_to_cart(request, provider, min_value: Decimal=None, max_value: D
|
|||||||
from pretix.presale.views.cart import cart_session
|
from pretix.presale.views.cart import cart_session
|
||||||
|
|
||||||
cs = cart_session(request)
|
cs = cart_session(request)
|
||||||
cs.setdefault('payments', [])
|
add_payment_to_cart_session(cs, provider, min_value, max_value, info_data)
|
||||||
|
|
||||||
cs['payments'].append({
|
|
||||||
'id': str(uuid.uuid4()),
|
|
||||||
'provider': provider.identifier,
|
|
||||||
'multi_use_supported': provider.multi_use_supported,
|
|
||||||
'min_value': str(min_value) if min_value is not None else None,
|
|
||||||
'max_value': str(max_value) if max_value is not None else None,
|
|
||||||
'info_data': info_data or {},
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
def get_fees(event, request, total, invoice_address, payments, positions):
|
def get_fees(event, request, total, invoice_address, payments, positions):
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ from django.utils.translation import (
|
|||||||
from django_countries.fields import Country
|
from django_countries.fields import Country
|
||||||
from hierarkey.models import GlobalSettingsBase, Hierarkey
|
from hierarkey.models import GlobalSettingsBase, Hierarkey
|
||||||
from i18nfield.forms import I18nFormField, I18nTextarea, I18nTextInput
|
from i18nfield.forms import I18nFormField, I18nTextarea, I18nTextInput
|
||||||
|
from i18nfield.rest_framework import I18nField
|
||||||
from i18nfield.strings import LazyI18nString
|
from i18nfield.strings import LazyI18nString
|
||||||
from phonenumbers import PhoneNumber, parse
|
from phonenumbers import PhoneNumber, parse
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
@@ -63,7 +64,7 @@ from rest_framework import serializers
|
|||||||
from pretix.api.serializers.fields import (
|
from pretix.api.serializers.fields import (
|
||||||
ListMultipleChoiceField, UploadedFileField,
|
ListMultipleChoiceField, UploadedFileField,
|
||||||
)
|
)
|
||||||
from pretix.api.serializers.i18n import I18nField, I18nURLField
|
from pretix.api.serializers.i18n import I18nURLField
|
||||||
from pretix.base.forms import I18nMarkdownTextarea, I18nURLFormField
|
from pretix.base.forms import I18nMarkdownTextarea, I18nURLFormField
|
||||||
from pretix.base.models.tax import VAT_ID_COUNTRIES, TaxRule
|
from pretix.base.models.tax import VAT_ID_COUNTRIES, TaxRule
|
||||||
from pretix.base.reldate import (
|
from pretix.base.reldate import (
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ def money_filter(value: Decimal, arg='', hide_currency=False):
|
|||||||
# would make the numbers incorrect. If this branch executes, it's likely a bug in
|
# would make the numbers incorrect. If this branch executes, it's likely a bug in
|
||||||
# pretix, but we won't show wrong numbers!
|
# pretix, but we won't show wrong numbers!
|
||||||
if hide_currency:
|
if hide_currency:
|
||||||
return floatformat(value, 2)
|
return floatformat(value, "2g")
|
||||||
else:
|
else:
|
||||||
return '{} {}'.format(arg, floatformat(value, 2))
|
return '{} {}'.format(arg, floatformat(value, "2g"))
|
||||||
|
|
||||||
if hide_currency:
|
if hide_currency:
|
||||||
return floatformat(value, places)
|
return floatformat(value, f"{places}g")
|
||||||
|
|
||||||
locale_parts = translation.get_language().split("-", 1)
|
locale_parts = translation.get_language().split("-", 1)
|
||||||
locale = locale_parts[0]
|
locale = locale_parts[0]
|
||||||
@@ -70,7 +70,7 @@ def money_filter(value: Decimal, arg='', hide_currency=False):
|
|||||||
try:
|
try:
|
||||||
return format_currency(value, arg, locale=locale)
|
return format_currency(value, arg, locale=locale)
|
||||||
except:
|
except:
|
||||||
return '{} {}'.format(arg, floatformat(value, places))
|
return '{} {}'.format(arg, floatformat(value, f"{places}g"))
|
||||||
|
|
||||||
|
|
||||||
@register.filter("money_numberfield")
|
@register.filter("money_numberfield")
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ from zoneinfo import ZoneInfo
|
|||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.contrib.humanize.templatetags.humanize import intcomma
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
Count, IntegerField, Max, Min, OuterRef, Prefetch, Q, Subquery, Sum,
|
Count, IntegerField, Max, Min, OuterRef, Prefetch, Q, Subquery, Sum,
|
||||||
)
|
)
|
||||||
@@ -47,7 +48,6 @@ from django.http import JsonResponse
|
|||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import formats
|
|
||||||
from django.utils.formats import date_format
|
from django.utils.formats import date_format
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
@@ -67,6 +67,7 @@ from pretix.control.signals import (
|
|||||||
from pretix.helpers.daterange import daterange
|
from pretix.helpers.daterange import daterange
|
||||||
|
|
||||||
from ...base.models.orders import CancellationRequest
|
from ...base.models.orders import CancellationRequest
|
||||||
|
from ...base.templatetags.money import money_filter
|
||||||
from ..logdisplay import OVERVIEW_BANLIST
|
from ..logdisplay import OVERVIEW_BANLIST
|
||||||
|
|
||||||
NUM_WIDGET = '<div class="numwidget"><span class="num">{num}</span><span class="text">{text}</span></div>'
|
NUM_WIDGET = '<div class="numwidget"><span class="num">{num}</span><span class="text">{text}</span></div>'
|
||||||
@@ -111,7 +112,7 @@ def base_widgets(sender, subevent=None, lazy=False, **kwargs):
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
'content': None if lazy else NUM_WIDGET.format(num=tickc, text=_('Attendees (ordered)')),
|
'content': None if lazy else NUM_WIDGET.format(num=intcomma(tickc), text=_('Attendees (ordered)')),
|
||||||
'lazy': 'attendees-ordered',
|
'lazy': 'attendees-ordered',
|
||||||
'display_size': 'small',
|
'display_size': 'small',
|
||||||
'priority': 100,
|
'priority': 100,
|
||||||
@@ -121,7 +122,7 @@ def base_widgets(sender, subevent=None, lazy=False, **kwargs):
|
|||||||
}) + ('?subevent={}'.format(subevent.pk) if subevent else '')
|
}) + ('?subevent={}'.format(subevent.pk) if subevent else '')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'content': None if lazy else NUM_WIDGET.format(num=paidc, text=_('Attendees (paid)')),
|
'content': None if lazy else NUM_WIDGET.format(num=intcomma(paidc), text=_('Attendees (paid)')),
|
||||||
'lazy': 'attendees-paid',
|
'lazy': 'attendees-paid',
|
||||||
'display_size': 'small',
|
'display_size': 'small',
|
||||||
'priority': 100,
|
'priority': 100,
|
||||||
@@ -132,7 +133,9 @@ def base_widgets(sender, subevent=None, lazy=False, **kwargs):
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'content': None if lazy else NUM_WIDGET.format(
|
'content': None if lazy else NUM_WIDGET.format(
|
||||||
num=formats.localize(round_decimal(rev, sender.currency)), text=_('Total revenue ({currency})').format(currency=sender.currency)),
|
num=money_filter(round_decimal(rev, sender.currency), sender.currency, hide_currency=True),
|
||||||
|
text=_('Total revenue ({currency})').format(currency=sender.currency)
|
||||||
|
),
|
||||||
'lazy': 'total-revenue',
|
'lazy': 'total-revenue',
|
||||||
'display_size': 'small',
|
'display_size': 'small',
|
||||||
'priority': 100,
|
'priority': 100,
|
||||||
@@ -207,7 +210,7 @@ def waitinglist_widgets(sender, subevent=None, lazy=False, **kwargs):
|
|||||||
|
|
||||||
widgets.append({
|
widgets.append({
|
||||||
'content': None if lazy else NUM_WIDGET.format(
|
'content': None if lazy else NUM_WIDGET.format(
|
||||||
num=str(happy), text=_('available to give to people on waiting list')
|
num=intcomma(happy), text=_('available to give to people on waiting list')
|
||||||
),
|
),
|
||||||
'lazy': 'waitinglist-avail',
|
'lazy': 'waitinglist-avail',
|
||||||
'priority': 50,
|
'priority': 50,
|
||||||
@@ -217,7 +220,7 @@ def waitinglist_widgets(sender, subevent=None, lazy=False, **kwargs):
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
widgets.append({
|
widgets.append({
|
||||||
'content': None if lazy else NUM_WIDGET.format(num=str(wles.count()), text=_('total waiting list length')),
|
'content': None if lazy else NUM_WIDGET.format(num=intcomma(wles.count()), text=_('total waiting list length')),
|
||||||
'lazy': 'waitinglist-length',
|
'lazy': 'waitinglist-length',
|
||||||
'display_size': 'small',
|
'display_size': 'small',
|
||||||
'priority': 50,
|
'priority': 50,
|
||||||
@@ -245,7 +248,7 @@ def quota_widgets(sender, subevent=None, lazy=False, **kwargs):
|
|||||||
status, left = qa.results[q] if q in qa.results else q.availability(allow_cache=True)
|
status, left = qa.results[q] if q in qa.results else q.availability(allow_cache=True)
|
||||||
widgets.append({
|
widgets.append({
|
||||||
'content': None if lazy else NUM_WIDGET.format(
|
'content': None if lazy else NUM_WIDGET.format(
|
||||||
num='{}/{}'.format(left, q.size) if q.size is not None else '\u221e',
|
num='{}/{}'.format(intcomma(left), intcomma(q.size)) if q.size is not None else '\u221e',
|
||||||
text=_('{quota} left').format(quota=escape(q.name))
|
text=_('{quota} left').format(quota=escape(q.name))
|
||||||
),
|
),
|
||||||
'lazy': 'quota-{}'.format(q.pk),
|
'lazy': 'quota-{}'.format(q.pk),
|
||||||
@@ -297,7 +300,7 @@ def checkin_widget(sender, subevent=None, lazy=False, **kwargs):
|
|||||||
for cl in qs:
|
for cl in qs:
|
||||||
widgets.append({
|
widgets.append({
|
||||||
'content': None if lazy else NUM_WIDGET.format(
|
'content': None if lazy else NUM_WIDGET.format(
|
||||||
num='{}/{}'.format(cl.inside_count, cl.position_count),
|
num='{}/{}'.format(intcomma(cl.inside_count), intcomma(cl.position_count)),
|
||||||
text=_('Present – {list}').format(list=escape(cl.name))
|
text=_('Present – {list}').format(list=escape(cl.name))
|
||||||
),
|
),
|
||||||
'lazy': 'checkin-{}'.format(cl.pk),
|
'lazy': 'checkin-{}'.format(cl.pk),
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-11-19 15:34+0000\n"
|
"POT-Creation-Date: 2024-11-19 15:34+0000\n"
|
||||||
"PO-Revision-Date: 2024-11-29 23:00+0000\n"
|
"PO-Revision-Date: 2024-12-03 20:00+0000\n"
|
||||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||||
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix/"
|
"Language-Team: Spanish <https://translate.pretix.eu/projects/pretix/pretix/"
|
||||||
"es/>\n"
|
"es/>\n"
|
||||||
@@ -31498,7 +31498,7 @@ msgstr "Lo sentimos, se ha producido un error en el proceso de pago."
|
|||||||
#: pretix/plugins/ticketoutputpdf/apps.py:44
|
#: pretix/plugins/ticketoutputpdf/apps.py:44
|
||||||
#: pretix/plugins/ticketoutputpdf/apps.py:47
|
#: pretix/plugins/ticketoutputpdf/apps.py:47
|
||||||
msgid "PDF ticket output"
|
msgid "PDF ticket output"
|
||||||
msgstr "Salida de entradas de PDF"
|
msgstr "Salida de entradas en PDF"
|
||||||
|
|
||||||
#: pretix/plugins/ticketoutputpdf/apps.py:52
|
#: pretix/plugins/ticketoutputpdf/apps.py:52
|
||||||
msgid ""
|
msgid ""
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: 1\n"
|
"Project-Id-Version: 1\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-11-19 15:34+0000\n"
|
"POT-Creation-Date: 2024-11-19 15:34+0000\n"
|
||||||
"PO-Revision-Date: 2024-11-29 23:00+0000\n"
|
"PO-Revision-Date: 2024-12-03 20:00+0000\n"
|
||||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||||
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix/fr/"
|
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix/fr/"
|
||||||
">\n"
|
">\n"
|
||||||
@@ -8954,7 +8954,7 @@ msgstr "Nombre maximum d'articles par commande"
|
|||||||
|
|
||||||
#: pretix/base/settings.py:316
|
#: pretix/base/settings.py:316
|
||||||
msgid "Add-on products will not be counted."
|
msgid "Add-on products will not be counted."
|
||||||
msgstr "Les Add-Ons ne seront pas pris en compte."
|
msgstr "Les Add-Ons e sont pas comptabilisés."
|
||||||
|
|
||||||
#: pretix/base/settings.py:325
|
#: pretix/base/settings.py:325
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -20630,17 +20630,16 @@ msgid ""
|
|||||||
"product. You can also specify the minimum and maximum number of add-ons of "
|
"product. You can also specify the minimum and maximum number of add-ons of "
|
||||||
"the given category that can or need to be chosen."
|
"the given category that can or need to be chosen."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Avec les modules complémentaires, vous pouvez spécifier des produits qui "
|
"Avec les add-ons, vous pouvez spécifier des produits qui peuvent être "
|
||||||
"peuvent être achetés en complément de ce produit. Par exemple, si vous "
|
"achetés en complément de ce produit. Par exemple, si vous organisez une "
|
||||||
"organisez une conférence avec un ticket de conférence de base et un certain "
|
"conférence avec un ticket de conférence de base et un certain nombre d’"
|
||||||
"nombre d’ateliers, vous pouvez définir les ateliers comme des modules "
|
"ateliers, vous pouvez définir les ateliers comme des modules complémentaires "
|
||||||
"complémentaires au ticket de conférence. Avec cette configuration, les "
|
"au ticket de conférence. Avec cette configuration, les ateliers ne peuvent "
|
||||||
"ateliers ne peuvent pas être achetés seuls, mais uniquement en combinaison "
|
"pas être achetés seuls, mais uniquement en combinaison avec un billet de "
|
||||||
"avec un billet de conférence. Vous pouvez spécifier ici des catégories de "
|
"conférence. Vous pouvez spécifier ici des catégories de produits qui peuvent "
|
||||||
"produits qui peuvent être utilisés comme modules complémentaires à ce "
|
"être utilisés comme modules complémentaires à ce produit. Vous pouvez "
|
||||||
"produit. Vous pouvez également spécifier le nombre minimal et maximal de "
|
"également spécifier le nombre minimal et maximal de modules complémentaires "
|
||||||
"modules complémentaires de la catégorie donnée qui peuvent ou doivent être "
|
"de la catégorie donnée qui peuvent ou doivent être choisis."
|
||||||
"choisis."
|
|
||||||
|
|
||||||
#: pretix/control/templates/pretixcontrol/item/include_addons.html:28
|
#: pretix/control/templates/pretixcontrol/item/include_addons.html:28
|
||||||
#: pretix/control/templates/pretixcontrol/item/include_addons.html:62
|
#: pretix/control/templates/pretixcontrol/item/include_addons.html:62
|
||||||
@@ -31762,7 +31761,7 @@ msgstr "Désolé, une erreur s’est produite dans le processus de paiement."
|
|||||||
#: pretix/plugins/ticketoutputpdf/apps.py:44
|
#: pretix/plugins/ticketoutputpdf/apps.py:44
|
||||||
#: pretix/plugins/ticketoutputpdf/apps.py:47
|
#: pretix/plugins/ticketoutputpdf/apps.py:47
|
||||||
msgid "PDF ticket output"
|
msgid "PDF ticket output"
|
||||||
msgstr "Sortie du ticket PDF"
|
msgstr "Génération de billets au format PDF"
|
||||||
|
|
||||||
#: pretix/plugins/ticketoutputpdf/apps.py:52
|
#: pretix/plugins/ticketoutputpdf/apps.py:52
|
||||||
msgid ""
|
msgid ""
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ msgstr ""
|
|||||||
"Project-Id-Version: French\n"
|
"Project-Id-Version: French\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
"POT-Creation-Date: 2024-11-08 13:45+0000\n"
|
||||||
"PO-Revision-Date: 2024-11-16 05:00+0000\n"
|
"PO-Revision-Date: 2024-12-03 20:00+0000\n"
|
||||||
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
"Last-Translator: CVZ-es <damien.bremont@casadevelazquez.org>\n"
|
||||||
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
"Language-Team: French <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||||
"fr/>\n"
|
"fr/>\n"
|
||||||
@@ -16,7 +16,7 @@ msgstr ""
|
|||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||||
"X-Generator: Weblate 5.8.3\n"
|
"X-Generator: Weblate 5.8.4\n"
|
||||||
|
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
|
||||||
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
|
||||||
@@ -150,7 +150,7 @@ msgstr "Méthode de paiement non disponible"
|
|||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
||||||
msgid "Placed orders"
|
msgid "Placed orders"
|
||||||
msgstr "Commandes placées"
|
msgstr "Commandes réalisées"
|
||||||
|
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
|
||||||
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
|
||||||
|
|||||||
@@ -6,13 +6,14 @@
|
|||||||
{% load eventsignal %}
|
{% load eventsignal %}
|
||||||
{% load rich_text %}
|
{% load rich_text %}
|
||||||
{% for c in form.categories %}
|
{% for c in form.categories %}
|
||||||
|
{% with category_idx=forloop.counter %}
|
||||||
<fieldset data-addon-max-count="{{ c.max_count }}"{% if c.multi_allowed %} data-addon-multi-allowed{% endif %}>
|
<fieldset data-addon-max-count="{{ c.max_count }}"{% if c.multi_allowed %} data-addon-multi-allowed{% endif %}>
|
||||||
<legend>{{ c.category.name }}</legend>
|
<legend>{{ c.category.name }}</legend>
|
||||||
{% if c.category.description %}
|
{% if c.category.description %}
|
||||||
{{ c.category.description|rich_text }}
|
{{ c.category.description|rich_text }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if c.min_count == c.max_count %}
|
{% if c.min_count == c.max_count %}
|
||||||
<p class="addon-count-desc">
|
<p class="addon-count-desc" id="c-{{ form.pos.pk }}-{{ category_idx }}-addon-count-desc">
|
||||||
{% blocktrans trimmed count min_count=c.min_count %}
|
{% blocktrans trimmed count min_count=c.min_count %}
|
||||||
You need to choose exactly one option from this category.
|
You need to choose exactly one option from this category.
|
||||||
{% plural %}
|
{% plural %}
|
||||||
@@ -21,7 +22,7 @@
|
|||||||
</p>
|
</p>
|
||||||
{% elif c.min_count == 0 and c.max_count >= c.items|length and not c.multi_allowed %}
|
{% elif c.min_count == 0 and c.max_count >= c.items|length and not c.multi_allowed %}
|
||||||
{% elif c.min_count == 0 %}
|
{% elif c.min_count == 0 %}
|
||||||
<p class="addon-count-desc">
|
<p class="addon-count-desc" id="c-{{ form.pos.pk }}-{{ category_idx }}-addon-count-desc">
|
||||||
{% blocktrans trimmed count max_count=c.max_count %}
|
{% blocktrans trimmed count max_count=c.max_count %}
|
||||||
You can choose {{ max_count }} option from this category.
|
You can choose {{ max_count }} option from this category.
|
||||||
{% plural %}
|
{% plural %}
|
||||||
@@ -29,7 +30,7 @@
|
|||||||
{% endblocktrans %}
|
{% endblocktrans %}
|
||||||
</p>
|
</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="addon-count-desc">
|
<p class="addon-count-desc" id="c-{{ form.pos.pk }}-{{ category_idx }}-addon-count-desc">
|
||||||
{% blocktrans trimmed with min_count=c.min_count max_count=c.max_count %}
|
{% blocktrans trimmed with min_count=c.min_count max_count=c.max_count %}
|
||||||
You can choose between {{ min_count }} and {{ max_count }} options from
|
You can choose between {{ min_count }} and {{ max_count }} options from
|
||||||
this category.
|
this category.
|
||||||
@@ -58,7 +59,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if item.min_per_order and item.min_per_order > 1 %}
|
{% if item.min_per_order and item.min_per_order > 1 %}
|
||||||
<p>
|
<p id="cp-{{ form.pos.pk }}-item-{{ item.pk }}-min-order">
|
||||||
<small>
|
<small>
|
||||||
{% blocktrans trimmed with num=item.min_per_order %}
|
{% blocktrans trimmed with num=item.min_per_order %}
|
||||||
minimum amount to order: {{ num }}
|
minimum amount to order: {{ num }}
|
||||||
@@ -196,12 +197,14 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
id="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}"
|
id="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}"
|
||||||
name="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}"
|
name="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}"
|
||||||
aria-label="{% blocktrans with item=item.name var=var %}Add {{ item }}, {{ var }} to cart{% endblocktrans %}">
|
aria-label="{% blocktrans with item=item.name var=var %}Add {{ item }}, {{ var }} to cart{% endblocktrans %}"
|
||||||
|
aria-describedby="c-{{ form.pos.pk }}-{{ category_idx }}-addon-count-desc">
|
||||||
<i class="fa fa-shopping-cart" aria-hidden="true"></i>
|
<i class="fa fa-shopping-cart" aria-hidden="true"></i>
|
||||||
{% trans "Select" context "checkbox" %}
|
{% trans "Select" context "checkbox" %}
|
||||||
</label>
|
</label>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="input-item-count-group">
|
<fieldset class="input-item-count-group" aria-describedby="c-{{ form.pos.pk }}-{{ category_idx }}-addon-count-desc cp-{{ form.pos.pk }}-item-{{ item.pk }}-min-order">
|
||||||
|
<legend class="sr-only">{% blocktrans with item=item.name %}Add {{ item }}, {{ var }} to cart{% endblocktrans %}</legend>
|
||||||
<button type="button" data-step="-1" data-controls="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}">-</button>
|
<button type="button" data-step="-1" data-controls="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}">-</button>
|
||||||
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
|
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
|
||||||
{% if var.initial %}value="{{ var.initial }}"{% endif %}
|
{% if var.initial %}value="{{ var.initial }}"{% endif %}
|
||||||
@@ -211,9 +214,9 @@
|
|||||||
max="{{ c.max_count }}"
|
max="{{ c.max_count }}"
|
||||||
id="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}"
|
id="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}"
|
||||||
name="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}"
|
name="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}"
|
||||||
aria-label="{% blocktrans with item=item.name var=var %}Quantity of {{ item }}, {{ var }} to order{% endblocktrans %}">
|
aria-label="{% trans "Quantity" %}">
|
||||||
<button type="button" data-step="1" data-controls="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}">+</button>
|
<button type="button" data-step="1" data-controls="cp_{{ form.pos.pk }}_variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}">+</button>
|
||||||
</div>
|
</fieldset>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -250,7 +253,7 @@
|
|||||||
{% include "pretixpresale/event/fragment_quota_left.html" with avail=item.cached_availability %}
|
{% include "pretixpresale/event/fragment_quota_left.html" with avail=item.cached_availability %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if item.min_per_order and item.min_per_order > 1 %}
|
{% if item.min_per_order and item.min_per_order > 1 %}
|
||||||
<p>
|
<p id="cp-{{ form.pos.pk }}-item-{{ item.pk }}-min-order">
|
||||||
<small>
|
<small>
|
||||||
{% blocktrans trimmed with num=item.min_per_order %}
|
{% blocktrans trimmed with num=item.min_per_order %}
|
||||||
minimum amount to order: {{ num }}
|
minimum amount to order: {{ num }}
|
||||||
@@ -341,12 +344,13 @@
|
|||||||
name="cp_{{ form.pos.pk }}_item_{{ item.id }}"
|
name="cp_{{ form.pos.pk }}_item_{{ item.id }}"
|
||||||
id="cp_{{ form.pos.pk }}_item_{{ item.id }}"
|
id="cp_{{ form.pos.pk }}_item_{{ item.id }}"
|
||||||
aria-label="{% blocktrans with item=item.name %}Add {{ item }} to cart{% endblocktrans %}"
|
aria-label="{% blocktrans with item=item.name %}Add {{ item }} to cart{% endblocktrans %}"
|
||||||
{% if item.description %} aria-describedby="cp-{{ form.pos.pk }}-item-{{ item.id }}-description"{% endif %}>
|
aria-describedby="c-{{ form.pos.pk }}-{{ category_idx }}-addon-count-desc">
|
||||||
<i class="fa fa-shopping-cart" aria-hidden="true"></i>
|
<i class="fa fa-shopping-cart" aria-hidden="true"></i>
|
||||||
{% trans "Select" context "checkbox" %}
|
{% trans "Select" context "checkbox" %}
|
||||||
</label>
|
</label>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="input-item-count-group">
|
<fieldset class="input-item-count-group" aria-describedby="c-{{ form.pos.pk }}-{{ category_idx }}-addon-count-desc cp-{{ form.pos.pk }}-item-{{ item.pk }}-min-order">
|
||||||
|
<legend class="sr-only">{% blocktrans with item=item.name %}Add {{ item }} to cart{% endblocktrans %}</legend>
|
||||||
<button type="button" data-step="-1" data-controls="cp_{{ form.pos.pk }}_item_{{ item.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}">-</button>
|
<button type="button" data-step="-1" data-controls="cp_{{ form.pos.pk }}_item_{{ item.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}">-</button>
|
||||||
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
|
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
|
||||||
{% if item.free_price %}
|
{% if item.free_price %}
|
||||||
@@ -356,10 +360,9 @@
|
|||||||
{% if item.initial %}value="{{ item.initial }}"{% endif %}
|
{% if item.initial %}value="{{ item.initial }}"{% endif %}
|
||||||
name="cp_{{ form.pos.pk }}_item_{{ item.id }}"
|
name="cp_{{ form.pos.pk }}_item_{{ item.id }}"
|
||||||
id="cp_{{ form.pos.pk }}_item_{{ item.id }}"
|
id="cp_{{ form.pos.pk }}_item_{{ item.id }}"
|
||||||
aria-label="{% blocktrans with item=item.name %}Quantity of {{ item }} to order{% endblocktrans %}"
|
aria-label="{% trans "Quantity" %}">
|
||||||
{% if item.description %} aria-describedby="cp-{{ form.pos.pk }}-item-{{ item.id }}-description"{% endif %}>
|
|
||||||
<button type="button" data-step="1" data-controls="cp_{{ form.pos.pk }}_item_{{ item.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}">+</button>
|
<button type="button" data-step="1" data-controls="cp_{{ form.pos.pk }}_item_{{ item.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}">+</button>
|
||||||
</div>
|
</fieldset>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -370,6 +373,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
{% endwith %}
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<em>
|
<em>
|
||||||
{% trans "There are no add-ons available for this product." %}
|
{% trans "There are no add-ons available for this product." %}
|
||||||
|
|||||||
@@ -10,18 +10,41 @@
|
|||||||
<i class="fa fa-shopping-cart" aria-hidden="true"></i>
|
<i class="fa fa-shopping-cart" aria-hidden="true"></i>
|
||||||
<strong>{% trans "Your cart" %}</strong>
|
<strong>{% trans "Your cart" %}</strong>
|
||||||
</span>
|
</span>
|
||||||
<strong id="cart-deadline-short" data-expires="{{ cart.first_expiry|date:"Y-m-d H:i:sO" }}" aria-hidden="true">
|
{% if cart.positions %}
|
||||||
{% if cart.minutes_left > 0 or cart.seconds_left > 0 %}
|
<strong id="cart-deadline-short" data-expires="{{ cart.first_expiry|date:"Y-m-d H:i:sO" }}" aria-hidden="true">
|
||||||
{{ cart.minutes_left|stringformat:"02d" }}:{{ cart.seconds_left|stringformat:"02d" }}
|
{% if cart.minutes_left > 0 or cart.seconds_left > 0 %}
|
||||||
{% else %}
|
{{ cart.minutes_left|stringformat:"02d" }}:{{ cart.seconds_left|stringformat:"02d" }}
|
||||||
{% trans "Cart expired" %}
|
{% else %}
|
||||||
{% endif %}
|
{% trans "Cart expired" %}
|
||||||
</strong>
|
{% endif %}
|
||||||
|
</strong>
|
||||||
|
{% endif %}
|
||||||
</h2>
|
</h2>
|
||||||
</summary>
|
</summary>
|
||||||
<div>
|
<div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
{% include "pretixpresale/event/fragment_cart.html" with cart=cart event=request.event editable=True %}
|
{% if cart.positions %}
|
||||||
|
{% include "pretixpresale/event/fragment_cart.html" with cart=cart event=request.event editable=True %}
|
||||||
|
{% endif %}
|
||||||
|
{% if cart.current_selected_payments %}
|
||||||
|
<p>{% trans "You already selected the following payment methods:" %}</p>
|
||||||
|
<div class="list-group">
|
||||||
|
{% for p in cart.current_selected_payments %}
|
||||||
|
<div class="list-group-item">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-9">
|
||||||
|
{{ p.provider_name }}
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-3 text-right">
|
||||||
|
{% if p.payment_amount %}
|
||||||
|
{{ p.payment_amount|money:request.event.currency }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="checkout-button-row">
|
<div class="checkout-button-row">
|
||||||
<form class="checkout-button-primary" method="get" action="{% eventurl request.event "presale:event.checkout.start" cart_namespace=cart_namespace %}">
|
<form class="checkout-button-primary" method="get" action="{% eventurl request.event "presale:event.checkout.start" cart_namespace=cart_namespace %}">
|
||||||
<p><button class="btn btn-primary btn-lg" type="submit"{% if has_addon_choices or cart.total == 0 %} aria-label="{% trans "Continue with order process" %}"{% endif %}>
|
<p><button class="btn btn-primary btn-lg" type="submit"{% if has_addon_choices or cart.total == 0 %} aria-label="{% trans "Continue with order process" %}"{% endif %}>
|
||||||
|
|||||||
@@ -219,7 +219,8 @@
|
|||||||
{% trans "Select" context "checkbox" %}
|
{% trans "Select" context "checkbox" %}
|
||||||
</label>
|
</label>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="input-item-count-group">
|
<fieldset class="input-item-count-group">
|
||||||
|
<legend class="sr-only">{% blocktrans with item=item.name %}Add {{ item }}, {{ var }} to cart{% endblocktrans %}</legend>
|
||||||
<button type="button" data-step="-1" data-controls="{{ form_prefix }}variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}"
|
<button type="button" data-step="-1" data-controls="{{ form_prefix }}variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}"
|
||||||
{% if not ev.presale_is_running %}disabled{% endif %}>-</button>
|
{% if not ev.presale_is_running %}disabled{% endif %}>-</button>
|
||||||
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
|
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
|
||||||
@@ -230,10 +231,10 @@
|
|||||||
max="{{ var.order_max }}"
|
max="{{ var.order_max }}"
|
||||||
id="{{ form_prefix }}variation_{{ item.id }}_{{ var.id }}"
|
id="{{ form_prefix }}variation_{{ item.id }}_{{ var.id }}"
|
||||||
name="{{ form_prefix }}variation_{{ item.id }}_{{ var.id }}"
|
name="{{ form_prefix }}variation_{{ item.id }}_{{ var.id }}"
|
||||||
aria-label="{% blocktrans with item=item.name var=var.name %}Quantity of {{ item }}, {{ var }} to order{% endblocktrans %}">
|
aria-label="{% trans "Quantity" %}">
|
||||||
<button type="button" data-step="1" data-controls="{{ form_prefix }}variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}"
|
<button type="button" data-step="1" data-controls="{{ form_prefix }}variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}"
|
||||||
{% if not ev.presale_is_running %}disabled{% endif %}>+</button>
|
{% if not ev.presale_is_running %}disabled{% endif %}>+</button>
|
||||||
</div>
|
</fieldset>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -370,7 +371,8 @@
|
|||||||
{% trans "Select" context "checkbox" %}
|
{% trans "Select" context "checkbox" %}
|
||||||
</label>
|
</label>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="input-item-count-group">
|
<fieldset class="input-item-count-group">
|
||||||
|
<legend class="sr-only">{% blocktrans with item=item.name %}Add {{ item }} to cart{% endblocktrans %}</legend>
|
||||||
<button type="button" data-step="-1" data-controls="{{ form_prefix }}item_{{ item.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}"
|
<button type="button" data-step="-1" data-controls="{{ form_prefix }}item_{{ item.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}"
|
||||||
{% if not ev.presale_is_running %}disabled{% endif %}>-</button>
|
{% if not ev.presale_is_running %}disabled{% endif %}>-</button>
|
||||||
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
|
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
|
||||||
@@ -382,11 +384,10 @@
|
|||||||
max="{{ item.order_max }}"
|
max="{{ item.order_max }}"
|
||||||
name="{{ form_prefix }}item_{{ item.id }}"
|
name="{{ form_prefix }}item_{{ item.id }}"
|
||||||
id="{{ form_prefix }}item_{{ item.id }}"
|
id="{{ form_prefix }}item_{{ item.id }}"
|
||||||
aria-label="{% blocktrans with item=item.name %}Quantity of {{ item }} to order{% endblocktrans %}"
|
aria-label="{% trans "Quantity" %}">
|
||||||
{% if item.description %} aria-describedby="{{ form_prefix }}item-{{ item.id }}-description"{% endif %}>
|
|
||||||
<button type="button" data-step="1" data-controls="{{ form_prefix }}item_{{ item.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}"
|
<button type="button" data-step="1" data-controls="{{ form_prefix }}item_{{ item.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}"
|
||||||
{% if not ev.presale_is_running %}disabled{% endif %}>+</button>
|
{% if not ev.presale_is_running %}disabled{% endif %}>+</button>
|
||||||
</div>
|
</fieldset>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@@ -231,16 +231,17 @@
|
|||||||
{% trans "Select" context "checkbox" %}
|
{% trans "Select" context "checkbox" %}
|
||||||
</label>
|
</label>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="input-item-count-group">
|
<fieldset class="input-item-count-group">
|
||||||
|
<legend class="sr-only">{% blocktrans with item=item.name %}Add {{ item }}, {{ var }} to cart{% endblocktrans %}</legend>
|
||||||
<button type="button" data-step="-1" data-controls="variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}">-</button>
|
<button type="button" data-step="-1" data-controls="variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}">-</button>
|
||||||
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
|
<input type="number" class="form-control input-item-count" placeholder="0" min="0"
|
||||||
max="{{ var.order_max }}"
|
max="{{ var.order_max }}"
|
||||||
id="variation_{{ item.id }}_{{ var.id }}"
|
id="variation_{{ item.id }}_{{ var.id }}"
|
||||||
name="variation_{{ item.id }}_{{ var.id }}"
|
name="variation_{{ item.id }}_{{ var.id }}"
|
||||||
{% if options == 1 %}value="1"{% endif %}
|
{% if options == 1 %}value="1"{% endif %}
|
||||||
aria-label="{% blocktrans with item=item.name var=var.name %}Quantity of {{ item }}, {{ var }} to order{% endblocktrans %}">
|
aria-label="{% trans "Quantity" %}">
|
||||||
<button type="button" data-step="1" data-controls="variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}">+</button>
|
<button type="button" data-step="1" data-controls="variation_{{ item.id }}_{{ var.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}">+</button>
|
||||||
</div>
|
</fieldset>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<label>
|
<label>
|
||||||
@@ -385,7 +386,8 @@
|
|||||||
{% trans "Select" context "checkbox" %}
|
{% trans "Select" context "checkbox" %}
|
||||||
</label>
|
</label>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="input-item-count-group">
|
<fieldset class="input-item-count-group">
|
||||||
|
<legend class="sr-only">{% blocktrans with item=item.name %}Add {{ item }} to cart{% endblocktrans %}</legend>
|
||||||
<button type="button" data-step="-1" data-controls="item_{{ item.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}">-</button>
|
<button type="button" data-step="-1" data-controls="item_{{ item.id }}" class="btn btn-default input-item-count-dec" aria-label="{% trans "Decrease quantity" %}">-</button>
|
||||||
<input type="number" class="form-control input-item-count"
|
<input type="number" class="form-control input-item-count"
|
||||||
placeholder="0" min="0"
|
placeholder="0" min="0"
|
||||||
@@ -393,10 +395,9 @@
|
|||||||
id="item_{{ item.id }}"
|
id="item_{{ item.id }}"
|
||||||
name="item_{{ item.id }}"
|
name="item_{{ item.id }}"
|
||||||
{% if options == 1 %}value="1"{% endif %}
|
{% if options == 1 %}value="1"{% endif %}
|
||||||
aria-label="{% blocktrans with item=item.name %}Quantity of {{ item }} to order{% endblocktrans %}"
|
aria-label="{% trans "Quantity" %}">
|
||||||
{% if item.description %} aria-describedby="item-{{ item.id }}-description"{% endif %}>
|
|
||||||
<button type="button" data-step="1" data-controls="item_{{ item.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}">+</button>
|
<button type="button" data-step="1" data-controls="item_{{ item.id }}" class="btn btn-default input-item-count-inc" aria-label="{% trans "Increase quantity" %}">+</button>
|
||||||
</div>
|
</fieldset>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<label>
|
<label>
|
||||||
|
|||||||
@@ -251,7 +251,8 @@ class CartMixin:
|
|||||||
'seconds_left': seconds_left,
|
'seconds_left': seconds_left,
|
||||||
'first_expiry': first_expiry,
|
'first_expiry': first_expiry,
|
||||||
'is_ordered': bool(order),
|
'is_ordered': bool(order),
|
||||||
'itemcount': sum(c.count for c in positions if not c.addon_to)
|
'itemcount': sum(c.count for c in positions if not c.addon_to),
|
||||||
|
'current_selected_payments': [p for p in self.current_selected_payments(total) if p.get('multi_use_supported')]
|
||||||
}
|
}
|
||||||
|
|
||||||
def current_selected_payments(self, total, warn=False, total_includes_payment_fees=False):
|
def current_selected_payments(self, total, warn=False, total_includes_payment_fees=False):
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ from urllib.parse import quote
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.core.cache import caches
|
from django.core.cache import caches
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http import FileResponse, Http404, JsonResponse
|
from django.http import FileResponse, Http404, JsonResponse
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
@@ -57,7 +58,7 @@ from django.views.generic import TemplateView, View
|
|||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
CartPosition, InvoiceAddress, QuestionAnswer, SubEvent, Voucher,
|
CartPosition, GiftCard, InvoiceAddress, QuestionAnswer, SubEvent, Voucher,
|
||||||
)
|
)
|
||||||
from pretix.base.services.cart import (
|
from pretix.base.services.cart import (
|
||||||
CartError, add_items_to_cart, apply_voucher, clear_cart, error_messages,
|
CartError, add_items_to_cart, apply_voucher, clear_cart, error_messages,
|
||||||
@@ -438,8 +439,48 @@ class CartApplyVoucher(EventViewMixin, CartActionMixin, AsyncAction, View):
|
|||||||
return _('We applied the voucher to as many products in your cart as we could.')
|
return _('We applied the voucher to as many products in your cart as we could.')
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
|
from pretix.base.payment import GiftCardPayment
|
||||||
|
|
||||||
if 'voucher' in request.POST:
|
if 'voucher' in request.POST:
|
||||||
return self.do(self.request.event.id, request.POST.get('voucher'), get_or_create_cart_id(self.request),
|
code = request.POST.get('voucher').strip()
|
||||||
|
|
||||||
|
if not self.request.event.vouchers.filter(code__iexact=code):
|
||||||
|
try:
|
||||||
|
gc = self.request.event.organizer.accepted_gift_cards.get(secret=code)
|
||||||
|
gcp = GiftCardPayment(self.request.event)
|
||||||
|
if not gcp.is_enabled or not gcp.is_allowed(self.request, Decimal("1.00")):
|
||||||
|
raise ValidationError(error_messages['voucher_invalid'])
|
||||||
|
else:
|
||||||
|
cs = cart_session(request)
|
||||||
|
gcp._add_giftcard_to_cart(cs, gc)
|
||||||
|
messages.success(
|
||||||
|
request,
|
||||||
|
_("The gift card has been saved to your cart. Please continue your checkout.")
|
||||||
|
)
|
||||||
|
if "ajax" in self.request.POST or "ajax" in self.request.GET:
|
||||||
|
return JsonResponse({
|
||||||
|
'ready': True,
|
||||||
|
'success': True,
|
||||||
|
'redirect': self.get_success_url(),
|
||||||
|
'message': str(
|
||||||
|
_("The gift card has been saved to your cart. Please continue your checkout.")
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return redirect_to_url(self.get_success_url())
|
||||||
|
except GiftCard.DoesNotExist:
|
||||||
|
pass
|
||||||
|
except ValidationError as e:
|
||||||
|
messages.error(self.request, str(e.message))
|
||||||
|
if "ajax" in self.request.POST or "ajax" in self.request.GET:
|
||||||
|
return JsonResponse({
|
||||||
|
'ready': True,
|
||||||
|
'success': False,
|
||||||
|
'redirect': self.get_success_url(),
|
||||||
|
'message': str(e.message)
|
||||||
|
})
|
||||||
|
return redirect_to_url(self.get_error_url())
|
||||||
|
|
||||||
|
return self.do(self.request.event.id, code, get_or_create_cart_id(self.request),
|
||||||
translation.get_language(), request.sales_channel.identifier,
|
translation.get_language(), request.sales_channel.identifier,
|
||||||
time_machine_now(default=None))
|
time_machine_now(default=None))
|
||||||
else:
|
else:
|
||||||
@@ -631,6 +672,8 @@ class RedeemView(NoSearchIndexViewMixin, EventViewMixin, CartMixin, TemplateView
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
def dispatch(self, request, *args, **kwargs):
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
from pretix.base.payment import GiftCardPayment
|
||||||
|
|
||||||
err = None
|
err = None
|
||||||
v = request.GET.get('voucher')
|
v = request.GET.get('voucher')
|
||||||
|
|
||||||
@@ -653,10 +696,24 @@ class RedeemView(NoSearchIndexViewMixin, EventViewMixin, CartMixin, TemplateView
|
|||||||
if v_avail < 1 and not err:
|
if v_avail < 1 and not err:
|
||||||
err = error_messages['voucher_redeemed_cart'] % self.request.event.settings.reservation_time
|
err = error_messages['voucher_redeemed_cart'] % self.request.event.settings.reservation_time
|
||||||
except Voucher.DoesNotExist:
|
except Voucher.DoesNotExist:
|
||||||
if self.request.event.organizer.accepted_gift_cards.filter(secret__iexact=request.GET.get("voucher")).exists():
|
try:
|
||||||
err = error_messages['gift_card']
|
gc = self.request.event.organizer.accepted_gift_cards.get(secret=v.strip())
|
||||||
else:
|
gcp = GiftCardPayment(self.request.event)
|
||||||
|
if not gcp.is_enabled or not gcp.is_allowed(self.request, Decimal("1.00")):
|
||||||
|
err = error_messages['voucher_invalid']
|
||||||
|
else:
|
||||||
|
cs = cart_session(request)
|
||||||
|
gcp._add_giftcard_to_cart(cs, gc)
|
||||||
|
messages.success(
|
||||||
|
request,
|
||||||
|
_("The gift card has been saved to your cart. Please now select the products "
|
||||||
|
"you want to purchase.")
|
||||||
|
)
|
||||||
|
return redirect_to_url(self.get_next_url())
|
||||||
|
except GiftCard.DoesNotExist:
|
||||||
err = error_messages['voucher_invalid']
|
err = error_messages['voucher_invalid']
|
||||||
|
except ValidationError as e:
|
||||||
|
err = str(e.message)
|
||||||
else:
|
else:
|
||||||
context = {}
|
context = {}
|
||||||
context['cart'] = self.get_cart()
|
context['cart'] = self.get_cart()
|
||||||
|
|||||||
@@ -632,7 +632,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
context['subevent_list_cache_key'] = self._subevent_list_cachekey()
|
context['subevent_list_cache_key'] = self._subevent_list_cachekey()
|
||||||
|
|
||||||
context['show_cart'] = (
|
context['show_cart'] = (
|
||||||
context['cart']['positions'] and (
|
(context['cart']['positions'] or context['cart'].get('current_selected_payments')) and (
|
||||||
self.request.event.has_subevents or self.request.event.presale_is_running
|
self.request.event.has_subevents or self.request.event.presale_is_running
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ input[type="checkbox"] {
|
|||||||
// Note: Neither radios nor checkboxes can be readonly.
|
// Note: Neither radios nor checkboxes can be readonly.
|
||||||
&[disabled],
|
&[disabled],
|
||||||
&.disabled,
|
&.disabled,
|
||||||
fieldset[disabled] &:not(fieldset[disabled] > legend &) {
|
fieldset[disabled] & {
|
||||||
cursor: $cursor-disabled;
|
cursor: $cursor-disabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,9 +558,6 @@ table td > .checkbox input[type="checkbox"] {
|
|||||||
fieldset.accordion-panel > legend {
|
fieldset.accordion-panel > legend {
|
||||||
display: contents;
|
display: contents;
|
||||||
}
|
}
|
||||||
fieldset.accordion-panel[disabled] > .panel-body {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.maildesignpreview {
|
.maildesignpreview {
|
||||||
label {
|
label {
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -244,9 +244,9 @@ function setup_basics(el) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
$("fieldset.accordion-panel > legend input[type=radio]").change(function() {
|
$("fieldset.accordion-panel > legend input[type=radio]").change(function() {
|
||||||
$(this).closest("fieldset").siblings("fieldset").prop('disabled', true);
|
$(this).closest("fieldset").siblings("fieldset").prop('disabled', true).children('.panel-body').slideUp();
|
||||||
$(this).closest("fieldset").prop('disabled', false);
|
$(this).closest("fieldset").prop('disabled', false).children('.panel-body').slideDown();
|
||||||
}).each(function() { $(this).closest("fieldset").prop('disabled', true); }).filter(":checked").trigger('change');
|
}).filter(':not(:checked)').each(function() { $(this).closest("fieldset").prop('disabled', true).children('.panel-body').hide(); });
|
||||||
|
|
||||||
el.find(".js-only").removeClass("js-only");
|
el.find(".js-only").removeClass("js-only");
|
||||||
el.find(".js-hidden").hide();
|
el.find(".js-hidden").hide();
|
||||||
|
|||||||
@@ -136,6 +136,10 @@ article.item-with-variations .product-row:last-child:after {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.panel-body:not(:has(*)) {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.panel-body > *:last-child,
|
.panel-body > *:last-child,
|
||||||
.panel-body address:last-child {
|
.panel-body address:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
|||||||
@@ -135,9 +135,13 @@ a.btn, button.btn {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
.panel-default>.accordion-radio>.panel-heading, fieldset.accordion-panel>legend>.panel-heading {
|
.panel-default>.accordion-radio>.panel-heading, fieldset.accordion-panel>legend>.panel-heading {
|
||||||
|
display: block;
|
||||||
color: #333;
|
color: #333;
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
padding: 8px 15px;
|
padding: 8px 15px;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.428571429;
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
input[type=radio] {
|
input[type=radio] {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
@@ -150,8 +154,9 @@ a.btn, button.btn {
|
|||||||
fieldset.accordion-panel > legend {
|
fieldset.accordion-panel > legend {
|
||||||
display: contents;
|
display: contents;
|
||||||
}
|
}
|
||||||
fieldset.accordion-panel[disabled] > .panel-body {
|
fieldset[disabled] legend input[type="radio"],
|
||||||
display: none;
|
fieldset[disabled] legend input[type="checkbox"] {
|
||||||
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-tabs {
|
.nav-tabs {
|
||||||
|
|||||||
@@ -335,6 +335,11 @@ body.loading .container {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.font-normal {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
.blank-after {
|
.blank-after {
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ def test_urlreplace_replace_parameter():
|
|||||||
|
|
||||||
# rounding errors
|
# rounding errors
|
||||||
("de", Decimal("1.234"), "EUR", "1,23" + NBSP + "€"),
|
("de", Decimal("1.234"), "EUR", "1,23" + NBSP + "€"),
|
||||||
("de", Decimal("1023.1"), "JPY", "JPY 1023,10"),
|
("de", Decimal("1023.1"), "JPY", "JPY 1.023,10"),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
def test_money_filter(locale, amount, currency, expected):
|
def test_money_filter(locale, amount, currency, expected):
|
||||||
@@ -99,9 +99,9 @@ def test_money_filter(locale, amount, currency, expected):
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"locale,amount,currency,expected",
|
"locale,amount,currency,expected",
|
||||||
[
|
[
|
||||||
("de", Decimal("1000.00"), "EUR", "1000,00"),
|
("de", Decimal("1000.00"), "EUR", "1.000,00"),
|
||||||
("en", Decimal("1000.00"), "EUR", "1000.00"),
|
("en", Decimal("1000.00"), "EUR", "1,000.00"),
|
||||||
("de", Decimal("1023.1"), "JPY", "1023,10"),
|
("de", Decimal("1023.1"), "JPY", "1.023,10"),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
def test_money_filter_hidecurrency(locale, amount, currency, expected):
|
def test_money_filter_hidecurrency(locale, amount, currency, expected):
|
||||||
|
|||||||
@@ -2306,6 +2306,25 @@ class CartTest(CartTestMixin, TestCase):
|
|||||||
assert cp1.voucher is None
|
assert cp1.voucher is None
|
||||||
assert cp2.voucher is None
|
assert cp2.voucher is None
|
||||||
|
|
||||||
|
def test_voucher_apply_is_a_giftcard(self):
|
||||||
|
with scopes_disabled():
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, cart_id=self.session_key, item=self.ticket,
|
||||||
|
price=23, listed_price=23, price_after_voucher=23, expires=now() + timedelta(minutes=10)
|
||||||
|
)
|
||||||
|
CartPosition.objects.create(
|
||||||
|
event=self.event, cart_id=self.session_key, item=self.shirt, variation=self.shirt_blue,
|
||||||
|
price=8, expires=now() + timedelta(minutes=10),
|
||||||
|
)
|
||||||
|
gc = self.orga.issued_gift_cards.create(secret="GIFTCARD", currency=self.event.currency)
|
||||||
|
gc.transactions.create(value=Decimal("12.24"), acceptor=self.orga)
|
||||||
|
|
||||||
|
html = self.client.post('/%s/%s/cart/voucher' % (self.orga.slug, self.event.slug), {
|
||||||
|
'voucher': 'GIFTCARD',
|
||||||
|
}, follow=True)
|
||||||
|
assert "alert-success" in html.rendered_content
|
||||||
|
assert "€12.24" in html.rendered_content
|
||||||
|
|
||||||
def test_discount(self):
|
def test_discount(self):
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
Discount.objects.create(event=self.event, condition_min_count=2, benefit_discount_matching_percent=20,
|
Discount.objects.create(event=self.event, condition_min_count=2, benefit_discount_matching_percent=20,
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ from pretix.base.models import (
|
|||||||
)
|
)
|
||||||
from pretix.base.models.items import SubEventItem, SubEventItemVariation
|
from pretix.base.models.items import SubEventItem, SubEventItemVariation
|
||||||
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
from pretix.base.reldate import RelativeDate, RelativeDateWrapper
|
||||||
|
from pretix.testutils.sessions import get_cart_session_key
|
||||||
|
|
||||||
|
|
||||||
class EventTestMixin:
|
class EventTestMixin:
|
||||||
@@ -1003,6 +1004,25 @@ class VoucherRedeemItemDisplayTest(EventTestMixin, SoupTest):
|
|||||||
assert 'name="variation_%d_%d' % (self.item.pk, var1.pk) not in html.rendered_content
|
assert 'name="variation_%d_%d' % (self.item.pk, var1.pk) not in html.rendered_content
|
||||||
assert 'name="variation_%d_%d' % (self.item.pk, var2.pk) not in html.rendered_content
|
assert 'name="variation_%d_%d' % (self.item.pk, var2.pk) not in html.rendered_content
|
||||||
|
|
||||||
|
def test_voucher_is_a_gift_card(self):
|
||||||
|
gc = self.orga.issued_gift_cards.create(secret="GIFTCARD", currency=self.event.currency)
|
||||||
|
gc.transactions.create(value=Decimal("12.00"), acceptor=self.orga)
|
||||||
|
|
||||||
|
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, 'GIFTCARD'), follow=True)
|
||||||
|
assert "alert-success" in html.rendered_content
|
||||||
|
assert "€12.00" in html.rendered_content
|
||||||
|
|
||||||
|
payments = self.client.session['carts'][get_cart_session_key(self.client, self.event)]["payments"]
|
||||||
|
assert payments[0]["info_data"]["gift_card_secret"] == "GIFTCARD"
|
||||||
|
|
||||||
|
def test_voucher_is_a_gift_card_but_invalid(self):
|
||||||
|
gc = self.orga.issued_gift_cards.create(secret="GIFTCARD", currency=self.event.currency, expires=now() - datetime.timedelta(days=1))
|
||||||
|
gc.transactions.create(value=Decimal("12.00"), acceptor=self.orga)
|
||||||
|
|
||||||
|
html = self.client.get('/%s/%s/redeem?voucher=%s' % (self.orga.slug, self.event.slug, 'GIFTCARD'), follow=True)
|
||||||
|
assert "alert-danger" in html.rendered_content
|
||||||
|
assert "This gift card is no longer valid" in html.rendered_content
|
||||||
|
|
||||||
|
|
||||||
class WaitingListTest(EventTestMixin, SoupTest):
|
class WaitingListTest(EventTestMixin, SoupTest):
|
||||||
@scopes_disabled()
|
@scopes_disabled()
|
||||||
|
|||||||
Reference in New Issue
Block a user