forked from CGM_Public/pretix_original
Add signal validate_cart_addons
This commit is contained in:
@@ -20,7 +20,7 @@ Order events
|
||||
There are multiple signals that will be sent out in the ordering cycle:
|
||||
|
||||
.. automodule:: pretix.base.signals
|
||||
:members: validate_cart, validate_order, order_fee_calculation, order_paid, order_placed, order_canceled, order_expired, order_modified, order_changed, order_approved, order_denied, order_fee_type_name, allow_ticket_download
|
||||
:members: validate_cart, validate_cart_addons, validate_order, order_fee_calculation, order_paid, order_placed, order_canceled, order_expired, order_modified, order_changed, order_approved, order_denied, order_fee_type_name, allow_ticket_download
|
||||
|
||||
Frontend
|
||||
--------
|
||||
|
||||
@@ -85,8 +85,14 @@ Use case: Conference with workshops
|
||||
|
||||
When running a conference, you might also organize a number of workshops with smaller capacity. To be able to plan, it would be great to know which workshops an attendee plans to attend.
|
||||
|
||||
Option A: Questions
|
||||
"""""""""""""""""""
|
||||
|
||||
Your first and simplest option is to just create a multiple-choice question. This has the upside of making it easy for users to change their mind later on, but will not allow you to restrict the number of attendees signing up for a given workshop – or even charge extra for a given workshop.
|
||||
|
||||
Option B: Add-on products with fixed time slots
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
The usually better option is to go with add-on products. Let's take for example the following conference schedule, in which the lecture can be attended by anyone, but the workshops only have space for 20 persons each:
|
||||
|
||||
==================== =================================== ===================================
|
||||
@@ -117,6 +123,28 @@ Assuming you already created one or more products for your general conference ad
|
||||
|
||||
* One add-on configuration on your base product that allows users to choose between 0 and 2 products from the category "Workshops"
|
||||
|
||||
Option C: Add-on products with variable time slots
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
The above option only works if your conference uses fixed timeslots and every workshop uses exactly one timeslot. If
|
||||
your schedule looks like this, it's not going to work great:
|
||||
|
||||
+------------+------------+-----------+
|
||||
| Time | Room A | Room B |
|
||||
+============+============+===========+
|
||||
| body row 1 | column 2 | column 3 |
|
||||
+------------+------------+-----------+
|
||||
| body row 2 | Cells may span columns.|
|
||||
+------------+------------+-----------+
|
||||
| body row 3 | Cells may | - Cells |
|
||||
+------------+ span rows. | - contain |
|
||||
| body row 4 | | - blocks. |
|
||||
+------------+------------+-----------+
|
||||
|
||||
**This option is currently only available on pretix Hosted. If you are interested in using it with pretix Enterprise,
|
||||
please contact sales@pretix.eu.**
|
||||
|
||||
|
||||
Use case: Discounted packages
|
||||
-----------------------------
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ from pretix.base.services.locking import LockTimeoutException, NoLockManager
|
||||
from pretix.base.services.pricing import get_price
|
||||
from pretix.base.services.tasks import ProfiledEventTask
|
||||
from pretix.base.settings import PERSON_NAME_SCHEMES
|
||||
from pretix.base.signals import validate_cart_addons
|
||||
from pretix.base.templatetags.rich_text import rich_text
|
||||
from pretix.celery_app import app
|
||||
from pretix.presale.signals import (
|
||||
@@ -643,6 +644,15 @@ class CartManager:
|
||||
'cat': str(iao.addon_category.name),
|
||||
}
|
||||
)
|
||||
validate_cart_addons.send(
|
||||
sender=self.event,
|
||||
addons={
|
||||
(self._items_cache[s[0]], self._variations_cache[s[1]] if s[1] else None)
|
||||
for s in selected
|
||||
},
|
||||
base_position=cp,
|
||||
iao=iao
|
||||
)
|
||||
|
||||
# Detect removed add-ons and create RemoveOperations
|
||||
for cp, al in current_addons.items():
|
||||
|
||||
@@ -265,6 +265,21 @@ appropriate exception message.
|
||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
||||
"""
|
||||
|
||||
validate_cart_addons = EventPluginSignal(
|
||||
providing_args=["addons", "base_position", "iao"]
|
||||
)
|
||||
"""
|
||||
This signal is sent when a user tries to select a combination of addons. In contrast to
|
||||
``validate_cart``, this is executed before the cart is actually modified. You are passed
|
||||
an argument ``addons`` containing a set of ``(item, variation or None)`` tuples as well
|
||||
as the ``ItemAddOn`` object as the argument ``iao`` and the base cart position as
|
||||
``base_position``.
|
||||
The response of receivers will be ignored, but you can raise a CartError with an
|
||||
appropriate exception message.
|
||||
|
||||
As with all event-plugin signals, the ``sender`` keyword argument will contain the event.
|
||||
"""
|
||||
|
||||
order_placed = EventPluginSignal(
|
||||
providing_args=["order"]
|
||||
)
|
||||
|
||||
@@ -239,6 +239,7 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep):
|
||||
'form': AddOnsForm(
|
||||
event=self.request.event,
|
||||
prefix='{}_{}'.format(cartpos.pk, iao.addon_category.pk),
|
||||
base_position=cartpos,
|
||||
iao=iao,
|
||||
price_included=iao.price_included,
|
||||
initial=current_addon_products,
|
||||
|
||||
@@ -14,7 +14,8 @@ from pretix.base.forms.questions import (
|
||||
)
|
||||
from pretix.base.models import ItemVariation
|
||||
from pretix.base.models.tax import TAXED_ZERO
|
||||
from pretix.base.services.cart import error_messages
|
||||
from pretix.base.services.cart import CartError, error_messages
|
||||
from pretix.base.signals import validate_cart_addons
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
from pretix.base.templatetags.rich_text import rich_text
|
||||
from pretix.base.validators import EmailBlacklistValidator
|
||||
@@ -205,13 +206,14 @@ class AddOnsForm(forms.Form):
|
||||
"""
|
||||
self.iao = kwargs.pop('iao')
|
||||
category = self.iao.addon_category
|
||||
event = kwargs.pop('event')
|
||||
self.event = kwargs.pop('event')
|
||||
subevent = kwargs.pop('subevent')
|
||||
current_addons = kwargs.pop('initial')
|
||||
quota_cache = kwargs.pop('quota_cache')
|
||||
item_cache = kwargs.pop('item_cache')
|
||||
self.price_included = kwargs.pop('price_included')
|
||||
self.sales_channel = kwargs.pop('sales_channel')
|
||||
self.base_position = kwargs.pop('base_position')
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
@@ -231,12 +233,12 @@ class AddOnsForm(forms.Form):
|
||||
).select_related('tax_rule').prefetch_related(
|
||||
Prefetch('quotas',
|
||||
to_attr='_subevent_quotas',
|
||||
queryset=event.quotas.filter(subevent=subevent)),
|
||||
queryset=self.event.quotas.filter(subevent=subevent)),
|
||||
Prefetch('variations', to_attr='available_variations',
|
||||
queryset=ItemVariation.objects.filter(active=True, quotas__isnull=False).prefetch_related(
|
||||
Prefetch('quotas',
|
||||
to_attr='_subevent_quotas',
|
||||
queryset=event.quotas.filter(subevent=subevent))
|
||||
queryset=self.event.quotas.filter(subevent=subevent))
|
||||
).distinct()),
|
||||
'event'
|
||||
).annotate(
|
||||
@@ -260,7 +262,7 @@ class AddOnsForm(forms.Form):
|
||||
self.vars_cache[v.pk] = v
|
||||
choices.append(
|
||||
(v.pk,
|
||||
self._label(event, v, cached_availability,
|
||||
self._label(self.event, v, cached_availability,
|
||||
override_price=var_price_override.get(v.pk)),
|
||||
v.description)
|
||||
)
|
||||
@@ -294,7 +296,7 @@ class AddOnsForm(forms.Form):
|
||||
continue
|
||||
cached_availability = i.check_quotas(subevent=subevent, _cache=quota_cache)
|
||||
field = forms.BooleanField(
|
||||
label=self._label(event, i, cached_availability,
|
||||
label=self._label(self.event, i, cached_availability,
|
||||
override_price=item_price_override.get(i.pk)),
|
||||
required=False,
|
||||
initial=i.pk in current_addons,
|
||||
@@ -333,3 +335,8 @@ class AddOnsForm(forms.Form):
|
||||
'cat': str(self.iao.addon_category.name),
|
||||
}
|
||||
)
|
||||
try:
|
||||
validate_cart_addons.send(sender=self.event, addons=selected, base_position=self.base_position,
|
||||
iao=self.iao)
|
||||
except CartError as e:
|
||||
raise ValidationError(str(e))
|
||||
|
||||
Reference in New Issue
Block a user