From f2e5e89970b0c1049282828c6c752d68c5015739 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Wed, 14 Oct 2020 16:29:32 +0200 Subject: [PATCH] Order import: Allow to reference question options by value --- src/pretix/base/models/items.py | 4 ++++ src/pretix/base/orderimport.py | 40 ++++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/pretix/base/models/items.py b/src/pretix/base/models/items.py index f8b8825d8a..7aba6ce597 100644 --- a/src/pretix/base/models/items.py +++ b/src/pretix/base/models/items.py @@ -1140,6 +1140,8 @@ class Question(LoggedModel): return None if self.type == Question.TYPE_CHOICE: + if isinstance(answer, QuestionOption): + return answer q = Q(identifier=answer) if isinstance(answer, int) or answer.isdigit(): q |= Q(pk=answer) @@ -1154,6 +1156,8 @@ class Question(LoggedModel): Q(identifier__in=answer.split(",")) )) llen = len(answer.split(',')) + elif all(isinstance(o, QuestionOption) for o in answer): + return o else: l_ = list(self.options.filter( Q(pk__in=[a for a in answer if isinstance(a, int) or a.isdigit()]) | diff --git a/src/pretix/base/orderimport.py b/src/pretix/base/orderimport.py index e2589b2401..1b49ab382f 100644 --- a/src/pretix/base/orderimport.py +++ b/src/pretix/base/orderimport.py @@ -1,4 +1,5 @@ import re +from collections import defaultdict from decimal import Decimal, DecimalException import pycountry @@ -12,12 +13,13 @@ from django.utils.translation import ( ) from django_countries import countries from django_countries.fields import Country +from i18nfield.strings import LazyI18nString from pretix.base.channels import get_all_sales_channels from pretix.base.forms.questions import guess_country from pretix.base.models import ( ItemVariation, OrderPosition, QuestionAnswer, QuestionOption, Seat, -) + Question) from pretix.base.services.pricing import get_price from pretix.base.settings import ( COUNTRIES_WITH_STATE_IN_ADDRESS, PERSON_NAME_SCHEMES, @@ -626,6 +628,22 @@ class Comment(ImportColumn): class QuestionColumn(ImportColumn): def __init__(self, event, q): self.q = q + self.option_resolve_cache = defaultdict(set) + + for opt in q.options.all(): + self.option_resolve_cache[str(opt.id)].add(opt) + self.option_resolve_cache[opt.identifier].add(opt) + + if isinstance(opt.answer, LazyI18nString): + + if isinstance(opt.answer.data, dict): + for v in opt.answer.data.values(): + self.option_resolve_cache[v.strip()].add(opt) + else: + self.option_resolve_cache[opt.answer.strip()].add(opt) + + else: + self.option_resolve_cache[opt.answer.strip()].add(opt) super().__init__(event) @property @@ -638,7 +656,23 @@ class QuestionColumn(ImportColumn): def clean(self, value, previous_values): if value: - return self.q.clean_answer(value) + if self.q.type == Question.TYPE_CHOICE: + if value not in self.option_resolve_cache: + raise ValidationError(_('Invalid option selected.')) + if len(self.option_resolve_cache[value]) > 1: + raise ValidationError(_('Ambigous option selected.')) + return list(self.option_resolve_cache[value])[0] + + elif self.q.type == Question.TYPE_CHOICE_MULTIPLE: + values = value.split(',') + if any(v.strip() not in self.option_resolve_cache for v in values): + raise ValidationError(_('Invalid option selected.')) + if any(len(self.option_resolve_cache[v.strip()]) > 1 for v in values): + raise ValidationError(_('Ambigous option selected.')) + return [list(self.option_resolve_cache[v.strip()])[0] for v in values] + + else: + return self.q.clean_answer(value) def assign(self, value, order, position, invoice_address, **kwargs): if value: @@ -702,7 +736,7 @@ def get_all_columns(event): SeatColumn(event), Comment(event) ] - for q in event.questions.exclude(type='F'): + for q in event.questions.prefetch_related('options').exclude(type=Question.TYPE_FILE): default.append(QuestionColumn(event, q)) for recv, resp in order_import_columns.send(sender=event):