From 4054b6ccded0755420e512bfd1fa21e29aa167ca Mon Sep 17 00:00:00 2001 From: Mira Weller Date: Thu, 17 Sep 2026 16:16:34 +0200 Subject: [PATCH] Support order-level questionnaires in OrderLevelQuestionsForm --- src/pretix/api/serializers/item.py | 28 ++++++++++++++-------- src/pretix/base/forms/questions.py | 37 ++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/pretix/api/serializers/item.py b/src/pretix/api/serializers/item.py index ae0ade3795..5f20a968a8 100644 --- a/src/pretix/api/serializers/item.py +++ b/src/pretix/api/serializers/item.py @@ -725,19 +725,29 @@ class QuestionnaireSerializer(I18nAwareModelSerializer): data = super().validate(data) event = self.context['event'] - #full_data = self.to_internal_value(self.to_representation(self.instance)) if self.instance else {} - #full_data.update(data) + try: + full_data = self.to_internal_value(self.to_representation(self.instance)) if self.instance else {} + full_data.update(data) + except rest_framework.exceptions.ValidationError as e: + # we already have invalid state in the database, what should we do? hope it gets better after saving? + print(e) + else: + print('full_data', full_data) + #if full_data.get('ask_during_checkin') and full_data.get('dependency_question'): + # raise ValidationError('Dependencies are not supported during check-in.') - #if full_data.get('ask_during_checkin') and full_data.get('dependency_question'): - # raise ValidationError('Dependencies are not supported during check-in.') + #if full_data.get('ask_during_checkin') and full_data.get('type') in Question.ASK_DURING_CHECKIN_UNSUPPORTED: + # raise ValidationError(_('This type of question cannot be asked during check-in.')) - #if full_data.get('ask_during_checkin') and full_data.get('type') in Question.ASK_DURING_CHECKIN_UNSUPPORTED: - # raise ValidationError(_('This type of question cannot be asked during check-in.')) + #if full_data.get('show_during_checkin') and full_data.get('type') in Question.SHOW_DURING_CHECKIN_UNSUPPORTED: + # raise ValidationError(_('This type of question cannot be shown during check-in.')) - #if full_data.get('show_during_checkin') and full_data.get('type') in Question.SHOW_DURING_CHECKIN_UNSUPPORTED: - # raise ValidationError(_('This type of question cannot be shown during check-in.')) + #Question.clean_items(event, full_data.get('items') or []) + + if (not full_data.get('type').startswith('P') + and any(c['system_datafield'] for c in full_data['children'])): + raise ValidationError('System data fields are only supported on order positions.') - #Question.clean_items(event, full_data.get('items') or []) return data def validate_children(self, value): diff --git a/src/pretix/base/forms/questions.py b/src/pretix/base/forms/questions.py index 473e268674..ce32091a72 100644 --- a/src/pretix/base/forms/questions.py +++ b/src/pretix/base/forms/questions.py @@ -49,8 +49,8 @@ from django.contrib import messages from django.core.exceptions import ValidationError from django.core.files.uploadedfile import SimpleUploadedFile from django.core.validators import MaxValueValidator, MinValueValidator -from django.db.models import QuerySet from django.db import ProgrammingError +from django.db.models import Prefetch, QuerySet from django.forms import Select, widgets from django.forms.widgets import FILE_INPUT_CONTRADICTION from django.utils.formats import date_format @@ -82,7 +82,7 @@ from pretix.base.i18n import ( from pretix.base.invoicing.transmission import ( get_transmission_types, transmission_types, ) -from pretix.base.models import InvoiceAddress, Item, Question, QuestionOption +from pretix.base.models import InvoiceAddress, Item, Question, QuestionOption, Questionnaire, QuestionnaireChild from pretix.base.models.tax import ask_for_vat_id from pretix.base.services.tax import ( VATIDFinalError, VATIDTemporaryError, normalize_vat_id, validate_vat_id, @@ -957,15 +957,34 @@ class OrderLevelQuestionsForm(BaseQuestionsForm): super().__init__(*args, **kwargs) - # TODO(questionnaires) - switch olq's to questionnaires ! - questions = Question.objects.filter( - event=event, container_type=Question.ContainerType.ORDER, - ask_during_checkin=False, hidden=False, - ).order_by('position') + questionnaires = Questionnaire.objects.filter( + event=event, type=Questionnaire.QuestionnaireType.ORDER_SALE, + ).order_by('position').prefetch_related( + Prefetch('children', QuestionnaireChild.objects.prefetch_related( + Prefetch('user_datafield', Question.objects.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='childlist') + ) answerlist = container.answers.prefetch_related('options') - for q in questions: - self.fields['question_%s' % q.id] = self.build_user_question_field(request, event, answerlist, q) + idx = 0 + for questionnaire in questionnaires: + for child in getattr(questionnaire, 'childlist', questionnaire.children.all()): + if child.user_datafield: + df = child.user_datafield + self.fields['question_%s' % df.id] = self.build_user_question_field(request, event, answerlist, child, df) + else: + self.fields['text_%d' % idx] = self.build_text_block(request, event, child) + idx += 1 def clean(self): d = super().clean()