Compare commits

..

3 Commits

Author SHA1 Message Date
Mira Weller
9099a38bc8 Use shorter OrderPosition.code 2024-09-24 12:43:48 +02:00
Mira Weller
7cb66879ba Add inline "json_script" as supported data source for select2 2024-09-23 18:47:09 +02:00
Mira Weller
29808ad92d Add full_code property to OrderPosition 2024-09-23 18:47:09 +02:00
65 changed files with 33924 additions and 37331 deletions

View File

@@ -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"

View File

@@ -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

View File

@@ -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(

View File

@@ -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")

View File

@@ -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)

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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'),

View File

@@ -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):

View File

@@ -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:

View File

@@ -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