mirror of
https://github.com/pretix/pretix.git
synced 2025-12-05 21:32:28 +00:00
Compare commits
1 Commits
show-curre
...
subevent-e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df656d1580 |
@@ -313,38 +313,9 @@ class EventMixin:
|
||||
items=GroupConcat('pk', delimiter=',')
|
||||
).values('items')
|
||||
|
||||
q_variation = (
|
||||
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)
|
||||
& 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(
|
||||
sq_active_variation = ItemVariation.objects.filter_available(channel=channel, voucher=voucher).filter(
|
||||
Q(quotas__pk=OuterRef('pk'))
|
||||
).order_by().values_list('quotas__pk').annotate(
|
||||
items=GroupConcat('pk', delimiter=',')
|
||||
).values('items')
|
||||
quota_base_qs = Quota.objects.using(settings.DATABASE_REPLICA).filter(
|
||||
|
||||
@@ -303,6 +303,48 @@ def filter_available(qs, channel='web', voucher=None, allow_addons=False):
|
||||
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):
|
||||
def filter_available(self, channel='web', voucher=None, allow_addons=False):
|
||||
return filter_available(self, channel, voucher, allow_addons)
|
||||
@@ -317,6 +359,20 @@ class ItemQuerySetManager(ScopedManager(organizer='event__organizer').__class__)
|
||||
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):
|
||||
"""
|
||||
An item is a thing which can be sold. It belongs to an event and may or may not belong to a category.
|
||||
@@ -1199,7 +1255,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.')
|
||||
)
|
||||
|
||||
objects = ScopedManager(organizer='item__event__organizer')
|
||||
objects = ItemVariationQuerySetManager()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Product variation")
|
||||
|
||||
@@ -56,7 +56,7 @@ from django.views.generic.base import TemplateResponseMixin
|
||||
from django_scopes import scopes_disabled
|
||||
|
||||
from pretix.base.models import Customer, Membership, Order
|
||||
from pretix.base.models.items import Question
|
||||
from pretix.base.models.items import ItemAddOn, ItemVariation, Question
|
||||
from pretix.base.models.orders import (
|
||||
InvoiceAddress, OrderPayment, QuestionAnswer,
|
||||
)
|
||||
@@ -486,9 +486,33 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep):
|
||||
label = pgettext_lazy('checkoutflow', 'Add-on products')
|
||||
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):
|
||||
if not hasattr(request, '_checkoutflow_addons_applicable'):
|
||||
request._checkoutflow_addons_applicable = get_cart(request).filter(item__addons__isnull=False).exists()
|
||||
request._checkoutflow_addons_applicable = self._is_applicable(request)
|
||||
return request._checkoutflow_addons_applicable
|
||||
|
||||
def is_completed(self, request, warn=False):
|
||||
|
||||
Reference in New Issue
Block a user