forked from CGM_Public/pretix_original
New implementation of sales channels (#4111)
Co-authored-by: Martin Gross <gross@rami.io>
This commit is contained in:
@@ -249,7 +249,7 @@ class CustomerStep(CartMixin, TemplateFlowStep):
|
||||
icon = 'user'
|
||||
|
||||
def is_applicable(self, request):
|
||||
return request.organizer.settings.customer_accounts and request.sales_channel.customer_accounts_supported
|
||||
return request.organizer.settings.customer_accounts and request.sales_channel.type_instance.customer_accounts_supported
|
||||
|
||||
@cached_property
|
||||
def login_form(self):
|
||||
@@ -539,7 +539,7 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep):
|
||||
self.request.event,
|
||||
subevent=cartpos.subevent,
|
||||
voucher=None,
|
||||
channel=self.request.sales_channel.identifier,
|
||||
channel=self.request.sales_channel,
|
||||
base_qs=iao.addon_category.items,
|
||||
allow_addons=True,
|
||||
quota_cache=quota_cache,
|
||||
@@ -935,7 +935,7 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
|
||||
event=self.request.event,
|
||||
cart_id=get_or_create_cart_id(request),
|
||||
invoice_address=addr,
|
||||
sales_channel=request.sales_channel.identifier,
|
||||
sales_channel=request.sales_channel,
|
||||
)
|
||||
diff = cm.recompute_final_prices_and_taxes()
|
||||
except TaxRule.SaleNotAllowed:
|
||||
|
||||
@@ -51,7 +51,10 @@ class WaitingListForm(forms.ModelForm):
|
||||
('', '')
|
||||
]
|
||||
items, display_add_to_cart = get_grouped_items(
|
||||
self.event, self.instance.subevent, require_seat=None,
|
||||
self.event,
|
||||
subevent=self.instance.subevent,
|
||||
require_seat=None,
|
||||
channel=self.event.organizer.sales_channels.get(identifier="web"),
|
||||
memberships=(
|
||||
customer.usable_memberships(
|
||||
for_event=self.instance.subevent or self.event,
|
||||
|
||||
@@ -36,7 +36,6 @@ from django.template.response import TemplateResponse
|
||||
from django.urls import resolve
|
||||
from django_scopes import scope
|
||||
|
||||
from pretix.base.channels import WebshopSalesChannel
|
||||
from pretix.base.timemachine import time_machine_now_assigned_from_request
|
||||
from pretix.presale.signals import process_response
|
||||
|
||||
@@ -57,10 +56,6 @@ class EventMiddleware:
|
||||
url = resolve(request.path_info)
|
||||
request._namespace = url.namespace
|
||||
|
||||
if not hasattr(request, 'sales_channel'):
|
||||
# The environ lookup is only relevant during unit testing
|
||||
request.sales_channel = request.environ.get('PRETIX_SALES_CHANNEL', WebshopSalesChannel())
|
||||
|
||||
if url.namespace != 'presale':
|
||||
return self.get_response(request)
|
||||
|
||||
@@ -71,6 +66,12 @@ class EventMiddleware:
|
||||
|
||||
with scope(organizer=getattr(request, 'organizer', None)), \
|
||||
time_machine_now_assigned_from_request(request):
|
||||
if not hasattr(request, 'sales_channel') and hasattr(request, 'organizer'):
|
||||
# The environ lookup is only relevant during unit testing
|
||||
request.sales_channel = request.organizer.sales_channels.get(
|
||||
identifier=request.environ.get('PRETIX_SALES_CHANNEL', 'web')
|
||||
)
|
||||
|
||||
response = self.get_response(request)
|
||||
|
||||
if hasattr(request, '_namespace') and request._namespace == 'presale' and hasattr(request, 'event'):
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
{% if request.event.testmode %}
|
||||
{% if request.sales_channel.testmode_supported %}
|
||||
{% if request.sales_channel.type_instance.testmode_supported %}
|
||||
<div class="alert alert-warning">
|
||||
<p><strong>
|
||||
<span class="sr-only">{% trans "Warning" context "alert-messages" %}:</span>
|
||||
@@ -194,7 +194,7 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if request.event.testmode %}
|
||||
{% if request.sales_channel.testmode_supported %}
|
||||
{% if request.sales_channel.type_instance.testmode_supported %}
|
||||
<div class="alert alert-testmode alert-warning">
|
||||
<p><strong>
|
||||
<span class="sr-only">{% trans "Warning" context "alert-messages" %}:</span>
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
<div class="alert alert-info">
|
||||
<p>{{ p.provider.test_mode_message }}</p>
|
||||
</div>
|
||||
{% if not request.sales_channel.testmode_supported %}
|
||||
{% if not request.sales_channel.type_instance.testmode_supported %}
|
||||
<div class="alert alert-danger">
|
||||
<p>
|
||||
{% trans "This sales channel does not provide support for test mode." %}
|
||||
|
||||
@@ -415,6 +415,12 @@ def _event_view(function=None, require_live=True, require_plugin=None):
|
||||
else:
|
||||
with scope(organizer=getattr(request, 'organizer', None)), \
|
||||
time_machine_now_assigned_from_request(request):
|
||||
if not hasattr(request, 'sales_channel') and hasattr(request, 'organizer'):
|
||||
# The environ lookup is only relevant during unit testing
|
||||
request.sales_channel = request.organizer.sales_channels.get(
|
||||
identifier=request.environ.get('PRETIX_SALES_CHANNEL', 'web')
|
||||
)
|
||||
|
||||
response = func(request=request, *args, **kwargs)
|
||||
if getattr(request, 'event', None):
|
||||
for receiver, r in process_response.send(request.event, request=request, response=response):
|
||||
|
||||
@@ -515,7 +515,7 @@ class CartAdd(EventViewMixin, CartActionMixin, AsyncAction, View):
|
||||
return u
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
if request.sales_channel.identifier not in request.event.sales_channels:
|
||||
if not request.event.all_sales_channels and request.sales_channel.identifier not in (s.identifier for s in request.event.limit_sales_channels.all()):
|
||||
raise Http404(_('Tickets for this event cannot be purchased on this sales channel.'))
|
||||
|
||||
cart_id = get_or_create_cart_id(self.request)
|
||||
@@ -564,9 +564,9 @@ class RedeemView(NoSearchIndexViewMixin, EventViewMixin, CartMixin, TemplateView
|
||||
# Fetch all items
|
||||
items, display_add_to_cart = get_grouped_items(
|
||||
self.request.event,
|
||||
self.subevent,
|
||||
subevent=self.subevent,
|
||||
voucher=self.voucher,
|
||||
channel=self.request.sales_channel.identifier,
|
||||
channel=self.request.sales_channel,
|
||||
memberships=(
|
||||
self.request.customer.usable_memberships(
|
||||
for_event=self.subevent or self.request.event,
|
||||
|
||||
@@ -63,10 +63,9 @@ from django.views import View
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from pretix.base.channels import get_all_sales_channels
|
||||
from pretix.base.forms.widgets import SplitDateTimePickerWidget
|
||||
from pretix.base.models import (
|
||||
ItemVariation, Quota, SeatCategoryMapping, Voucher,
|
||||
ItemVariation, Quota, SalesChannel, SeatCategoryMapping, Voucher,
|
||||
)
|
||||
from pretix.base.models.event import Event, SubEvent
|
||||
from pretix.base.models.items import (
|
||||
@@ -110,7 +109,7 @@ def item_group_by_category(items):
|
||||
)
|
||||
|
||||
|
||||
def get_grouped_items(event, subevent=None, voucher=None, channel='web', require_seat=0, base_qs=None, allow_addons=False,
|
||||
def get_grouped_items(event, *, channel: SalesChannel, subevent=None, voucher=None, require_seat=0, base_qs=None, allow_addons=False,
|
||||
quota_cache=None, filter_items=None, filter_categories=None, memberships=None,
|
||||
ignore_hide_sold_out_for_item_ids=None):
|
||||
base_qs_set = base_qs is not None
|
||||
@@ -152,8 +151,8 @@ def get_grouped_items(event, subevent=None, voucher=None, channel='web', require
|
||||
),
|
||||
).filter(
|
||||
variation_q,
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=channel.identifier),
|
||||
active=True,
|
||||
sales_channels__contains=channel,
|
||||
quotas__isnull=False,
|
||||
subevent_disabled=False
|
||||
).prefetch_related(
|
||||
@@ -192,7 +191,7 @@ def get_grouped_items(event, subevent=None, voucher=None, channel='web', require
|
||||
)
|
||||
)
|
||||
|
||||
items = base_qs.using(settings.DATABASE_REPLICA).filter_available(channel=channel, voucher=voucher, allow_addons=allow_addons).select_related(
|
||||
items = base_qs.using(settings.DATABASE_REPLICA).filter_available(channel=channel.identifier, voucher=voucher, allow_addons=allow_addons).select_related(
|
||||
'category', 'tax_rule', # for re-grouping
|
||||
'hidden_if_available',
|
||||
).prefetch_related(
|
||||
@@ -244,7 +243,7 @@ def get_grouped_items(event, subevent=None, voucher=None, channel='web', require
|
||||
items = items.filter(category_id__in=[a for a in filter_categories if a.isdigit()])
|
||||
|
||||
display_add_to_cart = False
|
||||
quota_cache_key = f'item_quota_cache:{subevent.id if subevent else 0}:{channel}:{bool(require_seat)}'
|
||||
quota_cache_key = f'item_quota_cache:{subevent.id if subevent else 0}:{channel.identifier}:{bool(require_seat)}'
|
||||
quota_cache = quota_cache or event.cache.get(quota_cache_key) or {}
|
||||
quota_cache_existed = bool(quota_cache)
|
||||
|
||||
@@ -284,7 +283,7 @@ def get_grouped_items(event, subevent=None, voucher=None, channel='web', require
|
||||
item.available_variations = [v for v in item.available_variations
|
||||
if v.pk == voucher.variation_id]
|
||||
|
||||
if get_all_sales_channels()[channel].unlimited_items_per_order:
|
||||
if channel.type_instance.unlimited_items_per_order:
|
||||
max_per_order = sys.maxsize
|
||||
else:
|
||||
max_per_order = item.max_per_order or int(event.settings.max_items_per_order)
|
||||
@@ -527,7 +526,7 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
r._csp_ignore = True
|
||||
return r
|
||||
|
||||
if request.sales_channel.identifier not in request.event.sales_channels:
|
||||
if not request.event.all_sales_channels and request.sales_channel.identifier not in (s.identifier for s in request.event.limit_sales_channels.all()):
|
||||
raise Http404(_('Tickets for this event cannot be purchased on this sales channel.'))
|
||||
|
||||
if request.event.has_subevents:
|
||||
@@ -565,11 +564,12 @@ class EventIndex(EventViewMixin, EventListMixin, CartMixin, TemplateView):
|
||||
if not self.request.event.has_subevents or self.subevent:
|
||||
# Fetch all items
|
||||
items, display_add_to_cart = get_grouped_items(
|
||||
self.request.event, self.subevent,
|
||||
self.request.event,
|
||||
subevent=self.subevent,
|
||||
filter_items=self.request.GET.getlist('item'),
|
||||
filter_categories=self.request.GET.getlist('category'),
|
||||
require_seat=None,
|
||||
channel=self.request.sales_channel.identifier,
|
||||
channel=self.request.sales_channel,
|
||||
memberships=(
|
||||
self.request.customer.usable_memberships(
|
||||
for_event=self.subevent or self.request.event,
|
||||
|
||||
@@ -705,7 +705,7 @@ class OrderPayChangeMethod(EventViewMixin, OrderDetailMixin, TemplateView):
|
||||
|
||||
def can_generate_invoice(event, order, ignore_payments=False):
|
||||
v = (
|
||||
order.sales_channel in event.settings.get('invoice_generate_sales_channels')
|
||||
order.sales_channel.identifier in event.settings.get('invoice_generate_sales_channels')
|
||||
and (
|
||||
event.settings.get('invoice_generate') in ('user', 'True')
|
||||
or (
|
||||
|
||||
@@ -185,7 +185,7 @@ class EventListMixin:
|
||||
def _get_event_list_queryset(self):
|
||||
query = Q(is_public=True) & Q(live=True)
|
||||
qs = self.request.organizer.events.using(settings.DATABASE_REPLICA).filter(query)
|
||||
qs = qs.filter(sales_channels__contains=self.request.sales_channel.identifier)
|
||||
qs = qs.filter(Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier))
|
||||
qs = qs.annotate(
|
||||
min_from=Min('subevents__date_from'),
|
||||
min_to=Min('subevents__date_to'),
|
||||
@@ -724,13 +724,13 @@ class CalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
|
||||
ctx['has_before'], ctx['has_after'] = has_before_after(
|
||||
self.request.organizer.events.filter(
|
||||
sales_channels__contains=self.request.sales_channel.identifier
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
),
|
||||
SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) | Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
event__sales_channels__contains=self.request.sales_channel.identifier
|
||||
),
|
||||
before,
|
||||
after,
|
||||
@@ -749,13 +749,14 @@ class CalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, 'web').using(
|
||||
settings.DATABASE_REPLICA
|
||||
).filter(
|
||||
sales_channels__contains=self.request.sales_channel.identifier
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
), before, after, ebd, timezones)
|
||||
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
event__sales_channels__contains=self.request.sales_channel.identifier
|
||||
).prefetch_related(
|
||||
Prefetch(
|
||||
'event',
|
||||
@@ -806,13 +807,14 @@ class WeekCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
|
||||
ctx['has_before'], ctx['has_after'] = has_before_after(
|
||||
self.request.organizer.events.filter(
|
||||
sales_channels__contains=self.request.sales_channel.identifier
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
),
|
||||
SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
event__sales_channels__contains=self.request.sales_channel.identifier
|
||||
),
|
||||
before,
|
||||
after,
|
||||
@@ -843,13 +845,14 @@ class WeekCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, 'web').using(
|
||||
settings.DATABASE_REPLICA
|
||||
).filter(
|
||||
sales_channels__contains=self.request.sales_channel.identifier
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
), before, after, ebd, timezones)
|
||||
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
event__sales_channels__contains=self.request.sales_channel.identifier
|
||||
).prefetch_related(
|
||||
Prefetch(
|
||||
'event',
|
||||
@@ -943,13 +946,14 @@ class DayCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
|
||||
ctx['has_before'], ctx['has_after'] = has_before_after(
|
||||
self.request.organizer.events.filter(
|
||||
sales_channels__contains=self.request.sales_channel.identifier
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
),
|
||||
SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
event__sales_channels__contains=self.request.sales_channel.identifier
|
||||
),
|
||||
before,
|
||||
after,
|
||||
@@ -1193,13 +1197,14 @@ class DayCalendarView(OrganizerViewMixin, EventListMixin, TemplateView):
|
||||
add_events_for_days(self.request, Event.annotated(self.request.organizer.events, 'web').using(
|
||||
settings.DATABASE_REPLICA
|
||||
).filter(
|
||||
sales_channels__contains=self.request.sales_channel.identifier
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
), before, after, ebd, timezones)
|
||||
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
event__sales_channels__contains=self.request.sales_channel.identifier
|
||||
).prefetch_related(
|
||||
Prefetch(
|
||||
'event',
|
||||
@@ -1224,10 +1229,10 @@ class OrganizerIcalDownload(OrganizerViewMixin, View):
|
||||
filter_qs_by_attr(
|
||||
self.request.organizer.events.filter(
|
||||
Q(date_from__gt=cutoff) | Q(date_to__gt=cutoff),
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
is_public=True,
|
||||
live=True,
|
||||
has_subevents=False,
|
||||
sales_channels__contains=self.request.sales_channel.identifier,
|
||||
),
|
||||
request
|
||||
).order_by(
|
||||
@@ -1244,12 +1249,13 @@ class OrganizerIcalDownload(OrganizerViewMixin, View):
|
||||
filter_qs_by_attr(
|
||||
SubEvent.objects.filter(
|
||||
Q(date_from__gt=cutoff) | Q(date_to__gt=cutoff),
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
is_public=True,
|
||||
active=True,
|
||||
event__sales_channels__contains=self.request.sales_channel.identifier
|
||||
),
|
||||
request
|
||||
).prefetch_related(
|
||||
|
||||
@@ -274,7 +274,7 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
self.request.event,
|
||||
subevent=self.subevent,
|
||||
voucher=self.voucher,
|
||||
channel=self.request.sales_channel.identifier,
|
||||
channel=self.request.sales_channel,
|
||||
base_qs=qs,
|
||||
require_seat=None,
|
||||
memberships=(
|
||||
@@ -372,7 +372,7 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
'error': gettext('This ticket shop is currently disabled.')
|
||||
})
|
||||
|
||||
if request.sales_channel.identifier not in request.event.sales_channels:
|
||||
if not request.event.all_sales_channels and request.sales_channel.identifier not in (s.identifier for s in request.event.limit_sales_channels.all()):
|
||||
return self.response({
|
||||
'error': gettext('Tickets for this event cannot be purchased on this sales channel.')
|
||||
})
|
||||
@@ -546,7 +546,8 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
add_subevents_for_days(
|
||||
filter_qs_by_attr(
|
||||
self.request.event.subevents_annotated('web').filter(
|
||||
event__sales_channels__contains=self.request.sales_channel.identifier
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
), self.request
|
||||
),
|
||||
limit_before, after, ebd, set(), self.request.event,
|
||||
@@ -558,16 +559,17 @@ class WidgetAPIProductList(EventListMixin, View):
|
||||
self.request,
|
||||
filter_qs_by_attr(
|
||||
Event.annotated(self.request.organizer.events, 'web').filter(
|
||||
sales_channels__contains=self.request.sales_channel.identifier
|
||||
Q(all_sales_channels=True) | Q(limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
), self.request
|
||||
),
|
||||
limit_before, after, ebd, timezones
|
||||
)
|
||||
add_subevents_for_days(filter_qs_by_attr(SubEvent.annotated(SubEvent.objects.filter(
|
||||
Q(event__all_sales_channels=True) |
|
||||
Q(event__limit_sales_channels__identifier=self.request.sales_channel.identifier),
|
||||
event__organizer=self.request.organizer,
|
||||
event__is_public=True,
|
||||
event__live=True,
|
||||
event__sales_channels__contains=self.request.sales_channel.identifier
|
||||
).prefetch_related(
|
||||
'event___settings_objects', 'event__organizer___settings_objects'
|
||||
)), self.request), limit_before, after, ebd, timezones)
|
||||
|
||||
Reference in New Issue
Block a user