Allow attendees to modify their data (Z#23152886) (#4138)

* Allow attendees to modify their data

* Allow attendees to change ticket information

* Update src/pretix/control/templates/pretixcontrol/event/settings.html

Co-authored-by: Mira <weller@rami.io>

* Update src/pretix/presale/views/order.py

Co-authored-by: Mira <weller@rami.io>

* Update src/pretix/base/services/placeholders.py

Co-authored-by: Mira <weller@rami.io>

* Tests fix

* Fix test

---------

Co-authored-by: Mira <weller@rami.io>
This commit is contained in:
Raphael Michel
2024-05-08 15:18:33 +02:00
committed by GitHub
parent aa55eb2de2
commit e8f7cea1bf
12 changed files with 347 additions and 28 deletions

View File

@@ -850,6 +850,9 @@ class Order(LockModel, LoggedModel):
if self.status not in (Order.STATUS_PENDING, Order.STATUS_PAID, Order.STATUS_EXPIRED):
return False
if self.event.settings.allow_modifications not in ("order", "attendee"):
return False
modify_deadline = self.modify_deadline
if modify_deadline is not None and now() > modify_deadline:
return False
@@ -2513,6 +2516,43 @@ class OrderPosition(AbstractPosition):
reasons[b] = b
return reasons
@property
def can_modify_answers(self) -> bool:
"""
``True`` if the user can change the question answers / attendee names that are
related to the position. This checks order status and modification deadlines. It also
returns ``False`` if there are no questions that can be answered.
"""
from .checkin import Checkin
if self.order.status not in (Order.STATUS_PENDING, Order.STATUS_PAID, Order.STATUS_EXPIRED):
return False
if self.event.settings.allow_modifications != "attendee":
return False
modify_deadline = self.order.modify_deadline
if modify_deadline is not None and now() > modify_deadline:
return False
positions = list(
self.order.positions.all().annotate(
has_checkin=Exists(Checkin.objects.filter(position_id=OuterRef('pk'), list__consider_tickets_used=True))
).select_related('item').prefetch_related('item__questions')
)
if not self.event.settings.allow_modifications_after_checkin:
for cp in positions:
if cp.has_checkin:
return False
ask_names = self.event.settings.get('attendee_names_asked', as_type=bool)
for cp in positions:
if cp.pk == self.pk or cp.addon_to_id == self.pk:
if (cp.item.ask_attendee_data and ask_names) or cp.item.questions.all():
return True
return False # nothing there to modify
@classmethod
def transform_cart_positions(cls, cp: List, order) -> list:
from . import Voucher

View File

@@ -337,6 +337,40 @@ def base_placeholders(sender, **kwargs):
}
),
),
SimpleFunctionalTextPlaceholder(
'url_info_change', ['position', 'event'], lambda position, event: build_absolute_uri(
event,
'presale:event.order.position.modify', kwargs={
'order': position.order.code,
'secret': position.web_secret,
'position': position.positionid
}
), lambda event: build_absolute_uri(
event,
'presale:event.order.position.modify', kwargs={
'order': 'F8VVL',
'secret': '6zzjnumtsx136ddy',
'position': '123',
}
),
),
SimpleFunctionalTextPlaceholder(
'url_products_change', ['position', 'event'], lambda position, event: build_absolute_uri(
event,
'presale:event.order.position.change', kwargs={
'order': position.order.code,
'secret': position.web_secret,
'position': position.positionid
}
), lambda event: build_absolute_uri(
event,
'presale:event.order.position.change', kwargs={
'order': 'F8VVL',
'secret': '6zzjnumtsx136ddy',
'position': '123'
}
),
),
SimpleFunctionalTextPlaceholder(
'order_modification_deadline_date_and_time', ['order', 'event'],
lambda order, event:

View File

@@ -1653,6 +1653,28 @@ DEFAULTS = {
"calendar.")
)
},
'allow_modifications': {
'default': 'order',
'type': str,
'form_class': forms.ChoiceField,
'serializer_class': serializers.ChoiceField,
'serializer_kwargs': dict(
choices=(
('no', _('No modifications after order was submitted')),
('order', _('Only the person who ordered can make changes')),
('attendee', _('Both the attendee and the person who ordered can make changes')),
)
),
'form_kwargs': dict(
label=_("Allow customers to modify their information"),
widget=forms.RadioSelect,
choices=(
('no', _('No modifications after order was submitted')),
('order', _('Only the person who ordered can make changes')),
('attendee', _('Both the attendee and the person who ordered can make changes')),
)
),
},
'allow_modifications_after_checkin': {
'default': 'False',
'type': bool,
@@ -1660,6 +1682,8 @@ DEFAULTS = {
'serializer_class': serializers.BooleanField,
'form_kwargs': dict(
label=_("Allow customers to modify their information after they checked in."),
help_text=_("By default, no more modifications are possible for an order as soon as one of the tickets "
"in the order has been checked in.")
)
},
'last_order_modification_date': {