agendas: Booking.user_check_type becomes 2 fields (slug, label) (#66015)

This commit is contained in:
Lauréline Guérin 2022-06-09 14:53:13 +02:00
parent 244dd89cf9
commit b5d836d46d
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
14 changed files with 308 additions and 174 deletions

View File

@ -0,0 +1,21 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agendas', '0133_auto_20220628_1600'),
]
operations = [
migrations.AddField(
model_name='booking',
name='user_check_type_label',
field=models.CharField(blank=True, null=True, max_length=150),
),
migrations.AddField(
model_name='booking',
name='user_check_type_slug',
field=models.CharField(blank=True, null=True, max_length=160),
),
]

View File

@ -0,0 +1,46 @@
from collections import defaultdict
from django.db import migrations
def forwards(apps, schema_editor):
Booking = apps.get_model('agendas', 'Booking')
for booking in Booking.objects.filter(user_check_type__isnull=False):
booking.user_check_type_slug = booking.user_check_type.slug
booking.user_check_type_label = booking.user_check_type.label
booking.save()
def backwards(apps, schema_editor):
Booking = apps.get_model('agendas', 'Booking')
Agenda = apps.get_model('agendas', 'Agenda')
check_types_by_agenda_id = defaultdict(list)
for agenda in Agenda.objects.filter(kind='events'):
if not agenda.check_type_group:
continue
for check_type in agenda.check_type_group.check_types.all():
check_types_by_agenda_id[agenda.pk].append(check_type)
for booking in Booking.objects.filter(user_check_type_slug__isnull=False, user_was_present__isnull=False):
if booking.event.agenda_id not in check_types_by_agenda_id:
# no check_types for this agenda
continue
for check_type in check_types_by_agenda_id[booking.event.agenda_id]:
if check_type.kind == 'absence' and booking.user_was_present is True:
continue
if check_type.kind == 'presence' and booking.user_was_present is False:
continue
if check_type.slug == booking.user_check_type_slug:
booking.user_check_type = check_type
booking.save()
break
class Migration(migrations.Migration):
dependencies = [
('agendas', '0134_remove_check_type'),
]
operations = [
migrations.RunPython(forwards, reverse_code=backwards),
]

View File

@ -0,0 +1,15 @@
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('agendas', '0135_remove_check_type'),
]
operations = [
migrations.RemoveField(
model_name='booking',
name='user_check_type',
),
]

View File

@ -1958,7 +1958,8 @@ class Booking(models.Model):
user_email = models.EmailField(blank=True)
user_phone_number = models.CharField(max_length=16, blank=True)
user_was_present = models.NullBooleanField()
user_check_type = models.ForeignKey('agendas.CheckType', on_delete=models.PROTECT, blank=True, null=True)
user_check_type_slug = models.CharField(max_length=160, blank=True, null=True)
user_check_type_label = models.CharField(max_length=150, blank=True, null=True)
out_of_min_delay = models.BooleanField(default=False)
extra_emails = ArrayField(models.EmailField(), default=list)
@ -2009,22 +2010,24 @@ class Booking(models.Model):
self.secondary_booking_set.update(in_waiting_list=True)
self.save()
def mark_user_absence(self, check_type=None):
check_type = check_type or None
self.user_check_type = check_type
def mark_user_absence(self, check_type_slug=None, check_type_label=None):
self.user_check_type_slug = check_type_slug
self.user_check_type_label = check_type_label
self.user_was_present = False
with transaction.atomic():
self.secondary_booking_set.update(user_check_type=check_type)
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.save()
self.event.set_is_checked()
def mark_user_presence(self, check_type=None):
check_type = check_type or None
self.user_check_type = check_type
def mark_user_presence(self, check_type_slug=None, check_type_label=None):
self.user_check_type_slug = check_type_slug
self.user_check_type_label = check_type_label
self.user_was_present = True
with transaction.atomic():
self.secondary_booking_set.update(user_check_type=check_type)
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.save()
self.event.set_is_checked()

View File

@ -223,9 +223,12 @@ class BookingSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
ret = super().to_representation(instance)
check_type_slug = self.instance.user_check_type.slug if self.instance.user_check_type else ''
ret['user_absence_reason'] = check_type_slug if self.instance.user_was_present is False else ''
ret['user_presence_reason'] = check_type_slug if self.instance.user_was_present is True else ''
ret['user_absence_reason'] = (
self.instance.user_check_type_slug if self.instance.user_was_present is False else None
)
ret['user_presence_reason'] = (
self.instance.user_check_type_slug if self.instance.user_was_present is True else None
)
return ret
def _validate_check_type(self, kind, value):
@ -268,10 +271,14 @@ class BookingSerializer(serializers.ModelSerializer):
{'user_absence_reason': _('can not set user_absence_reason and user_presence_reason')}
)
if 'user_absence_reason' in attrs:
attrs['user_check_type'] = attrs['user_absence_reason']
check_type = attrs['user_absence_reason']
attrs['user_check_type_slug'] = check_type.slug if check_type else None
attrs['user_check_type_label'] = check_type.label if check_type else None
del attrs['user_absence_reason']
elif 'user_presence_reason' in attrs:
attrs['user_check_type'] = attrs['user_presence_reason']
check_type = attrs['user_presence_reason']
attrs['user_check_type_slug'] = check_type.slug if check_type else None
attrs['user_check_type_label'] = check_type.label if check_type else None
del attrs['user_presence_reason']
return attrs

View File

@ -2134,7 +2134,7 @@ class MultipleAgendasEventsCheckStatus(APIView):
booking_queryset = Booking.objects.filter(
event__in=events,
user_external_id=user_external_id,
).select_related('user_check_type')
)
bookings_by_event_id = collections.defaultdict(list)
for booking in booking_queryset:
bookings_by_event_id[booking.event_id].append(booking)
@ -2159,7 +2159,7 @@ class MultipleAgendasEventsCheckStatus(APIView):
else:
check_status = {
'status': 'presence' if booking.user_was_present else 'absence',
'check_type': booking.user_check_type.slug if booking.user_check_type else '',
'check_type': booking.user_check_type_slug,
}
data.append(
{
@ -2365,15 +2365,13 @@ class BookingFilter(filters.FilterSet):
def filter_user_absence_reason(self, queryset, name, value):
return queryset.filter(
Q(user_check_type__slug=value) | Q(user_check_type__label=value),
user_check_type__kind='absence',
Q(user_check_type_slug=value) | Q(user_check_type_label=value),
user_was_present=False,
)
def filter_user_presence_reason(self, queryset, name, value):
return queryset.filter(
Q(user_check_type__slug=value) | Q(user_check_type__label=value),
user_check_type__kind='presence',
Q(user_check_type_slug=value) | Q(user_check_type_label=value),
user_was_present=True,
)
@ -2502,7 +2500,8 @@ class BookingAPI(APIView):
if 'use_color_for' in request.data:
secondary_bookings_update['color'] = self.booking.color
if 'user_absence_reason' in request.data or 'user_presence_reason' in request.data:
secondary_bookings_update['user_check_type'] = self.booking.user_check_type
secondary_bookings_update['user_check_type_slug'] = self.booking.user_check_type_slug
secondary_bookings_update['user_check_type_label'] = self.booking.user_check_type_label
if extra_data:
secondary_bookings_update['extra_data'] = self.booking.extra_data
if secondary_bookings_update:

View File

@ -446,14 +446,14 @@ class BookingCheckFilterSet(django_filters.FilterSet):
]
if self.agenda.check_type_group:
status_choices += [
('presence-%s' % r.pk, _('Presence (%s)') % r.label)
('presence::%s' % r.slug, _('Presence (%s)') % r.label)
for r in self.agenda.check_type_group.check_types.all()
if r.kind == 'presence' and not r.disabled
]
status_choices += [('absence', _('Absence'))]
if self.agenda.check_type_group:
status_choices += [
('absence-%s' % r.pk, _('Absence (%s)') % r.label)
('absence::%s' % r.slug, _('Absence (%s)') % r.label)
for r in self.agenda.check_type_group.check_types.all()
if r.kind == 'absence' and not r.disabled
]
@ -480,10 +480,10 @@ class BookingCheckFilterSet(django_filters.FilterSet):
return queryset.filter(user_was_present=True)
if value == 'absence':
return queryset.filter(user_was_present=False)
if value.startswith('absence-'):
return queryset.filter(user_was_present=False, user_check_type=value.split('-')[1])
if value.startswith('presence-'):
return queryset.filter(user_was_present=True, user_check_type=value.split('-')[1])
if value.startswith('absence::'):
return queryset.filter(user_was_present=False, user_check_type_slug=value.split('::')[1])
if value.startswith('presence::'):
return queryset.filter(user_was_present=True, user_check_type_slug=value.split('::')[1])
return queryset
def do_nothing(self, queryset, name, value):
@ -509,7 +509,7 @@ class BookingCheckAbsenceForm(forms.Form):
super().__init__(*args, **kwargs)
if agenda.check_type_group:
self.fields['check_type'].choices = [('', '---------')] + [
(r.pk, r.label)
(r.slug, r.label)
for r in agenda.check_type_group.check_types.all()
if r.kind == 'absence' and not r.disabled
]
@ -523,7 +523,7 @@ class BookingCheckPresenceForm(forms.Form):
super().__init__(*args, **kwargs)
if agenda.check_type_group:
self.fields['check_type'].choices = [('', '---------')] + [
(r.pk, r.label)
(r.slug, r.label)
for r in agenda.check_type_group.check_types.all()
if r.kind == 'presence' and not r.disabled
]
@ -1340,7 +1340,7 @@ class AgendaBookingCheckSettingsForm(forms.ModelForm):
super().__init__(*args, **kwargs)
if not CheckTypeGroup.objects.exists():
del self.fields['check_type_group']
elif Booking.objects.filter(event__agenda=self.instance, user_check_type__isnull=False).exists():
elif Booking.objects.filter(event__agenda=self.instance, user_check_type_slug__isnull=False).exists():
# not possible to update check_type_group if bookings with non null check_type exist
del self.fields['check_type_group']

View File

@ -3,8 +3,8 @@
<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 %}
({{ booking.user_check_type }})
{% if booking.user_was_present is not None and booking.user_check_type_label %}
({{ booking.user_check_type_label }})
{% endif %}
</td>
{% if not event.checked or not agenda.disable_check_update %}

View File

@ -724,19 +724,6 @@ class CheckTypeGroupDeleteView(DeleteView):
raise PermissionDenied()
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['cannot_delete'] = Booking.objects.filter(user_check_type__group=self.get_object()).exists()
context['cannot_delete_msg'] = _(
'Can not delete this check type group: a check type of this group is set on some existing bookings.'
)
return context
def delete(self, request, *args, **kwargs):
if Booking.objects.filter(user_check_type__group=self.get_object()).exists():
raise Http404
return super().delete(request, *args, **kwargs)
def get_success_url(self):
return reverse('chrono-manager-check-type-list')
@ -807,7 +794,7 @@ class CheckTypeEditView(UpdateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['is_used'] = Booking.objects.filter(user_check_type=self.get_object()).exists()
context['is_used'] = Booking.objects.filter(user_check_type_slug=self.get_object().slug).exists()
return context
def get_success_url(self):
@ -832,14 +819,16 @@ class CheckTypeDeleteView(DeleteView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['cannot_delete'] = Booking.objects.filter(user_check_type=self.get_object()).exists()
context['cannot_delete'] = Booking.objects.filter(
user_check_type_slug=self.get_object().slug
).exists()
context['cannot_delete_msg'] = _(
'Can not delete this check type: it is set on some existing bookings.'
)
return context
def delete(self, request, *args, **kwargs):
if Booking.objects.filter(user_check_type=self.get_object()).exists():
if Booking.objects.filter(user_check_type_slug=self.get_object().slug).exists():
raise Http404
return super().delete(request, *args, **kwargs)
@ -2404,7 +2393,7 @@ class EventCheckView(ViewableAgendaMixin, DetailView):
booking_qs_kwargs = {}
if not self.agenda.subscriptions.exists():
booking_qs_kwargs = {'cancellation_datetime__isnull': True}
booking_qs = event.booking_set.prefetch_related('user_check_type')
booking_qs = event.booking_set
booked_qs = booking_qs.filter(
in_waiting_list=False, primary_booking__isnull=True, **booking_qs_kwargs
)
@ -2450,11 +2439,11 @@ class EventCheckView(ViewableAgendaMixin, DetailView):
booked_without_status = True
booking.absence_form = BookingCheckAbsenceForm(
agenda=self.agenda,
initial={'check_type': booking.user_check_type_id},
initial={'check_type': booking.user_check_type_slug},
)
booking.presence_form = BookingCheckPresenceForm(
agenda=self.agenda,
initial={'check_type': booking.user_check_type_id},
initial={'check_type': booking.user_check_type_slug},
)
booking.kind = 'booking'
results.append(booking)
@ -2512,6 +2501,15 @@ class EventCheckMixin:
user_was_present__isnull=True,
)
def get_check_type(self, kind):
form = self.get_form()
check_type = None
if form.is_valid() and form.cleaned_data['check_type']:
check_type = CheckType.objects.filter(
slug=form.cleaned_data['check_type'], kind=kind, group=self.agenda.check_type_group
).first()
return check_type
def response(self, request):
return HttpResponseRedirect(
reverse(
@ -2530,10 +2528,10 @@ class EventPresenceView(EventCheckMixin, ViewableAgendaMixin, FormView):
return kwargs
def post(self, request, *args, **kwargs):
form = self.get_form()
qs_kwargs = {}
if form.is_valid():
qs_kwargs['user_check_type'] = form.cleaned_data['check_type']
check_type = self.get_check_type(kind='presence')
qs_kwargs['user_check_type_slug'] = check_type.slug if check_type else None
qs_kwargs['user_check_type_label'] = check_type.label if check_type else None
bookings = self.get_bookings()
bookings.update(user_was_present=True, **qs_kwargs)
self.event.set_is_checked()
@ -2552,10 +2550,10 @@ class EventAbsenceView(EventCheckMixin, ViewableAgendaMixin, FormView):
return kwargs
def post(self, request, *args, **kwargs):
form = self.get_form()
qs_kwargs = {}
if form.is_valid():
qs_kwargs['user_check_type'] = form.cleaned_data['check_type']
check_type = self.get_check_type(kind='absence')
qs_kwargs['user_check_type_slug'] = check_type.slug if check_type else None
qs_kwargs['user_check_type_label'] = check_type.label if check_type else None
bookings = self.get_bookings()
bookings.update(user_was_present=False, **qs_kwargs)
self.event.set_is_checked()
@ -3266,20 +3264,22 @@ class BookingCheckMixin:
primary_booking__isnull=True,
)
def get_check_type(self):
def get_check_type(self, kind):
form = self.get_form()
check_type = None
if form.is_valid() and form.cleaned_data['check_type']:
check_type = CheckType.objects.get(pk=form.cleaned_data['check_type'])
check_type = CheckType.objects.filter(
slug=form.cleaned_data['check_type'], kind=kind, group=self.agenda.check_type_group
).first()
return check_type
def response(self, request, booking):
if request.is_ajax():
booking.absence_form = BookingCheckAbsenceForm(
agenda=self.agenda, initial={'check_type': booking.user_check_type_id}
agenda=self.agenda, initial={'check_type': booking.user_check_type_slug}
)
booking.presence_form = BookingCheckPresenceForm(
agenda=self.agenda, initial={'check_type': booking.user_check_type_id}
agenda=self.agenda, initial={'check_type': booking.user_check_type_slug}
)
return render(
request,
@ -3304,7 +3304,11 @@ class BookingPresenceView(ViewableAgendaMixin, BookingCheckMixin, FormView):
def post(self, request, *args, **kwargs):
booking = self.get_booking(**kwargs)
booking.mark_user_presence(check_type=self.get_check_type())
check_type = self.get_check_type(kind='presence')
booking.mark_user_presence(
check_type_slug=check_type.slug if check_type else None,
check_type_label=check_type.label if check_type else None,
)
return self.response(request, booking)
@ -3321,7 +3325,11 @@ class BookingAbsenceView(ViewableAgendaMixin, BookingCheckMixin, FormView):
def post(self, request, *args, **kwargs):
booking = self.get_booking(**kwargs)
booking.mark_user_absence(check_type=self.get_check_type())
check_type = self.get_check_type(kind='absence')
booking.mark_user_absence(
check_type_slug=check_type.slug if check_type else None,
check_type_label=check_type.label if check_type else None,
)
return self.response(request, booking)

View File

@ -1249,7 +1249,7 @@ def test_datetimes_multiple_agendas_with_status(app):
event=event_absence_with_reason,
user_external_id='xxx',
user_was_present=False,
user_check_type=check_type_absence,
user_check_type_slug=check_type_absence.slug,
)
event_presence = Event.objects.create(
slug='event-presence',
@ -1268,7 +1268,7 @@ def test_datetimes_multiple_agendas_with_status(app):
event=event_presence_with_reason,
user_external_id='xxx',
user_was_present=True,
user_check_type=check_type_presence,
user_check_type_slug=check_type_presence.slug,
)
event_booked_future = Event.objects.create(
slug='event-booked-future',

View File

@ -151,8 +151,8 @@ def test_bookings_api(app, user):
'user_email': '',
'user_phone_number': '',
'user_was_present': None,
'user_absence_reason': '',
'user_presence_reason': '',
'user_absence_reason': None,
'user_presence_reason': None,
'use_color_for': None,
'extra_data': None,
'cancellation_datetime': None,
@ -166,8 +166,8 @@ def test_bookings_api(app, user):
'user_email': '',
'user_phone_number': '',
'user_was_present': None,
'user_absence_reason': '',
'user_presence_reason': '',
'user_absence_reason': None,
'user_presence_reason': None,
'use_color_for': None,
'extra_data': None,
'event': resp.json['data'][1]['event'],
@ -182,8 +182,8 @@ def test_bookings_api(app, user):
'user_email': '',
'user_phone_number': '',
'user_was_present': None,
'user_absence_reason': '',
'user_presence_reason': '',
'user_absence_reason': None,
'user_presence_reason': None,
'use_color_for': None,
'extra_data': None,
'event': resp.json['data'][1]['event'],
@ -333,10 +333,18 @@ def test_bookings_api_filter_user_absence_reason(app, user):
)
Booking.objects.create(event=event, user_external_id='42', user_was_present=False)
booking2 = Booking.objects.create(
event=event, user_external_id='42', user_was_present=False, user_check_type=check_type_absence
event=event,
user_external_id='42',
user_was_present=False,
user_check_type_slug=check_type_absence.slug,
user_check_type_label=check_type_absence.label,
)
Booking.objects.create(
event=event, user_external_id='42', user_was_present=False, user_check_type=check_type_presence
event=event,
user_external_id='42',
user_was_present=True,
user_check_type_slug=check_type_presence.slug,
user_check_type_label=check_type_presence.label,
)
app.authorization = ('Basic', ('john.doe', 'password'))
@ -376,10 +384,18 @@ def test_bookings_api_filter_user_presence_reason(app, user):
)
Booking.objects.create(event=event, user_external_id='42', user_was_present=True)
booking2 = Booking.objects.create(
event=event, user_external_id='42', user_was_present=True, user_check_type=check_type_presence
event=event,
user_external_id='42',
user_was_present=True,
user_check_type_slug=check_type_presence.slug,
user_check_type_label=check_type_presence.label,
)
Booking.objects.create(
event=event, user_external_id='42', user_was_present=True, user_check_type=check_type_absence
event=event,
user_external_id='42',
user_was_present=False,
user_check_type_slug=check_type_absence.slug,
user_check_type_label=check_type_absence.label,
)
app.authorization = ('Basic', ('john.doe', 'password'))
@ -483,14 +499,14 @@ def test_booking_api_present(app, user, flag):
)
agenda = Agenda.objects.create(label='Foo bar', kind='events')
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
booking = Booking.objects.create(event=event, user_was_present=flag, user_check_type=check_type)
booking = Booking.objects.create(event=event, user_was_present=flag, user_check_type_slug=check_type.slug)
app.authorization = ('Basic', ('john.doe', 'password'))
resp = app.get('/api/booking/%s/' % booking.pk)
assert resp.json['booking_id'] == booking.pk
assert resp.json['user_was_present'] == flag
assert resp.json['user_absence_reason'] == ('foo-bar' if flag is False else '')
assert resp.json['user_presence_reason'] == ('foo-bar' if flag is True else '')
assert resp.json['user_absence_reason'] == ('foo-bar' if flag is False else None)
assert resp.json['user_presence_reason'] == ('foo-bar' if flag is True else None)
@pytest.mark.parametrize('flag', [True, False])
@ -663,7 +679,8 @@ def test_booking_patch_api_absence_reason(app, user):
# it works with label
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': 'Foo bar'})
booking.refresh_from_db()
assert booking.user_check_type == check_type_absence
assert booking.user_check_type_slug == check_type_absence.slug
assert booking.user_check_type_label == check_type_absence.label
# disabled
resp = app.patch_json(
@ -677,10 +694,12 @@ def test_booking_patch_api_absence_reason(app, user):
# reset
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': ''})
booking.refresh_from_db()
assert booking.user_check_type is None
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': None})
booking.refresh_from_db()
assert booking.user_check_type is None
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
# make secondary bookings
Booking.objects.create(event=event, primary_booking=booking, user_was_present=False)
@ -691,14 +710,16 @@ def test_booking_patch_api_absence_reason(app, user):
# it works also with slug
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': check_type_absence.slug})
booking.refresh_from_db()
assert booking.user_check_type == check_type_absence
assert booking.user_check_type_slug == check_type_absence.slug
assert booking.user_check_type_label == check_type_absence.label
# all secondary bookings are updated
assert list(booking.secondary_booking_set.values_list('user_check_type', flat=True)) == [
check_type_absence.pk,
check_type_absence.pk,
assert list(booking.secondary_booking_set.values_list('user_check_type_slug', flat=True)) == [
check_type_absence.slug,
check_type_absence.slug,
]
other_booking.refresh_from_db()
assert other_booking.user_check_type is None # not changed
assert other_booking.user_check_type_slug is None # not changed
assert other_booking.user_check_type_label is None # not changed
# user_was_present is True, can not set user_absence_reason
Booking.objects.update(user_was_present=True)
@ -716,7 +737,8 @@ def test_booking_patch_api_absence_reason(app, user):
assert resp.json['err'] == 0
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_check_type == check_type_absence
assert booking.user_check_type_slug == check_type_absence.slug
assert booking.user_check_type_label == check_type_absence.label
# mark the event as checked
event.checked = True
@ -783,7 +805,8 @@ def test_booking_patch_api_presence_reason(app, user):
# it works with label
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': 'Foo bar'})
booking.refresh_from_db()
assert booking.user_check_type == check_type_presence
assert booking.user_check_type_slug == check_type_presence.slug
assert booking.user_check_type_label == check_type_presence.label
# disabled
resp = app.patch_json(
@ -797,10 +820,12 @@ def test_booking_patch_api_presence_reason(app, user):
# reset
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': ''})
booking.refresh_from_db()
assert booking.user_check_type is None
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': None})
booking.refresh_from_db()
assert booking.user_check_type is None
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
# make secondary bookings
Booking.objects.create(event=event, primary_booking=booking, user_was_present=True)
@ -811,14 +836,16 @@ def test_booking_patch_api_presence_reason(app, user):
# it works also with slug
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': check_type_presence.slug})
booking.refresh_from_db()
assert booking.user_check_type == check_type_presence
assert booking.user_check_type_slug == check_type_presence.slug
assert booking.user_check_type_label == check_type_presence.label
# all secondary bookings are updated
assert list(booking.secondary_booking_set.values_list('user_check_type', flat=True)) == [
check_type_presence.pk,
check_type_presence.pk,
assert list(booking.secondary_booking_set.values_list('user_check_type_slug', flat=True)) == [
check_type_presence.slug,
check_type_presence.slug,
]
other_booking.refresh_from_db()
assert other_booking.user_check_type is None # not changed
assert other_booking.user_check_type_slug is None # not changed
assert other_booking.user_check_type_label is None # not changed
# user_was_present is False, can not set user_presence_reason
Booking.objects.update(user_was_present=False)
@ -836,7 +863,8 @@ def test_booking_patch_api_presence_reason(app, user):
assert resp.json['err'] == 0
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type == check_type_presence
assert booking.user_check_type_slug == check_type_presence.slug
assert booking.user_check_type_label == check_type_presence.label
# mark the event as checked
event.checked = True

View File

@ -5,7 +5,7 @@ from django.db import connection
from django.test.utils import CaptureQueriesContext
from django.utils.timezone import localtime, make_aware, now
from chrono.agendas.models import Agenda, Booking, CheckType, CheckTypeGroup, Event, EventsType, Subscription
from chrono.agendas.models import Agenda, Booking, Event, EventsType, Subscription
pytestmark = pytest.mark.django_db
@ -1017,16 +1017,14 @@ def test_events_check_status(app, user):
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['check_status'] == {
'status': 'absence',
'check_type': '',
'check_type': None,
}
assert resp.json['data'][0]['booking']['user_was_present'] is False
assert resp.json['data'][0]['booking']['user_absence_reason'] == ''
assert resp.json['data'][0]['booking']['user_presence_reason'] == ''
assert resp.json['data'][0]['booking']['user_absence_reason'] is None
assert resp.json['data'][0]['booking']['user_presence_reason'] is None
# absence with check type
group = CheckTypeGroup.objects.create(label='Foo bar')
check_type = CheckType.objects.create(label='Foo reason', group=group, kind='absence')
booking.user_check_type = check_type
booking.user_check_type_slug = 'foo-reason'
booking.save()
resp = app.get(url, params=params)
assert resp.json['err'] == 0
@ -1037,10 +1035,10 @@ def test_events_check_status(app, user):
}
assert resp.json['data'][0]['booking']['user_was_present'] is False
assert resp.json['data'][0]['booking']['user_absence_reason'] == 'foo-reason'
assert resp.json['data'][0]['booking']['user_presence_reason'] == ''
assert resp.json['data'][0]['booking']['user_presence_reason'] is None
# presence
booking.user_check_type = None
booking.user_check_type_slug = None
booking.user_was_present = True
booking.save()
resp = app.get(url, params=params)
@ -1048,16 +1046,14 @@ def test_events_check_status(app, user):
assert len(resp.json['data']) == 1
assert resp.json['data'][0]['check_status'] == {
'status': 'presence',
'check_type': '',
'check_type': None,
}
assert resp.json['data'][0]['booking']['user_was_present'] is True
assert resp.json['data'][0]['booking']['user_absence_reason'] == ''
assert resp.json['data'][0]['booking']['user_presence_reason'] == ''
assert resp.json['data'][0]['booking']['user_absence_reason'] is None
assert resp.json['data'][0]['booking']['user_presence_reason'] is None
# presence with check type
check_type.kind = 'presence'
check_type.save()
booking.user_check_type = check_type
booking.user_check_type_slug = 'foo-reason'
booking.save()
resp = app.get(url, params=params)
assert resp.json['err'] == 0
@ -1067,7 +1063,7 @@ def test_events_check_status(app, user):
'check_type': 'foo-reason',
}
assert resp.json['data'][0]['booking']['user_was_present'] is True
assert resp.json['data'][0]['booking']['user_absence_reason'] == ''
assert resp.json['data'][0]['booking']['user_absence_reason'] is None
assert resp.json['data'][0]['booking']['user_presence_reason'] == 'foo-reason'
@ -1081,8 +1077,6 @@ def test_events_check_status_events(app, user):
{'varname': 'bool', 'label': 'Bool', 'field_type': 'bool'},
],
)
group = CheckTypeGroup.objects.create(label='Foo bar')
check_type = CheckType.objects.create(label='Foo reason', group=group, kind='absence')
agenda = Agenda.objects.create(label='Foo', events_type=events_type)
start_datetime = now()
# recurring event
@ -1137,10 +1131,13 @@ def test_events_check_status_events(app, user):
date_end=datetime.date(year=2022, month=9, day=1),
)
booking1 = Booking.objects.create(
event=first_event, user_external_id='child:42', user_was_present=True, user_check_type=check_type
event=first_event,
user_external_id='child:42',
user_was_present=True,
user_check_type_slug='foo-reason',
)
booking2 = Booking.objects.create(
event=event, user_external_id='child:42', user_was_present=True, user_check_type=check_type
event=event, user_external_id='child:42', user_was_present=True, user_check_type_slug='foo-reason'
)
app.authorization = ('Basic', ('john.doe', 'password'))
@ -1209,12 +1206,12 @@ def test_events_check_status_events(app, user):
'extra_data': None,
'id': booking2.pk,
'in_waiting_list': False,
'user_absence_reason': '',
'user_absence_reason': None,
'user_email': '',
'user_first_name': '',
'user_last_name': '',
'user_phone_number': '',
'user_presence_reason': check_type.slug,
'user_presence_reason': 'foo-reason',
'user_was_present': True,
},
},
@ -1247,12 +1244,12 @@ def test_events_check_status_events(app, user):
'extra_data': None,
'id': booking1.pk,
'in_waiting_list': False,
'user_absence_reason': '',
'user_absence_reason': None,
'user_email': '',
'user_first_name': '',
'user_last_name': '',
'user_phone_number': '',
'user_presence_reason': check_type.slug,
'user_presence_reason': 'foo-reason',
'user_was_present': True,
},
},

View File

@ -83,17 +83,6 @@ def test_delete_group(app, admin_user):
assert CheckTypeGroup.objects.exists() is False
assert CheckType.objects.exists() is False
# check_type is used
group = CheckTypeGroup.objects.create(label='Foo bar')
check_type = CheckType.objects.create(label='Foo reason', group=group)
Booking.objects.update(user_check_type=check_type)
resp = app.get('/manage/check-type/group/%s/delete/' % group.pk)
assert (
'Can not delete this check type group: a check type of this group is set on some existing bookings.'
in resp
)
resp.form.submit(status=404)
def test_delete_group_as_manager(app, manager_user, agenda_with_restrictions):
group = CheckTypeGroup.objects.create(label='Foo bar')
@ -169,7 +158,7 @@ def test_edit_check_type(app, admin_user):
assert check_type.disabled is True
# check_type is used
Booking.objects.update(user_check_type=check_type)
Booking.objects.update(user_check_type_slug=check_type.slug)
resp = app.get('/manage/check-type/group/%s/%s/edit/' % (group.pk, check_type.pk))
assert 'This check type is set on some existing bookings, modify it with caution.' in resp
@ -201,7 +190,7 @@ def test_delete_check_type(app, admin_user):
# check_type is used
check_type = CheckType.objects.create(label='Foo reason', group=group)
Booking.objects.update(user_check_type=check_type)
Booking.objects.update(user_check_type_slug=check_type.slug)
resp = app.get('/manage/check-type/group/%s/%s/delete/' % (group.pk, check_type.pk))
assert 'Can not delete this check type: it is set on some existing bookings.' in resp
resp.form.submit(status=404)
@ -259,7 +248,7 @@ def test_agenda_group(app, admin_user):
assert 'Check type group: Foo bar' in resp
# cannot change check_type group booking with non null check_type exists
booking.user_check_type = check_type
booking.user_check_type_slug = check_type.slug
booking.save()
resp = app.get('/manage/agendas/%s/check-options' % agenda.pk)
assert 'check_type_group' not in resp.context['form'].fields

View File

@ -1707,7 +1707,7 @@ def test_event_check_filters(app, admin_user):
user_last_name='foo-none bar-val2 reason-foo',
extra_data={'bar': 'val2'},
user_was_present=False,
user_check_type=check_type_absence,
user_check_type_slug=check_type_absence.slug,
)
Booking.objects.create(
event=event,
@ -1716,7 +1716,7 @@ def test_event_check_filters(app, admin_user):
user_last_name='foo-none bar-val2 reason-bar',
extra_data={'bar': 'val2'},
user_was_present=True,
user_check_type=check_type_presence,
user_check_type_slug=check_type_presence.slug,
)
Booking.objects.create(
event=event,
@ -1725,7 +1725,7 @@ def test_event_check_filters(app, admin_user):
user_last_name='foo-none bar-val2 cancelled-absence',
extra_data={'bar': 'val2'},
user_was_present=False,
user_check_type=check_type_absence,
user_check_type_slug=check_type_absence.slug,
cancellation_datetime=now(),
)
Booking.objects.create(
@ -1735,7 +1735,7 @@ def test_event_check_filters(app, admin_user):
user_last_name='foo-none bar-val2 cancelled-presence',
extra_data={'bar': 'val2'},
user_was_present=True,
user_check_type=check_type_presence,
user_check_type_slug=check_type_presence.slug,
cancellation_datetime=now(),
)
@ -1816,14 +1816,14 @@ def test_event_check_filters(app, admin_user):
assert 'Subscription foo-val2 bar-val1' in resp
assert 'Subscription foo-val1 bar-val2' in resp
assert 'Subscription foo-none bar-val2' in resp
assert len(resp.pyquery.find('input[value=absence-%s]' % check_type_absence_disabled.pk)) == 0
assert len(resp.pyquery.find('input[value=absence-%s]' % check_type_presence_disabled.pk)) == 0
assert len(resp.pyquery.find('input[value=absence-%s]' % check_type_absence_disabled.slug)) == 0
assert len(resp.pyquery.find('input[value=absence-%s]' % check_type_presence_disabled.slug)) == 0
with CaptureQueriesContext(connection) as ctx:
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'extra-data-foo': 'val1'}
)
assert len(ctx.captured_queries) == 13
assert len(ctx.captured_queries) == 12
assert 'User none' not in resp
assert 'User empty' not in resp
assert 'User foo-val1 bar-none presence' in resp
@ -1996,7 +1996,7 @@ def test_event_check_filters(app, admin_user):
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
params={'booking-status': 'absence-%s' % check_type_absence.pk},
params={'booking-status': 'absence::%s' % check_type_absence.slug},
)
assert 'User none' not in resp
assert 'User empty' not in resp
@ -2016,7 +2016,7 @@ def test_event_check_filters(app, admin_user):
resp = app.get(
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
params={'booking-status': 'presence-%s' % check_type_presence.pk},
params={'booking-status': 'presence::%s' % check_type_presence.slug},
)
assert 'User none' not in resp
assert 'User empty' not in resp
@ -2107,10 +2107,12 @@ def test_event_check_booking(app, admin_user):
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type is None
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type is None
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is False
@ -2127,10 +2129,12 @@ def test_event_check_booking(app, admin_user):
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Absence'
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_check_type is None
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is False
assert secondary_booking.user_check_type is None
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is True
@ -2150,15 +2154,17 @@ def test_event_check_booking(app, admin_user):
# set as absent with check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
).follow()
assert 'Foo reason' in resp
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_check_type == check_type_absence
assert booking.user_check_type_slug == check_type_absence.slug
assert booking.user_check_type_label == check_type_absence.label
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is False
assert secondary_booking.user_check_type == check_type_absence
assert secondary_booking.user_check_type_slug == check_type_absence.slug
assert secondary_booking.user_check_type_label == check_type_absence.label
# set as present without check_type
resp = app.post(
@ -2170,10 +2176,12 @@ def test_event_check_booking(app, admin_user):
assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type is None
assert booking.user_check_type_slug is None
assert booking.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type is None
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is True
@ -2191,15 +2199,17 @@ def test_event_check_booking(app, admin_user):
# set as present with check_type
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
).follow()
assert 'Bar reason' in resp
booking.refresh_from_db()
assert booking.user_was_present is True
assert booking.user_check_type == check_type_presence
assert booking.user_check_type_slug == check_type_presence.slug
assert booking.user_check_type_label == check_type_presence.label
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type == check_type_presence
assert secondary_booking.user_check_type_slug == check_type_presence.slug
assert secondary_booking.user_check_type_label == check_type_presence.label
# mark the event as checked
event.checked = True
@ -2257,26 +2267,26 @@ def test_event_check_booking_ajax(app, admin_user):
# set as present
resp = app.post(
'/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
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 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="%s" selected>Bar reason</option>' % check_type_presence.pk in resp
assert '<option value="%s" selected>Bar reason</option>' % check_type_presence.slug in resp
# set as absent
resp = app.post(
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
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 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="%s" selected>Foo reason</option>' % check_type_absence.pk in resp
assert '<option value="%s" selected>Foo reason</option>' % check_type_absence.slug in resp
def test_event_check_all_bookings(app, admin_user):
@ -2306,7 +2316,8 @@ def test_event_check_all_bookings(app, admin_user):
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type is None
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
event.refresh_from_db()
assert event.checked is False
@ -2332,13 +2343,16 @@ def test_event_check_all_bookings(app, admin_user):
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type is None
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type is None
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
secondary_booking.refresh_from_db()
assert secondary_booking.user_was_present is True
assert secondary_booking.user_check_type is None
assert secondary_booking.user_check_type_slug is None
assert secondary_booking.user_check_type_label is None
event.refresh_from_db()
assert event.checked is True
@ -2348,37 +2362,44 @@ def test_event_check_all_bookings(app, admin_user):
assert 'Mark all bookings without status' in resp
app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type is None
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type is None
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
booking3.refresh_from_db()
assert booking3.user_was_present is False
assert booking3.user_check_type == check_type_absence
assert booking3.user_check_type_slug == check_type_absence.slug
assert booking3.user_check_type_label == check_type_absence.label
booking4 = Booking.objects.create(event=event, user_first_name='User', user_last_name='52')
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
assert 'Mark all bookings without status' in resp
app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
)
booking1.refresh_from_db()
assert booking1.user_was_present is False
assert booking1.user_check_type is None
assert booking1.user_check_type_slug is None
assert booking1.user_check_type_label is None
booking2.refresh_from_db()
assert booking2.user_was_present is True
assert booking2.user_check_type is None
assert booking2.user_check_type_slug is None
assert booking2.user_check_type_label is None
booking3.refresh_from_db()
assert booking3.user_was_present is False
assert booking3.user_check_type == check_type_absence
assert booking3.user_check_type_slug == check_type_absence.slug
assert booking3.user_check_type_label == check_type_absence.label
booking4.refresh_from_db()
assert booking4.user_was_present is True
assert booking4.user_check_type == check_type_presence
assert booking4.user_check_type_slug == check_type_presence.slug
assert booking4.user_check_type_label == check_type_presence.label
# now disable check update
agenda.disable_check_update = True
@ -2388,7 +2409,7 @@ def test_event_check_all_bookings(app, admin_user):
assert 'Mark all bookings without status' not in resp
app.post(
'/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
status=404,
)
resp = app.post(
@ -2398,7 +2419,7 @@ def test_event_check_all_bookings(app, admin_user):
)
app.post(
'/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
status=404,
)
resp = app.post(