agendas: Booking.user_check_type becomes a FK (#63847)
This commit is contained in:
parent
a2350a6e36
commit
e2cd0d6ad6
|
@ -0,0 +1,19 @@
|
|||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('agendas', '0120_check_types'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='booking',
|
||||
name='new_user_check_type',
|
||||
field=models.ForeignKey(
|
||||
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='agendas.CheckType'
|
||||
),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,45 @@
|
|||
from collections import defaultdict
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def forwards(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.exclude(user_check_type='').filter(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.label == booking.user_check_type:
|
||||
booking.new_user_check_type = check_type
|
||||
booking.save()
|
||||
break
|
||||
|
||||
|
||||
def backwards(apps, schema_editor):
|
||||
Booking = apps.get_model('agendas', 'Booking')
|
||||
for booking in Booking.objects.filter(new_user_check_type__isnull=False):
|
||||
booking.user_check_type = booking.new_user_check_type.label
|
||||
booking.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('agendas', '0121_user_check_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(forwards, reverse_code=backwards),
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('agendas', '0122_user_check_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='booking',
|
||||
name='user_check_type',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='booking',
|
||||
old_name='new_user_check_type',
|
||||
new_name='user_check_type',
|
||||
),
|
||||
]
|
|
@ -1930,7 +1930,7 @@ 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.CharField(max_length=250, blank=True)
|
||||
user_check_type = models.ForeignKey('agendas.CheckType', on_delete=models.PROTECT, blank=True, null=True)
|
||||
out_of_min_delay = models.BooleanField(default=False)
|
||||
|
||||
extra_emails = ArrayField(models.EmailField(), default=list)
|
||||
|
@ -1982,7 +1982,7 @@ class Booking(models.Model):
|
|||
self.save()
|
||||
|
||||
def mark_user_absence(self, check_type=None):
|
||||
check_type = check_type or ''
|
||||
check_type = check_type or None
|
||||
self.user_check_type = check_type
|
||||
self.user_was_present = False
|
||||
with transaction.atomic():
|
||||
|
@ -1992,7 +1992,7 @@ class Booking(models.Model):
|
|||
self.event.set_is_checked()
|
||||
|
||||
def mark_user_presence(self, check_type=None):
|
||||
check_type = check_type or ''
|
||||
check_type = check_type or None
|
||||
self.user_check_type = check_type
|
||||
self.user_was_present = True
|
||||
with transaction.atomic():
|
||||
|
|
|
@ -155,17 +155,14 @@ class BookingSerializer(serializers.ModelSerializer):
|
|||
|
||||
def to_representation(self, instance):
|
||||
ret = super().to_representation(instance)
|
||||
ret['user_absence_reason'] = (
|
||||
self.instance.user_check_type if self.instance.user_was_present is False else ''
|
||||
)
|
||||
ret['user_presence_reason'] = (
|
||||
self.instance.user_check_type if self.instance.user_was_present is True else ''
|
||||
)
|
||||
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 ''
|
||||
return ret
|
||||
|
||||
def _validate_check_type(self, kind, value):
|
||||
if not value:
|
||||
return ''
|
||||
return None
|
||||
|
||||
error_messages = {
|
||||
'absence': _('unknown absence reason'),
|
||||
|
@ -177,14 +174,13 @@ class BookingSerializer(serializers.ModelSerializer):
|
|||
|
||||
check_types_qs = self.instance.event.agenda.check_type_group.check_types.filter(kind=kind)
|
||||
try:
|
||||
check_type = check_types_qs.get(slug=value)
|
||||
value = check_type.label
|
||||
return check_types_qs.get(slug=value)
|
||||
except CheckType.DoesNotExist:
|
||||
if not check_types_qs.filter(label=value).exists():
|
||||
try:
|
||||
return check_types_qs.get(label=value)
|
||||
except (CheckType.DoesNotExist, CheckType.MultipleObjectsReturned):
|
||||
raise serializers.ValidationError(error_messages[kind])
|
||||
|
||||
return value
|
||||
|
||||
def validate_user_absence_reason(self, value):
|
||||
return self._validate_check_type('absence', value)
|
||||
|
||||
|
|
|
@ -2239,10 +2239,18 @@ class BookingFilter(filters.FilterSet):
|
|||
return queryset.filter(Q(event__slug=value) | Q(event__primary_event__slug=value))
|
||||
|
||||
def filter_user_absence_reason(self, queryset, name, value):
|
||||
return queryset.filter(user_check_type=value, user_was_present=False)
|
||||
return queryset.filter(
|
||||
Q(user_check_type__slug=value) | Q(user_check_type__label=value),
|
||||
user_check_type__kind='absence',
|
||||
user_was_present=False,
|
||||
)
|
||||
|
||||
def filter_user_presence_reason(self, queryset, name, value):
|
||||
return queryset.filter(user_check_type=value, user_was_present=True)
|
||||
return queryset.filter(
|
||||
Q(user_check_type__slug=value) | Q(user_check_type__label=value),
|
||||
user_check_type__kind='presence',
|
||||
user_was_present=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Booking
|
||||
|
|
|
@ -462,14 +462,16 @@ class BookingCheckFilterSet(django_filters.FilterSet):
|
|||
]
|
||||
if self.agenda.check_type_group:
|
||||
status_choices += [
|
||||
('presence-%s' % r.label, _('Presence (%s)') % r.label)
|
||||
for r in self.agenda.check_type_group.check_types.presences()
|
||||
('presence-%s' % r.pk, _('Presence (%s)') % r.label)
|
||||
for r in self.agenda.check_type_group.check_types.all()
|
||||
if r.kind == 'presence'
|
||||
]
|
||||
status_choices += [('absence', _('Absence'))]
|
||||
if self.agenda.check_type_group:
|
||||
status_choices += [
|
||||
('absence-%s' % r.label, _('Absence (%s)') % r.label)
|
||||
for r in self.agenda.check_type_group.check_types.absences()
|
||||
('absence-%s' % r.pk, _('Absence (%s)') % r.label)
|
||||
for r in self.agenda.check_type_group.check_types.all()
|
||||
if r.kind == 'absence'
|
||||
]
|
||||
self.filters['booking-status'] = django_filters.ChoiceFilter(
|
||||
label=_('Filter by status'),
|
||||
|
@ -495,9 +497,9 @@ class BookingCheckFilterSet(django_filters.FilterSet):
|
|||
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[8:])
|
||||
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[9:])
|
||||
return queryset.filter(user_was_present=True, user_check_type=value.split('-')[1])
|
||||
return queryset
|
||||
|
||||
def do_nothing(self, queryset, name, value):
|
||||
|
@ -516,26 +518,26 @@ class SubscriptionCheckFilterSet(BookingCheckFilterSet):
|
|||
|
||||
|
||||
class BookingCheckAbsenceForm(forms.Form):
|
||||
check_type = forms.ChoiceField(required=False)
|
||||
check_type = forms.ChoiceField(required=False) # and not ModelChoiceField, to reduce querysets
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
agenda = kwargs.pop('agenda')
|
||||
super().__init__(*args, **kwargs)
|
||||
if agenda.check_type_group:
|
||||
self.fields['check_type'].choices = [('', '---------')] + [
|
||||
(r.label, r.label) for r in agenda.check_type_group.check_types.absences()
|
||||
(r.pk, r.label) for r in agenda.check_type_group.check_types.all() if r.kind == 'absence'
|
||||
]
|
||||
|
||||
|
||||
class BookingCheckPresenceForm(forms.Form):
|
||||
check_type = forms.ChoiceField(required=False)
|
||||
check_type = forms.ChoiceField(required=False) # and not ModelChoiceField, to reduce querysets
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
agenda = kwargs.pop('agenda')
|
||||
super().__init__(*args, **kwargs)
|
||||
if agenda.check_type_group:
|
||||
self.fields['check_type'].choices = [('', '---------')] + [
|
||||
(r.label, r.label) for r in agenda.check_type_group.check_types.presences()
|
||||
(r.pk, r.label) for r in agenda.check_type_group.check_types.all() if r.kind == 'presence'
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -2294,7 +2294,8 @@ class EventCheckView(ViewableAgendaMixin, DetailView):
|
|||
booking_qs_kwargs = {}
|
||||
if not self.agenda.subscriptions.exists():
|
||||
booking_qs_kwargs = {'cancellation_datetime__isnull': True}
|
||||
booked_qs = event.booking_set.filter(
|
||||
booking_qs = event.booking_set.prefetch_related('user_check_type')
|
||||
booked_qs = booking_qs.filter(
|
||||
in_waiting_list=False, primary_booking__isnull=True, **booking_qs_kwargs
|
||||
)
|
||||
booked_qs = booked_qs.annotate(
|
||||
|
@ -2302,7 +2303,7 @@ class EventCheckView(ViewableAgendaMixin, DetailView):
|
|||
)
|
||||
|
||||
# waiting list queryset
|
||||
waiting_qs = event.booking_set.filter(
|
||||
waiting_qs = booking_qs.filter(
|
||||
in_waiting_list=True, primary_booking__isnull=True, **booking_qs_kwargs
|
||||
).order_by('user_last_name', 'user_first_name')
|
||||
waiting_qs = waiting_qs.annotate(
|
||||
|
@ -2339,11 +2340,11 @@ class EventCheckView(ViewableAgendaMixin, DetailView):
|
|||
booked_without_status = True
|
||||
booking.absence_form = BookingCheckAbsenceForm(
|
||||
agenda=self.agenda,
|
||||
initial={'check_type': booking.user_check_type if booking.user_was_present is False else ''},
|
||||
initial={'check_type': booking.user_check_type_id},
|
||||
)
|
||||
booking.presence_form = BookingCheckPresenceForm(
|
||||
agenda=self.agenda,
|
||||
initial={'check_type': booking.user_check_type if booking.user_was_present is True else ''},
|
||||
initial={'check_type': booking.user_check_type_id},
|
||||
)
|
||||
booking.kind = 'booking'
|
||||
results.append(booking)
|
||||
|
@ -3138,13 +3139,20 @@ class BookingCheckMixin:
|
|||
primary_booking__isnull=True,
|
||||
)
|
||||
|
||||
def get_check_type(self):
|
||||
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'])
|
||||
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}
|
||||
agenda=self.agenda, initial={'check_type': booking.user_check_type_id}
|
||||
)
|
||||
booking.presence_form = BookingCheckPresenceForm(
|
||||
agenda=self.agenda, initial={'check_type': booking.user_check_type}
|
||||
agenda=self.agenda, initial={'check_type': booking.user_check_type_id}
|
||||
)
|
||||
return render(
|
||||
request,
|
||||
|
@ -3169,11 +3177,7 @@ class BookingPresenceView(ViewableAgendaMixin, BookingCheckMixin, FormView):
|
|||
|
||||
def post(self, request, *args, **kwargs):
|
||||
booking = self.get_booking(**kwargs)
|
||||
form = self.get_form()
|
||||
check_type = None
|
||||
if form.is_valid():
|
||||
check_type = form.cleaned_data['check_type']
|
||||
booking.mark_user_presence(check_type=check_type)
|
||||
booking.mark_user_presence(check_type=self.get_check_type())
|
||||
return self.response(request, booking)
|
||||
|
||||
|
||||
|
@ -3190,11 +3194,7 @@ class BookingAbsenceView(ViewableAgendaMixin, BookingCheckMixin, FormView):
|
|||
|
||||
def post(self, request, *args, **kwargs):
|
||||
booking = self.get_booking(**kwargs)
|
||||
form = self.get_form()
|
||||
check_type = None
|
||||
if form.is_valid():
|
||||
check_type = form.cleaned_data['check_type']
|
||||
booking.mark_user_absence(check_type=check_type)
|
||||
booking.mark_user_absence(check_type=self.get_check_type())
|
||||
return self.response(request, booking)
|
||||
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@ from chrono.agendas.models import (
|
|||
Agenda,
|
||||
Booking,
|
||||
Category,
|
||||
CheckType,
|
||||
CheckTypeGroup,
|
||||
Desk,
|
||||
Event,
|
||||
EventsType,
|
||||
|
@ -1183,6 +1185,9 @@ def test_datetimes_multiple_agendas_shared_custody_holiday_rules(app):
|
|||
|
||||
|
||||
def test_datetimes_multiple_agendas_with_status(app):
|
||||
group = CheckTypeGroup.objects.create(label='Foo bar')
|
||||
check_type_absence = CheckType.objects.create(label='Foo reason', group=group, kind='absence')
|
||||
check_type_presence = CheckType.objects.create(label='Foo reason', group=group, kind='presence')
|
||||
agenda = Agenda.objects.create(label='agenda', kind='events')
|
||||
Desk.objects.create(agenda=agenda, slug='_exceptions_holder')
|
||||
event_booked = Event.objects.create(
|
||||
|
@ -1222,7 +1227,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='foobar',
|
||||
user_check_type=check_type_absence,
|
||||
)
|
||||
event_presence = Event.objects.create(
|
||||
slug='event-presence',
|
||||
|
@ -1231,6 +1236,18 @@ def test_datetimes_multiple_agendas_with_status(app):
|
|||
agenda=agenda,
|
||||
)
|
||||
Booking.objects.create(event=event_presence, user_external_id='xxx', user_was_present=True)
|
||||
event_presence_with_reason = Event.objects.create(
|
||||
slug='event-presence_with_reason',
|
||||
start_datetime=now() - datetime.timedelta(days=9),
|
||||
places=5,
|
||||
agenda=agenda,
|
||||
)
|
||||
Booking.objects.create(
|
||||
event=event_presence_with_reason,
|
||||
user_external_id='xxx',
|
||||
user_was_present=True,
|
||||
user_check_type=check_type_presence,
|
||||
)
|
||||
event_booked_future = Event.objects.create(
|
||||
slug='event-booked-future',
|
||||
start_datetime=now() + datetime.timedelta(days=1),
|
||||
|
@ -1256,6 +1273,7 @@ def test_datetimes_multiple_agendas_with_status(app):
|
|||
'agenda@event-absence',
|
||||
'agenda@event-absence_with_reason',
|
||||
'agenda@event-presence',
|
||||
'agenda@event-presence_with_reason',
|
||||
'agenda@event-booked-future',
|
||||
'agenda@event-free-future',
|
||||
]
|
||||
|
@ -1278,6 +1296,7 @@ def test_datetimes_multiple_agendas_with_status(app):
|
|||
'agenda@event-absence',
|
||||
'agenda@event-absence_with_reason',
|
||||
'agenda@event-presence',
|
||||
'agenda@event-presence_with_reason',
|
||||
'agenda@event-booked-future',
|
||||
'agenda@event-free-future',
|
||||
]
|
||||
|
@ -1289,6 +1308,7 @@ def test_datetimes_multiple_agendas_with_status(app):
|
|||
'absence',
|
||||
'booked',
|
||||
'booked',
|
||||
'booked',
|
||||
'free',
|
||||
]
|
||||
|
||||
|
@ -1309,6 +1329,7 @@ def test_datetimes_multiple_agendas_with_status(app):
|
|||
'agenda@event-absence',
|
||||
'agenda@event-absence_with_reason',
|
||||
'agenda@event-presence',
|
||||
'agenda@event-presence_with_reason',
|
||||
'agenda@event-booked-future',
|
||||
'agenda@event-free-future',
|
||||
]
|
||||
|
@ -1321,6 +1342,7 @@ def test_datetimes_multiple_agendas_with_status(app):
|
|||
'free',
|
||||
'free',
|
||||
'free',
|
||||
'free',
|
||||
]
|
||||
|
||||
# check errors
|
||||
|
|
|
@ -302,47 +302,87 @@ def test_bookings_api_filter_user_was_present(app, user):
|
|||
|
||||
|
||||
def test_bookings_api_filter_user_absence_reason(app, user):
|
||||
group = CheckTypeGroup.objects.create(label='Foo')
|
||||
check_type_absence = CheckType.objects.create(group=group, label='Foo bar', kind='absence')
|
||||
check_type_presence = CheckType.objects.create(group=group, label='Foo bar', kind='presence')
|
||||
agenda = Agenda.objects.create(label='Foo bar')
|
||||
event = Event.objects.create(
|
||||
agenda=agenda, start_datetime=make_aware(datetime.datetime(2017, 5, 22, 0, 0)), places=10
|
||||
)
|
||||
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='foo-bar'
|
||||
event=event, user_external_id='42', user_was_present=False, user_check_type=check_type_absence
|
||||
)
|
||||
Booking.objects.create(
|
||||
event=event, user_external_id='42', user_was_present=False, user_check_type=check_type_presence
|
||||
)
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': 'foo'})
|
||||
assert resp.json['err'] == 0
|
||||
assert [b['id'] for b in resp.json['data']] == []
|
||||
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': 'foo-bar'})
|
||||
resp = app.get(
|
||||
'/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': check_type_absence.slug}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
assert [b['id'] for b in resp.json['data']] == [booking2.pk]
|
||||
resp = app.get(
|
||||
'/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': check_type_absence.label}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
assert [b['id'] for b in resp.json['data']] == [booking2.pk]
|
||||
resp = app.get(
|
||||
'/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': check_type_presence.slug}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
assert [b['id'] for b in resp.json['data']] == []
|
||||
Booking.objects.update(user_was_present=True)
|
||||
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': 'foo-bar'})
|
||||
resp = app.get(
|
||||
'/api/bookings/', params={'user_external_id': '42', 'user_absence_reason': check_type_absence.label}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
assert [b['id'] for b in resp.json['data']] == []
|
||||
|
||||
|
||||
def test_bookings_api_filter_user_presence_reason(app, user):
|
||||
group = CheckTypeGroup.objects.create(label='Foo')
|
||||
check_type_absence = CheckType.objects.create(group=group, label='Foo bar', kind='absence')
|
||||
check_type_presence = CheckType.objects.create(group=group, label='Foo bar', kind='presence')
|
||||
agenda = Agenda.objects.create(label='Foo bar')
|
||||
event = Event.objects.create(
|
||||
agenda=agenda, start_datetime=make_aware(datetime.datetime(2017, 5, 22, 0, 0)), places=10
|
||||
)
|
||||
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='foo-bar'
|
||||
event=event, user_external_id='42', user_was_present=True, user_check_type=check_type_presence
|
||||
)
|
||||
Booking.objects.create(
|
||||
event=event, user_external_id='42', user_was_present=True, user_check_type=check_type_absence
|
||||
)
|
||||
|
||||
app.authorization = ('Basic', ('john.doe', 'password'))
|
||||
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_presence_reason': 'foo'})
|
||||
assert resp.json['err'] == 0
|
||||
assert [b['id'] for b in resp.json['data']] == []
|
||||
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_presence_reason': 'foo-bar'})
|
||||
resp = app.get(
|
||||
'/api/bookings/', params={'user_external_id': '42', 'user_presence_reason': check_type_presence.slug}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
assert [b['id'] for b in resp.json['data']] == [booking2.pk]
|
||||
resp = app.get(
|
||||
'/api/bookings/', params={'user_external_id': '42', 'user_presence_reason': check_type_presence.label}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
assert [b['id'] for b in resp.json['data']] == [booking2.pk]
|
||||
resp = app.get(
|
||||
'/api/bookings/', params={'user_external_id': '42', 'user_presence_reason': check_type_absence.slug}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
assert [b['id'] for b in resp.json['data']] == []
|
||||
Booking.objects.update(user_was_present=False)
|
||||
resp = app.get('/api/bookings/', params={'user_external_id': '42', 'user_presence_reason': 'foo-bar'})
|
||||
resp = app.get(
|
||||
'/api/bookings/', params={'user_external_id': '42', 'user_presence_reason': check_type_presence.label}
|
||||
)
|
||||
assert resp.json['err'] == 0
|
||||
assert [b['id'] for b in resp.json['data']] == []
|
||||
|
||||
|
@ -415,16 +455,20 @@ def test_bookings_api_filter_event(app, user):
|
|||
|
||||
@pytest.mark.parametrize('flag', [True, False, None])
|
||||
def test_booking_api_present(app, user, flag):
|
||||
group = CheckTypeGroup.objects.create(label='Foo')
|
||||
check_type = CheckType.objects.create(
|
||||
group=group, label='Foo bar', kind='presence' if flag else 'absence'
|
||||
)
|
||||
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='foobar')
|
||||
booking = Booking.objects.create(event=event, user_was_present=flag, user_check_type=check_type)
|
||||
|
||||
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'] == ('foobar' if flag is False else '')
|
||||
assert resp.json['user_presence_reason'] == ('foobar' if flag is True else '')
|
||||
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 '')
|
||||
|
||||
|
||||
@pytest.mark.parametrize('flag', [True, False])
|
||||
|
@ -594,15 +638,15 @@ 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 == 'Foo bar'
|
||||
assert booking.user_check_type == check_type_absence
|
||||
|
||||
# reset
|
||||
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': ''})
|
||||
booking.refresh_from_db()
|
||||
assert booking.user_check_type == ''
|
||||
assert booking.user_check_type is None
|
||||
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': None})
|
||||
booking.refresh_from_db()
|
||||
assert booking.user_check_type == ''
|
||||
assert booking.user_check_type is None
|
||||
|
||||
# make secondary bookings
|
||||
Booking.objects.create(event=event, primary_booking=booking, user_was_present=False)
|
||||
|
@ -613,14 +657,14 @@ 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 == 'Foo bar'
|
||||
assert booking.user_check_type == check_type_absence
|
||||
# all secondary bookings are updated
|
||||
assert list(booking.secondary_booking_set.values_list('user_check_type', flat=True)) == [
|
||||
'Foo bar',
|
||||
'Foo bar',
|
||||
check_type_absence.pk,
|
||||
check_type_absence.pk,
|
||||
]
|
||||
other_booking.refresh_from_db()
|
||||
assert other_booking.user_check_type == '' # not changed
|
||||
assert other_booking.user_check_type is None # not changed
|
||||
|
||||
# user_was_present is True, can not set user_absence_reason
|
||||
Booking.objects.update(user_was_present=True)
|
||||
|
@ -638,7 +682,7 @@ 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 == 'Foo bar'
|
||||
assert booking.user_check_type == check_type_absence
|
||||
|
||||
# mark the event as checked
|
||||
event.checked = True
|
||||
|
@ -702,15 +746,15 @@ 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 == 'Foo bar'
|
||||
assert booking.user_check_type == check_type_presence
|
||||
|
||||
# reset
|
||||
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': ''})
|
||||
booking.refresh_from_db()
|
||||
assert booking.user_check_type == ''
|
||||
assert booking.user_check_type is None
|
||||
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': None})
|
||||
booking.refresh_from_db()
|
||||
assert booking.user_check_type == ''
|
||||
assert booking.user_check_type is None
|
||||
|
||||
# make secondary bookings
|
||||
Booking.objects.create(event=event, primary_booking=booking, user_was_present=True)
|
||||
|
@ -721,14 +765,14 @@ 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 == 'Foo bar'
|
||||
assert booking.user_check_type == check_type_presence
|
||||
# all secondary bookings are updated
|
||||
assert list(booking.secondary_booking_set.values_list('user_check_type', flat=True)) == [
|
||||
'Foo bar',
|
||||
'Foo bar',
|
||||
check_type_presence.pk,
|
||||
check_type_presence.pk,
|
||||
]
|
||||
other_booking.refresh_from_db()
|
||||
assert other_booking.user_check_type == '' # not changed
|
||||
assert other_booking.user_check_type is None # not changed
|
||||
|
||||
# user_was_present is False, can not set user_presence_reason
|
||||
Booking.objects.update(user_was_present=False)
|
||||
|
@ -746,7 +790,7 @@ 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 == 'Foo bar'
|
||||
assert booking.user_check_type == check_type_presence
|
||||
|
||||
# mark the event as checked
|
||||
event.checked = True
|
||||
|
|
|
@ -1672,7 +1672,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.label,
|
||||
user_check_type=check_type_absence,
|
||||
)
|
||||
Booking.objects.create(
|
||||
event=event,
|
||||
|
@ -1681,7 +1681,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.label,
|
||||
user_check_type=check_type_presence,
|
||||
)
|
||||
Booking.objects.create(
|
||||
event=event,
|
||||
|
@ -1690,7 +1690,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.label,
|
||||
user_check_type=check_type_absence,
|
||||
cancellation_datetime=now(),
|
||||
)
|
||||
Booking.objects.create(
|
||||
|
@ -1700,7 +1700,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.label,
|
||||
user_check_type=check_type_presence,
|
||||
cancellation_datetime=now(),
|
||||
)
|
||||
|
||||
|
@ -1782,9 +1782,11 @@ def test_event_check_filters(app, admin_user):
|
|||
assert 'Subscription foo-val1 bar-val2' in resp
|
||||
assert 'Subscription foo-none bar-val2' in resp
|
||||
|
||||
resp = app.get(
|
||||
'/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'extra-data-foo': 'val1'}
|
||||
)
|
||||
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 'User none' not in resp
|
||||
assert 'User empty' not in resp
|
||||
assert 'User foo-val1 bar-none presence' in resp
|
||||
|
@ -1957,7 +1959,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-Foo reason'},
|
||||
params={'booking-status': 'absence-%s' % check_type_absence.pk},
|
||||
)
|
||||
assert 'User none' not in resp
|
||||
assert 'User empty' not in resp
|
||||
|
@ -1977,7 +1979,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-Bar reason'},
|
||||
params={'booking-status': 'presence-%s' % check_type_presence.pk},
|
||||
)
|
||||
assert 'User none' not in resp
|
||||
assert 'User empty' not in resp
|
||||
|
@ -2068,10 +2070,10 @@ 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 == ''
|
||||
assert booking.user_check_type is None
|
||||
secondary_booking.refresh_from_db()
|
||||
assert secondary_booking.user_was_present is True
|
||||
assert secondary_booking.user_check_type == ''
|
||||
assert secondary_booking.user_check_type is None
|
||||
event.refresh_from_db()
|
||||
assert event.checked is False
|
||||
|
||||
|
@ -2088,10 +2090,10 @@ 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 == ''
|
||||
assert booking.user_check_type is None
|
||||
secondary_booking.refresh_from_db()
|
||||
assert secondary_booking.user_was_present is False
|
||||
assert secondary_booking.user_check_type == ''
|
||||
assert secondary_booking.user_check_type is None
|
||||
event.refresh_from_db()
|
||||
assert event.checked is True
|
||||
|
||||
|
@ -2101,7 +2103,7 @@ def test_event_check_booking(app, admin_user):
|
|||
assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 0
|
||||
assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
|
||||
|
||||
CheckType.objects.create(label='Foo reason', group=group, kind='absence')
|
||||
check_type_absence = CheckType.objects.create(label='Foo reason', group=group, kind='absence')
|
||||
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
|
||||
assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
|
||||
assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
|
||||
|
@ -2109,15 +2111,15 @@ 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': 'Foo reason'},
|
||||
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
|
||||
).follow()
|
||||
assert 'Foo reason' in resp
|
||||
booking.refresh_from_db()
|
||||
assert booking.user_was_present is False
|
||||
assert booking.user_check_type == 'Foo reason'
|
||||
assert booking.user_check_type == check_type_absence
|
||||
secondary_booking.refresh_from_db()
|
||||
assert secondary_booking.user_was_present is False
|
||||
assert secondary_booking.user_check_type == 'Foo reason'
|
||||
assert secondary_booking.user_check_type == check_type_absence
|
||||
|
||||
# set as present without check_type
|
||||
resp = app.post(
|
||||
|
@ -2129,10 +2131,10 @@ 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 == ''
|
||||
assert booking.user_check_type is None
|
||||
secondary_booking.refresh_from_db()
|
||||
assert secondary_booking.user_was_present is True
|
||||
assert secondary_booking.user_check_type == ''
|
||||
assert secondary_booking.user_check_type is None
|
||||
event.refresh_from_db()
|
||||
assert event.checked is True
|
||||
|
||||
|
@ -2142,7 +2144,7 @@ def test_event_check_booking(app, admin_user):
|
|||
assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
|
||||
assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
|
||||
|
||||
CheckType.objects.create(label='Bar reason', group=group, kind='presence')
|
||||
check_type_presence = CheckType.objects.create(label='Bar reason', group=group, kind='presence')
|
||||
resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
|
||||
assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
|
||||
assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 1
|
||||
|
@ -2150,15 +2152,15 @@ 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': 'Bar reason'},
|
||||
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
|
||||
).follow()
|
||||
assert 'Bar reason' in resp
|
||||
booking.refresh_from_db()
|
||||
assert booking.user_was_present is True
|
||||
assert booking.user_check_type == 'Bar reason'
|
||||
assert booking.user_check_type == check_type_presence
|
||||
secondary_booking.refresh_from_db()
|
||||
assert secondary_booking.user_was_present is True
|
||||
assert secondary_booking.user_check_type == 'Bar reason'
|
||||
assert secondary_booking.user_check_type == check_type_presence
|
||||
|
||||
# mark the event as checked
|
||||
event.checked = True
|
||||
|
@ -2197,7 +2199,8 @@ def test_event_check_booking(app, admin_user):
|
|||
|
||||
def test_event_check_booking_ajax(app, admin_user):
|
||||
group = CheckTypeGroup.objects.create(label='Foo bar')
|
||||
CheckType.objects.create(label='Foo reason', group=group)
|
||||
check_type_absence = CheckType.objects.create(label='Foo reason', group=group)
|
||||
check_type_presence = CheckType.objects.create(label='Bar reason', group=group, kind='presence')
|
||||
agenda = Agenda.objects.create(label='Events', kind='events', check_type_group=group)
|
||||
event = Event.objects.create(
|
||||
label='xyz',
|
||||
|
@ -2215,30 +2218,32 @@ 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},
|
||||
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
|
||||
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'
|
||||
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
|
||||
|
||||
# set as absent
|
||||
resp = app.post(
|
||||
'/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
|
||||
params={'csrfmiddlewaretoken': token, 'check_type': 'Foo reason'},
|
||||
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
|
||||
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="Foo reason" selected>Foo reason</option>' in resp
|
||||
assert '<option value="%s" selected>Foo reason</option>' % check_type_absence.pk in resp
|
||||
|
||||
|
||||
def test_event_check_all_bookings(app, admin_user):
|
||||
group = CheckTypeGroup.objects.create(label='Foo bar')
|
||||
CheckType.objects.create(label='Foo reason', group=group)
|
||||
CheckType.objects.create(label='Bar reason', group=group, kind='presence')
|
||||
check_type_absence = CheckType.objects.create(label='Foo reason', group=group)
|
||||
check_type_presence = CheckType.objects.create(label='Bar reason', group=group, kind='presence')
|
||||
agenda = Agenda.objects.create(label='Events', kind='events', check_type_group=group)
|
||||
event = Event.objects.create(
|
||||
label='xyz',
|
||||
|
@ -2262,7 +2267,7 @@ 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 == ''
|
||||
assert booking1.user_check_type is None
|
||||
event.refresh_from_db()
|
||||
assert event.checked is False
|
||||
|
||||
|
@ -2288,13 +2293,13 @@ 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 == ''
|
||||
assert booking1.user_check_type is None
|
||||
booking2.refresh_from_db()
|
||||
assert booking2.user_was_present is True
|
||||
assert booking2.user_check_type == ''
|
||||
assert booking2.user_check_type is None
|
||||
secondary_booking.refresh_from_db()
|
||||
assert secondary_booking.user_was_present is True
|
||||
assert secondary_booking.user_check_type == ''
|
||||
assert secondary_booking.user_check_type is None
|
||||
event.refresh_from_db()
|
||||
assert event.checked is True
|
||||
|
||||
|
@ -2304,37 +2309,37 @@ 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': 'Foo reason'},
|
||||
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
|
||||
)
|
||||
booking1.refresh_from_db()
|
||||
assert booking1.user_was_present is False
|
||||
assert booking1.user_check_type == ''
|
||||
assert booking1.user_check_type is None
|
||||
booking2.refresh_from_db()
|
||||
assert booking2.user_was_present is True
|
||||
assert booking2.user_check_type == ''
|
||||
assert booking2.user_check_type is None
|
||||
booking3.refresh_from_db()
|
||||
assert booking3.user_was_present is False
|
||||
assert booking3.user_check_type == 'Foo reason'
|
||||
assert booking3.user_check_type == check_type_absence
|
||||
|
||||
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': 'Bar reason'},
|
||||
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
|
||||
)
|
||||
booking1.refresh_from_db()
|
||||
assert booking1.user_was_present is False
|
||||
assert booking1.user_check_type == ''
|
||||
assert booking1.user_check_type is None
|
||||
booking2.refresh_from_db()
|
||||
assert booking2.user_was_present is True
|
||||
assert booking2.user_check_type == ''
|
||||
assert booking2.user_check_type is None
|
||||
booking3.refresh_from_db()
|
||||
assert booking3.user_was_present is False
|
||||
assert booking3.user_check_type == 'Foo reason'
|
||||
assert booking3.user_check_type == check_type_absence
|
||||
booking4.refresh_from_db()
|
||||
assert booking4.user_was_present is True
|
||||
assert booking4.user_check_type == 'Bar reason'
|
||||
assert booking4.user_check_type == check_type_presence
|
||||
|
||||
# now disable check update
|
||||
agenda.disable_check_update = True
|
||||
|
@ -2344,7 +2349,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': 'Foo reason'},
|
||||
params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
|
||||
status=404,
|
||||
)
|
||||
resp = app.post(
|
||||
|
@ -2354,7 +2359,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': 'Bar reason'},
|
||||
params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
|
||||
status=404,
|
||||
)
|
||||
resp = app.post(
|
||||
|
|
Loading…
Reference in New Issue