mirror of
https://github.com/pretix/pretix.git
synced 2026-05-06 15:24:02 +00:00
Allow plugins to disable and pre-fill questions and contact form fields (#1824)
Co-authored-by: Raphael Michel <michel@rami.io> Co-authored-by: Raphael Michel <mail@raphaelmichel.de>
This commit is contained in:
@@ -14,6 +14,7 @@ from pretix.base.models import (
|
||||
CartPosition, InvoiceAddress, OrderPosition, Question, QuestionAnswer,
|
||||
QuestionOption,
|
||||
)
|
||||
from pretix.presale.signals import contact_form_fields_overrides
|
||||
|
||||
|
||||
class BaseQuestionsViewMixin:
|
||||
@@ -34,6 +35,9 @@ class BaseQuestionsViewMixin:
|
||||
def _positions_for_questions(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def get_question_override_sets(self, position):
|
||||
return []
|
||||
|
||||
@cached_property
|
||||
def forms(self):
|
||||
"""
|
||||
@@ -62,6 +66,23 @@ class BaseQuestionsViewMixin:
|
||||
self.request.event.settings.attendee_addresses_asked
|
||||
))
|
||||
)
|
||||
|
||||
override_sets = self.get_question_override_sets(cr)
|
||||
for overrides in override_sets:
|
||||
for question_name, question_field in form.fields.items():
|
||||
if hasattr(question_field, 'question'):
|
||||
if question_field.question.identifier in overrides:
|
||||
if 'initial' in overrides[question_field.question.identifier]:
|
||||
question_field.initial = overrides[question_field.question.identifier]['initial']
|
||||
if 'disabled' in overrides[question_field.question.identifier]:
|
||||
question_field.disabled = overrides[question_field.question.identifier]['disabled']
|
||||
else:
|
||||
if question_name in overrides:
|
||||
if 'initial' in overrides[question_name]:
|
||||
question_field.initial = overrides[question_name]['initial']
|
||||
if 'disabled' in overrides[question_name]:
|
||||
question_field.disabled = overrides[question_name]['disabled']
|
||||
|
||||
if len(form.fields) > 0:
|
||||
formlist.append(form)
|
||||
return formlist
|
||||
@@ -213,24 +234,47 @@ class OrderQuestionsViewMixin(BaseQuestionsViewMixin):
|
||||
self.order.total != Decimal('0.00') or not self.request.event.settings.invoice_address_not_asked_free
|
||||
)
|
||||
|
||||
@cached_property
|
||||
def _contact_override_sets(self):
|
||||
override_sets = [
|
||||
resp for recv, resp in contact_form_fields_overrides.send(
|
||||
self.request.event,
|
||||
request=self.request,
|
||||
order=self.order,
|
||||
)
|
||||
]
|
||||
for override in override_sets:
|
||||
for k in override:
|
||||
# We don't want initial values to be modified, they should come from the order directly
|
||||
override[k].pop('initial', None)
|
||||
return override_sets
|
||||
|
||||
@cached_property
|
||||
def invoice_form(self):
|
||||
if not self.address_asked and self.request.event.settings.invoice_name_required:
|
||||
return self.invoice_name_form_class(
|
||||
f = self.invoice_name_form_class(
|
||||
data=self.request.POST if self.request.method == "POST" else None,
|
||||
event=self.request.event,
|
||||
instance=self.invoice_address, validate_vat_id=False,
|
||||
all_optional=self.all_optional
|
||||
)
|
||||
if self.address_asked:
|
||||
return self.invoice_form_class(
|
||||
elif self.address_asked:
|
||||
f = self.invoice_form_class(
|
||||
data=self.request.POST if self.request.method == "POST" else None,
|
||||
event=self.request.event,
|
||||
instance=self.invoice_address, validate_vat_id=False,
|
||||
all_optional=self.all_optional,
|
||||
)
|
||||
else:
|
||||
return forms.Form(data=self.request.POST if self.request.method == "POST" else None)
|
||||
f = forms.Form(data=self.request.POST if self.request.method == "POST" else None)
|
||||
|
||||
override_sets = self._contact_override_sets
|
||||
for overrides in override_sets:
|
||||
for fname, val in overrides.items():
|
||||
if 'disabled' in val and fname in f.fields:
|
||||
f.fields[fname].disabled = val['disabled']
|
||||
|
||||
return f
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
|
||||
@@ -32,7 +32,9 @@ from pretix.presale.forms.checkout import (
|
||||
)
|
||||
from pretix.presale.signals import (
|
||||
checkout_all_optional, checkout_confirm_messages, checkout_flow_steps,
|
||||
contact_form_fields, order_meta_from_request, question_form_fields,
|
||||
contact_form_fields, contact_form_fields_overrides,
|
||||
order_meta_from_request, question_form_fields,
|
||||
question_form_fields_overrides,
|
||||
)
|
||||
from pretix.presale.views import (
|
||||
CartMixin, get_cart, get_cart_is_free, get_cart_total,
|
||||
@@ -423,6 +425,16 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
|
||||
return True
|
||||
return False
|
||||
|
||||
@cached_property
|
||||
def _contact_override_sets(self):
|
||||
return [
|
||||
resp for recv, resp in contact_form_fields_overrides.send(
|
||||
self.request.event,
|
||||
request=self.request,
|
||||
order=None,
|
||||
)
|
||||
]
|
||||
|
||||
@cached_property
|
||||
def contact_form(self):
|
||||
wd = self.cart_session.get('widget_data', {})
|
||||
@@ -433,14 +445,36 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
|
||||
)
|
||||
}
|
||||
initial.update(self.cart_session.get('contact_form_data', {}))
|
||||
|
||||
override_sets = self._contact_override_sets
|
||||
for overrides in override_sets:
|
||||
initial.update({
|
||||
k: v['initial'] for k, v in overrides.items() if 'initial' in v
|
||||
})
|
||||
|
||||
f = ContactForm(data=self.request.POST if self.request.method == "POST" else None,
|
||||
event=self.request.event,
|
||||
request=self.request,
|
||||
initial=initial, all_optional=self.all_optional)
|
||||
if wd.get('email', '') and wd.get('fix', '') == "true":
|
||||
f.fields['email'].disabled = True
|
||||
|
||||
for overrides in override_sets:
|
||||
for fname, val in overrides.items():
|
||||
if 'disabled' in val and fname in f.fields:
|
||||
f.fields[fname].disabled = val['disabled']
|
||||
|
||||
return f
|
||||
|
||||
def get_question_override_sets(self, cart_position):
|
||||
return [
|
||||
resp for recv, resp in question_form_fields_overrides.send(
|
||||
self.request.event,
|
||||
position=cart_position,
|
||||
request=self.request
|
||||
)
|
||||
]
|
||||
|
||||
@cached_property
|
||||
def eu_reverse_charge_relevant(self):
|
||||
return any([p.item.tax_rule and (p.item.tax_rule.eu_reverse_charge or p.item.tax_rule.custom_rules)
|
||||
@@ -466,6 +500,13 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
|
||||
else:
|
||||
wd_initial = {}
|
||||
initial = dict(wd_initial)
|
||||
|
||||
override_sets = self._contact_override_sets
|
||||
for overrides in override_sets:
|
||||
initial.update({
|
||||
k: v['initial'] for k, v in overrides.items() if 'initial' in v
|
||||
})
|
||||
|
||||
if not self.address_asked and self.request.event.settings.invoice_name_required:
|
||||
f = InvoiceNameForm(data=self.request.POST if self.request.method == "POST" else None,
|
||||
event=self.request.event,
|
||||
@@ -483,6 +524,12 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
|
||||
for name, field in f.fields.items():
|
||||
if wd_initial.get(name) and wd.get('fix', '') == 'true':
|
||||
field.disabled = True
|
||||
|
||||
for overrides in override_sets:
|
||||
for fname, val in overrides.items():
|
||||
if 'disabled' in val and fname in f.fields:
|
||||
f.fields[fname].disabled = val['disabled']
|
||||
|
||||
return f
|
||||
|
||||
@cached_property
|
||||
|
||||
@@ -180,6 +180,21 @@ As with all plugin signals, the ``sender`` keyword argument will contain the eve
|
||||
argument will contain the request object.
|
||||
"""
|
||||
|
||||
contact_form_fields_overrides = EventPluginSignal(
|
||||
providing_args=["request", "order"]
|
||||
)
|
||||
"""
|
||||
This signal allows you to override fields of the contact form that is presented during checkout
|
||||
and by default only asks for the email address. It is also being used for the invoice address
|
||||
form. You are supposed to return a dictionary of dictionaries with globally unique keys. The
|
||||
value-dictionary should contain one or more of the following keys: ``initial``, ``disabled``. The
|
||||
key of the dictionary should be the name of the form field.
|
||||
|
||||
As with all plugin signals, the ``sender`` keyword argument will contain the event. A ``request``
|
||||
argument will contain the request object. The ``order`` argument is ``None`` during the checkout
|
||||
process and contains an order if the customer is trying to change an existing order.
|
||||
"""
|
||||
|
||||
question_form_fields = EventPluginSignal(
|
||||
providing_args=["position"]
|
||||
)
|
||||
@@ -196,6 +211,22 @@ later.
|
||||
As with all plugin signals, the ``sender`` keyword argument will contain the event.
|
||||
"""
|
||||
|
||||
question_form_fields_overrides = EventPluginSignal(
|
||||
providing_args=["position", "request"]
|
||||
)
|
||||
"""
|
||||
This signal allows you to override fields of the questions form that is presented during checkout
|
||||
and by default only asks for the questions configured in the backend. You are supposed to return a
|
||||
dictionary of dictionaries with globally unique keys. The value-dictionary should contain one or
|
||||
more of the following keys: ``initial``, ``disabled``. The key of the dictionary should not be the
|
||||
question's form field name (``question_n``) but rather the questions ``identifier``.
|
||||
|
||||
The ``position`` keyword argument will contain a ``CartPosition`` or ``OrderPosition`` object.
|
||||
|
||||
As with all plugin signals, the ``sender`` keyword argument will contain the event. A ``request``
|
||||
argument will contain the request object.
|
||||
"""
|
||||
|
||||
order_info = EventPluginSignal(
|
||||
providing_args=["order", "request"]
|
||||
)
|
||||
|
||||
@@ -50,6 +50,7 @@ from pretix.helpers.safedownload import check_token
|
||||
from pretix.multidomain.urlreverse import build_absolute_uri, eventreverse
|
||||
from pretix.presale.forms.checkout import InvoiceAddressForm, QuestionsForm
|
||||
from pretix.presale.forms.order import OrderPositionChangeForm
|
||||
from pretix.presale.signals import question_form_fields_overrides
|
||||
from pretix.presale.views import (
|
||||
CartMixin, EventViewMixin, iframe_entry_view_wrapper,
|
||||
)
|
||||
@@ -673,6 +674,20 @@ class OrderModify(EventViewMixin, OrderDetailMixin, OrderQuestionsViewMixin, Tem
|
||||
return []
|
||||
return super().positions
|
||||
|
||||
def get_question_override_sets(self, order_position):
|
||||
override_sets = [
|
||||
resp for recv, resp in question_form_fields_overrides.send(
|
||||
self.request.event,
|
||||
position=order_position,
|
||||
request=self.request
|
||||
)
|
||||
]
|
||||
for override in override_sets:
|
||||
for k in override:
|
||||
# We don't want initial values to be modified, they should come from the order directly
|
||||
override[k].pop('initial', None)
|
||||
return override_sets
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
failed = not self.save() or not self.invoice_form.is_valid()
|
||||
if failed:
|
||||
|
||||
Reference in New Issue
Block a user