forked from CGM_Public/pretix_original
Compare commits
3 Commits
subevent-e
...
utils
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9099a38bc8 | ||
|
|
7cb66879ba | ||
|
|
29808ad92d |
@@ -19,4 +19,4 @@
|
|||||||
# 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/>.
|
||||||
#
|
#
|
||||||
__version__ = "2024.10.0.dev0"
|
__version__ = "2024.9.0.dev0"
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ class Command(BaseCommand):
|
|||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument('--tasks', action='store', type=str, help='Only execute the tasks with this name '
|
parser.add_argument('--tasks', action='store', type=str, help='Only execute the tasks with this name '
|
||||||
'(dotted path, comma separation)')
|
'(dotted path, comma separation)')
|
||||||
parser.add_argument('--list-tasks', action='store_true', help='Only list all tasks')
|
|
||||||
parser.add_argument('--exclude', action='store', type=str, help='Exclude the tasks with this name '
|
parser.add_argument('--exclude', action='store', type=str, help='Exclude the tasks with this name '
|
||||||
'(dotted path, comma separation)')
|
'(dotted path, comma separation)')
|
||||||
|
|
||||||
@@ -62,9 +61,6 @@ class Command(BaseCommand):
|
|||||||
|
|
||||||
for receiver in periodic_task._live_receivers(self):
|
for receiver in periodic_task._live_receivers(self):
|
||||||
name = f'{receiver.__module__}.{receiver.__name__}'
|
name = f'{receiver.__module__}.{receiver.__name__}'
|
||||||
if options['list_tasks']:
|
|
||||||
print(name)
|
|
||||||
continue
|
|
||||||
if options.get('tasks'):
|
if options.get('tasks'):
|
||||||
if name not in options.get('tasks').split(','):
|
if name not in options.get('tasks').split(','):
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -313,9 +313,38 @@ class EventMixin:
|
|||||||
items=GroupConcat('pk', delimiter=',')
|
items=GroupConcat('pk', delimiter=',')
|
||||||
).values('items')
|
).values('items')
|
||||||
|
|
||||||
sq_active_variation = ItemVariation.objects.filter_available(channel=channel, voucher=voucher).filter(
|
q_variation = (
|
||||||
Q(quotas__pk=OuterRef('pk'))
|
Q(active=True)
|
||||||
).order_by().values_list('quotas__pk').annotate(
|
& Q(Q(available_from__isnull=True) | Q(available_from__lte=time_machine_now()))
|
||||||
|
& Q(Q(available_until__isnull=True) | Q(available_until__gte=time_machine_now()))
|
||||||
|
& Q(item__active=True)
|
||||||
|
& Q(Q(item__available_from__isnull=True) | Q(item__available_from__lte=time_machine_now()))
|
||||||
|
& Q(Q(item__available_until__isnull=True) | Q(item__available_until__gte=time_machine_now()))
|
||||||
|
& Q(Q(item__category__isnull=True) | Q(item__category__is_addon=False))
|
||||||
|
& Q(item__require_bundling=False)
|
||||||
|
& Q(quotas__pk=OuterRef('pk'))
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(channel, str):
|
||||||
|
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
|
||||||
|
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__identifier=channel))
|
||||||
|
else:
|
||||||
|
q_variation &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
|
||||||
|
q_variation &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels=channel))
|
||||||
|
|
||||||
|
if voucher:
|
||||||
|
if voucher.variation_id:
|
||||||
|
q_variation &= Q(pk=voucher.variation_id)
|
||||||
|
elif voucher.item_id:
|
||||||
|
q_variation &= Q(item_id=voucher.item_id)
|
||||||
|
elif voucher.quota_id:
|
||||||
|
q_variation &= Q(quotas__in=[voucher.quota_id])
|
||||||
|
|
||||||
|
if not voucher or not voucher.show_hidden_items:
|
||||||
|
q_variation &= Q(hide_without_voucher=False)
|
||||||
|
q_variation &= Q(item__hide_without_voucher=False)
|
||||||
|
|
||||||
|
sq_active_variation = ItemVariation.objects.filter(q_variation).order_by().values_list('quotas__pk').annotate(
|
||||||
items=GroupConcat('pk', delimiter=',')
|
items=GroupConcat('pk', delimiter=',')
|
||||||
).values('items')
|
).values('items')
|
||||||
quota_base_qs = Quota.objects.using(settings.DATABASE_REPLICA).filter(
|
quota_base_qs = Quota.objects.using(settings.DATABASE_REPLICA).filter(
|
||||||
|
|||||||
@@ -303,48 +303,6 @@ def filter_available(qs, channel='web', voucher=None, allow_addons=False):
|
|||||||
return qs.filter(q)
|
return qs.filter(q)
|
||||||
|
|
||||||
|
|
||||||
def filter_variations_available(qs, channel='web', voucher=None, allow_addons=False):
|
|
||||||
# Channel can currently be a SalesChannel or a str, since we need that compatibility, but a SalesChannel
|
|
||||||
# makes the query SIGNIFICANTLY faster
|
|
||||||
from .organizer import SalesChannel
|
|
||||||
|
|
||||||
assert isinstance(channel, (SalesChannel, str))
|
|
||||||
q = (
|
|
||||||
Q(active=True)
|
|
||||||
& Q(Q(available_from__isnull=True) | Q(available_from__lte=time_machine_now()))
|
|
||||||
& Q(Q(available_until__isnull=True) | Q(available_until__gte=time_machine_now()))
|
|
||||||
& Q(item__active=True)
|
|
||||||
& Q(Q(item__available_from__isnull=True) | Q(item__available_from__lte=time_machine_now()))
|
|
||||||
& Q(Q(item__available_until__isnull=True) | Q(item__available_until__gte=time_machine_now()))
|
|
||||||
& Q(Q(item__category__isnull=True) | Q(item__category__is_addon=False))
|
|
||||||
& Q(item__require_bundling=False)
|
|
||||||
)
|
|
||||||
|
|
||||||
if isinstance(channel, str):
|
|
||||||
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel))
|
|
||||||
q &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels__identifier=channel))
|
|
||||||
else:
|
|
||||||
q &= Q(Q(all_sales_channels=True) | Q(limit_sales_channels=channel))
|
|
||||||
q &= Q(Q(item__all_sales_channels=True) | Q(item__limit_sales_channels=channel))
|
|
||||||
|
|
||||||
if not allow_addons:
|
|
||||||
q &= Q(Q(item__category__isnull=True) | Q(item__category__is_addon=False))
|
|
||||||
|
|
||||||
if voucher:
|
|
||||||
if voucher.variation_id:
|
|
||||||
q &= Q(pk=voucher.variation_id)
|
|
||||||
elif voucher.item_id:
|
|
||||||
q &= Q(item_id=voucher.item_id)
|
|
||||||
elif voucher.quota_id:
|
|
||||||
q &= Q(quotas__in=[voucher.quota_id])
|
|
||||||
|
|
||||||
if not voucher or not voucher.show_hidden_items:
|
|
||||||
q &= Q(hide_without_voucher=False)
|
|
||||||
q &= Q(item__hide_without_voucher=False)
|
|
||||||
|
|
||||||
return qs.filter(q)
|
|
||||||
|
|
||||||
|
|
||||||
class ItemQuerySet(models.QuerySet):
|
class ItemQuerySet(models.QuerySet):
|
||||||
def filter_available(self, channel='web', voucher=None, allow_addons=False):
|
def filter_available(self, channel='web', voucher=None, allow_addons=False):
|
||||||
return filter_available(self, channel, voucher, allow_addons)
|
return filter_available(self, channel, voucher, allow_addons)
|
||||||
@@ -359,20 +317,6 @@ class ItemQuerySetManager(ScopedManager(organizer='event__organizer').__class__)
|
|||||||
return filter_available(self.get_queryset(), channel, voucher, allow_addons)
|
return filter_available(self.get_queryset(), channel, voucher, allow_addons)
|
||||||
|
|
||||||
|
|
||||||
class ItemVariationQuerySet(models.QuerySet):
|
|
||||||
def filter_available(self, channel='web', voucher=None, allow_addons=False):
|
|
||||||
return filter_variations_available(self, channel, voucher, allow_addons)
|
|
||||||
|
|
||||||
|
|
||||||
class ItemVariationQuerySetManager(ScopedManager(organizer='item__event__organizer').__class__):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self._queryset_class = ItemVariationQuerySet
|
|
||||||
|
|
||||||
def filter_available(self, channel='web', voucher=None, allow_addons=False):
|
|
||||||
return filter_variations_available(self.get_queryset(), channel, voucher, allow_addons)
|
|
||||||
|
|
||||||
|
|
||||||
class Item(LoggedModel):
|
class Item(LoggedModel):
|
||||||
"""
|
"""
|
||||||
An item is a thing which can be sold. It belongs to an event and may or may not belong to a category.
|
An item is a thing which can be sold. It belongs to an event and may or may not belong to a category.
|
||||||
@@ -1255,7 +1199,7 @@ class ItemVariation(models.Model):
|
|||||||
help_text=_('This text will be shown by the check-in app if a ticket of this type is scanned.')
|
help_text=_('This text will be shown by the check-in app if a ticket of this type is scanned.')
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = ItemVariationQuerySetManager()
|
objects = ScopedManager(organizer='item__event__organizer')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
verbose_name = _("Product variation")
|
verbose_name = _("Product variation")
|
||||||
|
|||||||
@@ -1182,11 +1182,10 @@ def process_exit_all(sender, **kwargs):
|
|||||||
positions = cl.positions_inside_query(ignore_status=True, at_time=cl.exit_all_at)
|
positions = cl.positions_inside_query(ignore_status=True, at_time=cl.exit_all_at)
|
||||||
for p in positions:
|
for p in positions:
|
||||||
with scope(organizer=cl.event.organizer):
|
with scope(organizer=cl.event.organizer):
|
||||||
ci, created = Checkin.objects.get_or_create(
|
ci = Checkin.objects.create(
|
||||||
position=p, list=cl, auto_checked_in=True, type=Checkin.TYPE_EXIT, datetime=cl.exit_all_at
|
position=p, list=cl, auto_checked_in=True, type=Checkin.TYPE_EXIT, datetime=cl.exit_all_at
|
||||||
)
|
)
|
||||||
if created:
|
checkin_created.send(cl.event, checkin=ci)
|
||||||
checkin_created.send(cl.event, checkin=ci)
|
|
||||||
d = cl.exit_all_at.astimezone(cl.event.timezone)
|
d = cl.exit_all_at.astimezone(cl.event.timezone)
|
||||||
if cl.event.settings.get(f'autocheckin_dst_hack_{cl.pk}'): # move time back if yesterday was DST switch
|
if cl.event.settings.get(f'autocheckin_dst_hack_{cl.pk}'): # move time back if yesterday was DST switch
|
||||||
d -= timedelta(hours=1)
|
d -= timedelta(hours=1)
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
{% bootstrap_field form.eu_reverse_charge layout="control" %}
|
{% bootstrap_field form.eu_reverse_charge layout="control" %}
|
||||||
{% bootstrap_field form.home_country layout="control" %}
|
{% bootstrap_field form.home_country layout="control" %}
|
||||||
{% bootstrap_field form.keep_gross_if_rate_changes layout="control" %}
|
{% bootstrap_field form.keep_gross_if_rate_changes layout="control" %}
|
||||||
<h3>{% trans "Custom rules" %}</h3>
|
<h3>{% trans "Custom taxation rules" %}</h3>
|
||||||
<div class="alert alert-warning">
|
<div class="alert alert-warning">
|
||||||
{% blocktrans trimmed %}
|
{% blocktrans trimmed %}
|
||||||
These settings are intended for professional users with very specific taxation situations.
|
These settings are intended for professional users with very specific taxation situations.
|
||||||
|
|||||||
@@ -133,7 +133,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{{ i.default_price|money:request.event.currency }}
|
{{ i.default_price|money:request.event.currency }}
|
||||||
{% if i.original_price %}<strike class="text-muted">{{ i.original_price|money:request.event.currency }}</strike>{% endif %}
|
{% if i.original_price %}<strike class="text-muted">{{ i.original_price|money:request.event.currency }}</strike>{% endif %}
|
||||||
{% if i.tax_rule %}
|
{% if i.tax_rule and i.default_price %}
|
||||||
<br/>
|
<br/>
|
||||||
<small class="text-muted">
|
<small class="text-muted">
|
||||||
{% if not i.tax_rule.price_includes_tax %}
|
{% if not i.tax_rule.price_includes_tax %}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,6 @@ AES
|
|||||||
Absenderadresse
|
Absenderadresse
|
||||||
Absenderinformation
|
Absenderinformation
|
||||||
Absendername
|
Absendername
|
||||||
ABGEKÜNDIGT
|
|
||||||
Admin
|
Admin
|
||||||
Adminbereich
|
Adminbereich
|
||||||
Affirm
|
Affirm
|
||||||
@@ -26,7 +25,6 @@ Ausgangsscans
|
|||||||
ausgeklappt
|
ausgeklappt
|
||||||
ausgecheckt
|
ausgecheckt
|
||||||
auswahl
|
auswahl
|
||||||
Auth
|
|
||||||
Authentication
|
Authentication
|
||||||
Authenticator
|
Authenticator
|
||||||
Authentifizierungsmechanismus
|
Authentifizierungsmechanismus
|
||||||
@@ -38,7 +36,6 @@ Bancontact
|
|||||||
BankID
|
BankID
|
||||||
Banking
|
Banking
|
||||||
barcodes
|
barcodes
|
||||||
Baskisch
|
|
||||||
Bcc
|
Bcc
|
||||||
BCC
|
BCC
|
||||||
Beispielevent
|
Beispielevent
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,6 @@ AES
|
|||||||
Absenderadresse
|
Absenderadresse
|
||||||
Absenderinformation
|
Absenderinformation
|
||||||
Absendername
|
Absendername
|
||||||
ABGEKÜNDIGT
|
|
||||||
Admin
|
Admin
|
||||||
Adminbereich
|
Adminbereich
|
||||||
Affirm
|
Affirm
|
||||||
@@ -26,7 +25,6 @@ Ausgangsscans
|
|||||||
ausgeklappt
|
ausgeklappt
|
||||||
ausgecheckt
|
ausgecheckt
|
||||||
auswahl
|
auswahl
|
||||||
Auth
|
|
||||||
Authentication
|
Authentication
|
||||||
Authenticator
|
Authenticator
|
||||||
Authentifizierungsmechanismus
|
Authentifizierungsmechanismus
|
||||||
@@ -38,7 +36,6 @@ Bancontact
|
|||||||
BankID
|
BankID
|
||||||
Banking
|
Banking
|
||||||
barcodes
|
barcodes
|
||||||
Baskisch
|
|
||||||
Bcc
|
Bcc
|
||||||
BCC
|
BCC
|
||||||
Beispielevent
|
Beispielevent
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
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-09-26 11:23+0000\n"
|
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ msgid ""
|
|||||||
msgstr ""
|
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-09-26 11:23+0000\n"
|
"POT-Creation-Date: 2024-08-27 13:34+0000\n"
|
||||||
"PO-Revision-Date: 2024-09-06 08:47+0000\n"
|
"PO-Revision-Date: 2024-09-06 08:47+0000\n"
|
||||||
"Last-Translator: Albizuri <oier@puntu.eus>\n"
|
"Last-Translator: Albizuri <oier@puntu.eus>\n"
|
||||||
"Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
"Language-Team: Basque <https://translate.pretix.eu/projects/pretix/pretix-js/"
|
||||||
@@ -557,14 +557,17 @@ msgid "absent"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:171
|
#: pretix/static/pretixcontrol/js/ui/editor.js:171
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:72
|
||||||
msgid "Check-in QR"
|
msgid "Check-in QR"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:543
|
#: pretix/static/pretixcontrol/js/ui/editor.js:543
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:387
|
||||||
msgid "The PDF background file could not be loaded for the following reason:"
|
msgid "The PDF background file could not be loaded for the following reason:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:894
|
#: pretix/static/pretixcontrol/js/ui/editor.js:894
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:656
|
||||||
msgid "Group of objects"
|
msgid "Group of objects"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -577,35 +580,44 @@ msgid "Text box"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:903
|
#: pretix/static/pretixcontrol/js/ui/editor.js:903
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:663
|
||||||
msgid "Barcode area"
|
msgid "Barcode area"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:905
|
#: pretix/static/pretixcontrol/js/ui/editor.js:905
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:665
|
||||||
msgid "Image area"
|
msgid "Image area"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:907
|
#: pretix/static/pretixcontrol/js/ui/editor.js:907
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:667
|
||||||
msgid "Powered by pretix"
|
msgid "Powered by pretix"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:909
|
#: pretix/static/pretixcontrol/js/ui/editor.js:909
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:669
|
||||||
msgid "Object"
|
msgid "Object"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:913
|
#: pretix/static/pretixcontrol/js/ui/editor.js:913
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:673
|
||||||
msgid "Ticket design"
|
msgid "Ticket design"
|
||||||
msgstr "Sarrera diseinua"
|
msgstr "Sarrera diseinua"
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:1250
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1250
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:972
|
||||||
msgid "Saving failed."
|
msgid "Saving failed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:1319
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1319
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:1370
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1370
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1041
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1091
|
||||||
msgid "Error while uploading your PDF file, please try again."
|
msgid "Error while uploading your PDF file, please try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/editor.js:1353
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1353
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:1074
|
||||||
msgid "Do you really want to leave the editor without saving your changes?"
|
msgid "Do you really want to leave the editor without saving your changes?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -622,14 +634,17 @@ msgid "Unknown error."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:318
|
#: pretix/static/pretixcontrol/js/ui/main.js:318
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:313
|
||||||
msgid "Your color has great contrast and is very easy to read!"
|
msgid "Your color has great contrast and is very easy to read!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:322
|
#: pretix/static/pretixcontrol/js/ui/main.js:322
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:317
|
||||||
msgid "Your color has decent contrast and is probably good-enough to read!"
|
msgid "Your color has decent contrast and is probably good-enough to read!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:326
|
#: pretix/static/pretixcontrol/js/ui/main.js:326
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:321
|
||||||
msgid ""
|
msgid ""
|
||||||
"Your color has bad contrast for text on white background, please choose a "
|
"Your color has bad contrast for text on white background, please choose a "
|
||||||
"darker shade."
|
"darker shade."
|
||||||
@@ -637,38 +652,48 @@ msgstr ""
|
|||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:491
|
#: pretix/static/pretixcontrol/js/ui/main.js:491
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:511
|
#: pretix/static/pretixcontrol/js/ui/main.js:511
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:475
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:495
|
||||||
msgid "Search query"
|
msgid "Search query"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:509
|
#: pretix/static/pretixcontrol/js/ui/main.js:509
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:493
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr "Guztiak"
|
msgstr "Guztiak"
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:510
|
#: pretix/static/pretixcontrol/js/ui/main.js:510
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:494
|
||||||
msgid "None"
|
msgid "None"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
#: pretix/static/pretixcontrol/js/ui/main.js:514
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:498
|
||||||
msgid "Selected only"
|
msgid "Selected only"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:847
|
#: pretix/static/pretixcontrol/js/ui/main.js:847
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:828
|
||||||
msgid "Enter page number between 1 and %(max)s."
|
msgid "Enter page number between 1 and %(max)s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:850
|
#: pretix/static/pretixcontrol/js/ui/main.js:850
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:831
|
||||||
msgid "Invalid page number."
|
msgid "Invalid page number."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:1008
|
#: pretix/static/pretixcontrol/js/ui/main.js:1008
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:989
|
||||||
msgid "Use a different name internally"
|
msgid "Use a different name internally"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:1048
|
#: pretix/static/pretixcontrol/js/ui/main.js:1048
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:1029
|
||||||
msgid "Click to close"
|
msgid "Click to close"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pretix/static/pretixcontrol/js/ui/main.js:1123
|
#: pretix/static/pretixcontrol/js/ui/main.js:1123
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/main.js:1104
|
||||||
msgid "You have unsaved changes!"
|
msgid "You have unsaved changes!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -706,8 +731,7 @@ msgstr "Saskia iraungita"
|
|||||||
msgid "The items in your cart are reserved for you for one minute."
|
msgid "The items in your cart are reserved for you for one minute."
|
||||||
msgid_plural "The items in your cart are reserved for you for {num} minutes."
|
msgid_plural "The items in your cart are reserved for you for {num} minutes."
|
||||||
msgstr[0] "Zure saskiko produktuak minutu -ez erreserbatuta daude zuretzat."
|
msgstr[0] "Zure saskiko produktuak minutu -ez erreserbatuta daude zuretzat."
|
||||||
msgstr[1] ""
|
msgstr[1] "Zure saskiko produktuak {num} minutuz erreserbatuta daude zuretzat."
|
||||||
"Zure saskiko produktuak {num} minutuz erreserbatuta daude zuretzat."
|
|
||||||
|
|
||||||
#: pretix/static/pretixpresale/js/ui/main.js:203
|
#: pretix/static/pretixpresale/js/ui/main.js:203
|
||||||
msgid "The organizer keeps %(currency)s %(amount)s"
|
msgid "The organizer keeps %(currency)s %(amount)s"
|
||||||
@@ -1075,3 +1099,7 @@ msgstr ""
|
|||||||
#: pretix/static/pretixpresale/js/widget/widget.js:89
|
#: pretix/static/pretixpresale/js/widget/widget.js:89
|
||||||
msgid "December"
|
msgid "December"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: pretix/static/pretixcontrol/js/ui/editor.js:661
|
||||||
|
msgid "Text object"
|
||||||
|
msgstr ""
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,6 @@ acceptor
|
|||||||
analytics
|
analytics
|
||||||
anonymize
|
anonymize
|
||||||
anonymized
|
anonymized
|
||||||
Auth
|
|
||||||
authenticator
|
authenticator
|
||||||
automatical
|
automatical
|
||||||
availabilities
|
availabilities
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -31,8 +31,6 @@
|
|||||||
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
|
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
|
||||||
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# License for the specific language governing permissions and limitations under the License.
|
# License for the specific language governing permissions and limitations under the License.
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from django.db.models import Exists, OuterRef, Q
|
from django.db.models import Exists, OuterRef, Q
|
||||||
from i18nfield.strings import LazyI18nString
|
from i18nfield.strings import LazyI18nString
|
||||||
|
|
||||||
@@ -47,7 +45,6 @@ from pretix.helpers.format import format_map
|
|||||||
|
|
||||||
@app.task(base=ProfiledEventTask, acks_late=True)
|
@app.task(base=ProfiledEventTask, acks_late=True)
|
||||||
def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict, objects: list, items: list,
|
def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict, objects: list, items: list,
|
||||||
subevent: int, subevents_from: datetime, subevents_to: datetime,
|
|
||||||
recipients: str, filter_checkins: bool, not_checked_in: bool, checkin_lists: list,
|
recipients: str, filter_checkins: bool, not_checked_in: bool, checkin_lists: list,
|
||||||
attachments: list = None, attach_tickets: bool = False,
|
attachments: list = None, attach_tickets: bool = False,
|
||||||
attach_ical: bool = False) -> None:
|
attach_ical: bool = False) -> None:
|
||||||
@@ -79,7 +76,7 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
|
|||||||
list_id__in=checkin_lists or []
|
list_id__in=checkin_lists or []
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
).prefetch_related('addons', 'subevent'):
|
).prefetch_related('addons'):
|
||||||
if p.addon_to_id is not None:
|
if p.addon_to_id is not None:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -102,15 +99,6 @@ def send_mails_to_orders(event: Event, user: int, subject: dict, message: dict,
|
|||||||
if p.attendee_email == o.email and send_to_order:
|
if p.attendee_email == o.email and send_to_order:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if subevent and p.subevent_id != subevent:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if subevents_from and p.subevent.date_from < subevents_from:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if subevents_to and p.subevent.date_from >= subevents_to:
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with language(o.locale, event.settings.region):
|
with language(o.locale, event.settings.region):
|
||||||
email_context = get_email_context(event=event, order=o, invoice_address=ia, position=p)
|
email_context = get_email_context(event=event, order=o, invoice_address=ia, position=p)
|
||||||
|
|||||||
@@ -429,9 +429,6 @@ class OrderSendView(BaseSenderView):
|
|||||||
kwargs.update({
|
kwargs.update({
|
||||||
'recipients': form.cleaned_data['recipients'],
|
'recipients': form.cleaned_data['recipients'],
|
||||||
'items': [i.pk for i in form.cleaned_data.get('items')],
|
'items': [i.pk for i in form.cleaned_data.get('items')],
|
||||||
'subevent': form.cleaned_data['subevent'].pk if form.cleaned_data.get('subevent') else None,
|
|
||||||
'subevents_from': form.cleaned_data.get('subevents_from'),
|
|
||||||
'subevents_to': form.cleaned_data.get('subevents_to'),
|
|
||||||
'not_checked_in': form.cleaned_data.get('not_checked_in'),
|
'not_checked_in': form.cleaned_data.get('not_checked_in'),
|
||||||
'checkin_lists': [i.pk for i in form.cleaned_data.get('checkin_lists')],
|
'checkin_lists': [i.pk for i in form.cleaned_data.get('checkin_lists')],
|
||||||
'filter_checkins': form.cleaned_data.get('filter_checkins'),
|
'filter_checkins': form.cleaned_data.get('filter_checkins'),
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ from django.views.generic.base import TemplateResponseMixin
|
|||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
from pretix.base.models import Customer, Membership, Order
|
from pretix.base.models import Customer, Membership, Order
|
||||||
from pretix.base.models.items import ItemAddOn, ItemVariation, Question
|
from pretix.base.models.items import Question
|
||||||
from pretix.base.models.orders import (
|
from pretix.base.models.orders import (
|
||||||
InvoiceAddress, OrderPayment, QuestionAnswer,
|
InvoiceAddress, OrderPayment, QuestionAnswer,
|
||||||
)
|
)
|
||||||
@@ -486,33 +486,9 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep):
|
|||||||
label = pgettext_lazy('checkoutflow', 'Add-on products')
|
label = pgettext_lazy('checkoutflow', 'Add-on products')
|
||||||
icon = 'puzzle-piece'
|
icon = 'puzzle-piece'
|
||||||
|
|
||||||
def _is_applicable(self, request):
|
|
||||||
categories = set(ItemAddOn.objects.filter(
|
|
||||||
base_item_id__in=get_cart(request).values_list("item_id", flat=True)
|
|
||||||
).values_list("addon_category_id", flat=True))
|
|
||||||
if not categories:
|
|
||||||
return False
|
|
||||||
|
|
||||||
has_available_addons = (
|
|
||||||
self.event.items.filter_available(
|
|
||||||
channel=request.sales_channel,
|
|
||||||
allow_addons=True
|
|
||||||
).filter(
|
|
||||||
variations__isnull=True,
|
|
||||||
category__in=categories,
|
|
||||||
).exists() or ItemVariation.objects.filter_available(
|
|
||||||
channel=request.sales_channel,
|
|
||||||
allow_addons=True
|
|
||||||
).filter(
|
|
||||||
item__event=self.event,
|
|
||||||
item__category__in=categories,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return has_available_addons
|
|
||||||
|
|
||||||
def is_applicable(self, request):
|
def is_applicable(self, request):
|
||||||
if not hasattr(request, '_checkoutflow_addons_applicable'):
|
if not hasattr(request, '_checkoutflow_addons_applicable'):
|
||||||
request._checkoutflow_addons_applicable = self._is_applicable(request)
|
request._checkoutflow_addons_applicable = get_cart(request).filter(item__addons__isnull=False).exists()
|
||||||
return request._checkoutflow_addons_applicable
|
return request._checkoutflow_addons_applicable
|
||||||
|
|
||||||
def is_completed(self, request, warn=False):
|
def is_completed(self, request, warn=False):
|
||||||
|
|||||||
@@ -263,8 +263,6 @@ def get_grouped_items(event, *, channel: SalesChannel, subevent=None, voucher=No
|
|||||||
|
|
||||||
quotas_to_compute = []
|
quotas_to_compute = []
|
||||||
for item in items:
|
for item in items:
|
||||||
assert item.event_id == event.pk
|
|
||||||
item.event = event # save a database query if this is looked up
|
|
||||||
if item.has_variations:
|
if item.has_variations:
|
||||||
for v in item.available_variations:
|
for v in item.available_variations:
|
||||||
for q in v._subevent_quotas:
|
for q in v._subevent_quotas:
|
||||||
|
|||||||
@@ -406,79 +406,6 @@ def test_sendmail_attendee_product_filter(logged_in_client, sendmail_url, event,
|
|||||||
assert '/order/' not in djmail.outbox[0].body
|
assert '/order/' not in djmail.outbox[0].body
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_sendmail_attendee_subevent_filter(logged_in_client, sendmail_url, event, item, order, pos):
|
|
||||||
event.settings.attendee_emails_asked = True
|
|
||||||
event.has_subevents = True
|
|
||||||
event.save()
|
|
||||||
with scopes_disabled():
|
|
||||||
se1 = event.subevents.create(name='Subevent FOO', date_from=now())
|
|
||||||
se2 = event.subevents.create(name='Bar', date_from=now())
|
|
||||||
pos.attendee_email = 'attendee1@dummy.test'
|
|
||||||
pos.subevent = se1
|
|
||||||
pos.save()
|
|
||||||
with scopes_disabled():
|
|
||||||
order.positions.create(
|
|
||||||
item=item, price=0, attendee_email='attendee2@dummy.test', subevent=se2
|
|
||||||
)
|
|
||||||
|
|
||||||
djmail.outbox = []
|
|
||||||
response = logged_in_client.post(sendmail_url + 'orders/',
|
|
||||||
{'sendto': 'na',
|
|
||||||
'action': 'send',
|
|
||||||
'recipients': 'attendees',
|
|
||||||
'items': item.pk,
|
|
||||||
'subject_0': 'Test subject',
|
|
||||||
'message_0': 'This is a test file for sending mails.',
|
|
||||||
'subevent': se2.pk,
|
|
||||||
},
|
|
||||||
follow=True)
|
|
||||||
assert response.status_code == 200
|
|
||||||
assert 'alert-success' in response.rendered_content
|
|
||||||
assert len(djmail.outbox) == 1
|
|
||||||
assert djmail.outbox[0].to == ['attendee2@dummy.test']
|
|
||||||
assert '/ticket/' in djmail.outbox[0].body
|
|
||||||
assert '/order/' not in djmail.outbox[0].body
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
|
||||||
def test_sendmail_attendee_subevent_range_filter(logged_in_client, sendmail_url, event, item, order, pos):
|
|
||||||
event.settings.attendee_emails_asked = True
|
|
||||||
event.has_subevents = True
|
|
||||||
event.save()
|
|
||||||
with scopes_disabled():
|
|
||||||
se1 = event.subevents.create(name='Subevent FOO', date_from=datetime.datetime(2023, 7, 6, 1, 2, 3, tzinfo=event.timezone))
|
|
||||||
se2 = event.subevents.create(name='Bar', date_from=datetime.datetime(2023, 8, 9, 1, 2, 3, tzinfo=event.timezone))
|
|
||||||
pos.attendee_email = 'attendee1@dummy.test'
|
|
||||||
pos.subevent = se1
|
|
||||||
pos.save()
|
|
||||||
with scopes_disabled():
|
|
||||||
order.positions.create(
|
|
||||||
item=item, price=0, attendee_email='attendee2@dummy.test', subevent=se2
|
|
||||||
)
|
|
||||||
|
|
||||||
djmail.outbox = []
|
|
||||||
response = logged_in_client.post(sendmail_url + 'orders/',
|
|
||||||
{'sendto': 'na',
|
|
||||||
'action': 'send',
|
|
||||||
'recipients': 'attendees',
|
|
||||||
'items': item.pk,
|
|
||||||
'subject_0': 'Test subject',
|
|
||||||
'message_0': 'This is a test file for sending mails.',
|
|
||||||
'subevents_from_0': '2023-07-01',
|
|
||||||
'subevents_from_1': '00:00:00',
|
|
||||||
'subevents_to_0': '2023-08-01',
|
|
||||||
'subevents_to_1': '00:00:00',
|
|
||||||
},
|
|
||||||
follow=True)
|
|
||||||
assert response.status_code == 200
|
|
||||||
assert 'alert-success' in response.rendered_content
|
|
||||||
assert len(djmail.outbox) == 1
|
|
||||||
assert djmail.outbox[0].to == ['attendee1@dummy.test']
|
|
||||||
assert '/ticket/' in djmail.outbox[0].body
|
|
||||||
assert '/order/' not in djmail.outbox[0].body
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_sendmail_attendee_checkin_filter(logged_in_client, sendmail_url, event, order, checkin_list, item, pos):
|
def test_sendmail_attendee_checkin_filter(logged_in_client, sendmail_url, event, order, checkin_list, item, pos):
|
||||||
event.settings.attendee_emails_asked = True
|
event.settings.attendee_emails_asked = True
|
||||||
|
|||||||
Reference in New Issue
Block a user