add edit view for waitinglist entry

This commit is contained in:
Lukas Bockstaller
2025-12-10 15:40:40 +01:00
parent 0e41353a0e
commit d5fda6d319
5 changed files with 166 additions and 3 deletions

View File

@@ -19,12 +19,18 @@
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.forms import ChoiceField, EmailField
from django.urls import reverse
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from django_scopes.forms import SafeModelChoiceField
from phonenumber_field.formfields import PhoneNumberField
from pretix.base.forms import I18nModelForm
from pretix.base.models import WaitingListEntry
from pretix.control.forms.widgets import Select2
from pretix.base.forms.questions import NamePartsFormField
from pretix.base.models import Item, ItemVariation, WaitingListEntry
from pretix.control.forms.widgets import Select2, Select2ItemVarQuota
class WaitingListEntryTransferForm(I18nModelForm):
@@ -54,3 +60,93 @@ class WaitingListEntryTransferForm(I18nModelForm):
field_classes = {
'subevent': SafeModelChoiceField,
}
class WaitingListEntryEditForm(I18nModelForm):
itemvar = ChoiceField()
def __init__(self, *args, **kwargs):
self.instance = kwargs.get('instance', None)
initial = kwargs.get('initial', {})
if self.instance and self.instance.pk and 'itemvar' not in initial:
if self.instance.variation is not None:
initial['itemvar'] = f'{self.instance.item.pk}-{self.instance.variation.pk}'
else:
initial['itemvar'] = self.instance.item.pk
kwargs['initial'] = initial
super().__init__(*args, **kwargs)
# Prevent the item field cleaning from complaining that it isn't populated
# the value for item is derived and populated during form.clean()
self.fields['item'].required = False
self.fields['name_parts'] = NamePartsFormField(
max_length=255,
required=True,
scheme=self.event.organizer.settings.name_scheme,
titles=self.event.organizer.settings.name_scheme_titles,
label=_('Name'),
)
self.fields['name_parts'].required = self.event.settings.waiting_list_names_required
self.fields['phone'].required = self.event.settings.waiting_list_phones_required
choices = []
items = self.event.items.prefetch_related('variations')
for item in items:
if len(item.variations.all()) > 0:
for v in item.variations.all():
choices.append((
'{}-{}'.format(item.pk, v.pk),
'{} {}'.format(item, v.value) if item.active else mark_safe(
f'<strike class="text-muted">{escape(item)} {escape(v.value)}</strike>')
))
else:
choices.append(('{}'.format(item.pk), str(item) if item.active else mark_safe(
f'<strike class="text-muted">{escape(item)}</strike>')))
self.fields['itemvar'].label = _("Item and Variation")
self.fields['itemvar'].required = True
self.fields['itemvar'].widget = Select2ItemVarQuota(
attrs={
'data-model-select2': 'generic',
'data-select2-url': reverse('control:event.items.itemvars.select2', kwargs={
'event': self.event.slug,
'organizer': self.event.organizer.slug,
}),
},
choices=choices
)
self.fields['itemvar'].choices = choices
def clean(self):
cleaned_data = super().clean()
itemvar = cleaned_data.get('itemvar')
cleaned_data['item'] = Item.objects.get(pk=itemvar.split('-')[0])
if '-' in itemvar:
cleaned_data['variation'] = ItemVariation.objects.get(pk=itemvar.split('-')[1])
return cleaned_data
class Meta:
model = WaitingListEntry
fields = [
'email',
'name_parts',
'phone',
'item',
'variation',
]
field_classes = {
'email': EmailField,
'phone': PhoneNumberField,
'item': SafeModelChoiceField,
'variation': SafeModelChoiceField,
}
exclude = [
'subevent', # handled by EntryTransfer view
'voucher', # handled by the assign operation in the WaitingListActionView
'priority' # handled via thumbs up/down
]

View File

@@ -0,0 +1,24 @@
{% extends "pretixcontrol/event/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block title %}{% trans "Edit waiting list entry" %}{% endblock %}
{% block content %}
<h1>{% trans "Edit waiting list entry" %}</h1>
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
{% bootstrap_field form.email layout="control" %}
{% if names_asked %}
{% bootstrap_field form.name_parts layout="control" %}
{% endif %}
{% if phones_asked %}
{% bootstrap_field form.phone layout="control" %}
{% endif %}
{% bootstrap_field form.itemvar layout="control" %}
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Submit" %}
</button>
</div>
</form>
{% endblock %}

View File

@@ -274,6 +274,7 @@
<i class="fa fa-calendar" aria-hidden="true"></i>
</a>
{% endif %}
<a href="{% url "control:event.orders.waitinglist.edit" organizer=request.event.organizer.slug event=request.event.slug entry=e.id %}" class="btn btn-default btn-sm"><i class="fa fa-pencil"></i></a>
<a href="{% url "control:event.orders.waitinglist.delete" organizer=request.event.organizer.slug event=request.event.slug entry=e.id %}?next={{ request.get_full_path|urlencode }}" class="btn btn-danger btn-sm"><i class="fa fa-trash"></i></a>
{% else %}
<button class="btn btn-default btn-sm disabled">

View File

@@ -474,6 +474,8 @@ urlpatterns = [
re_path(r'^waitinglist/$', waitinglist.WaitingListView.as_view(), name='event.orders.waitinglist'),
re_path(r'^waitinglist/action$', waitinglist.WaitingListActionView.as_view(), name='event.orders.waitinglist.action'),
re_path(r'^waitinglist/auto_assign$', waitinglist.AutoAssign.as_view(), name='event.orders.waitinglist.auto'),
re_path(r'^waitinglist/(?P<entry>\d+)/edit$', waitinglist.EntryEdit.as_view(),
name='event.orders.waitinglist.edit'),
re_path(r'^waitinglist/(?P<entry>\d+)/delete$', waitinglist.EntryDelete.as_view(),
name='event.orders.waitinglist.delete'),
re_path(r'^waitinglist/(?P<entry>\d+)/transfer$', waitinglist.EntryTransfer.as_view(),

View File

@@ -53,7 +53,9 @@ from pretix.base.models import Item, LogEntry, Quota, WaitingListEntry
from pretix.base.models.waitinglist import WaitingListException
from pretix.base.services.waitinglist import assign_automatically
from pretix.base.views.tasks import AsyncAction
from pretix.control.forms.waitinglist import WaitingListEntryTransferForm
from pretix.control.forms.waitinglist import (
WaitingListEntryEditForm, WaitingListEntryTransferForm,
)
from pretix.control.permissions import EventPermissionRequiredMixin
from pretix.control.views import PaginationMixin
@@ -390,6 +392,44 @@ class EntryDelete(EventPermissionRequiredMixin, CompatDeleteView):
})
class EntryEdit(EventPermissionRequiredMixin, UpdateView):
model = WaitingListEntry
template_name = 'pretixcontrol/waitinglist/edit.html'
permission = 'can_change_orders'
form_class = WaitingListEntryEditForm
context_object_name = 'entry'
def get_object(self, queryset=None):
return get_object_or_404(WaitingListEntry, pk=self.kwargs['entry'], event=self.request.event)
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
ctx['names_asked'] = self.request.event.settings.waiting_list_names_asked
ctx['phones_asked'] = self.request.event.settings.waiting_list_phones_asked
return ctx
@transaction.atomic
def form_valid(self, form):
messages.success(self.request, _('The waitinglist entry has been updated.'))
if form.has_changed():
self.object.log_action(
'pretix.event.orders.waitinglist.changed', user=self.request.user, data={
k: form.cleaned_data.get(k) for k in form.changed_data
}
)
return super().form_valid(form)
def form_invalid(self, form):
messages.error(self.request, _('We could not save your changes. See below for details.'))
return super().form_invalid(form)
def get_success_url(self) -> str:
return reverse('control:event.orders.waitinglist', kwargs={
'event': self.request.event.slug,
'organizer': self.request.event.organizer.slug
})
class EntryTransfer(EventPermissionRequiredMixin, UpdateView):
model = WaitingListEntry
template_name = 'pretixcontrol/waitinglist/transfer.html'