Questions at check-in time (#745)

Questions at check-in time
This commit is contained in:
Raphael Michel
2018-01-22 22:55:54 +01:00
committed by GitHub
parent 7fb2d0526e
commit d0dfde382c
20 changed files with 754 additions and 47 deletions

View File

@@ -374,9 +374,9 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
for cp in self._positions_for_questions:
answ = {
aw.question_id: aw.answer for aw in cp.answers.all()
aw.question_id: aw.answer for aw in cp.answerlist
}
for q in cp.item.questions.all():
for q in cp.item.questions_to_ask:
if q.required and q.id not in answ:
if warn:
messages.warning(request, _('Please fill in answers to all required questions.'))

View File

@@ -212,7 +212,7 @@ class QuestionsForm(forms.Form):
orderpos = self.orderpos = kwargs.pop('orderpos', None)
pos = cartpos or orderpos
item = pos.item
questions = list(item.questions.all())
questions = pos.item.questions_to_ask
event = kwargs.pop('event')
super().__init__(*args, **kwargs)
@@ -232,11 +232,7 @@ class QuestionsForm(forms.Form):
for q in questions:
# Do we already have an answer? Provide it as the initial value
answers = [
a for a
in (cartpos.answers.all() if cartpos else orderpos.answers.all())
if a.question_id == q.id
]
answers = [a for a in pos.answerlist if a.question_id == q.id]
if answers:
initial = answers[0]
else:
@@ -282,7 +278,7 @@ class QuestionsForm(forms.Form):
)
elif q.type == Question.TYPE_CHOICE:
field = forms.ModelChoiceField(
queryset=q.options.all(),
queryset=q.options,
label=q.question, required=q.required,
help_text=q.help_text,
widget=forms.Select,
@@ -291,7 +287,7 @@ class QuestionsForm(forms.Form):
)
elif q.type == Question.TYPE_CHOICE_MULTIPLE:
field = forms.ModelMultipleChoiceField(
queryset=q.options.all(),
queryset=q.options,
label=q.question, required=q.required,
help_text=q.help_text,
widget=forms.CheckboxSelectMultiple,

View File

@@ -114,7 +114,7 @@ class CartMixin:
group.has_questions = answers and k[0] != ""
group.tax_rule = group.item.tax_rule
if answers:
group.cache_answers()
group.cache_answers(all=False)
group.additional_answers = pos_additional_fields.get(group.pk)
positions.append(group)
@@ -155,6 +155,16 @@ class CartMixin:
}
def cart_exists(request):
from pretix.presale.views.cart import get_or_create_cart_id
if not hasattr(request, '_cart_cache'):
return CartPosition.objects.filter(
cart_id=get_or_create_cart_id(request), event=request.event
).exists()
return bool(request._cart_cache)
def get_cart(request):
from pretix.presale.views.cart import get_or_create_cart_id
@@ -166,8 +176,6 @@ def get_cart(request):
).select_related(
'item', 'variation', 'subevent', 'subevent__event', 'subevent__event__organizer',
'item__tax_rule'
).prefetch_related(
'item__questions', 'answers'
)
return request._cart_cache

View File

@@ -10,7 +10,8 @@ from pretix.base.signals import validate_cart
from pretix.multidomain.urlreverse import eventreverse
from pretix.presale.checkoutflow import get_checkout_flow
from pretix.presale.views import (
allow_frame_if_namespaced, get_cart, iframe_entry_view_wrapper,
allow_frame_if_namespaced, cart_exists, get_cart,
iframe_entry_view_wrapper,
)
@@ -27,7 +28,7 @@ class CheckoutView(View):
def dispatch(self, request, *args, **kwargs):
self.request = request
if not get_cart(request) and "async_id" not in request.GET:
if not cart_exists(request) and "async_id" not in request.GET:
messages.error(request, _("Your cart is empty"))
return redirect(self.get_index_url(self.request))

View File

@@ -4,7 +4,7 @@ from decimal import Decimal
from django.contrib import messages
from django.db import transaction
from django.db.models import Sum
from django.db.models import Prefetch, Sum
from django.http import FileResponse, Http404, JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.utils.decorators import method_decorator
@@ -14,7 +14,9 @@ from django.utils.translation import ugettext_lazy as _
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.generic import TemplateView, View
from pretix.base.models import CachedTicket, Invoice, Order, OrderPosition
from pretix.base.models import (
CachedTicket, Invoice, Order, OrderPosition, Question, QuestionOption,
)
from pretix.base.models.orders import (
CachedCombinedTicket, InvoiceAddress, OrderFee, QuestionAnswer,
)
@@ -435,7 +437,21 @@ class OrderModify(EventViewMixin, OrderDetailMixin, QuestionsViewMixin, Template
return list(self.order.positions.select_related(
'item', 'variation'
).prefetch_related(
'variation', 'item__questions', 'answers'
Prefetch('answers',
QuestionAnswer.objects.prefetch_related('options'),
to_attr='answerlist'),
Prefetch('item__questions',
Question.objects.filter(ask_during_checkin=False).prefetch_related(
Prefetch('options', QuestionOption.objects.prefetch_related(Prefetch(
# This prefetch statement is utter bullshit, but it actually prevents Django from doing
# a lot of queries since ModelChoiceIterator stops trying to be clever once we have
# a prefetch lookup on this query...
'question',
Question.objects.none(),
to_attr='dummy'
)))
),
to_attr='questions_to_ask')
))
@cached_property

View File

@@ -3,9 +3,12 @@ from collections import OrderedDict
from django import forms
from django.core.files.uploadedfile import UploadedFile
from django.db.models import Prefetch
from django.utils.functional import cached_property
from pretix.base.models import CartPosition, OrderPosition, QuestionAnswer
from pretix.base.models import (
CartPosition, OrderPosition, Question, QuestionAnswer, QuestionOption,
)
from pretix.presale.forms.checkout import QuestionsForm
from pretix.presale.views import get_cart
@@ -26,7 +29,24 @@ class QuestionsViewMixin:
def _positions_for_questions(self):
cart = get_cart(self.request).select_related(
'addon_to'
).prefetch_related('addons', 'addons__item', 'addons__variation')
).prefetch_related(
'addons', 'addons__item', 'addons__variation',
Prefetch('answers',
QuestionAnswer.objects.prefetch_related('options'),
to_attr='answerlist'),
Prefetch('item__questions',
Question.objects.filter(ask_during_checkin=False).prefetch_related(
Prefetch('options', QuestionOption.objects.prefetch_related(Prefetch(
# This prefetch statement is utter bullshit, but it actually prevents Django from doing
# a lot of queries since ModelChoiceIterator stops trying to be clever once we have
# a prefetch lookup on this query...
'question',
Question.objects.none(),
to_attr='dummy'
)))
),
to_attr='questions_to_ask')
)
return sorted(list(cart), key=self._keyfunc)
@cached_property