mirror of
https://github.com/pretix/pretix.git
synced 2026-03-10 13:42:27 +00:00
Compare commits
15 Commits
dnspython2
...
widget-sea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b62737d4c | ||
|
|
d3698b3e2f | ||
|
|
ff828ecc92 | ||
|
|
d0236572f0 | ||
|
|
8ea6f3bc7d | ||
|
|
5587aebcd8 | ||
|
|
0b708067de | ||
|
|
e75dc74661 | ||
|
|
f0c5e54e34 | ||
|
|
eeb6e11934 | ||
|
|
1238165e7a | ||
|
|
bcf65603e4 | ||
|
|
c4aed04a18 | ||
|
|
8be09ee937 | ||
|
|
a1ec45daf6 |
@@ -87,6 +87,18 @@ website. If you confident to have a good reason for not using SSL, you can overr
|
|||||||
|
|
||||||
<pretix-widget event="https://pretix.eu/demo/democon/" skip-ssl-check></pretix-widget>
|
<pretix-widget event="https://pretix.eu/demo/democon/" skip-ssl-check></pretix-widget>
|
||||||
|
|
||||||
|
Seating plans
|
||||||
|
-------------
|
||||||
|
|
||||||
|
By default, events with seating plans just show a button that opens the seating plan. You can also have the seating
|
||||||
|
plan embedded into the widget directly by using::
|
||||||
|
|
||||||
|
<pretix-widget event="https://pretix.eu/demo/democon/" seating-embedded></pretix-widget>
|
||||||
|
|
||||||
|
Note that the seating plan will only be embedded if the widget has enough space (currently min. 992 pixels width, may change
|
||||||
|
in the future) and that the seating plan part of the widget can unfortunately *not* be styled with CSS like the rest of
|
||||||
|
the widget.
|
||||||
|
|
||||||
Always open a new tab
|
Always open a new tab
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
|
|||||||
@@ -59,10 +59,10 @@ class RelativeDateWrapper:
|
|||||||
def date(self, event) -> datetime.date:
|
def date(self, event) -> datetime.date:
|
||||||
from .models import SubEvent
|
from .models import SubEvent
|
||||||
|
|
||||||
if isinstance(self.data, datetime.date):
|
if isinstance(self.data, datetime.datetime):
|
||||||
return self.data
|
|
||||||
elif isinstance(self.data, datetime.datetime):
|
|
||||||
return self.data.date()
|
return self.data.date()
|
||||||
|
elif isinstance(self.data, datetime.date):
|
||||||
|
return self.data
|
||||||
else:
|
else:
|
||||||
if self.data.minutes_before is not None:
|
if self.data.minutes_before is not None:
|
||||||
raise ValueError('A minute-based relative datetime can not be used as a date')
|
raise ValueError('A minute-based relative datetime can not be used as a date')
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ error_messages = {
|
|||||||
'addon_min_count': _('You need to select at least %(min)s add-ons from the category %(cat)s for the '
|
'addon_min_count': _('You need to select at least %(min)s add-ons from the category %(cat)s for the '
|
||||||
'product %(base)s.'),
|
'product %(base)s.'),
|
||||||
'addon_no_multi': _('You can select every add-ons from the category %(cat)s for the product %(base)s at most once.'),
|
'addon_no_multi': _('You can select every add-ons from the category %(cat)s for the product %(base)s at most once.'),
|
||||||
'addon_only': _('One of the products you selected can only be bought as an add-on to another project.'),
|
'addon_only': _('One of the products you selected can only be bought as an add-on to another product.'),
|
||||||
'bundled_only': _('One of the products you selected can only be bought part of a bundle.'),
|
'bundled_only': _('One of the products you selected can only be bought part of a bundle.'),
|
||||||
'seat_required': _('You need to select a specific seat.'),
|
'seat_required': _('You need to select a specific seat.'),
|
||||||
'seat_invalid': _('Please select a valid seat.'),
|
'seat_invalid': _('Please select a valid seat.'),
|
||||||
|
|||||||
@@ -353,6 +353,12 @@ class Recover(TemplateView):
|
|||||||
user.save()
|
user.save()
|
||||||
messages.success(request, _('You can now login using your new password.'))
|
messages.success(request, _('You can now login using your new password.'))
|
||||||
user.log_action('pretix.control.auth.user.forgot_password.recovered')
|
user.log_action('pretix.control.auth.user.forgot_password.recovered')
|
||||||
|
|
||||||
|
has_redis = settings.HAS_REDIS
|
||||||
|
if has_redis:
|
||||||
|
from django_redis import get_redis_connection
|
||||||
|
rc = get_redis_connection("redis")
|
||||||
|
rc.delete('pretix_pwreset_%s' % user.id)
|
||||||
return redirect('control:auth.login')
|
return redirect('control:auth.login')
|
||||||
else:
|
else:
|
||||||
return self.get(request, *args, **kwargs)
|
return self.get(request, *args, **kwargs)
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ 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: 2022-12-14 13:09+0000\n"
|
"POT-Creation-Date: 2022-12-14 13:09+0000\n"
|
||||||
"PO-Revision-Date: 2021-09-27 06:00+0000\n"
|
"PO-Revision-Date: 2022-12-21 20:00+0000\n"
|
||||||
"Last-Translator: Diego Rodrigo <diegorodrigo90@gmail.com>\n"
|
"Last-Translator: Fazenda Dengo <fazendadengo@gmail.com>\n"
|
||||||
"Language-Team: Portuguese (Brazil) <https://translate.pretix.eu/projects/"
|
"Language-Team: Portuguese (Brazil) <https://translate.pretix.eu/projects/"
|
||||||
"pretix/pretix/pt_BR/>\n"
|
"pretix/pretix/pt_BR/>\n"
|
||||||
"Language: pt_BR\n"
|
"Language: pt_BR\n"
|
||||||
@@ -17,7 +17,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 4.8\n"
|
"X-Generator: Weblate 4.15\n"
|
||||||
|
|
||||||
#: pretix/api/auth/devicesecurity.py:28
|
#: pretix/api/auth/devicesecurity.py:28
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -9268,10 +9268,8 @@ msgstr "Nome do evento"
|
|||||||
#: pretix/base/settings.py:3031 pretix/base/settings.py:3045
|
#: pretix/base/settings.py:3031 pretix/base/settings.py:3045
|
||||||
#: pretix/base/settings.py:3096 pretix/base/settings.py:3114
|
#: pretix/base/settings.py:3096 pretix/base/settings.py:3114
|
||||||
#: pretix/base/settings.py:3133
|
#: pretix/base/settings.py:3133
|
||||||
#, fuzzy
|
|
||||||
#| msgid "Full name"
|
|
||||||
msgid "Family name"
|
msgid "Family name"
|
||||||
msgstr "Nome completo"
|
msgstr "Sobrenome"
|
||||||
|
|
||||||
#: pretix/base/settings.py:2943 pretix/base/settings.py:2959
|
#: pretix/base/settings.py:2943 pretix/base/settings.py:2959
|
||||||
#: pretix/base/settings.py:2975 pretix/base/settings.py:2990
|
#: pretix/base/settings.py:2975 pretix/base/settings.py:2990
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ 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: 2022-12-14 13:09+0000\n"
|
"POT-Creation-Date: 2022-12-14 13:09+0000\n"
|
||||||
"PO-Revision-Date: 2022-11-28 19:03+0000\n"
|
"PO-Revision-Date: 2022-12-21 20:00+0000\n"
|
||||||
"Last-Translator: Vasco Baleia <vb2003.12@gmail.com>\n"
|
"Last-Translator: Fazenda Dengo <fazendadengo@gmail.com>\n"
|
||||||
"Language-Team: Portuguese (Portugal) <https://translate.pretix.eu/projects/"
|
"Language-Team: Portuguese (Portugal) <https://translate.pretix.eu/projects/"
|
||||||
"pretix/pretix/pt_PT/>\n"
|
"pretix/pretix/pt_PT/>\n"
|
||||||
"Language: pt_PT\n"
|
"Language: pt_PT\n"
|
||||||
@@ -17,7 +17,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 4.14.1\n"
|
"X-Generator: Weblate 4.15\n"
|
||||||
|
|
||||||
#: pretix/api/auth/devicesecurity.py:28
|
#: pretix/api/auth/devicesecurity.py:28
|
||||||
msgid ""
|
msgid ""
|
||||||
@@ -9560,7 +9560,7 @@ msgstr "Nome próprio"
|
|||||||
#: pretix/base/settings.py:3096 pretix/base/settings.py:3114
|
#: pretix/base/settings.py:3096 pretix/base/settings.py:3114
|
||||||
#: pretix/base/settings.py:3133
|
#: pretix/base/settings.py:3133
|
||||||
msgid "Family name"
|
msgid "Family name"
|
||||||
msgstr "Apelido"
|
msgstr "Sobrenome"
|
||||||
|
|
||||||
#: pretix/base/settings.py:2943 pretix/base/settings.py:2959
|
#: pretix/base/settings.py:2943 pretix/base/settings.py:2959
|
||||||
#: pretix/base/settings.py:2975 pretix/base/settings.py:2990
|
#: pretix/base/settings.py:2975 pretix/base/settings.py:2990
|
||||||
|
|||||||
@@ -698,7 +698,7 @@ class PaypalMethod(BasePaymentProvider):
|
|||||||
except ReferencedPayPalObject.MultipleObjectsReturned:
|
except ReferencedPayPalObject.MultipleObjectsReturned:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if capture.status == 'PENDING':
|
if capture.status != 'COMPLETED':
|
||||||
messages.warning(request, _('PayPal has not yet approved the payment. We will inform you as '
|
messages.warning(request, _('PayPal has not yet approved the payment. We will inform you as '
|
||||||
'soon as the payment completed.'))
|
'soon as the payment completed.'))
|
||||||
payment.info = json.dumps(pp_captured_order.dict())
|
payment.info = json.dumps(pp_captured_order.dict())
|
||||||
|
|||||||
@@ -73,12 +73,21 @@ var pretixpaypal = {
|
|||||||
pretixpaypal.locale = this.guessLocale();
|
pretixpaypal.locale = this.guessLocale();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no payment option is selected, and we're not on the paypage (which doesn't have a continue button),
|
$("input[name=payment][value^='paypal']").change(function () {
|
||||||
// disable the continue button
|
if (pretixpaypal.paypal !== null) {
|
||||||
if (!pretixpaypal.paypage) {
|
pretixpaypal.renderButton($(this).val());
|
||||||
if (!pretixpaypal.continue_button[0].form.elements['payment'].value) {
|
} else {
|
||||||
pretixpaypal.continue_button.prop("disabled", true);
|
pretixpaypal.continue_button.prop("disabled", true);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("input[name=payment]").not("[value^='paypal']").change(function () {
|
||||||
|
pretixpaypal.restore();
|
||||||
|
});
|
||||||
|
|
||||||
|
// If paypal is pre-selected, we must disable the continue button and handle it after SDK is loaded
|
||||||
|
if ($("input[name=payment][value^='paypal']").is(':checked')) {
|
||||||
|
pretixpaypal.continue_button.prop("disabled", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are setting the cogwheel already here, as the renderAPM() method might take some time to get loaded.
|
// We are setting the cogwheel already here, as the renderAPM() method might take some time to get loaded.
|
||||||
@@ -139,14 +148,6 @@ var pretixpaypal = {
|
|||||||
pretixpaypal.renderAPMs();
|
pretixpaypal.renderAPMs();
|
||||||
}
|
}
|
||||||
|
|
||||||
$("input[name=payment][value^='paypal']").change(function () {
|
|
||||||
pretixpaypal.renderButton($(this).val());
|
|
||||||
});
|
|
||||||
|
|
||||||
$("input[name=payment]").not("[value^='paypal']").change(function () {
|
|
||||||
pretixpaypal.restore();
|
|
||||||
});
|
|
||||||
|
|
||||||
if ($("input[name=payment][value^='paypal']").is(':checked')) {
|
if ($("input[name=payment][value^='paypal']").is(':checked')) {
|
||||||
pretixpaypal.renderButton($("input[name=payment][value^='paypal']:checked").val());
|
pretixpaypal.renderButton($("input[name=payment][value^='paypal']:checked").val());
|
||||||
} else if ($(".payment-redo-form").length) {
|
} else if ($(".payment-redo-form").length) {
|
||||||
@@ -162,8 +163,8 @@ var pretixpaypal = {
|
|||||||
$('#paypal-button-container').empty()
|
$('#paypal-button-container').empty()
|
||||||
pretixpaypal.continue_button.text(gettext('Continue'));
|
pretixpaypal.continue_button.text(gettext('Continue'));
|
||||||
pretixpaypal.continue_button.show();
|
pretixpaypal.continue_button.show();
|
||||||
pretixpaypal.continue_button.prop("disabled", false);
|
|
||||||
}
|
}
|
||||||
|
pretixpaypal.continue_button.prop("disabled", false);
|
||||||
},
|
},
|
||||||
|
|
||||||
renderButton: function (method) {
|
renderButton: function (method) {
|
||||||
@@ -321,6 +322,15 @@ var pretixpaypal = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
|
// This script is always loaded if paypal is enabled as a payment method, regardless of
|
||||||
|
// whether it is available (it could e.g. be hidden or limited to certain countries).
|
||||||
|
// We do not want to unnecessarily load the sdk.
|
||||||
|
// If no paypal/paypal_apm payment option is present and we are not on
|
||||||
|
// the (APM) PayView, then we do not need the SDK.
|
||||||
|
if (!$("input[name=payment][value^='paypal']").length && !$('#paypal-button-container').data('paypage')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
pretixpaypal.load();
|
pretixpaypal.load();
|
||||||
|
|
||||||
(async() => {
|
(async() => {
|
||||||
|
|||||||
@@ -426,7 +426,10 @@ def webhook(request, *args, **kwargs):
|
|||||||
if not payment:
|
if not payment:
|
||||||
return HttpResponse('Payment not found', status=200)
|
return HttpResponse('Payment not found', status=200)
|
||||||
|
|
||||||
payment.order.log_action('pretix.plugins.paypal.event', data=event_json)
|
payment.order.log_action('pretix.plugins.paypal.event', data={
|
||||||
|
**event_json,
|
||||||
|
'_order_state': sale.dict(),
|
||||||
|
})
|
||||||
|
|
||||||
if payment.state == OrderPayment.PAYMENT_STATE_CONFIRMED and sale['status'] in ('PARTIALLY_REFUNDED', 'REFUNDED', 'COMPLETED'):
|
if payment.state == OrderPayment.PAYMENT_STATE_CONFIRMED and sale['status'] in ('PARTIALLY_REFUNDED', 'REFUNDED', 'COMPLETED'):
|
||||||
if event_json['resource_type'] == 'refund':
|
if event_json['resource_type'] == 'refund':
|
||||||
@@ -470,10 +473,27 @@ def webhook(request, *args, **kwargs):
|
|||||||
elif payment.state in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED,
|
elif payment.state in (OrderPayment.PAYMENT_STATE_PENDING, OrderPayment.PAYMENT_STATE_CREATED,
|
||||||
OrderPayment.PAYMENT_STATE_CANCELED, OrderPayment.PAYMENT_STATE_FAILED) \
|
OrderPayment.PAYMENT_STATE_CANCELED, OrderPayment.PAYMENT_STATE_FAILED) \
|
||||||
and sale['status'] == 'COMPLETED':
|
and sale['status'] == 'COMPLETED':
|
||||||
try:
|
any_captures = False
|
||||||
payment.confirm()
|
all_captures_completed = True
|
||||||
except Quota.QuotaExceededException:
|
for purchaseunit in sale['purchase_units']:
|
||||||
pass
|
for capture in purchaseunit['payments']['captures']:
|
||||||
|
try:
|
||||||
|
ReferencedPayPalObject.objects.get_or_create(order=payment.order, payment=payment,
|
||||||
|
reference=capture['id'])
|
||||||
|
except ReferencedPayPalObject.MultipleObjectsReturned:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if capture['status'] not in ('COMPLETED', 'REFUNDED', 'PARTIALLY_REFUNDED'):
|
||||||
|
all_captures_completed = False
|
||||||
|
else:
|
||||||
|
any_captures = True
|
||||||
|
if any_captures and all_captures_completed:
|
||||||
|
try:
|
||||||
|
payment.info = json.dumps(sale.dict())
|
||||||
|
payment.save(update_fields=['info'])
|
||||||
|
payment.confirm()
|
||||||
|
except Quota.QuotaExceededException:
|
||||||
|
pass
|
||||||
|
|
||||||
return HttpResponse(status=200)
|
return HttpResponse(status=200)
|
||||||
|
|
||||||
|
|||||||
@@ -663,11 +663,15 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(allow_frame_if_namespaced, 'dispatch')
|
|
||||||
@method_decorator(iframe_entry_view_wrapper, 'dispatch')
|
@method_decorator(iframe_entry_view_wrapper, 'dispatch')
|
||||||
class SeatingPlanView(EventViewMixin, TemplateView):
|
class SeatingPlanView(EventViewMixin, TemplateView):
|
||||||
template_name = "pretixpresale/event/seatingplan.html"
|
template_name = "pretixpresale/event/seatingplan.html"
|
||||||
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
r = super().dispatch(request, *args, **kwargs)
|
||||||
|
r.xframe_options_exempt = True
|
||||||
|
return r
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
from pretix.presale.views.cart import get_or_create_cart_id
|
from pretix.presale.views.cart import get_or_create_cart_id
|
||||||
|
|
||||||
|
|||||||
@@ -243,6 +243,7 @@ class WidgetAPIProductList(EventListMixin, View):
|
|||||||
voucher=self.voucher,
|
voucher=self.voucher,
|
||||||
channel=self.request.sales_channel.identifier,
|
channel=self.request.sales_channel.identifier,
|
||||||
base_qs=qs,
|
base_qs=qs,
|
||||||
|
require_seat=None,
|
||||||
memberships=(
|
memberships=(
|
||||||
self.request.customer.usable_memberships(
|
self.request.customer.usable_memberships(
|
||||||
for_event=self.subevent or self.request.event,
|
for_event=self.subevent or self.request.event,
|
||||||
@@ -252,7 +253,7 @@ class WidgetAPIProductList(EventListMixin, View):
|
|||||||
)
|
)
|
||||||
|
|
||||||
grps = []
|
grps = []
|
||||||
for cat, g in item_group_by_category(items):
|
for cat, g in item_group_by_category([i for i in items if not i.requires_seat]):
|
||||||
grps.append({
|
grps.append({
|
||||||
'id': cat.pk if cat else None,
|
'id': cat.pk if cat else None,
|
||||||
'name': str(cat.name) if cat else None,
|
'name': str(cat.name) if cat else None,
|
||||||
@@ -312,7 +313,7 @@ class WidgetAPIProductList(EventListMixin, View):
|
|||||||
} for item in g
|
} for item in g
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
return grps, display_add_to_cart, len(items)
|
return grps, display_add_to_cart, len(items), items
|
||||||
|
|
||||||
def post_process(self, data):
|
def post_process(self, data):
|
||||||
data['poweredby'] = get_powered_by(self.request, safelink=False)
|
data['poweredby'] = get_powered_by(self.request, safelink=False)
|
||||||
@@ -711,14 +712,30 @@ class WidgetAPIProductList(EventListMixin, View):
|
|||||||
fail = True
|
fail = True
|
||||||
|
|
||||||
if not fail and (ev.presale_is_running or request.event.settings.show_items_outside_presale_period):
|
if not fail and (ev.presale_is_running or request.event.settings.show_items_outside_presale_period):
|
||||||
data['items_by_category'], data['display_add_to_cart'], data['itemnum'] = self._get_items()
|
data['items_by_category'], data['display_add_to_cart'], data['itemnum'], items = self._get_items()
|
||||||
data['display_add_to_cart'] = data['display_add_to_cart'] and ev.presale_is_running
|
data['display_add_to_cart'] = data['display_add_to_cart'] and ev.presale_is_running
|
||||||
else:
|
else:
|
||||||
|
items = []
|
||||||
data['items_by_category'] = []
|
data['items_by_category'] = []
|
||||||
data['display_add_to_cart'] = False
|
data['display_add_to_cart'] = False
|
||||||
data['itemnum'] = 0
|
data['itemnum'] = 0
|
||||||
|
|
||||||
data['has_seating_plan'] = ev.seating_plan is not None
|
data['has_seating_plan'] = ev.seating_plan is not None
|
||||||
|
data['has_seating_plan_waitinglist'] = False
|
||||||
|
if request.event.settings.waiting_list_enabled and ev.presale_is_running:
|
||||||
|
for i in items:
|
||||||
|
if not i.allow_waitinglist or not i.requires_seat:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if i.has_variations:
|
||||||
|
for v in i.available_variations:
|
||||||
|
if v.cached_availability[0] != Quota.AVAILABILITY_OK:
|
||||||
|
data['has_seating_plan_waitinglist'] = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if i.cached_availability[0] != Quota.AVAILABILITY_OK:
|
||||||
|
data['has_seating_plan_waitinglist'] = True
|
||||||
|
break
|
||||||
|
|
||||||
vouchers_exist = self.request.event.get_cache().get('vouchers_exist')
|
vouchers_exist = self.request.event.get_cache().get('vouchers_exist')
|
||||||
if vouchers_exist is None:
|
if vouchers_exist is None:
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ DATABASES = {
|
|||||||
'HOST': config.get('database', 'host', fallback=''),
|
'HOST': config.get('database', 'host', fallback=''),
|
||||||
'PORT': config.get('database', 'port', fallback=''),
|
'PORT': config.get('database', 'port', fallback=''),
|
||||||
'CONN_MAX_AGE': 0 if db_backend == 'sqlite3' else 120,
|
'CONN_MAX_AGE': 0 if db_backend == 'sqlite3' else 120,
|
||||||
|
'CONN_HEALTH_CHECKS': db_backend != 'sqlite3', # Will only be used from Django 4.1 onwards
|
||||||
'OPTIONS': db_options,
|
'OPTIONS': db_options,
|
||||||
'TEST': {
|
'TEST': {
|
||||||
'CHARSET': 'utf8mb4',
|
'CHARSET': 'utf8mb4',
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ var strings = {
|
|||||||
'next_week': django.pgettext('widget', 'Next week'),
|
'next_week': django.pgettext('widget', 'Next week'),
|
||||||
'previous_week': django.pgettext('widget', 'Previous week'),
|
'previous_week': django.pgettext('widget', 'Previous week'),
|
||||||
'show_seating': django.pgettext('widget', 'Open seat selection'),
|
'show_seating': django.pgettext('widget', 'Open seat selection'),
|
||||||
|
'seating_plan_waiting_list': django.pgettext('widget', 'Some or all ticket categories are currently sold out. If you want, you can add yourself to the waiting list. We will then notify if seats are available again.'),
|
||||||
'load_more': django.pgettext('widget', 'Load more'),
|
'load_more': django.pgettext('widget', 'Load more'),
|
||||||
'days': {
|
'days': {
|
||||||
'MO': django.gettext('Mo'),
|
'MO': django.gettext('Mo'),
|
||||||
@@ -140,18 +141,21 @@ var api = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
'_postFormJSON': function (endpoint, form, callback, err_callback) {
|
'_postFormJSON': function (endpoint, form, callback, err_callback) {
|
||||||
var params = [].filter.call(form.elements, function (el) {
|
var params;
|
||||||
return (el.type !== 'checkbox' && el.type !== 'radio') || el.checked;
|
if (Array.isArray(form)) {
|
||||||
})
|
params = form
|
||||||
.filter(function (el) {
|
} else {
|
||||||
return !!el.name && !!el.value;
|
params = [].filter.call(form.elements, function (el) {
|
||||||
})
|
return (el.type !== 'checkbox' && el.type !== 'radio') || el.checked;
|
||||||
.filter(function (el) {
|
}).filter(function (el) {
|
||||||
|
return !!el.name && !!el.value;
|
||||||
|
}).filter(function (el) {
|
||||||
return !el.disabled;
|
return !el.disabled;
|
||||||
})
|
})
|
||||||
.map(function (el) {
|
}
|
||||||
return encodeURIComponent(el.name) + '=' + encodeURIComponent(el.value);
|
params = params.map(function (el) {
|
||||||
}).join('&');
|
return encodeURIComponent(el.name) + '=' + encodeURIComponent(el.value);
|
||||||
|
}).join('&');
|
||||||
|
|
||||||
var xhr = api._getXHR();
|
var xhr = api._getXHR();
|
||||||
xhr.open("POST", endpoint, true);
|
xhr.open("POST", endpoint, true);
|
||||||
@@ -360,6 +364,7 @@ Vue.component('variation', {
|
|||||||
template: ('<div class="pretix-widget-variation">'
|
template: ('<div class="pretix-widget-variation">'
|
||||||
+ '<div class="pretix-widget-item-row">'
|
+ '<div class="pretix-widget-item-row">'
|
||||||
|
|
||||||
|
// Variation description
|
||||||
+ '<div class="pretix-widget-item-info-col">'
|
+ '<div class="pretix-widget-item-info-col">'
|
||||||
+ '<div class="pretix-widget-item-title-and-description">'
|
+ '<div class="pretix-widget-item-title-and-description">'
|
||||||
+ '<strong class="pretix-widget-item-title">{{ variation.value }}</strong>'
|
+ '<strong class="pretix-widget-item-title">{{ variation.value }}</strong>'
|
||||||
@@ -371,12 +376,15 @@ Vue.component('variation', {
|
|||||||
+ '</div>'
|
+ '</div>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Price
|
||||||
+ '<div class="pretix-widget-item-price-col">'
|
+ '<div class="pretix-widget-item-price-col">'
|
||||||
+ '<pricebox :price="variation.price" :free_price="item.free_price" :original_price="orig_price"'
|
+ '<pricebox :price="variation.price" :free_price="item.free_price" :original_price="orig_price"'
|
||||||
+ ' :field_name="\'price_\' + item.id + \'_\' + variation.id" v-if="$root.showPrices">'
|
+ ' :field_name="\'price_\' + item.id + \'_\' + variation.id" v-if="$root.showPrices">'
|
||||||
+ '</pricebox>'
|
+ '</pricebox>'
|
||||||
+ '<span v-if="!$root.showPrices"> </span>'
|
+ '<span v-if="!$root.showPrices"> </span>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Availability
|
||||||
+ '<div class="pretix-widget-item-availability-col">'
|
+ '<div class="pretix-widget-item-availability-col">'
|
||||||
+ '<availbox :item="item" :variation="variation"></availbox>'
|
+ '<availbox :item="item" :variation="variation"></availbox>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
@@ -404,6 +412,7 @@ Vue.component('item', {
|
|||||||
template: ('<div v-bind:class="classObject">'
|
template: ('<div v-bind:class="classObject">'
|
||||||
+ '<div class="pretix-widget-item-row pretix-widget-main-item-row">'
|
+ '<div class="pretix-widget-item-row pretix-widget-main-item-row">'
|
||||||
|
|
||||||
|
// Product description
|
||||||
+ '<div class="pretix-widget-item-info-col">'
|
+ '<div class="pretix-widget-item-info-col">'
|
||||||
+ '<img :src="item.picture" v-if="item.picture" class="pretix-widget-item-picture">'
|
+ '<img :src="item.picture" v-if="item.picture" class="pretix-widget-item-picture">'
|
||||||
+ '<div class="pretix-widget-item-title-and-description">'
|
+ '<div class="pretix-widget-item-title-and-description">'
|
||||||
@@ -423,6 +432,7 @@ Vue.component('item', {
|
|||||||
+ '</div>'
|
+ '</div>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Price
|
||||||
+ '<div class="pretix-widget-item-price-col">'
|
+ '<div class="pretix-widget-item-price-col">'
|
||||||
+ '<pricebox :price="item.price" :free_price="item.free_price" v-if="!item.has_variations && $root.showPrices"'
|
+ '<pricebox :price="item.price" :free_price="item.free_price" v-if="!item.has_variations && $root.showPrices"'
|
||||||
+ ' :field_name="\'price_\' + item.id" :original_price="item.original_price">'
|
+ ' :field_name="\'price_\' + item.id" :original_price="item.original_price">'
|
||||||
@@ -430,6 +440,8 @@ Vue.component('item', {
|
|||||||
+ '<div class="pretix-widget-pricebox" v-if="item.has_variations && $root.showPrices">{{ pricerange }}</div>'
|
+ '<div class="pretix-widget-pricebox" v-if="item.has_variations && $root.showPrices">{{ pricerange }}</div>'
|
||||||
+ '<span v-if="!$root.showPrices"> </span>'
|
+ '<span v-if="!$root.showPrices"> </span>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Availability
|
||||||
+ '<div class="pretix-widget-item-availability-col">'
|
+ '<div class="pretix-widget-item-availability-col">'
|
||||||
+ '<a v-if="show_toggle" href="#" @click.prevent.stop="expand">'+ strings.variations + '</a>'
|
+ '<a v-if="show_toggle" href="#" @click.prevent.stop="expand">'+ strings.variations + '</a>'
|
||||||
+ '<availbox v-if="!item.has_variations" :item="item"></availbox>'
|
+ '<availbox v-if="!item.has_variations" :item="item"></availbox>'
|
||||||
@@ -438,6 +450,7 @@ Vue.component('item', {
|
|||||||
+ '<div class="pretix-widget-clear"></div>'
|
+ '<div class="pretix-widget-clear"></div>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Variations
|
||||||
+ '<div :class="varClasses" v-if="item.has_variations">'
|
+ '<div :class="varClasses" v-if="item.has_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" :key="variation.id">'
|
||||||
+ '</variation>'
|
+ '</variation>'
|
||||||
@@ -512,7 +525,7 @@ Vue.component('category', {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var shared_methods = {
|
var shared_methods = {
|
||||||
buy: function (event) {
|
buy: function (event, data) {
|
||||||
if (this.$root.useIframe) {
|
if (this.$root.useIframe) {
|
||||||
if (event) {
|
if (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -531,7 +544,7 @@ var shared_methods = {
|
|||||||
this.$root.overlay.frame_loading = true;
|
this.$root.overlay.frame_loading = true;
|
||||||
|
|
||||||
this.async_task_interval = 100;
|
this.async_task_interval = 100;
|
||||||
var form = this.$refs.form;
|
var form = data === undefined ? this.$refs.form : data;
|
||||||
if (form === undefined) {
|
if (form === undefined) {
|
||||||
form = this.$refs.formcomp.$refs.form;
|
form = this.$refs.formcomp.$refs.form;
|
||||||
}
|
}
|
||||||
@@ -653,7 +666,7 @@ var shared_methods = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleResize: function () {
|
handleResize: function () {
|
||||||
this.mobile = this.$refs.wrapper.clientWidth <= 800;
|
this.clientWidth = this.$refs.wrapper.clientWidth;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -664,7 +677,7 @@ var shared_widget_data = function () {
|
|||||||
async_task_timeout: null,
|
async_task_timeout: null,
|
||||||
async_task_interval: 100,
|
async_task_interval: 100,
|
||||||
voucher: null,
|
voucher: null,
|
||||||
mobile: false,
|
clientWidth: 1000,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -760,6 +773,7 @@ Vue.component('pretix-overlay', {
|
|||||||
|
|
||||||
Vue.component('pretix-widget-event-form', {
|
Vue.component('pretix-widget-event-form', {
|
||||||
template: ('<div class="pretix-widget-event-form">'
|
template: ('<div class="pretix-widget-event-form">'
|
||||||
|
// Back navigation
|
||||||
+ '<div class="pretix-widget-event-list-back" v-if="$root.events || $root.weeks || $root.days">'
|
+ '<div class="pretix-widget-event-list-back" v-if="$root.events || $root.weeks || $root.days">'
|
||||||
+ '<a href="#" @click.prevent.stop="back_to_list" v-if="!$root.subevent">‹ '
|
+ '<a href="#" @click.prevent.stop="back_to_list" v-if="!$root.subevent">‹ '
|
||||||
+ strings['back_to_list']
|
+ strings['back_to_list']
|
||||||
@@ -768,18 +782,28 @@ Vue.component('pretix-widget-event-form', {
|
|||||||
+ strings['back_to_dates']
|
+ strings['back_to_dates']
|
||||||
+ '</a>'
|
+ '</a>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Event name
|
||||||
+ '<div class="pretix-widget-event-header" v-if="$root.events || $root.weeks || $root.days">'
|
+ '<div class="pretix-widget-event-header" v-if="$root.events || $root.weeks || $root.days">'
|
||||||
+ '<strong>{{ $root.name }}</strong>'
|
+ '<strong>{{ $root.name }}</strong>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Date range
|
||||||
+ '<div class="pretix-widget-event-details" v-if="($root.events || $root.weeks || $root.days) && $root.date_range">'
|
+ '<div class="pretix-widget-event-details" v-if="($root.events || $root.weeks || $root.days) && $root.date_range">'
|
||||||
+ '{{ $root.date_range }}'
|
+ '{{ $root.date_range }}'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Form start
|
||||||
+ '<div class="pretix-widget-event-description" v-if="($root.events || $root.weeks || $root.days) && $root.frontpage_text" v-html="$root.frontpage_text"></div>'
|
+ '<div class="pretix-widget-event-description" v-if="($root.events || $root.weeks || $root.days) && $root.frontpage_text" v-html="$root.frontpage_text"></div>'
|
||||||
+ '<form method="post" :action="$root.formAction" ref="form" :target="$root.formTarget">'
|
+ '<form method="post" :action="$root.formAction" ref="form" :target="$root.formTarget">'
|
||||||
+ '<input type="hidden" name="_voucher_code" :value="$root.voucher_code" v-if="$root.voucher_code">'
|
+ '<input type="hidden" name="_voucher_code" :value="$root.voucher_code" v-if="$root.voucher_code">'
|
||||||
+ '<input type="hidden" name="subevent" :value="$root.subevent" />'
|
+ '<input type="hidden" name="subevent" :value="$root.subevent" />'
|
||||||
+ '<input type="hidden" name="widget_data" :value="$root.widget_data_json" />'
|
+ '<input type="hidden" name="widget_data" :value="$root.widget_data_json" />'
|
||||||
|
|
||||||
|
// Error message
|
||||||
+ '<div class="pretix-widget-error-message" v-if="$root.error">{{ $root.error }}</div>'
|
+ '<div class="pretix-widget-error-message" v-if="$root.error">{{ $root.error }}</div>'
|
||||||
|
|
||||||
|
// Resume cart
|
||||||
+ '<div class="pretix-widget-info-message pretix-widget-clickable"'
|
+ '<div class="pretix-widget-info-message pretix-widget-clickable"'
|
||||||
+ ' v-if="$root.cart_exists">'
|
+ ' v-if="$root.cart_exists">'
|
||||||
+ '<button @click.prevent.stop="$parent.resume" class="pretix-widget-resume-button" type="button">'
|
+ '<button @click.prevent.stop="$parent.resume" class="pretix-widget-resume-button" type="button">'
|
||||||
@@ -788,16 +812,43 @@ Vue.component('pretix-widget-event-form', {
|
|||||||
+ strings['cart_exists']
|
+ strings['cart_exists']
|
||||||
+ '<div class="pretix-widget-clear"></div>'
|
+ '<div class="pretix-widget-clear"></div>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
+ '<div class="pretix-widget-seating-link-wrapper" v-if="this.$root.has_seating_plan">'
|
|
||||||
|
// Seating plan
|
||||||
|
+ '<div class="pretix-widget-seating-link-wrapper" v-if="$root.has_seating_plan && !show_seating_plan_inline">'
|
||||||
+ '<button class="pretix-widget-seating-link" @click.prevent.stop="$root.startseating">'
|
+ '<button class="pretix-widget-seating-link" @click.prevent.stop="$root.startseating">'
|
||||||
+ strings['show_seating']
|
+ strings['show_seating']
|
||||||
+ '</button>'
|
+ '</button>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
+ '<div class="pretix-widget-seating-embed" v-else-if="$root.has_seating_plan && show_seating_plan_inline">'
|
||||||
|
+ '<iframe :key="\'seatingframe\' + $root.loadid" class="pretix-widget-seating-embed-iframe" ref="seatingframe"'
|
||||||
|
+ ' :src="seatingframe" frameborder="0" referrerpolicy="origin" allowtransparency="true">'
|
||||||
|
+ '</iframe>'
|
||||||
|
+ '</div>'
|
||||||
|
|
||||||
|
// Waiting list for seating plan
|
||||||
|
+ '<div class="pretix-widget-seating-waitinglist" v-if="this.$root.has_seating_plan && this.$root.has_seating_plan_waitinglist">'
|
||||||
|
+ '<div class="pretix-widget-seating-waitinglist-text">'
|
||||||
|
+ strings['seating_plan_waiting_list']
|
||||||
|
+ '</div>'
|
||||||
|
+ '<div class="pretix-widget-seating-waitinglist-button-wrap">'
|
||||||
|
+ '<button class="pretix-widget-seating-waitinglist-button" @click.prevent.stop="$root.startseating">'
|
||||||
|
+ strings['waiting_list']
|
||||||
|
+ '</button>'
|
||||||
|
+ '</div>'
|
||||||
|
+ '<div class="pretix-widget-clear"></div>'
|
||||||
|
+ '</div>'
|
||||||
|
|
||||||
|
// Actual product list
|
||||||
+ '<category v-for="category in this.$root.categories" :category="category" :key="category.id"></category>'
|
+ '<category v-for="category in this.$root.categories" :category="category" :key="category.id"></category>'
|
||||||
|
|
||||||
|
// Buy button
|
||||||
+ '<div class="pretix-widget-action" v-if="$root.display_add_to_cart">'
|
+ '<div class="pretix-widget-action" v-if="$root.display_add_to_cart">'
|
||||||
+ '<button @click="$parent.buy" type="submit" :disabled="buy_disabled">{{ this.buy_label }}</button>'
|
+ '<button @click="$parent.buy" type="submit" :disabled="buy_disabled">{{ this.buy_label }}</button>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
+ '</form>'
|
+ '</form>'
|
||||||
|
|
||||||
|
// Voucher form
|
||||||
+ '<form method="get" :action="$root.voucherFormTarget" target="_blank" '
|
+ '<form method="get" :action="$root.voucherFormTarget" target="_blank" '
|
||||||
+ ' v-if="$root.vouchers_exist && !$root.disable_vouchers && !$root.voucher_code">'
|
+ ' v-if="$root.vouchers_exist && !$root.disable_vouchers && !$root.voucher_code">'
|
||||||
+ '<div class="pretix-widget-voucher">'
|
+ '<div class="pretix-widget-voucher">'
|
||||||
@@ -812,8 +863,10 @@ Vue.component('pretix-widget-event-form', {
|
|||||||
+ '<div class="pretix-widget-voucher-button-wrap">'
|
+ '<div class="pretix-widget-voucher-button-wrap">'
|
||||||
+ '<button @click="$parent.redeem">' + strings.redeem + '</button>'
|
+ '<button @click="$parent.redeem">' + strings.redeem + '</button>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
+ '<div class="pretix-widget-clear"></div>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
+ '</form>'
|
+ '</form>'
|
||||||
|
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
),
|
),
|
||||||
data: function () {
|
data: function () {
|
||||||
@@ -825,10 +878,14 @@ Vue.component('pretix-widget-event-form', {
|
|||||||
this.$root.$on('amounts_changed', this.calculate_buy_disabled)
|
this.$root.$on('amounts_changed', this.calculate_buy_disabled)
|
||||||
this.$root.$on('focus_voucher_field', this.focus_voucher_field)
|
this.$root.$on('focus_voucher_field', this.focus_voucher_field)
|
||||||
this.calculate_buy_disabled()
|
this.calculate_buy_disabled()
|
||||||
|
|
||||||
|
window.addEventListener('message', this.on_seat_select);
|
||||||
},
|
},
|
||||||
beforeDestroy: function() {
|
beforeDestroy: function() {
|
||||||
this.$root.$off('amounts_changed', this.calculate_buy_disabled)
|
this.$root.$off('amounts_changed', this.calculate_buy_disabled)
|
||||||
this.$root.$off('focus_voucher_field', this.focus_voucher_field)
|
this.$root.$off('focus_voucher_field', this.focus_voucher_field)
|
||||||
|
|
||||||
|
window.addEventListener('message', this.on_seat_select);
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
buy_label: function () {
|
buy_label: function () {
|
||||||
@@ -858,9 +915,26 @@ Vue.component('pretix-widget-event-form', {
|
|||||||
} else {
|
} else {
|
||||||
return strings.buy;
|
return strings.buy;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
show_seating_plan_inline: function () {
|
||||||
|
return this.$root.seating_embedded && this.$parent.clientWidth > 992;
|
||||||
|
},
|
||||||
|
seatingframe: function () {
|
||||||
|
var seatingframe_url = this.$root.target_url;
|
||||||
|
if (this.$root.subevent){
|
||||||
|
seatingframe_url += '/' + this.$root.subevent;
|
||||||
|
}
|
||||||
|
seatingframe_url += '/seatingframe/?inline=1&locale=' + lang + '&widget_id=' + this.$root.widgetindex;
|
||||||
|
return seatingframe_url;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
on_seat_select: function (ev) {
|
||||||
|
if (ev.data.source !== "pretix_widget_seating") return;
|
||||||
|
if (parseInt(ev.data.widget_id) !== this.$root.widgetindex) return; // In case multiple widgets are on this page
|
||||||
|
if (ev.data.action !== "buy") return;
|
||||||
|
this.$parent.buy(null, ev.data.data);
|
||||||
|
},
|
||||||
focus_voucher_field: function() {
|
focus_voucher_field: function() {
|
||||||
this.$refs.voucherinput.scrollIntoView(false)
|
this.$refs.voucherinput.scrollIntoView(false)
|
||||||
this.$refs.voucherinput.focus()
|
this.$refs.voucherinput.focus()
|
||||||
@@ -1144,15 +1218,21 @@ Vue.component('pretix-widget-event-calendar-row', {
|
|||||||
|
|
||||||
Vue.component('pretix-widget-event-calendar', {
|
Vue.component('pretix-widget-event-calendar', {
|
||||||
template: ('<div class="pretix-widget-event-calendar" ref="calendar">'
|
template: ('<div class="pretix-widget-event-calendar" ref="calendar">'
|
||||||
|
|
||||||
|
// Back navigation
|
||||||
+ '<div class="pretix-widget-back" v-if="$root.events !== undefined">'
|
+ '<div class="pretix-widget-back" v-if="$root.events !== undefined">'
|
||||||
+ '<a href="#" @click.prevent.stop="back_to_list">‹ '
|
+ '<a href="#" @click.prevent.stop="back_to_list">‹ '
|
||||||
+ strings['back']
|
+ strings['back']
|
||||||
+ '</a>'
|
+ '</a>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Headline
|
||||||
+ '<div class="pretix-widget-event-header" v-if="$root.parent_stack.length > 0">'
|
+ '<div class="pretix-widget-event-header" v-if="$root.parent_stack.length > 0">'
|
||||||
+ '<strong>{{ $root.name }}</strong>'
|
+ '<strong>{{ $root.name }}</strong>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
+ '<div class="pretix-widget-event-description" v-if="$root.parent_stack.length > 0 && $root.frontpage_text" v-html="$root.frontpage_text"></div>'
|
+ '<div class="pretix-widget-event-description" v-if="$root.parent_stack.length > 0 && $root.frontpage_text" v-html="$root.frontpage_text"></div>'
|
||||||
|
|
||||||
|
// Calendar navigation
|
||||||
+ '<div class="pretix-widget-event-calendar-head">'
|
+ '<div class="pretix-widget-event-calendar-head">'
|
||||||
+ '<a class="pretix-widget-event-calendar-previous-month" href="#" @click.prevent.stop="prevmonth">« '
|
+ '<a class="pretix-widget-event-calendar-previous-month" href="#" @click.prevent.stop="prevmonth">« '
|
||||||
+ strings['previous_month']
|
+ strings['previous_month']
|
||||||
@@ -1162,6 +1242,8 @@ Vue.component('pretix-widget-event-calendar', {
|
|||||||
+ strings['next_month']
|
+ strings['next_month']
|
||||||
+ ' »</a>'
|
+ ' »</a>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Calendar
|
||||||
+ '<table class="pretix-widget-event-calendar-table">'
|
+ '<table class="pretix-widget-event-calendar-table">'
|
||||||
+ '<thead>'
|
+ '<thead>'
|
||||||
+ '<tr>'
|
+ '<tr>'
|
||||||
@@ -1220,14 +1302,19 @@ Vue.component('pretix-widget-event-calendar', {
|
|||||||
|
|
||||||
Vue.component('pretix-widget-event-week-calendar', {
|
Vue.component('pretix-widget-event-week-calendar', {
|
||||||
template: ('<div class="pretix-widget-event-calendar pretix-widget-event-week-calendar" ref="weekcalendar">'
|
template: ('<div class="pretix-widget-event-calendar pretix-widget-event-week-calendar" ref="weekcalendar">'
|
||||||
|
// Back navigation
|
||||||
+ '<div class="pretix-widget-back" v-if="$root.events !== undefined">'
|
+ '<div class="pretix-widget-back" v-if="$root.events !== undefined">'
|
||||||
+ '<a href="#" @click.prevent.stop="back_to_list">‹ '
|
+ '<a href="#" @click.prevent.stop="back_to_list">‹ '
|
||||||
+ strings['back']
|
+ strings['back']
|
||||||
+ '</a>'
|
+ '</a>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Event header
|
||||||
+ '<div class="pretix-widget-event-header" v-if="$root.parent_stack.length > 0">'
|
+ '<div class="pretix-widget-event-header" v-if="$root.parent_stack.length > 0">'
|
||||||
+ '<strong>{{ $root.name }}</strong>'
|
+ '<strong>{{ $root.name }}</strong>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Calendar navigation
|
||||||
+ '<div class="pretix-widget-event-description" v-if="$root.parent_stack.length > 0 && $root.frontpage_text" v-html="$root.frontpage_text"></div>'
|
+ '<div class="pretix-widget-event-description" v-if="$root.parent_stack.length > 0 && $root.frontpage_text" v-html="$root.frontpage_text"></div>'
|
||||||
+ '<div class="pretix-widget-event-calendar-head">'
|
+ '<div class="pretix-widget-event-calendar-head">'
|
||||||
+ '<a class="pretix-widget-event-calendar-previous-month" href="#" @click.prevent.stop="prevweek">« '
|
+ '<a class="pretix-widget-event-calendar-previous-month" href="#" @click.prevent.stop="prevweek">« '
|
||||||
@@ -1238,12 +1325,15 @@ Vue.component('pretix-widget-event-week-calendar', {
|
|||||||
+ strings['next_week']
|
+ strings['next_week']
|
||||||
+ ' »</a>'
|
+ ' »</a>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
|
// Actual calendar
|
||||||
+ '<div class="pretix-widget-event-week-table">'
|
+ '<div class="pretix-widget-event-week-table">'
|
||||||
+ '<div class="pretix-widget-event-week-col" v-for="d in $root.days">'
|
+ '<div class="pretix-widget-event-week-col" v-for="d in $root.days">'
|
||||||
+ '<pretix-widget-event-week-cell :day="d">'
|
+ '<pretix-widget-event-week-cell :day="d">'
|
||||||
+ '</pretix-widget-event-week-cell>'
|
+ '</pretix-widget-event-week-cell>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
|
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
+ '</div>'),
|
+ '</div>'),
|
||||||
computed: {
|
computed: {
|
||||||
@@ -1310,9 +1400,12 @@ Vue.component('pretix-widget', {
|
|||||||
data: shared_widget_data,
|
data: shared_widget_data,
|
||||||
methods: shared_methods,
|
methods: shared_methods,
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
this.mobile = this.$refs.wrapper.clientWidth <= 600;
|
this.clientWidth = this.$refs.wrapper.clientWidth;
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
mobile: function () {
|
||||||
|
return this.clientWidth <= 600;
|
||||||
|
},
|
||||||
classObject: function () {
|
classObject: function () {
|
||||||
o = {'pretix-widget': true};
|
o = {'pretix-widget': true};
|
||||||
if (this.mobile) {
|
if (this.mobile) {
|
||||||
@@ -1472,14 +1565,16 @@ var shared_root_methods = {
|
|||||||
root.cart_exists = data.cart_exists;
|
root.cart_exists = data.cart_exists;
|
||||||
root.vouchers_exist = data.vouchers_exist;
|
root.vouchers_exist = data.vouchers_exist;
|
||||||
root.has_seating_plan = data.has_seating_plan;
|
root.has_seating_plan = data.has_seating_plan;
|
||||||
|
root.has_seating_plan_waitinglist = data.has_seating_plan_waitinglist;
|
||||||
root.itemnum = data.itemnum;
|
root.itemnum = data.itemnum;
|
||||||
}
|
}
|
||||||
|
root.loadid++; // force-reload iframes
|
||||||
root.poweredby = data.poweredby;
|
root.poweredby = data.poweredby;
|
||||||
if (root.loading > 0) {
|
if (root.loading > 0) {
|
||||||
root.loading--;
|
root.loading--;
|
||||||
root.trigger_load_callback();
|
root.trigger_load_callback();
|
||||||
}
|
}
|
||||||
if (root.parent_stack.length > 0 && root.has_seating_plan && root.categories.length === 0 && !root.frame_dismissed && root.useIframe && !root.error) {
|
if (root.parent_stack.length > 0 && root.has_seating_plan && root.categories.length === 0 && !root.frame_dismissed && root.useIframe && !root.error && !root.has_seating_plan_waitinglist) {
|
||||||
// If we're on desktop and someone selects a seating-only event in a calendar, let's open it right away,
|
// If we're on desktop and someone selects a seating-only event in a calendar, let's open it right away,
|
||||||
// but only if the person didn't close it before.
|
// but only if the person didn't close it before.
|
||||||
root.startseating()
|
root.startseating()
|
||||||
@@ -1612,7 +1707,7 @@ var shared_root_computed = {
|
|||||||
},
|
},
|
||||||
widget_data_json: function () {
|
widget_data_json: function () {
|
||||||
return JSON.stringify(this.widget_data);
|
return JSON.stringify(this.widget_data);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var create_overlay = function (app) {
|
var create_overlay = function (app) {
|
||||||
@@ -1654,7 +1749,7 @@ function get_ga_client_id(tracking_id) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var create_widget = function (element) {
|
var create_widget = function (element, widgetindex) {
|
||||||
var target_url = element.attributes.event.value;
|
var target_url = element.attributes.event.value;
|
||||||
if (!target_url.match(/\/$/)) {
|
if (!target_url.match(/\/$/)) {
|
||||||
target_url += "/";
|
target_url += "/";
|
||||||
@@ -1663,6 +1758,7 @@ var create_widget = function (element) {
|
|||||||
var subevent = element.attributes.subevent ? element.attributes.subevent.value : null;
|
var subevent = element.attributes.subevent ? element.attributes.subevent.value : null;
|
||||||
var style = element.attributes.style ? element.attributes.style.value : null;
|
var style = element.attributes.style ? element.attributes.style.value : null;
|
||||||
var skip_ssl = element.attributes["skip-ssl-check"] ? true : false;
|
var skip_ssl = element.attributes["skip-ssl-check"] ? true : false;
|
||||||
|
var seating_embedded = element.attributes["seating-embedded"] ? true : false;
|
||||||
var disable_iframe = element.attributes["disable-iframe"] ? true : false;
|
var disable_iframe = element.attributes["disable-iframe"] ? true : false;
|
||||||
var disable_vouchers = element.attributes["disable-vouchers"] ? true : false;
|
var disable_vouchers = element.attributes["disable-vouchers"] ? true : false;
|
||||||
var widget_data = JSON.parse(JSON.stringify(window.PretixWidget.widget_data));
|
var widget_data = JSON.parse(JSON.stringify(window.PretixWidget.widget_data));
|
||||||
@@ -1685,6 +1781,7 @@ var create_widget = function (element) {
|
|||||||
el: element,
|
el: element,
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
|
widgetindex: widgetindex,
|
||||||
target_url: target_url,
|
target_url: target_url,
|
||||||
parent_stack: [],
|
parent_stack: [],
|
||||||
subevent: subevent,
|
subevent: subevent,
|
||||||
@@ -1706,6 +1803,7 @@ var create_widget = function (element) {
|
|||||||
voucher_explanation_text: null,
|
voucher_explanation_text: null,
|
||||||
show_variations_expanded: !!variations,
|
show_variations_expanded: !!variations,
|
||||||
skip_ssl: skip_ssl,
|
skip_ssl: skip_ssl,
|
||||||
|
seating_embedded: seating_embedded,
|
||||||
disable_iframe: disable_iframe,
|
disable_iframe: disable_iframe,
|
||||||
style: style,
|
style: style,
|
||||||
connection_error: false,
|
connection_error: false,
|
||||||
@@ -1720,6 +1818,7 @@ var create_widget = function (element) {
|
|||||||
display_add_to_cart: false,
|
display_add_to_cart: false,
|
||||||
widget_data: widget_data,
|
widget_data: widget_data,
|
||||||
loading: 1,
|
loading: 1,
|
||||||
|
loadid: 1,
|
||||||
widget_id: 'pretix-widget-' + widget_id,
|
widget_id: 'pretix-widget-' + widget_id,
|
||||||
vouchers_exist: false,
|
vouchers_exist: false,
|
||||||
disable_vouchers: disable_vouchers,
|
disable_vouchers: disable_vouchers,
|
||||||
@@ -1727,7 +1826,8 @@ var create_widget = function (element) {
|
|||||||
itemcount: 0,
|
itemcount: 0,
|
||||||
overlay: null,
|
overlay: null,
|
||||||
poweredby: "",
|
poweredby: "",
|
||||||
has_seating_plan: false
|
has_seating_plan: false,
|
||||||
|
has_seating_plan_waitinglist: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created: function () {
|
created: function () {
|
||||||
@@ -1819,7 +1919,7 @@ window.PretixWidget.buildWidgets = function () {
|
|||||||
var wlength = widgets.length;
|
var wlength = widgets.length;
|
||||||
for (var i = 0; i < wlength; i++) {
|
for (var i = 0; i < wlength; i++) {
|
||||||
var widget = widgets[i];
|
var widget = widgets[i];
|
||||||
widgetlist.push(create_widget(widget));
|
widgetlist.push(create_widget(widget, i + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
var buttons = document.querySelectorAll("pretix-button, div.pretix-button-compat");
|
var buttons = document.querySelectorAll("pretix-button, div.pretix-button-compat");
|
||||||
|
|||||||
@@ -331,6 +331,37 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pretix-widget-seating-embed {
|
||||||
|
margin: 0 -10px;
|
||||||
|
}
|
||||||
|
.pretix-widget-seating-embed-iframe {
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 2/1;
|
||||||
|
max-height: 60vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pretix-widget-seating-waitinglist {
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pretix-widget-seating-waitinglist-text {
|
||||||
|
padding: 0 15px;
|
||||||
|
width: 75%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pretix-widget-seating-waitinglist-button-wrap {
|
||||||
|
padding: 0 15px;
|
||||||
|
width: 25%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pretix-widget-seating-waitinglist-button {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.pretix-widget-item-with-picture .pretix-widget-main-item-row .pretix-widget-item-title-and-description {
|
.pretix-widget-item-with-picture .pretix-widget-main-item-row .pretix-widget-item-title-and-description {
|
||||||
margin-left: 70px;
|
margin-left: 70px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ setup(
|
|||||||
'django-scopes==1.2.*',
|
'django-scopes==1.2.*',
|
||||||
'django-statici18n==2.3.*',
|
'django-statici18n==2.3.*',
|
||||||
'djangorestframework==3.14.*',
|
'djangorestframework==3.14.*',
|
||||||
'dnspython<2.0', # do not upgrade, causes issues with eventlet / gunicorn 19 and we cannot upgrade gunicorn right now
|
'dnspython==2.2.*',
|
||||||
'drf_ujson2==1.7.*',
|
'drf_ujson2==1.7.*',
|
||||||
'isoweek',
|
'isoweek',
|
||||||
'jsonschema',
|
'jsonschema',
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ from decimal import Decimal
|
|||||||
import pytest
|
import pytest
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
|
from paypalhttp.http_response import Result
|
||||||
|
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
Event, Order, OrderPayment, OrderRefund, Organizer, Team, User,
|
Event, Order, OrderPayment, OrderRefund, Organizer, Team, User,
|
||||||
@@ -262,7 +263,7 @@ def init_api(self):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_webhook_all_good(env, client, monkeypatch):
|
def test_webhook_all_good(env, client, monkeypatch):
|
||||||
order = env[1]
|
order = env[1]
|
||||||
pp_order = get_test_order()
|
pp_order = Result(get_test_order())
|
||||||
monkeypatch.setattr("paypalcheckoutsdk.orders.OrdersGetRequest", lambda *args: pp_order)
|
monkeypatch.setattr("paypalcheckoutsdk.orders.OrdersGetRequest", lambda *args: pp_order)
|
||||||
monkeypatch.setattr("pretix.plugins.paypal2.payment.PaypalMethod.init_api", init_api)
|
monkeypatch.setattr("pretix.plugins.paypal2.payment.PaypalMethod.init_api", init_api)
|
||||||
|
|
||||||
@@ -406,7 +407,7 @@ def test_webhook_mark_paid(env, client, monkeypatch):
|
|||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
order.payments.update(state=OrderPayment.PAYMENT_STATE_PENDING)
|
order.payments.update(state=OrderPayment.PAYMENT_STATE_PENDING)
|
||||||
|
|
||||||
pp_order = get_test_order()
|
pp_order = Result(get_test_order())
|
||||||
monkeypatch.setattr("paypalcheckoutsdk.orders.OrdersGetRequest", lambda *args: pp_order)
|
monkeypatch.setattr("paypalcheckoutsdk.orders.OrdersGetRequest", lambda *args: pp_order)
|
||||||
monkeypatch.setattr("pretix.plugins.paypal2.payment.PaypalMethod.init_api", init_api)
|
monkeypatch.setattr("pretix.plugins.paypal2.payment.PaypalMethod.init_api", init_api)
|
||||||
with scopes_disabled():
|
with scopes_disabled():
|
||||||
@@ -503,8 +504,8 @@ def test_webhook_mark_paid(env, client, monkeypatch):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_webhook_refund1(env, client, monkeypatch):
|
def test_webhook_refund1(env, client, monkeypatch):
|
||||||
order = env[1]
|
order = env[1]
|
||||||
pp_order = get_test_order()
|
pp_order = Result(get_test_order())
|
||||||
pp_refund = get_test_refund()
|
pp_refund = Result(get_test_refund())
|
||||||
|
|
||||||
monkeypatch.setattr("paypalcheckoutsdk.orders.OrdersGetRequest", lambda *args: pp_order)
|
monkeypatch.setattr("paypalcheckoutsdk.orders.OrdersGetRequest", lambda *args: pp_order)
|
||||||
monkeypatch.setattr("paypalcheckoutsdk.payments.RefundsGetRequest", lambda *args: pp_refund)
|
monkeypatch.setattr("paypalcheckoutsdk.payments.RefundsGetRequest", lambda *args: pp_refund)
|
||||||
@@ -597,8 +598,8 @@ def test_webhook_refund1(env, client, monkeypatch):
|
|||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_webhook_refund2(env, client, monkeypatch):
|
def test_webhook_refund2(env, client, monkeypatch):
|
||||||
order = env[1]
|
order = env[1]
|
||||||
pp_order = get_test_order()
|
pp_order = Result(get_test_order())
|
||||||
pp_refund = get_test_refund()
|
pp_refund = Result(get_test_refund())
|
||||||
|
|
||||||
monkeypatch.setattr("paypalcheckoutsdk.orders.OrdersGetRequest", lambda *args: pp_order)
|
monkeypatch.setattr("paypalcheckoutsdk.orders.OrdersGetRequest", lambda *args: pp_order)
|
||||||
monkeypatch.setattr("paypalcheckoutsdk.payments.RefundsGetRequest", lambda *args: pp_refund)
|
monkeypatch.setattr("paypalcheckoutsdk.payments.RefundsGetRequest", lambda *args: pp_refund)
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
|
|||||||
"waiting_list_enabled": False,
|
"waiting_list_enabled": False,
|
||||||
"error": None,
|
"error": None,
|
||||||
"has_seating_plan": False,
|
"has_seating_plan": False,
|
||||||
|
"has_seating_plan_waitinglist": False,
|
||||||
'poweredby': '<a href="https://pretix.eu" target="_blank" rel="noopener">ticketing powered by pretix</a>',
|
'poweredby': '<a href="https://pretix.eu" target="_blank" rel="noopener">ticketing powered by pretix</a>',
|
||||||
"items_by_category": [
|
"items_by_category": [
|
||||||
{
|
{
|
||||||
@@ -348,6 +349,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
|
|||||||
"show_variations_expanded": False,
|
"show_variations_expanded": False,
|
||||||
"display_net_prices": False,
|
"display_net_prices": False,
|
||||||
"has_seating_plan": False,
|
"has_seating_plan": False,
|
||||||
|
"has_seating_plan_waitinglist": False,
|
||||||
"vouchers_exist": True,
|
"vouchers_exist": True,
|
||||||
"waiting_list_enabled": False,
|
"waiting_list_enabled": False,
|
||||||
"error": None,
|
"error": None,
|
||||||
@@ -401,6 +403,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
|
|||||||
"display_net_prices": False,
|
"display_net_prices": False,
|
||||||
"vouchers_exist": True,
|
"vouchers_exist": True,
|
||||||
"has_seating_plan": False,
|
"has_seating_plan": False,
|
||||||
|
"has_seating_plan_waitinglist": False,
|
||||||
"waiting_list_enabled": False,
|
"waiting_list_enabled": False,
|
||||||
"error": None,
|
"error": None,
|
||||||
'poweredby': '<a href="https://pretix.eu" target="_blank" rel="noopener">ticketing powered by pretix</a>',
|
'poweredby': '<a href="https://pretix.eu" target="_blank" rel="noopener">ticketing powered by pretix</a>',
|
||||||
@@ -469,6 +472,7 @@ class WidgetCartTest(CartTestMixin, TestCase):
|
|||||||
"show_variations_expanded": False,
|
"show_variations_expanded": False,
|
||||||
"display_net_prices": False,
|
"display_net_prices": False,
|
||||||
"has_seating_plan": False,
|
"has_seating_plan": False,
|
||||||
|
"has_seating_plan_waitinglist": False,
|
||||||
"vouchers_exist": True,
|
"vouchers_exist": True,
|
||||||
"waiting_list_enabled": False,
|
"waiting_list_enabled": False,
|
||||||
"error": "This voucher is expired.",
|
"error": "This voucher is expired.",
|
||||||
|
|||||||
Reference in New Issue
Block a user