manager: allow check for cancelled booking if subscription exist (#62235)

This commit is contained in:
Lauréline Guérin 2023-03-09 16:51:21 +01:00
parent e86cdf15fc
commit 45b72d53de
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
5 changed files with 104 additions and 33 deletions

View File

@ -2199,10 +2199,12 @@ class Booking(models.Model):
self.user_check_type_slug = check_type_slug
self.user_check_type_label = check_type_label
self.user_was_present = False
self.cancellation_datetime = None
with transaction.atomic():
self.secondary_booking_set.update(user_check_type_slug=check_type_slug)
self.secondary_booking_set.update(user_check_type_label=check_type_label)
self.secondary_booking_set.update(user_was_present=False)
self.secondary_booking_set.update(cancellation_datetime=None)
self.save()
self.event.set_is_checked()
@ -2210,10 +2212,12 @@ class Booking(models.Model):
self.user_check_type_slug = check_type_slug
self.user_check_type_label = check_type_label
self.user_was_present = True
self.cancellation_datetime = None
with transaction.atomic():
self.secondary_booking_set.update(user_check_type_slug=check_type_slug)
self.secondary_booking_set.update(user_check_type_label=check_type_label)
self.secondary_booking_set.update(user_was_present=True)
self.secondary_booking_set.update(cancellation_datetime=None)
self.save()
self.event.set_is_checked()

View File

@ -75,15 +75,7 @@
{% for result in results %}
<tr class="booking">
{% if result.kind == 'booking' %}
{% if result.cancellation_datetime is None %}
{% include "chrono/manager_event_check_booking_fragment.html" with booking=result %}
{% else %}
<td class="booking-username main-list">{{ result.get_user_block }}</td>
<td class="booking-status">({% trans "Cancelled" %})</td>
{% if not event.checked or not agenda.disable_check_update %}
<td class="booking-actions"></td>
{% endif %}
{% endif %}
{% include "chrono/manager_event_check_booking_fragment.html" with booking=result %}
{% elif result.kind == 'subscription' %}
<td class="booking-username main-list">{{ result.get_user_block }}</td>
<td class="booking-status">({% trans "Not booked" %})</td>

View File

@ -1,10 +1,14 @@
{% load i18n %}
<td class="booking-username main-list">{{ booking.get_user_block }}{% if booking.places_count > 1 %} ({{ booking.places_count }} {% trans "places" %}){% endif %}</td>
<td class="booking-status {% if booking.user_was_present is None %}without-status{% endif %}">
{{ booking.user_was_present|yesno:_('Present,Absent,-') }}
{% if booking.user_was_present is not None and booking.user_check_type_label %}
({{ booking.user_check_type_label }})
<td class="booking-status {% if booking.cancellation_datetime is None and booking.user_was_present is None %}without-status{% endif %}">
{% if booking.cancellation_datetime is None %}
{{ booking.user_was_present|yesno:_('Present,Absent,-') }}
{% if booking.user_was_present is not None and booking.user_check_type_label %}
({{ booking.user_check_type_label }})
{% endif %}
{% else %}
({% trans "Cancelled" %})
{% endif %}
</td>
{% if not event.checked or not agenda.disable_check_update %}

View File

@ -2637,9 +2637,8 @@ class EventCheckView(ViewableAgendaMixin, DetailView):
# set context
context['booked_without_status'] = booked_without_status
if context['booked_without_status']:
context['absence_form'] = BookingCheckAbsenceForm(agenda=self.agenda)
context['presence_form'] = BookingCheckPresenceForm(agenda=self.agenda)
context['absence_form'] = BookingCheckAbsenceForm(agenda=self.agenda)
context['presence_form'] = BookingCheckPresenceForm(agenda=self.agenda)
context['filterset'] = booked_filterset
context['results'] = results
context['waiting'] = waiting_qs
@ -3481,17 +3480,19 @@ booking_cancel = BookingCancelView.as_view()
class BookingCheckMixin:
def get_booking(self, **kwargs):
return get_object_or_404(
booking = get_object_or_404(
Booking,
Q(event__checked=False) | Q(event__agenda__disable_check_update=False),
pk=kwargs['booking_pk'],
event__agenda=self.agenda,
event__start_datetime__date__lte=now().date(),
event__cancelled=False,
cancellation_datetime__isnull=True,
in_waiting_list=False,
primary_booking__isnull=True,
)
if not booking.event.agenda.subscriptions.exists() and booking.cancellation_datetime is not None:
raise Http404
return booking
def get_check_type(self, kind):
form = self.get_form()

View File

@ -1608,20 +1608,8 @@ def test_event_check(app, admin_user, get_proper_html_str):
assert '&lt;b&gt;Subscription 14&lt;/b&gt; Foo Bar' in resp
assert '&lt;b&gt;User Waiting&lt;/b&gt; Foo Bar' in resp
# cancelled booking
token = resp.context['csrf_token']
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking6.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking6.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
# booking in waiting list
token = resp.context['csrf_token']
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking7.pk),
params={'csrfmiddlewaretoken': token},
@ -2331,6 +2319,88 @@ def test_event_check_booking(check_types, app, admin_user):
)
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_cancelled_booking(check_types, app, admin_user):
check_types.return_value = []
agenda = Agenda.objects.create(label='Events', kind='events')
event = Event.objects.create(
label='xyz',
start_datetime=now() - datetime.timedelta(days=1),
places=10,
waiting_list_places=5,
agenda=agenda,
)
booking = Booking.objects.create(event=event, user_first_name='User', user_last_name='42')
secondary_booking = Booking.objects.create(
event=event, user_first_name='User', user_last_name='42', primary_booking=booking
)
booking.cancel()
Booking.objects.create(event=event, user_first_name='User', user_last_name='43')
# no suscription: cancelled bookings are not displayed
login(app)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-status')) == 1
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) not in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) not in resp
token = resp.context['csrf_token']
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
status=404,
)
Subscription.objects.create(
agenda=agenda,
user_external_id='user:1',
user_first_name='Subscription',
user_last_name='42',
date_start=now(),
date_end=now() + datetime.timedelta(days=1),
)
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert len(resp.pyquery.find('td.booking-status')) == 2
assert resp.pyquery.find('td.booking-status')[0].text.strip() == '(Cancelled)'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 0
assert '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk) in resp
assert '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk) in resp
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
).follow()
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
booking.refresh_from_db()
assert booking.cancellation_datetime is None
assert booking.user_was_present is True
secondary_booking.refresh_from_db()
assert secondary_booking.cancellation_datetime is None
assert secondary_booking.user_was_present is True
booking.cancel()
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token},
).follow()
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Absent'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Absence'
booking.refresh_from_db()
assert booking.cancellation_datetime is None
assert booking.user_was_present is False
secondary_booking.refresh_from_db()
assert secondary_booking.cancellation_datetime is None
assert secondary_booking.user_was_present is False
@mock.patch('chrono.manager.forms.get_agenda_check_types')
def test_event_check_booking_ajax(check_types, app, admin_user):
check_types.return_value = [
@ -2358,7 +2428,7 @@ def test_event_check_booking_ajax(check_types, app, admin_user):
extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
)
assert '<tr>' not in resp # because this is a fragment
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present\n \n (Bar reason)'
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present\n \n (Bar reason)'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
assert '<option value="bar-reason" selected>Bar reason</option>' in resp
@ -2370,7 +2440,7 @@ def test_event_check_booking_ajax(check_types, app, admin_user):
extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
)
assert '<tr>' not in resp # because this is a fragment
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Absent\n \n (Foo reason)'
assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Absent\n \n (Foo reason)'
assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text.startswith('Absence')
assert '<option value="foo-reason" selected>Foo reason</option>' in resp