forked from CGM_Public/pretix_original
Event calendar: Respect voucher for availability (#3351)
This commit is contained in:
@@ -290,19 +290,19 @@ class EventMixin:
|
||||
return safe_string(json.dumps(eventdict))
|
||||
|
||||
@classmethod
|
||||
def annotated(cls, qs, channel='web'):
|
||||
def annotated(cls, qs, channel='web', voucher=None):
|
||||
from pretix.base.models import Item, ItemVariation, Quota
|
||||
|
||||
sq_active_item = Item.objects.using(settings.DATABASE_REPLICA).filter_available(channel=channel).filter(
|
||||
sq_active_item = Item.objects.using(settings.DATABASE_REPLICA).filter_available(channel=channel, voucher=voucher).filter(
|
||||
Q(variations__isnull=True)
|
||||
& Q(quotas__pk=OuterRef('pk'))
|
||||
).order_by().values_list('quotas__pk').annotate(
|
||||
items=GroupConcat('pk', delimiter=',')
|
||||
).values('items')
|
||||
sq_active_variation = ItemVariation.objects.filter(
|
||||
|
||||
q_variation = (
|
||||
Q(active=True)
|
||||
& Q(sales_channels__contains=channel)
|
||||
& Q(hide_without_voucher=False)
|
||||
& Q(Q(available_from__isnull=True) | Q(available_from__lte=now()))
|
||||
& Q(Q(available_until__isnull=True) | Q(available_until__gte=now()))
|
||||
& Q(item__active=True)
|
||||
@@ -310,10 +310,23 @@ class EventMixin:
|
||||
& Q(Q(item__available_until__isnull=True) | Q(item__available_until__gte=now()))
|
||||
& Q(Q(item__category__isnull=True) | Q(item__category__is_addon=False))
|
||||
& Q(item__sales_channels__contains=channel)
|
||||
& Q(item__hide_without_voucher=False)
|
||||
& Q(item__require_bundling=False)
|
||||
& Q(quotas__pk=OuterRef('pk'))
|
||||
).order_by().values_list('quotas__pk').annotate(
|
||||
)
|
||||
|
||||
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=',')
|
||||
).values('items')
|
||||
quota_base_qs = Quota.objects.using(settings.DATABASE_REPLICA).filter(
|
||||
@@ -1133,8 +1146,8 @@ class Event(EventMixin, LoggedModel):
|
||||
irs = self.get_invoice_renderers()
|
||||
return irs[self.settings.invoice_renderer]
|
||||
|
||||
def subevents_annotated(self, channel):
|
||||
return SubEvent.annotated(self.subevents, channel)
|
||||
def subevents_annotated(self, channel, voucher=None):
|
||||
return SubEvent.annotated(self.subevents, channel, voucher)
|
||||
|
||||
def subevents_sorted(self, queryset):
|
||||
ordering = self.settings.get('frontpage_subevent_ordering', default='date_ascending', as_type=str)
|
||||
@@ -1454,10 +1467,10 @@ class SubEvent(EventMixin, LoggedModel):
|
||||
return qs_annotated
|
||||
|
||||
@classmethod
|
||||
def annotated(cls, qs, channel='web'):
|
||||
def annotated(cls, qs, channel='web', voucher=None):
|
||||
from .items import SubEventItem, SubEventItemVariation
|
||||
|
||||
qs = super().annotated(qs, channel)
|
||||
qs = super().annotated(qs, channel, voucher=voucher)
|
||||
qs = qs.annotate(
|
||||
disabled_items=Coalesce(
|
||||
Subquery(
|
||||
|
||||
@@ -597,7 +597,13 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
|
||||
ebd = defaultdict(list)
|
||||
add_subevents_for_days(
|
||||
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request),
|
||||
filter_qs_by_attr(
|
||||
self.request.event.subevents_annotated(
|
||||
self.request.sales_channel.identifier,
|
||||
voucher,
|
||||
).using(settings.DATABASE_REPLICA),
|
||||
self.request
|
||||
),
|
||||
limit_before, after, ebd, set(), self.request.event,
|
||||
self.kwargs.get('cart_namespace'),
|
||||
voucher,
|
||||
@@ -649,7 +655,13 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
|
||||
ebd = defaultdict(list)
|
||||
add_subevents_for_days(
|
||||
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request),
|
||||
filter_qs_by_attr(
|
||||
self.request.event.subevents_annotated(
|
||||
self.request.sales_channel.identifier,
|
||||
voucher=voucher,
|
||||
).using(settings.DATABASE_REPLICA),
|
||||
self.request
|
||||
),
|
||||
limit_before, after, ebd, set(), self.request.event,
|
||||
self.kwargs.get('cart_namespace'),
|
||||
voucher,
|
||||
@@ -692,7 +704,13 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
)
|
||||
else:
|
||||
context['subevent_list'] = self.request.event.subevents_sorted(
|
||||
filter_qs_by_attr(self.request.event.subevents_annotated(self.request.sales_channel.identifier).using(settings.DATABASE_REPLICA), self.request)
|
||||
filter_qs_by_attr(
|
||||
self.request.event.subevents_annotated(
|
||||
self.request.sales_channel.identifier,
|
||||
voucher=voucher,
|
||||
).using(settings.DATABASE_REPLICA),
|
||||
self.request
|
||||
)
|
||||
)
|
||||
if self.request.event.settings.event_list_available_only and not voucher:
|
||||
context['subevent_list'] = [
|
||||
|
||||
@@ -2206,6 +2206,44 @@ class EventTest(TestCase):
|
||||
q.items.add(item)
|
||||
assert Event.annotated(Event.objects).first().active_quotas == []
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_active_quotas_annotation_product_hidden_by_voucher(self):
|
||||
event = Event.objects.create(
|
||||
organizer=self.organizer, name='Download', slug='download',
|
||||
date_from=now()
|
||||
)
|
||||
q = Quota.objects.create(event=event, name='Quota', size=2)
|
||||
item = Item.objects.create(event=event, name='Early-bird ticket', default_price=0, hide_without_voucher=True)
|
||||
q.items.add(item)
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='a', item=item, show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q]
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='b', item=item, show_hidden_items=False)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == []
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='c', show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q]
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='d', quota=q, show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q]
|
||||
|
||||
item2 = Item.objects.create(event=event, name='Early-bird ticket', default_price=0)
|
||||
var = item2.variations.create(item=item2, value='Test', hide_without_voucher=True)
|
||||
var2 = item2.variations.create(item=item2, value='Other test', hide_without_voucher=True, active=False)
|
||||
q.items.remove(item)
|
||||
q.items.add(item2)
|
||||
q.variations.add(var)
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='e', item=item2, variation=var, show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q]
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='f', item=item2, variation=var2, show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == []
|
||||
|
||||
voucher = Voucher.objects.create(event=event, code='g', quota=q, show_hidden_items=True)
|
||||
assert Event.annotated(Event.objects, voucher=voucher).first().active_quotas == [q]
|
||||
|
||||
@classscope(attr='organizer')
|
||||
def test_active_quotas_annotation_product_addon(self):
|
||||
event = Event.objects.create(
|
||||
|
||||
Reference in New Issue
Block a user