예제 #1
0
 def save(self):
     failed = False
     for form in self.forms:
         # Every form represents a CartPosition or OrderPosition with questions attached
         if not form.is_valid():
             failed = True
         else:
             # This form was correctly filled, so we store the data as
             # answers to the questions / in the CartPosition object
             for k, v in form.cleaned_data.items():
                 if k == 'attendee_name':
                     form.pos.attendee_name = v if v != '' else None
                     form.pos.save()
                 elif k.startswith('question_') and v is not None:
                     field = form.fields[k]
                     if hasattr(field, 'answer'):
                         # We already have a cached answer object, so we don't
                         # have to create a new one
                         if v == '':
                             field.answer.delete()
                         else:
                             self._save_to_answer(field, field.answer, v)
                             field.answer.save()
                     elif v != '':
                         answer = QuestionAnswer(
                             cartposition=(form.pos if isinstance(form.pos, CartPosition) else None),
                             orderposition=(form.pos if isinstance(form.pos, OrderPosition) else None),
                             question=field.question,
                         )
                         self._save_to_answer(field, answer, v)
                         answer.save()
     return not failed
예제 #2
0
    def save(self):
        failed = False
        for form in self.forms:
            meta_info = form.pos.meta_info_data
            # Every form represents a CartPosition or OrderPosition with questions attached
            if not form.is_valid():
                failed = True
            else:
                # This form was correctly filled, so we store the data as
                # answers to the questions / in the CartPosition object
                for k, v in form.cleaned_data.items():
                    if k == 'attendee_name_parts':
                        form.pos.attendee_name_parts = v if v else None
                    elif k == 'attendee_email':
                        form.pos.attendee_email = v if v != '' else None
                    elif k == 'company':
                        form.pos.company = v if v != '' else None
                    elif k == 'street':
                        form.pos.street = v if v != '' else None
                    elif k == 'zipcode':
                        form.pos.zipcode = v if v != '' else None
                    elif k == 'city':
                        form.pos.city = v if v != '' else None
                    elif k == 'country':
                        form.pos.country = v if v != '' else None
                    elif k == 'state':
                        form.pos.state = v if v != '' else None
                    elif k.startswith('question_'):
                        field = form.fields[k]
                        if hasattr(field, 'answer'):
                            # We already have a cached answer object, so we don't
                            # have to create a new one
                            if v == '' or v is None or (isinstance(field, forms.FileField) and v is False) \
                                    or (isinstance(v, QuerySet) and not v.exists()):
                                if field.answer.file:
                                    field.answer.file.delete()
                                field.answer.delete()
                            else:
                                self._save_to_answer(field, field.answer, v)
                                field.answer.save()
                        elif v != '' and v is not None:
                            answer = QuestionAnswer(
                                cartposition=(form.pos if isinstance(form.pos, CartPosition) else None),
                                orderposition=(form.pos if isinstance(form.pos, OrderPosition) else None),
                                question=field.question,
                            )
                            self._save_to_answer(field, answer, v)
                            answer.save()
                    else:
                        meta_info.setdefault('question_form_data', {})
                        if v is None:
                            if k in meta_info['question_form_data']:
                                del meta_info['question_form_data'][k]
                        else:
                            meta_info['question_form_data'][k] = v

            form.pos.meta_info = json.dumps(meta_info)
            form.pos.save()
        return not failed
예제 #3
0
    def save(self):
        failed = False
        for form in self.forms:
            meta_info = form.pos.meta_info_data
            # Every form represents a CartPosition or OrderPosition with questions attached
            if not form.is_valid():
                failed = True
            else:
                # This form was correctly filled, so we store the data as
                # answers to the questions / in the CartPosition object
                for k, v in form.cleaned_data.items():
                    if k == 'attendee_name_parts':
                        form.pos.attendee_name_parts = v if v else None
                        form.pos.save()
                    elif k == 'attendee_email':
                        form.pos.attendee_email = v if v != '' else None
                        form.pos.save()
                    elif k.startswith('question_'):
                        field = form.fields[k]
                        if hasattr(field, 'answer'):
                            # We already have a cached answer object, so we don't
                            # have to create a new one
                            if v == '' or v is None or (isinstance(field, forms.FileField) and v is False) \
                                    or (isinstance(v, QuerySet) and not v.exists()):
                                if field.answer.file:
                                    field.answer.file.delete()
                                field.answer.delete()
                            else:
                                self._save_to_answer(field, field.answer, v)
                                field.answer.save()
                        elif v != '' and v is not None:
                            answer = QuestionAnswer(
                                cartposition=(form.pos if isinstance(form.pos, CartPosition) else None),
                                orderposition=(form.pos if isinstance(form.pos, OrderPosition) else None),
                                question=field.question,
                            )
                            self._save_to_answer(field, answer, v)
                            answer.save()
                    else:
                        meta_info.setdefault('question_form_data', {})
                        if v is None:
                            if k in meta_info['question_form_data']:
                                del meta_info['question_form_data'][k]
                        else:
                            meta_info['question_form_data'][k] = v

            form.pos.meta_info = json.dumps(meta_info)
            form.pos.save(update_fields=['meta_info'])
        return not failed
예제 #4
0
    def save(self):
        failed = False
        for form in self.forms:
            meta_info = form.pos.meta_info_data
            # Every form represents a CartPosition or OrderPosition with questions attached
            if not form.is_valid():
                failed = True
            else:
                # This form was correctly filled, so we store the data as
                # answers to the questions / in the CartPosition object
                for k, v in form.cleaned_data.items():
                    if k == 'attendee_name_parts':
                        form.pos.attendee_name_parts = v if v else None
                    elif k == 'attendee_email':
                        form.pos.attendee_email = v if v != '' else None
                    elif k == 'company':
                        form.pos.company = v if v != '' else None
                    elif k == 'street':
                        form.pos.street = v if v != '' else None
                    elif k == 'zipcode':
                        form.pos.zipcode = v if v != '' else None
                    elif k == 'city':
                        form.pos.city = v if v != '' else None
                    elif k == 'country':
                        form.pos.country = v if v != '' else None
                    elif k == 'state':
                        form.pos.state = v if v != '' else None
                    elif k.startswith('question_'):
                        field = form.fields[k]
                        if hasattr(field, 'answer'):
                            # We already have a cached answer object, so we don't
                            # have to create a new one
                            if v == '' or v is None or (isinstance(field, forms.FileField) and v is False) \
                                    or (isinstance(v, QuerySet) and not v.exists()):
                                if field.answer.file:
                                    field.answer.file.delete()
                                field.answer.delete()
                            else:
                                self._save_to_answer(field, field.answer, v)
                                field.answer.save()
                        elif v != '' and v is not None:
                            answer = QuestionAnswer(
                                cartposition=(form.pos if isinstance(
                                    form.pos, CartPosition) else None),
                                orderposition=(form.pos if isinstance(
                                    form.pos, OrderPosition) else None),
                                question=field.question,
                            )
                            try:
                                self._save_to_answer(field, answer, v)
                                answer.save()
                            except IntegrityError:
                                # Since we prefill ``field.answer`` at form creation time, there's a possible race condition
                                # here if the users submits their save request a second time while the first one is still running,
                                # thus leading to duplicate QuestionAnswer objects. Since Django doesn't support UPSERT, the "proper"
                                # fix would be a transaction with select_for_update(), or at least fetching using get_or_create here
                                # again. However, both of these approaches have a significant performance overhead for *all* requests,
                                # while the issue happens very very rarely. So we opt for just catching the error and retrying properly.
                                answer = QuestionAnswer.objects.get(
                                    cartposition=(form.pos if isinstance(
                                        form.pos, CartPosition) else None),
                                    orderposition=(form.pos if isinstance(
                                        form.pos, OrderPosition) else None),
                                    question=field.question,
                                )
                                self._save_to_answer(field, answer, v)
                                answer.save()

                    else:
                        meta_info.setdefault('question_form_data', {})
                        if v is None:
                            if k in meta_info['question_form_data']:
                                del meta_info['question_form_data'][k]
                        else:
                            meta_info['question_form_data'][k] = v

            form.pos.meta_info = json.dumps(meta_info)
            form.pos.save()
        return not failed
예제 #5
0
    def save(self):
        failed = False
        for form in self.forms:
            meta_info = form.pos.meta_info_data
            # Every form represents a CartPosition or OrderPosition with questions attached
            if not form.is_valid():
                failed = True
            else:
                if form.cleaned_data.get('saved_id'):
                    prof = AttendeeProfile.objects.filter(
                        customer=self.cart_customer,
                        pk=form.cleaned_data.get(
                            'saved_id')).first() or AttendeeProfile(
                                customer=getattr(self, 'cart_customer', None))
                    answers_key_to_index = {
                        a.get('field_name'): i
                        for i, a in enumerate(prof.answers)
                    }
                else:
                    prof = AttendeeProfile(
                        customer=getattr(self, 'cart_customer', None))
                    answers_key_to_index = {}

                # This form was correctly filled, so we store the data as
                # answers to the questions / in the CartPosition object
                for k, v in form.cleaned_data.items():
                    if k in ('save', 'saved_id'):
                        continue
                    elif k == 'attendee_name_parts':
                        form.pos.attendee_name_parts = v if v else None
                        prof.attendee_name_parts = form.pos.attendee_name_parts
                        prof.attendee_name_cached = form.pos.attendee_name
                    elif k in ('attendee_email', 'company', 'street',
                               'zipcode', 'city', 'country', 'state'):
                        v = v if v != '' else None
                        setattr(form.pos, k, v)
                        setattr(prof, k, v)
                    elif k.startswith('question_'):
                        field = form.fields[k]
                        if hasattr(field, 'answer'):
                            # We already have a cached answer object, so we don't
                            # have to create a new one
                            if v == '' or v is None or (isinstance(field, forms.FileField) and v is False) \
                                    or (isinstance(v, QuerySet) and not v.exists()):
                                if field.answer.file:
                                    field.answer.file.delete()
                                field.answer.delete()
                            else:
                                self._save_to_answer(field, field.answer, v)
                                field.answer.save()
                                if isinstance(
                                        field, forms.ModelMultipleChoiceField
                                ) or isinstance(field, forms.ModelChoiceField):
                                    answer_value = {
                                        o.identifier: str(o)
                                        for o in field.answer.options.all()
                                    }
                                elif isinstance(field, forms.BooleanField):
                                    answer_value = bool(field.answer.answer)
                                else:
                                    answer_value = str(field.answer.answer)
                                answer_dict = {
                                    'field_name':
                                    k,
                                    'field_label':
                                    str(field.label),
                                    'value':
                                    answer_value,
                                    'question_type':
                                    field.question.type,
                                    'question_identifier':
                                    field.question.identifier,
                                }
                                if k in answers_key_to_index:
                                    prof.answers[
                                        answers_key_to_index[k]] = answer_dict
                                else:
                                    prof.answers.append(answer_dict)
                        elif v != '' and v is not None:
                            answer = QuestionAnswer(
                                cartposition=(form.pos if isinstance(
                                    form.pos, CartPosition) else None),
                                orderposition=(form.pos if isinstance(
                                    form.pos, OrderPosition) else None),
                                question=field.question,
                            )
                            try:
                                self._save_to_answer(field, answer, v)
                                answer.save()
                            except IntegrityError:
                                # Since we prefill ``field.answer`` at form creation time, there's a possible race condition
                                # here if the users submits their save request a second time while the first one is still running,
                                # thus leading to duplicate QuestionAnswer objects. Since Django doesn't support UPSERT, the "proper"
                                # fix would be a transaction with select_for_update(), or at least fetching using get_or_create here
                                # again. However, both of these approaches have a significant performance overhead for *all* requests,
                                # while the issue happens very very rarely. So we opt for just catching the error and retrying properly.
                                answer = QuestionAnswer.objects.get(
                                    cartposition=(form.pos if isinstance(
                                        form.pos, CartPosition) else None),
                                    orderposition=(form.pos if isinstance(
                                        form.pos, OrderPosition) else None),
                                    question=field.question,
                                )
                                self._save_to_answer(field, answer, v)
                                answer.save()

                            if isinstance(field, forms.ModelMultipleChoiceField
                                          ) or isinstance(
                                              field, forms.ModelChoiceField):
                                answer_value = {
                                    o.identifier: str(o)
                                    for o in answer.options.all()
                                }
                            elif isinstance(field, forms.BooleanField):
                                answer_value = bool(answer.answer)
                            else:
                                answer_value = str(answer.answer)
                            answer_dict = {
                                'field_name': k,
                                'field_label': str(field.label),
                                'value': answer_value,
                                'question_type': field.question.type,
                                'question_identifier':
                                field.question.identifier,
                            }
                            if k in answers_key_to_index:
                                prof.answers[
                                    answers_key_to_index[k]] = answer_dict
                            else:
                                prof.answers.append(answer_dict)

                    else:
                        field = form.fields[k]

                        meta_info.setdefault('question_form_data', {})
                        if v is None:
                            if k in meta_info['question_form_data']:
                                del meta_info['question_form_data'][k]
                        else:
                            meta_info['question_form_data'][k] = v

                        answer_dict = {
                            'field_name': k,
                            'field_label': str(field.label),
                            'value': str(v),
                            'question_type': None,
                            'question_identifier': None,
                        }
                        if k in answers_key_to_index:
                            prof.answers[answers_key_to_index[k]] = answer_dict
                        else:
                            prof.answers.append(answer_dict)

            form.pos.meta_info = json.dumps(meta_info)
            form.pos.save()

            if form.cleaned_data.get('save') and not failed:
                prof.save()
                self.cart_session[
                    f'saved_attendee_profile_{form.pos.pk}'] = prof.pk

        return not failed