Add new signal checkout_all_optional

This commit is contained in:
Raphael Michel
2018-12-11 16:44:15 +01:00
parent 49828186b0
commit 2bb2a40509
5 changed files with 56 additions and 21 deletions

View File

@@ -26,7 +26,7 @@ Frontend
-------- --------
.. automodule:: pretix.presale.signals .. automodule:: pretix.presale.signals
:members: html_head, html_footer, footer_links, front_page_top, front_page_bottom, fee_calculation_for_cart, contact_form_fields, question_form_fields, checkout_confirm_messages, checkout_confirm_page_content :members: html_head, html_footer, footer_links, front_page_top, front_page_bottom, fee_calculation_for_cart, contact_form_fields, question_form_fields, checkout_confirm_messages, checkout_confirm_page_content, checkout_all_optional
.. automodule:: pretix.presale.signals .. automodule:: pretix.presale.signals

View File

@@ -291,17 +291,18 @@ class BaseInvoiceAddressForm(forms.ModelForm):
self.event = event = kwargs.pop('event') self.event = event = kwargs.pop('event')
self.request = kwargs.pop('request', None) self.request = kwargs.pop('request', None)
self.validate_vat_id = kwargs.pop('validate_vat_id') self.validate_vat_id = kwargs.pop('validate_vat_id')
self.all_optional = kwargs.pop('all_optional', False)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if not event.settings.invoice_address_vatid: if not event.settings.invoice_address_vatid:
del self.fields['vat_id'] del self.fields['vat_id']
if not event.settings.invoice_address_required: if not event.settings.invoice_address_required or self.all_optional:
for k, f in self.fields.items(): for k, f in self.fields.items():
f.required = False f.required = False
f.widget.is_required = False f.widget.is_required = False
if 'required' in f.widget.attrs: if 'required' in f.widget.attrs:
del f.widget.attrs['required'] del f.widget.attrs['required']
elif event.settings.invoice_address_company_required: elif event.settings.invoice_address_company_required and not self.all_optional:
self.initial['is_business'] = True self.initial['is_business'] = True
self.fields['is_business'].widget = BusinessBooleanRadio(require_business=True) self.fields['is_business'].widget = BusinessBooleanRadio(require_business=True)
@@ -314,12 +315,12 @@ class BaseInvoiceAddressForm(forms.ModelForm):
self.fields['name_parts'] = NamePartsFormField( self.fields['name_parts'] = NamePartsFormField(
max_length=255, max_length=255,
required=event.settings.invoice_name_required, required=event.settings.invoice_name_required and not self.all_optional,
scheme=event.settings.name_scheme, scheme=event.settings.name_scheme,
label=_('Name'), label=_('Name'),
initial=(self.instance.name_parts if self.instance else self.instance.name_parts), initial=(self.instance.name_parts if self.instance else self.instance.name_parts),
) )
if event.settings.invoice_address_required and not event.settings.invoice_address_company_required: if event.settings.invoice_address_required and not event.settings.invoice_address_company_required and not self.all_optional:
self.fields['name_parts'].widget.attrs['data-required-if'] = '#id_is_business_0' self.fields['name_parts'].widget.attrs['data-required-if'] = '#id_is_business_0'
self.fields['name_parts'].widget.attrs['data-no-required-attr'] = '1' self.fields['name_parts'].widget.attrs['data-no-required-attr'] = '1'
self.fields['company'].widget.attrs['data-required-if'] = '#id_is_business_1' self.fields['company'].widget.attrs['data-required-if'] = '#id_is_business_1'

View File

@@ -23,8 +23,8 @@ from pretix.presale.forms.checkout import (
AddOnsForm, ContactForm, InvoiceAddressForm, InvoiceNameForm, AddOnsForm, ContactForm, InvoiceAddressForm, InvoiceNameForm,
) )
from pretix.presale.signals import ( from pretix.presale.signals import (
checkout_confirm_messages, checkout_flow_steps, contact_form_fields, checkout_all_optional, checkout_confirm_messages, checkout_flow_steps,
order_meta_from_request, question_form_fields, contact_form_fields, order_meta_from_request, question_form_fields,
) )
from pretix.presale.views import CartMixin, get_cart, get_cart_total from pretix.presale.views import CartMixin, get_cart, get_cart_total
from pretix.presale.views.cart import ( from pretix.presale.views.cart import (
@@ -308,6 +308,13 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
def is_applicable(self, request): def is_applicable(self, request):
return True return True
@cached_property
def all_optional(self):
for recv, resp in checkout_all_optional.send(sender=self.request.event, request=self.request):
if resp:
return True
return False
@cached_property @cached_property
def contact_form(self): def contact_form(self):
initial = { initial = {
@@ -320,7 +327,7 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
return ContactForm(data=self.request.POST if self.request.method == "POST" else None, return ContactForm(data=self.request.POST if self.request.method == "POST" else None,
event=self.request.event, event=self.request.event,
request=self.request, request=self.request,
initial=initial) initial=initial, all_optional=self.all_optional)
@cached_property @cached_property
def eu_reverse_charge_relevant(self): def eu_reverse_charge_relevant(self):
@@ -348,13 +355,13 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
request=self.request, request=self.request,
instance=self.invoice_address, instance=self.invoice_address,
initial=initial, initial=initial,
validate_vat_id=False) validate_vat_id=False, all_optional=self.all_optional)
return InvoiceAddressForm(data=self.request.POST if self.request.method == "POST" else None, return InvoiceAddressForm(data=self.request.POST if self.request.method == "POST" else None,
event=self.request.event, event=self.request.event,
request=self.request, request=self.request,
initial=initial, initial=initial,
instance=self.invoice_address, instance=self.invoice_address,
validate_vat_id=self.eu_reverse_charge_relevant) validate_vat_id=self.eu_reverse_charge_relevant, all_optional=self.all_optional)
def post(self, request): def post(self, request):
self.request = request self.request = request
@@ -383,23 +390,25 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
self.request = request self.request = request
try: try:
emailval = EmailValidator() emailval = EmailValidator()
if 'email' not in self.cart_session: if not self.cart_session.get('email') and not self.all_optional:
if warn: if warn:
messages.warning(request, _('Please enter a valid email address.')) messages.warning(request, _('Please enter a valid email address.'))
return False return False
emailval(self.cart_session.get('email')) if self.cart_session.get('email'):
emailval(self.cart_session.get('email'))
except ValidationError: except ValidationError:
if warn: if warn:
messages.warning(request, _('Please enter a valid email address.')) messages.warning(request, _('Please enter a valid email address.'))
return False return False
if request.event.settings.invoice_address_required and (not self.invoice_address or not self.invoice_address.street): if not self.all_optional:
messages.warning(request, _('Please enter your invoicing address.')) if request.event.settings.invoice_address_required and (not self.invoice_address or not self.invoice_address.street):
return False messages.warning(request, _('Please enter your invoicing address.'))
return False
if request.event.settings.invoice_name_required and (not self.invoice_address or not self.invoice_address.name): if request.event.settings.invoice_name_required and (not self.invoice_address or not self.invoice_address.name):
messages.warning(request, _('Please enter your name.')) messages.warning(request, _('Please enter your name.'))
return False return False
for cp in self._positions_for_questions: for cp in self._positions_for_questions:
answ = { answ = {
@@ -585,6 +594,8 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
@cached_property @cached_property
def confirm_messages(self): def confirm_messages(self):
if self.all_optional:
return {}
msgs = {} msgs = {}
responses = checkout_confirm_messages.send(self.request.event) responses = checkout_confirm_messages.send(self.request.event)
for receiver, response in responses: for receiver, response in responses:
@@ -603,10 +614,17 @@ class ConfirmStep(CartMixin, AsyncAction, TemplateFlowStep):
return self.get_result(request) return self.get_result(request)
return TemplateFlowStep.get(self, request) return TemplateFlowStep.get(self, request)
@cached_property
def all_optional(self):
for recv, resp in checkout_all_optional.send(sender=self.request.event, request=self.request):
if resp:
return True
return False
def post(self, request): def post(self, request):
self.request = request self.request = request
if self.confirm_messages: if self.confirm_messages and not self.all_optional:
for key, msg in self.confirm_messages.items(): for key, msg in self.confirm_messages.items():
if request.POST.get('confirm_{}'.format(key)) != 'yes': if request.POST.get('confirm_{}'.format(key)) != 'yes':
msg = str(_('You need to check all checkboxes on the bottom of the page.')) msg = str(_('You need to check all checkboxes on the bottom of the page.'))

View File

@@ -29,12 +29,13 @@ class ContactForm(forms.Form):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.event = kwargs.pop('event') self.event = kwargs.pop('event')
self.request = kwargs.pop('request') self.request = kwargs.pop('request')
self.all_optional = kwargs.pop('all_optional', False)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if self.event.settings.order_email_asked_twice: if self.event.settings.order_email_asked_twice:
self.fields['email_repeat'] = forms.EmailField( self.fields['email_repeat'] = forms.EmailField(
label=_('E-mail address (repeated)'), label=_('E-mail address (repeated)'),
help_text=_('Please enter the same email address again to make sure you typed it correctly.') help_text=_('Please enter the same email address again to make sure you typed it correctly.'),
) )
if not self.request.session.get('iframe_session', False): if not self.request.session.get('iframe_session', False):
@@ -44,10 +45,14 @@ class ContactForm(forms.Form):
self.fields['email'].widget.attrs['autofocus'] = 'autofocus' self.fields['email'].widget.attrs['autofocus'] = 'autofocus'
responses = contact_form_fields.send(self.event, request=self.request) responses = contact_form_fields.send(self.event, request=self.request)
for r, response in sorted(responses, key=lambda r: str(r[0])): for r, response in responses:
for key, value in response.items(): for key, value in response.items():
# We need to be this explicit, since OrderedDict.update does not retain ordering # We need to be this explicit, since OrderedDict.update does not retain ordering
self.fields[key] = value self.fields[key] = value
if self.all_optional:
for k, v in self.fields.items():
v.required = False
v.widget.is_required = False
def clean(self): def clean(self):
if self.event.settings.order_email_asked_twice and self.cleaned_data.get('email') and self.cleaned_data.get('email_repeat'): if self.event.settings.order_email_asked_twice and self.cleaned_data.get('email') and self.cleaned_data.get('email_repeat'):

View File

@@ -184,3 +184,14 @@ of products.
As with all plugin signals, the ``sender`` keyword argument will contain the event. The As with all plugin signals, the ``sender`` keyword argument will contain the event. The
receivers are expected to return HTML. receivers are expected to return HTML.
""" """
checkout_all_optional = EventPluginSignal(
providing_args=['request']
)
"""
If any receiver of this signal returns ``True``, all input fields during checkout (contact data,
invoice address, confirmations) will be optional, except for questions. Use with care!
As with all plugin signals, the ``sender`` keyword argument will contain the event. A ``request``
argument will contain the request object.
"""