forked from CGM_Public/pretix_original
Compare commits
23 Commits
release/20
...
data-attr-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f6c0c11c0 | ||
|
|
b89c076414 | ||
|
|
afdc95656f | ||
|
|
99b616ebd9 | ||
|
|
a3ce3b9af3 | ||
|
|
b6461e9303 | ||
|
|
f7dfd51c2c | ||
|
|
3b98d87a26 | ||
|
|
f045062055 | ||
|
|
eb501dd1ea | ||
|
|
2d8793c355 | ||
|
|
d32bd717b7 | ||
|
|
6e6b75d55e | ||
|
|
50b5f760bb | ||
|
|
9ab2e61c31 | ||
|
|
4876a0b61f | ||
|
|
56bbcb65c3 | ||
|
|
5bb1cb498f | ||
|
|
6bf23b0fdd | ||
|
|
5deb1a8c69 | ||
|
|
1523137300 | ||
|
|
04ef097eb1 | ||
|
|
a5d4434a64 |
@@ -345,7 +345,7 @@ to speed up various operations::
|
||||
The location of redis, as a URL of the form ``redis://[:password]@localhost:6379/0``
|
||||
or ``unix://[:password]@/path/to/socket.sock?db=0``
|
||||
|
||||
``session``
|
||||
``sessions``
|
||||
When this is set to ``True``, redis will be used as the session storage.
|
||||
|
||||
``sentinels``
|
||||
@@ -521,4 +521,4 @@ pretix can optionally make use of a GeoIP database for some features. It needs a
|
||||
|
||||
|
||||
.. _GeoAcumen: https://github.com/geoacumen/geoacumen-country
|
||||
.. _GeoLite2: https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
|
||||
.. _GeoLite2: https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
|
||||
|
||||
@@ -94,7 +94,9 @@ If you want the user to return to your application after the payment is complete
|
||||
"Plugins". Enable the plugin "Redirection from order page". Then, go to the new page "Settings", then "Redirection".
|
||||
Enter the base URL of your web application. This will allow you to redirect to pages under this base URL later on.
|
||||
For example, if you want users to be redirected to ``https://example.org/order/return?tx_id=1234``, you could now
|
||||
either enter ``https://example.org`` or ``https://example.org/order/``.
|
||||
either enter ``https://example.org/order/`` or ``https://example.org/``.
|
||||
Please note that in the latter case the trailing slash is required, ``https://example.org`` is not allowed to prevent.
|
||||
Only base URLs with a secure (``https://``) or local (``http://localhost``) origin are permitted.
|
||||
|
||||
The user will be redirected back to your page instead of pretix' order confirmation page after the payment,
|
||||
**regardless of whether it was successful or not**. We will append an ``error=…`` query parameter with an error
|
||||
|
||||
@@ -34,6 +34,7 @@ internal_id string Can be used for
|
||||
contact_name string Contact person (or ``null``)
|
||||
contact_name_parts object of strings Decomposition of contact name (i.e. given name, family name)
|
||||
contact_email string Contact person email address (or ``null``)
|
||||
contact_cc_email string Copy email addresses, can be multiple separated by comma (or ``null``)
|
||||
booth string Booth number (or ``null``). Maximum 100 characters.
|
||||
locale string Locale for communication with the exhibitor.
|
||||
access_code string Access code for the exhibitor to access their data or use the lead scanning app (read-only).
|
||||
@@ -109,6 +110,7 @@ Endpoints
|
||||
"title": "Dr"
|
||||
},
|
||||
"contact_email": "johnson@as.example.org",
|
||||
"contact_cc_email": "miller@as.example.org,smith@as.example.org",
|
||||
"booth": "A2",
|
||||
"locale": "de",
|
||||
"access_code": "VKHZ2FU84",
|
||||
@@ -162,6 +164,7 @@ Endpoints
|
||||
"title": "Dr"
|
||||
},
|
||||
"contact_email": "johnson@as.example.org",
|
||||
"contact_cc_email": "miller@as.example.org,smith@as.example.org",
|
||||
"booth": "A2",
|
||||
"locale": "de",
|
||||
"access_code": "VKHZ2FU84",
|
||||
@@ -365,6 +368,7 @@ Endpoints
|
||||
"title": "Dr"
|
||||
},
|
||||
"contact_email": "johnson@as.example.org",
|
||||
"contact_cc_email": "miller@as.example.org,smith@as.example.org",
|
||||
"booth": "A2",
|
||||
"locale": "de",
|
||||
"allow_lead_scanning": true,
|
||||
@@ -394,6 +398,7 @@ Endpoints
|
||||
"title": "Dr"
|
||||
},
|
||||
"contact_email": "johnson@as.example.org",
|
||||
"contact_cc_email": "miller@as.example.org,smith@as.example.org",
|
||||
"booth": "A2",
|
||||
"locale": "de",
|
||||
"access_code": "VKHZ2FU84",
|
||||
@@ -454,6 +459,7 @@ Endpoints
|
||||
"title": "Dr"
|
||||
},
|
||||
"contact_email": "johnson@as.example.org",
|
||||
"contact_cc_email": "miller@as.example.org,smith@as.example.org",
|
||||
"booth": "A2",
|
||||
"locale": "de",
|
||||
"access_code": "VKHZ2FU84",
|
||||
|
||||
@@ -84,7 +84,7 @@ dependencies = [
|
||||
"pycryptodome==3.20.*",
|
||||
"pypdf==3.9.*",
|
||||
"python-bidi==0.4.*", # Support for Arabic in reportlab
|
||||
"python-dateutil==2.8.*",
|
||||
"python-dateutil==2.9.*",
|
||||
"pytz",
|
||||
"pytz-deprecation-shim==0.1.*",
|
||||
"pyuca",
|
||||
|
||||
@@ -19,4 +19,4 @@
|
||||
# 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/>.
|
||||
#
|
||||
__version__ = "2024.2.0"
|
||||
__version__ = "2024.3.0.dev0"
|
||||
|
||||
@@ -86,6 +86,7 @@ class InvoiceExporterMixin:
|
||||
('', _('All payment providers')),
|
||||
] + [
|
||||
(k, v.verbose_name) for k, v in self.event.get_payment_providers().items()
|
||||
if not v.is_meta
|
||||
],
|
||||
required=False,
|
||||
help_text=_('Only include invoices for orders that have at least one payment attempt '
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 4.2.9 on 2024-01-30 11:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("pretixbase", "0256_itemvariation_unavail_modes"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="item",
|
||||
name="default_price",
|
||||
field=models.DecimalField(decimal_places=2, default=0, max_digits=13),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -265,6 +265,9 @@ class EventMixin:
|
||||
|
||||
@property
|
||||
def event_microdata(self):
|
||||
if self.settings.event_microdata:
|
||||
return self.settings.event_microdata
|
||||
|
||||
import json
|
||||
|
||||
eventdict = {
|
||||
|
||||
@@ -430,7 +430,7 @@ class Item(LoggedModel):
|
||||
help_text=_("If this product has multiple variations, you can set different prices for each of the "
|
||||
"variations. If a variation does not have a special price or if you do not have variations, "
|
||||
"this price will be used."),
|
||||
max_digits=13, decimal_places=2, null=True
|
||||
max_digits=13, decimal_places=2,
|
||||
)
|
||||
free_price = models.BooleanField(
|
||||
default=False,
|
||||
|
||||
@@ -351,9 +351,6 @@ class Voucher(LoggedModel):
|
||||
'variations.'))
|
||||
if variation and not item.variations.filter(pk=variation.pk).exists():
|
||||
raise ValidationError(_('This variation does not belong to this product.'))
|
||||
if item.has_variations and not variation and data.get('block_quota'):
|
||||
raise ValidationError(_('You can only block quota if you specify a specific product variation. '
|
||||
'Otherwise it might be unclear which quotas to block.'))
|
||||
if item.category and item.category.is_addon:
|
||||
raise ValidationError(_('It is currently not possible to create vouchers for add-on products.'))
|
||||
elif block_quota:
|
||||
@@ -431,7 +428,15 @@ class Voucher(LoggedModel):
|
||||
elif old_instance.variation:
|
||||
quotas |= set(old_instance.variation.quotas.filter(subevent=old_instance.subevent))
|
||||
elif old_instance.item:
|
||||
quotas |= set(old_instance.item.quotas.filter(subevent=old_instance.subevent))
|
||||
if old_instance.item.has_variations:
|
||||
quotas |= set(
|
||||
Quota.objects.filter(pk__in=Quota.variations.through.objects.filter(
|
||||
itemvariation__item=old_instance.item,
|
||||
quota__subevent=old_instance.subevent,
|
||||
).values('quota_id'))
|
||||
)
|
||||
else:
|
||||
quotas |= set(old_instance.item.quotas.filter(subevent=old_instance.subevent))
|
||||
return quotas
|
||||
|
||||
@staticmethod
|
||||
@@ -446,13 +451,19 @@ class Voucher(LoggedModel):
|
||||
|
||||
if quota:
|
||||
new_quotas = {quota}
|
||||
elif item and item.has_variations and not variation:
|
||||
raise ValidationError(_('You can only block quota if you specify a specific product variation. '
|
||||
'Otherwise it might be unclear which quotas to block.'))
|
||||
elif item and variation:
|
||||
new_quotas = set(variation.quotas.filter(subevent=data.get('subevent')))
|
||||
elif item and not item.has_variations:
|
||||
new_quotas = set(item.quotas.filter(subevent=data.get('subevent')))
|
||||
elif item and item.has_variations:
|
||||
new_quotas = set(
|
||||
Quota.objects.filter(
|
||||
pk__in=Quota.variations.through.objects.filter(
|
||||
itemvariation__item=old_instance.item,
|
||||
quota__subevent=data.get('subevent'),
|
||||
).values('quota_id')
|
||||
)
|
||||
)
|
||||
else:
|
||||
raise ValidationError(_('You need to select a specific product or quota if this voucher should reserve '
|
||||
'tickets.'))
|
||||
|
||||
@@ -383,6 +383,7 @@ def mail_send_task(self, *args, to: List[str], subject: str, body: str, html: st
|
||||
if event:
|
||||
with scopes_disabled():
|
||||
event = Event.objects.get(id=event)
|
||||
organizer = event.organizer
|
||||
backend = event.get_mail_backend()
|
||||
cm = lambda: scope(organizer=event.organizer) # noqa
|
||||
elif organizer:
|
||||
|
||||
@@ -90,8 +90,8 @@ class QuotaAvailability:
|
||||
self._count_waitinglist = count_waitinglist
|
||||
self._ignore_closed = ignore_closed
|
||||
self._full_results = full_results
|
||||
self._item_to_quotas = defaultdict(list)
|
||||
self._var_to_quotas = defaultdict(list)
|
||||
self._item_to_quotas = defaultdict(set)
|
||||
self._var_to_quotas = defaultdict(set)
|
||||
self._early_out = early_out
|
||||
self._quota_objects = {}
|
||||
self.results = {}
|
||||
@@ -243,13 +243,16 @@ class QuotaAvailability:
|
||||
quota_id__in=[q.pk for q in quotas]
|
||||
).values('quota_id', 'item_id')
|
||||
for m in q_items:
|
||||
self._item_to_quotas[m['item_id']].append(self._quota_objects[m['quota_id']])
|
||||
self._item_to_quotas[m['item_id']].add(self._quota_objects[m['quota_id']])
|
||||
|
||||
q_vars = Quota.variations.through.objects.filter(
|
||||
quota_id__in=[q.pk for q in quotas]
|
||||
).values('quota_id', 'itemvariation_id')
|
||||
).values('quota_id', 'itemvariation_id', 'itemvariation__item_id')
|
||||
for m in q_vars:
|
||||
self._var_to_quotas[m['itemvariation_id']].append(self._quota_objects[m['quota_id']])
|
||||
self._var_to_quotas[m['itemvariation_id']].add(self._quota_objects[m['quota_id']])
|
||||
# We can't be 100% certain that a quota, when it is connected to a variation, is also always connected to
|
||||
# the parent item, so we double-check here just to be sure.
|
||||
self._item_to_quotas[m['itemvariation__item_id']].add(self._quota_objects[m['quota_id']])
|
||||
|
||||
self._compute_orders(quotas, q_items, q_vars, size_left)
|
||||
|
||||
@@ -378,7 +381,10 @@ class QuotaAvailability:
|
||||
Q(
|
||||
Q(
|
||||
Q(variation_id__isnull=True) &
|
||||
Q(item_id__in={i['item_id'] for i in q_items if i['quota_id'] in quota_ids})
|
||||
Q(item_id__in=(
|
||||
{i['item_id'] for i in q_items if i['quota_id'] in quota_ids} |
|
||||
{i['itemvariation__item_id'] for i in q_vars if i['quota_id'] in quota_ids}
|
||||
))
|
||||
) | Q(
|
||||
variation_id__in={i['itemvariation_id'] for i in q_vars if i['quota_id'] in quota_ids}
|
||||
) | Q(
|
||||
|
||||
@@ -123,8 +123,6 @@ class ClearableBasenameFileInput(forms.ClearableFileInput):
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
if hasattr(self.file, 'display_name'):
|
||||
return self.file.display_name
|
||||
return self.file.name
|
||||
|
||||
@property
|
||||
|
||||
@@ -32,9 +32,14 @@ def clean_filename(fname):
|
||||
|
||||
"Terms.pdf" → "Terms.pdf.OybgvyAH.22c0583727d5bc.pdf"
|
||||
|
||||
This function reverses this operation:
|
||||
This function reverses this operation (leaving names without doubled extension as-is):
|
||||
|
||||
"Terms.pdf.OybgvyAH.22c0583727d5bc.pdf" → "Terms.pdf"
|
||||
"Terms.pdf" → "Terms.pdf"
|
||||
"""
|
||||
ext = '.' + fname.split('.')[-1]
|
||||
return fname.rsplit(ext + ".", 1)[0] + ext
|
||||
parts = fname.rsplit(ext + ".", 1)
|
||||
if len(parts) == 1:
|
||||
return parts[0]
|
||||
else:
|
||||
return parts[0] + ext
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -71,11 +71,15 @@ def returnurl_process_request(sender, request, **kwargs):
|
||||
u = request.GET.get('return_url')
|
||||
if not sender.settings.returnurl_prefix:
|
||||
raise PermissionDenied('No return URL prefix set.')
|
||||
elif not u.startswith(sender.settings.returnurl_prefix):
|
||||
elif not check_against_prefix_list(u, sender.settings.returnurl_prefix):
|
||||
raise PermissionDenied('Invalid return URL.')
|
||||
request.session[key] = u
|
||||
|
||||
|
||||
def check_against_prefix_list(u, allowlist):
|
||||
return any(u.startswith(allow.strip()) for allow in allowlist.split("\n") if allow.strip() != "")
|
||||
|
||||
|
||||
@receiver(nav_event_settings, dispatch_uid='returnurl_nav')
|
||||
def navbar_info(sender, request, **kwargs):
|
||||
url = resolve(request.path_info)
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
|
||||
# <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
import re
|
||||
|
||||
from django import forms
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
@@ -31,10 +33,14 @@ from pretix.control.views.event import (
|
||||
|
||||
|
||||
class ReturnSettingsForm(SettingsForm):
|
||||
returnurl_prefix = forms.URLField(
|
||||
label=_("Base redirection URL"),
|
||||
help_text=_("Redirection will only be allowed to URLs that start with this prefix."),
|
||||
returnurl_prefix = forms.RegexField(
|
||||
label=_("Base redirection URLs"),
|
||||
help_text=_("Redirection will only be allowed to URLs that start with one of these prefixes. "
|
||||
"Enter one or more allowed URL prefix per line. "
|
||||
"URL prefixes must include a slash after the hostname."),
|
||||
required=False,
|
||||
widget=forms.Textarea,
|
||||
regex=re.compile(r'^((https://.*/.*|http://localhost[:/].*)\n*)*$')
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -106,7 +106,10 @@
|
||||
</div>
|
||||
<div class="variations {% if not event.settings.show_variations_expanded %}variations-collapsed{% endif %}">
|
||||
{% for var in item.available_variations %}
|
||||
<article aria-labelledby="cp-{{ form.pos.pk }}-item-{{ item.pk }}-{{ var.pk }}-legend"{% if var.description %} aria-describedby="cp-{{ form.pos.pk }}-item-{{ item.pk }}-{{ var.pk }}-description"{% endif %} class="row-fluid product-row variation">
|
||||
<article aria-labelledby="cp-{{ form.pos.pk }}-item-{{ item.pk }}-{{ var.pk }}-legend"{% if var.description %} aria-describedby="cp-{{ form.pos.pk }}-item-{{ item.pk }}-{{ var.pk }}-description"{% endif %} class="row-fluid product-row variation"
|
||||
{% if not item.free_price %}
|
||||
data-price="{% if event.settings.display_net_prices %}{{ var.display_price.net|unlocalize }}{% else %}{{ var.display_price.gross|unlocalize }}{% endif %}"
|
||||
{% endif %}>
|
||||
<div class="col-md-8 col-sm-6 col-xs-12">
|
||||
<h5 id="cp-{{ form.pos.pk }}-item-{{ item.pk }}-{{ var.pk }}-legend">{{ var }}</h5>
|
||||
{% if var.description %}
|
||||
@@ -223,7 +226,10 @@
|
||||
</div>
|
||||
</article>
|
||||
{% else %}
|
||||
<article aria-labelledby="cp-{{ form.pos.pk }}-item-{{ item.pk }}-legend"{% if item.description %} aria-describedby="cp-{{ form.pos.pk }}-item-{{ item.pk }}-description"{% endif %} class="row-fluid product-row simple">
|
||||
<article aria-labelledby="cp-{{ form.pos.pk }}-item-{{ item.pk }}-legend"{% if item.description %} aria-describedby="cp-{{ form.pos.pk }}-item-{{ item.pk }}-description"{% endif %} class="row-fluid product-row simple"
|
||||
{% if not item.free_price %}
|
||||
data-price="{% if event.settings.display_net_prices %}{{ item.display_price.net|unlocalize }}{% else %}{{ item.display_price.gross|unlocalize }}{% endif %}"
|
||||
{% endif %}>
|
||||
<div class="col-md-8 col-sm-6 col-xs-12">
|
||||
{% if item.picture %}
|
||||
<a href="{{ item.picture.url }}" class="productpicture"
|
||||
|
||||
@@ -98,7 +98,10 @@
|
||||
</div>
|
||||
<div class="variations {% if not event.settings.show_variations_expanded %}variations-collapsed{% endif %}">
|
||||
{% for var in item.available_variations %}
|
||||
<article aria-labelledby="item-{{ item.pk }}-{{ var.pk }}-legend"{% if var.description %} aria-describedby="item-{{ item.pk }}-{{ var.pk }}-description"{% endif %} class="row product-row variation" id="item-{{ item.pk }}-{{ var.pk }}">
|
||||
<article aria-labelledby="item-{{ item.pk }}-{{ var.pk }}-legend"{% if var.description %} aria-describedby="item-{{ item.pk }}-{{ var.pk }}-description"{% endif %} class="row product-row variation" id="item-{{ item.pk }}-{{ var.pk }}"
|
||||
{% if not item.free_price %}
|
||||
data-price="{% if event.settings.display_net_prices %}{{ var.display_price.net|unlocalize }}{% else %}{{ var.display_price.gross|unlocalize }}{% endif %}"
|
||||
{% endif %}>
|
||||
<div class="col-md-8 col-sm-6 col-xs-12">
|
||||
<h5 id="item-{{ item.pk }}-{{ var.pk }}-legend">{{ var }}</h5>
|
||||
{% if var.description %}
|
||||
@@ -228,7 +231,10 @@
|
||||
</div>
|
||||
</article>
|
||||
{% else %}
|
||||
<article aria-labelledby="item-{{ item.pk }}-legend"{% if item.description %} aria-describedby="item-{{ item.pk }}-description"{% endif %} class="row product-row simple" id="item-{{ item.pk }}">
|
||||
<article aria-labelledby="item-{{ item.pk }}-legend"{% if item.description %} aria-describedby="item-{{ item.pk }}-description"{% endif %} class="row product-row simple" id="item-{{ item.pk }}"
|
||||
{% if not item.free_price %}
|
||||
data-price="{% if event.settings.display_net_prices %}{{ item.display_price.net|unlocalize }}{% else %}{{ item.display_price.gross|unlocalize }}{% endif %}"
|
||||
{% endif %}>
|
||||
<div class="col-md-8 col-sm-6 col-xs-12">
|
||||
{% if item.picture %}
|
||||
<a href="{{ item.picture.url }}" class="productpicture"
|
||||
|
||||
@@ -239,7 +239,7 @@
|
||||
<ul>
|
||||
{% for i in invoices %}
|
||||
<li>
|
||||
<a href="{% eventurl event "presale:event.invoice.download" invoice=i.pk secret=order.secret order=order.code %}">
|
||||
<a href="{% eventurl event "presale:event.invoice.download" invoice=i.pk secret=order.secret order=order.code %}" target="_blank">
|
||||
{% if i.is_cancellation %}{% trans "Cancellation" context "invoice" %}{% else %}{% trans "Invoice" %}{% endif %}
|
||||
{{ i.number }}</a> ({{ i.date|date:"SHORT_DATE_FORMAT" }})
|
||||
</li>
|
||||
|
||||
@@ -127,7 +127,10 @@
|
||||
</div>
|
||||
<div class="variations">
|
||||
{% for var in item.available_variations %}
|
||||
<article aria-labelledby="item-{{ item.pk }}-{{ var.pk }}-legend"{% if var.description %} aria-describedby="item-{{ item.pk }}-{{ var.pk }}-description"{% endif %} class="row product-row variation" id="item-{{ item.pk }}-{{ var.pk }}">
|
||||
<article aria-labelledby="item-{{ item.pk }}-{{ var.pk }}-legend"{% if var.description %} aria-describedby="item-{{ item.pk }}-{{ var.pk }}-description"{% endif %} class="row product-row variation" id="item-{{ item.pk }}-{{ var.pk }}"
|
||||
{% if not item.free_price %}
|
||||
data-price="{% if event.settings.display_net_prices %}{{ var.display_price.net|unlocalize }}{% else %}{{ var.display_price.gross|unlocalize }}{% endif %}"
|
||||
{% endif %}>
|
||||
<div class="col-md-8 col-sm-6 col-xs-12">
|
||||
<h5 id="item-{{ item.pk }}-{{ var.pk }}-legend">{{ var }}</h5>
|
||||
{% if var.description %}
|
||||
@@ -259,7 +262,10 @@
|
||||
</div>
|
||||
</article>
|
||||
{% else %}
|
||||
<article aria-labelledby="item-{{ item.pk }}-legend"{% if item.description %} aria-describedby="item-{{ item.pk }}-description"{% endif %} class="row product-row simple" id="item-{{ item.pk }}">
|
||||
<article aria-labelledby="item-{{ item.pk }}-legend"{% if item.description %} aria-describedby="item-{{ item.pk }}-description"{% endif %} class="row product-row simple" id="item-{{ item.pk }}"
|
||||
{% if not item.free_price %}
|
||||
data-price="{% if event.settings.display_net_prices %}{{ item.display_price.net|unlocalize }}{% else %}{{ item.display_price.gross|unlocalize }}{% endif %}"
|
||||
{% endif %}>
|
||||
<div class="col-md-8 col-sm-6 col-xs-12">
|
||||
{% if item.picture %}
|
||||
<a href="{{ item.picture.url }}" class="productpicture"
|
||||
|
||||
58
src/pretix/static/npm_dir/package-lock.json
generated
58
src/pretix/static/npm_dir/package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.23.9",
|
||||
"@babel/preset-env": "^7.23.9",
|
||||
"@babel/preset-env": "^7.24.0",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"rollup": "^2.79.1",
|
||||
@@ -335,9 +335,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helper-plugin-utils": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
|
||||
"integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
|
||||
"integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==",
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
@@ -1196,13 +1196,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-object-rest-spread": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz",
|
||||
"integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.0.tgz",
|
||||
"integrity": "sha512-y/yKMm7buHpFFXfxVFS4Vk1ToRJDilIa6fKRioB9Vjichv58TDGXTvqV0dN7plobAmTW5eSEGXDngE+Mm+uO+w==",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.23.3",
|
||||
"@babel/helper-compilation-targets": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/compat-data": "^7.23.5",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
||||
"@babel/plugin-transform-parameters": "^7.23.3"
|
||||
},
|
||||
@@ -1479,13 +1479,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/preset-env": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz",
|
||||
"integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.0.tgz",
|
||||
"integrity": "sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==",
|
||||
"dependencies": {
|
||||
"@babel/compat-data": "^7.23.5",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-validator-option": "^7.23.5",
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3",
|
||||
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3",
|
||||
@@ -1538,7 +1538,7 @@
|
||||
"@babel/plugin-transform-new-target": "^7.23.3",
|
||||
"@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4",
|
||||
"@babel/plugin-transform-numeric-separator": "^7.23.4",
|
||||
"@babel/plugin-transform-object-rest-spread": "^7.23.4",
|
||||
"@babel/plugin-transform-object-rest-spread": "^7.24.0",
|
||||
"@babel/plugin-transform-object-super": "^7.23.3",
|
||||
"@babel/plugin-transform-optional-catch-binding": "^7.23.4",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.23.4",
|
||||
@@ -4378,9 +4378,9 @@
|
||||
}
|
||||
},
|
||||
"@babel/helper-plugin-utils": {
|
||||
"version": "7.22.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
|
||||
"integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg=="
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz",
|
||||
"integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w=="
|
||||
},
|
||||
"@babel/helper-remap-async-to-generator": {
|
||||
"version": "7.22.20",
|
||||
@@ -4922,13 +4922,13 @@
|
||||
}
|
||||
},
|
||||
"@babel/plugin-transform-object-rest-spread": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz",
|
||||
"integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.0.tgz",
|
||||
"integrity": "sha512-y/yKMm7buHpFFXfxVFS4Vk1ToRJDilIa6fKRioB9Vjichv58TDGXTvqV0dN7plobAmTW5eSEGXDngE+Mm+uO+w==",
|
||||
"requires": {
|
||||
"@babel/compat-data": "^7.23.3",
|
||||
"@babel/helper-compilation-targets": "^7.22.15",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/compat-data": "^7.23.5",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/plugin-syntax-object-rest-spread": "^7.8.3",
|
||||
"@babel/plugin-transform-parameters": "^7.23.3"
|
||||
}
|
||||
@@ -5091,13 +5091,13 @@
|
||||
}
|
||||
},
|
||||
"@babel/preset-env": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz",
|
||||
"integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==",
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.0.tgz",
|
||||
"integrity": "sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==",
|
||||
"requires": {
|
||||
"@babel/compat-data": "^7.23.5",
|
||||
"@babel/helper-compilation-targets": "^7.23.6",
|
||||
"@babel/helper-plugin-utils": "^7.22.5",
|
||||
"@babel/helper-plugin-utils": "^7.24.0",
|
||||
"@babel/helper-validator-option": "^7.23.5",
|
||||
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3",
|
||||
"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3",
|
||||
@@ -5150,7 +5150,7 @@
|
||||
"@babel/plugin-transform-new-target": "^7.23.3",
|
||||
"@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4",
|
||||
"@babel/plugin-transform-numeric-separator": "^7.23.4",
|
||||
"@babel/plugin-transform-object-rest-spread": "^7.23.4",
|
||||
"@babel/plugin-transform-object-rest-spread": "^7.24.0",
|
||||
"@babel/plugin-transform-object-super": "^7.23.3",
|
||||
"@babel/plugin-transform-optional-catch-binding": "^7.23.4",
|
||||
"@babel/plugin-transform-optional-chaining": "^7.23.4",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"scripts": {},
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.23.9",
|
||||
"@babel/preset-env": "^7.23.9",
|
||||
"@babel/preset-env": "^7.24.0",
|
||||
"@rollup/plugin-babel": "^6.0.4",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"vue": "^2.7.16",
|
||||
|
||||
@@ -625,6 +625,7 @@ var form_handlers = function (el) {
|
||||
el.find('[data-model-select2=event]').each(function () {
|
||||
var $s = $(this);
|
||||
$s.select2({
|
||||
closeOnSelect: !this.hasAttribute('multiple'),
|
||||
theme: "bootstrap",
|
||||
delay: 100,
|
||||
allowClear: !$s.prop("required"),
|
||||
|
||||
@@ -904,8 +904,8 @@ details {
|
||||
}
|
||||
}
|
||||
|
||||
.select2-container [aria-multiselectable] .select2-results__option span strike::before,
|
||||
.select2-container [aria-multiselectable] .select2-results__option span span::before {
|
||||
.select2-container [aria-multiselectable] .select2-results__option > span > strike:first-child::before,
|
||||
.select2-container [aria-multiselectable] .select2-results__option > span > span:first-child::before {
|
||||
content: "";
|
||||
font-family: FontAwesome;
|
||||
display: inline-block;
|
||||
@@ -913,8 +913,8 @@ details {
|
||||
width: 1.28571em;
|
||||
text-align: center;
|
||||
}
|
||||
.select2-container [aria-multiselectable] .select2-results__option[aria-selected=true] span strike::before,
|
||||
.select2-container [aria-multiselectable] .select2-results__option[aria-selected=true] span span::before {
|
||||
.select2-container [aria-multiselectable] .select2-results__option[aria-selected=true] > span > strike:first-child::before,
|
||||
.select2-container [aria-multiselectable] .select2-results__option[aria-selected=true] > span > span:first-child::before {
|
||||
content: ""
|
||||
}
|
||||
|
||||
|
||||
@@ -967,8 +967,14 @@
|
||||
float: none;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.pretix-widget-item-info-col:after {
|
||||
display: block;
|
||||
content: "";
|
||||
clear: both;
|
||||
}
|
||||
.pretix-widget-item-price-col, .pretix-widget-item-availability-col {
|
||||
width: 50%;
|
||||
min-width: 140px;
|
||||
}
|
||||
.pretix-widget-action {
|
||||
width: 100%;
|
||||
|
||||
@@ -934,7 +934,7 @@ def test_cartpos_create_with_voucher_unknown(token_client, organizer, event, ite
|
||||
@pytest.mark.django_db
|
||||
def test_cartpos_create_with_voucher_invalid_item(token_client, organizer, event, item, quota):
|
||||
with scopes_disabled():
|
||||
item2 = event.items.create(name="item2")
|
||||
item2 = event.items.create(name="item2", default_price=0)
|
||||
voucher = event.vouchers.create(code="FOOBAR", item=item2)
|
||||
res = copy.deepcopy(CARTPOS_CREATE_PAYLOAD)
|
||||
res['item'] = item.pk
|
||||
|
||||
@@ -283,6 +283,29 @@ class QuotaTestCase(BaseQuotaTestCase):
|
||||
v.save()
|
||||
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_ORDERED, 0))
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_voucher_all_variations(self):
|
||||
self.quota.variations.add(self.var1)
|
||||
self.quota.size = 1
|
||||
self.quota.save()
|
||||
|
||||
self.quota2 = Quota.objects.create(name="Test", size=2, event=self.event)
|
||||
self.quota2.variations.add(self.var2)
|
||||
|
||||
self.quota3 = Quota.objects.create(name="Test", size=2, event=self.event)
|
||||
self.quota3.variations.add(self.var3)
|
||||
|
||||
v = Voucher.objects.create(item=self.item2, event=self.event)
|
||||
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_OK, 1))
|
||||
self.assertEqual(self.var2.check_quotas(), (Quota.AVAILABILITY_OK, 2))
|
||||
self.assertEqual(self.var3.check_quotas(), (Quota.AVAILABILITY_OK, 2))
|
||||
|
||||
v.block_quota = True
|
||||
v.save()
|
||||
self.assertEqual(self.var1.check_quotas(), (Quota.AVAILABILITY_ORDERED, 0))
|
||||
self.assertEqual(self.var2.check_quotas(), (Quota.AVAILABILITY_OK, 1))
|
||||
self.assertEqual(self.var3.check_quotas(), (Quota.AVAILABILITY_OK, 2))
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_voucher_quota(self):
|
||||
self.quota.variations.add(self.var1)
|
||||
@@ -979,9 +1002,8 @@ class VoucherTestCase(BaseQuotaTestCase):
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_voucher_specify_variation_for_block_quota(self):
|
||||
with self.assertRaises(ValidationError):
|
||||
v = Voucher(item=self.item2, block_quota=True, event=self.event)
|
||||
v.clean()
|
||||
v = Voucher(item=self.item2, block_quota=True, event=self.event)
|
||||
v.clean()
|
||||
|
||||
@classscope(attr='o')
|
||||
def test_voucher_no_item_but_variation(self):
|
||||
|
||||
@@ -254,7 +254,7 @@ class VoucherFormTest(SoupTestMixin, TransactionTestCase):
|
||||
self._create_voucher({
|
||||
'itemvar': '%d' % self.shirt.pk,
|
||||
'block_quota': 'on'
|
||||
}, expected_failure=True)
|
||||
})
|
||||
|
||||
def test_create_blocking_item_voucher_quota_full_invalid(self):
|
||||
self.quota_shirts.size = 0
|
||||
|
||||
Reference in New Issue
Block a user