Projet

Général

Profil

0002-agendas-Booking.user_check_type-becomes-2-fields-slu.patch

Lauréline Guérin, 10 juin 2022 10:20

Télécharger (48,1 ko)

Voir les différences:

Subject: [PATCH 2/5] agendas: Booking.user_check_type becomes 2 fields (slug,
 label) (#66015)

 .../migrations/0128_remove_check_type.py      |  21 ++++
 .../migrations/0129_remove_check_type.py      |  46 ++++++++
 .../migrations/0130_remove_check_type.py      |  15 +++
 chrono/agendas/models.py                      |  21 ++--
 chrono/api/serializers.py                     |  17 ++-
 chrono/api/views.py                           |   9 +-
 chrono/manager/forms.py                       |  18 ++--
 .../manager_event_check_booking_fragment.html |   4 +-
 chrono/manager/views.py                       |  70 ++++++------
 .../datetimes/test_events_multiple_agendas.py |   4 +-
 tests/api/test_booking.py                     |  74 +++++++++----
 tests/manager/test_check_type.py              |  17 +--
 tests/manager/test_event.py                   | 101 +++++++++++-------
 13 files changed, 277 insertions(+), 140 deletions(-)
 create mode 100644 chrono/agendas/migrations/0128_remove_check_type.py
 create mode 100644 chrono/agendas/migrations/0129_remove_check_type.py
 create mode 100644 chrono/agendas/migrations/0130_remove_check_type.py
chrono/agendas/migrations/0128_remove_check_type.py
1
from django.db import migrations, models
2

  
3

  
4
class Migration(migrations.Migration):
5

  
6
    dependencies = [
7
        ('agendas', '0127_remove_pricing_models'),
8
    ]
9

  
10
    operations = [
11
        migrations.AddField(
12
            model_name='booking',
13
            name='user_check_type_label',
14
            field=models.CharField(blank=True, null=True, max_length=150),
15
        ),
16
        migrations.AddField(
17
            model_name='booking',
18
            name='user_check_type_slug',
19
            field=models.CharField(blank=True, null=True, max_length=160),
20
        ),
21
    ]
chrono/agendas/migrations/0129_remove_check_type.py
1
from collections import defaultdict
2

  
3
from django.db import migrations
4

  
5

  
6
def forwards(apps, schema_editor):
7
    Booking = apps.get_model('agendas', 'Booking')
8
    for booking in Booking.objects.filter(user_check_type__isnull=False):
9
        booking.user_check_type_slug = booking.user_check_type.slug
10
        booking.user_check_type_label = booking.user_check_type.label
11
        booking.save()
12

  
13

  
14
def backwards(apps, schema_editor):
15
    Booking = apps.get_model('agendas', 'Booking')
16
    Agenda = apps.get_model('agendas', 'Agenda')
17
    check_types_by_agenda_id = defaultdict(list)
18
    for agenda in Agenda.objects.filter(kind='events'):
19
        if not agenda.check_type_group:
20
            continue
21
        for check_type in agenda.check_type_group.check_types.all():
22
            check_types_by_agenda_id[agenda.pk].append(check_type)
23
    for booking in Booking.objects.filter(user_check_type_slug__isnull=False, user_was_present__isnull=False):
24
        if booking.event.agenda_id not in check_types_by_agenda_id:
25
            # no check_types for this agenda
26
            continue
27
        for check_type in check_types_by_agenda_id[booking.event.agenda_id]:
28
            if check_type.kind == 'absence' and booking.user_was_present is True:
29
                continue
30
            if check_type.kind == 'presence' and booking.user_was_present is False:
31
                continue
32
            if check_type.slug == booking.user_check_type_slug:
33
                booking.user_check_type = check_type
34
                booking.save()
35
                break
36

  
37

  
38
class Migration(migrations.Migration):
39

  
40
    dependencies = [
41
        ('agendas', '0128_remove_check_type'),
42
    ]
43

  
44
    operations = [
45
        migrations.RunPython(forwards, reverse_code=backwards),
46
    ]
chrono/agendas/migrations/0130_remove_check_type.py
1
from django.db import migrations
2

  
3

  
4
class Migration(migrations.Migration):
5

  
6
    dependencies = [
7
        ('agendas', '0129_remove_check_type'),
8
    ]
9

  
10
    operations = [
11
        migrations.RemoveField(
12
            model_name='booking',
13
            name='user_check_type',
14
        ),
15
    ]
chrono/agendas/models.py
1943 1943
    user_email = models.EmailField(blank=True)
1944 1944
    user_phone_number = models.CharField(max_length=16, blank=True)
1945 1945
    user_was_present = models.NullBooleanField()
1946
    user_check_type = models.ForeignKey('agendas.CheckType', on_delete=models.PROTECT, blank=True, null=True)
1946
    user_check_type_slug = models.CharField(max_length=160, blank=True, null=True)
1947
    user_check_type_label = models.CharField(max_length=150, blank=True, null=True)
1947 1948
    out_of_min_delay = models.BooleanField(default=False)
1948 1949

  
1949 1950
    extra_emails = ArrayField(models.EmailField(), default=list)
......
1994 1995
            self.secondary_booking_set.update(in_waiting_list=True)
1995 1996
            self.save()
1996 1997

  
1997
    def mark_user_absence(self, check_type=None):
1998
        check_type = check_type or None
1999
        self.user_check_type = check_type
1998
    def mark_user_absence(self, check_type_slug=None, check_type_label=None):
1999
        self.user_check_type_slug = check_type_slug
2000
        self.user_check_type_label = check_type_label
2000 2001
        self.user_was_present = False
2001 2002
        with transaction.atomic():
2002
            self.secondary_booking_set.update(user_check_type=check_type)
2003
            self.secondary_booking_set.update(user_check_type_slug=check_type_slug)
2004
            self.secondary_booking_set.update(user_check_type_label=check_type_label)
2003 2005
            self.secondary_booking_set.update(user_was_present=False)
2004 2006
            self.save()
2005 2007
            self.event.set_is_checked()
2006 2008

  
2007
    def mark_user_presence(self, check_type=None):
2008
        check_type = check_type or None
2009
        self.user_check_type = check_type
2009
    def mark_user_presence(self, check_type_slug=None, check_type_label=None):
2010
        self.user_check_type_slug = check_type_slug
2011
        self.user_check_type_label = check_type_label
2010 2012
        self.user_was_present = True
2011 2013
        with transaction.atomic():
2012
            self.secondary_booking_set.update(user_check_type=check_type)
2014
            self.secondary_booking_set.update(user_check_type_slug=check_type_slug)
2015
            self.secondary_booking_set.update(user_check_type_label=check_type_label)
2013 2016
            self.secondary_booking_set.update(user_was_present=True)
2014 2017
            self.save()
2015 2018
            self.event.set_is_checked()
chrono/api/serializers.py
184 184

  
185 185
    def to_representation(self, instance):
186 186
        ret = super().to_representation(instance)
187
        check_type_slug = self.instance.user_check_type.slug if self.instance.user_check_type else ''
188
        ret['user_absence_reason'] = check_type_slug if self.instance.user_was_present is False else ''
189
        ret['user_presence_reason'] = check_type_slug if self.instance.user_was_present is True else ''
187
        ret['user_absence_reason'] = (
188
            self.instance.user_check_type_slug if self.instance.user_was_present is False else ''
189
        )
190
        ret['user_presence_reason'] = (
191
            self.instance.user_check_type_slug if self.instance.user_was_present is True else ''
192
        )
190 193
        return ret
191 194

  
192 195
    def _validate_check_type(self, kind, value):
......
225 228
                {'user_absence_reason': _('can not set user_absence_reason and user_presence_reason')}
226 229
            )
227 230
        if 'user_absence_reason' in attrs:
228
            attrs['user_check_type'] = attrs['user_absence_reason']
231
            check_type = attrs['user_absence_reason']
232
            attrs['user_check_type_slug'] = check_type.slug if check_type else None
233
            attrs['user_check_type_label'] = check_type.label if check_type else None
229 234
            del attrs['user_absence_reason']
230 235
        elif 'user_presence_reason' in attrs:
231
            attrs['user_check_type'] = attrs['user_presence_reason']
236
            check_type = attrs['user_presence_reason']
237
            attrs['user_check_type_slug'] = check_type.slug if check_type else None
238
            attrs['user_check_type_label'] = check_type.label if check_type else None
232 239
            del attrs['user_presence_reason']
233 240
        return attrs
234 241

  
chrono/api/views.py
2296 2296

  
2297 2297
    def filter_user_absence_reason(self, queryset, name, value):
2298 2298
        return queryset.filter(
2299
            Q(user_check_type__slug=value) | Q(user_check_type__label=value),
2300
            user_check_type__kind='absence',
2299
            Q(user_check_type_slug=value) | Q(user_check_type_label=value),
2301 2300
            user_was_present=False,
2302 2301
        )
2303 2302

  
2304 2303
    def filter_user_presence_reason(self, queryset, name, value):
2305 2304
        return queryset.filter(
2306
            Q(user_check_type__slug=value) | Q(user_check_type__label=value),
2307
            user_check_type__kind='presence',
2305
            Q(user_check_type_slug=value) | Q(user_check_type_label=value),
2308 2306
            user_was_present=True,
2309 2307
        )
2310 2308

  
......
2432 2430
            if key in request.data:
2433 2431
                secondary_bookings_update[key] = getattr(self.booking, key)
2434 2432
        if 'user_absence_reason' in request.data or 'user_presence_reason' in request.data:
2435
            secondary_bookings_update['user_check_type'] = self.booking.user_check_type
2433
            secondary_bookings_update['user_check_type_slug'] = self.booking.user_check_type_slug
2434
            secondary_bookings_update['user_check_type_label'] = self.booking.user_check_type_label
2436 2435
        if extra_data:
2437 2436
            secondary_bookings_update['extra_data'] = self.booking.extra_data
2438 2437
        if secondary_bookings_update:
chrono/manager/forms.py
445 445
        ]
446 446
        if self.agenda.check_type_group:
447 447
            status_choices += [
448
                ('presence-%s' % r.pk, _('Presence (%s)') % r.label)
448
                ('presence::%s' % r.slug, _('Presence (%s)') % r.label)
449 449
                for r in self.agenda.check_type_group.check_types.all()
450 450
                if r.kind == 'presence' and not r.disabled
451 451
            ]
452 452
        status_choices += [('absence', _('Absence'))]
453 453
        if self.agenda.check_type_group:
454 454
            status_choices += [
455
                ('absence-%s' % r.pk, _('Absence (%s)') % r.label)
455
                ('absence::%s' % r.slug, _('Absence (%s)') % r.label)
456 456
                for r in self.agenda.check_type_group.check_types.all()
457 457
                if r.kind == 'absence' and not r.disabled
458 458
            ]
......
479 479
            return queryset.filter(user_was_present=True)
480 480
        if value == 'absence':
481 481
            return queryset.filter(user_was_present=False)
482
        if value.startswith('absence-'):
483
            return queryset.filter(user_was_present=False, user_check_type=value.split('-')[1])
484
        if value.startswith('presence-'):
485
            return queryset.filter(user_was_present=True, user_check_type=value.split('-')[1])
482
        if value.startswith('absence::'):
483
            return queryset.filter(user_was_present=False, user_check_type_slug=value.split('::')[1])
484
        if value.startswith('presence::'):
485
            return queryset.filter(user_was_present=True, user_check_type_slug=value.split('::')[1])
486 486
        return queryset
487 487

  
488 488
    def do_nothing(self, queryset, name, value):
......
508 508
        super().__init__(*args, **kwargs)
509 509
        if agenda.check_type_group:
510 510
            self.fields['check_type'].choices = [('', '---------')] + [
511
                (r.pk, r.label)
511
                (r.slug, r.label)
512 512
                for r in agenda.check_type_group.check_types.all()
513 513
                if r.kind == 'absence' and not r.disabled
514 514
            ]
......
522 522
        super().__init__(*args, **kwargs)
523 523
        if agenda.check_type_group:
524 524
            self.fields['check_type'].choices = [('', '---------')] + [
525
                (r.pk, r.label)
525
                (r.slug, r.label)
526 526
                for r in agenda.check_type_group.check_types.all()
527 527
                if r.kind == 'presence' and not r.disabled
528 528
            ]
......
1304 1304
        super().__init__(*args, **kwargs)
1305 1305
        if not CheckTypeGroup.objects.exists():
1306 1306
            del self.fields['check_type_group']
1307
        elif Booking.objects.filter(event__agenda=self.instance, user_check_type__isnull=False).exists():
1307
        elif Booking.objects.filter(event__agenda=self.instance, user_check_type_slug__isnull=False).exists():
1308 1308
            # not possible to update check_type_group if bookings with non null check_type exist
1309 1309
            del self.fields['check_type_group']
1310 1310

  
chrono/manager/templates/chrono/manager_event_check_booking_fragment.html
3 3
<td class="booking-username main-list">{{ booking.get_user_block }}{% if booking.places_count > 1 %} ({{ booking.places_count }} {% trans "places" %}){% endif %}</td>
4 4
<td class="booking-status {% if booking.user_was_present is None %}without-status{% endif %}">
5 5
  {{ booking.user_was_present|yesno:_('Present,Absent,-') }}
6
  {% if booking.user_was_present is not None and booking.user_check_type %}
7
    ({{ booking.user_check_type }})
6
  {% if booking.user_was_present is not None and booking.user_check_type_label %}
7
    ({{ booking.user_check_type_label }})
8 8
  {% endif %}
9 9
</td>
10 10
{% if not event.checked or not agenda.disable_check_update %}
chrono/manager/views.py
714 714
            raise PermissionDenied()
715 715
        return super().dispatch(request, *args, **kwargs)
716 716

  
717
    def get_context_data(self, **kwargs):
718
        context = super().get_context_data(**kwargs)
719
        context['cannot_delete'] = Booking.objects.filter(user_check_type__group=self.get_object()).exists()
720
        context['cannot_delete_msg'] = _(
721
            'Can not delete this check type group: a check type of this group is set on some existing bookings.'
722
        )
723
        return context
724

  
725
    def delete(self, request, *args, **kwargs):
726
        if Booking.objects.filter(user_check_type__group=self.get_object()).exists():
727
            raise Http404
728
        return super().delete(request, *args, **kwargs)
729

  
730 717
    def get_success_url(self):
731 718
        return reverse('chrono-manager-check-type-list')
732 719

  
......
797 784

  
798 785
    def get_context_data(self, **kwargs):
799 786
        context = super().get_context_data(**kwargs)
800
        context['is_used'] = Booking.objects.filter(user_check_type=self.get_object()).exists()
787
        context['is_used'] = Booking.objects.filter(user_check_type_slug=self.get_object().slug).exists()
801 788
        return context
802 789

  
803 790
    def get_success_url(self):
......
822 809

  
823 810
    def get_context_data(self, **kwargs):
824 811
        context = super().get_context_data(**kwargs)
825
        context['cannot_delete'] = Booking.objects.filter(user_check_type=self.get_object()).exists()
812
        context['cannot_delete'] = Booking.objects.filter(
813
            user_check_type_slug=self.get_object().slug
814
        ).exists()
826 815
        context['cannot_delete_msg'] = _(
827 816
            'Can not delete this check type: it is set on some existing bookings.'
828 817
        )
829 818
        return context
830 819

  
831 820
    def delete(self, request, *args, **kwargs):
832
        if Booking.objects.filter(user_check_type=self.get_object()).exists():
821
        if Booking.objects.filter(user_check_type_slug=self.get_object().slug).exists():
833 822
            raise Http404
834 823
        return super().delete(request, *args, **kwargs)
835 824

  
......
2345 2334
        booking_qs_kwargs = {}
2346 2335
        if not self.agenda.subscriptions.exists():
2347 2336
            booking_qs_kwargs = {'cancellation_datetime__isnull': True}
2348
        booking_qs = event.booking_set.prefetch_related('user_check_type')
2337
        booking_qs = event.booking_set
2349 2338
        booked_qs = booking_qs.filter(
2350 2339
            in_waiting_list=False, primary_booking__isnull=True, **booking_qs_kwargs
2351 2340
        )
......
2391 2380
                booked_without_status = True
2392 2381
            booking.absence_form = BookingCheckAbsenceForm(
2393 2382
                agenda=self.agenda,
2394
                initial={'check_type': booking.user_check_type_id},
2383
                initial={'check_type': booking.user_check_type_slug},
2395 2384
            )
2396 2385
            booking.presence_form = BookingCheckPresenceForm(
2397 2386
                agenda=self.agenda,
2398
                initial={'check_type': booking.user_check_type_id},
2387
                initial={'check_type': booking.user_check_type_slug},
2399 2388
            )
2400 2389
            booking.kind = 'booking'
2401 2390
            results.append(booking)
......
2453 2442
            user_was_present__isnull=True,
2454 2443
        )
2455 2444

  
2445
    def get_check_type(self, kind):
2446
        form = self.get_form()
2447
        check_type = None
2448
        if form.is_valid() and form.cleaned_data['check_type']:
2449
            check_type = CheckType.objects.filter(
2450
                slug=form.cleaned_data['check_type'], kind=kind, group=self.agenda.check_type_group
2451
            ).first()
2452
        return check_type
2453

  
2456 2454
    def response(self, request):
2457 2455
        return HttpResponseRedirect(
2458 2456
            reverse(
......
2471 2469
        return kwargs
2472 2470

  
2473 2471
    def post(self, request, *args, **kwargs):
2474
        form = self.get_form()
2475 2472
        qs_kwargs = {}
2476
        if form.is_valid():
2477
            qs_kwargs['user_check_type'] = form.cleaned_data['check_type']
2473
        check_type = self.get_check_type(kind='presence')
2474
        qs_kwargs['user_check_type_slug'] = check_type.slug if check_type else None
2475
        qs_kwargs['user_check_type_label'] = check_type.label if check_type else None
2478 2476
        bookings = self.get_bookings()
2479 2477
        bookings.update(user_was_present=True, **qs_kwargs)
2480 2478
        self.event.set_is_checked()
......
2493 2491
        return kwargs
2494 2492

  
2495 2493
    def post(self, request, *args, **kwargs):
2496
        form = self.get_form()
2497 2494
        qs_kwargs = {}
2498
        if form.is_valid():
2499
            qs_kwargs['user_check_type'] = form.cleaned_data['check_type']
2495
        check_type = self.get_check_type(kind='absence')
2496
        qs_kwargs['user_check_type_slug'] = check_type.slug if check_type else None
2497
        qs_kwargs['user_check_type_label'] = check_type.label if check_type else None
2500 2498
        bookings = self.get_bookings()
2501 2499
        bookings.update(user_was_present=False, **qs_kwargs)
2502 2500
        self.event.set_is_checked()
......
3190 3188
            primary_booking__isnull=True,
3191 3189
        )
3192 3190

  
3193
    def get_check_type(self):
3191
    def get_check_type(self, kind):
3194 3192
        form = self.get_form()
3195 3193
        check_type = None
3196 3194
        if form.is_valid() and form.cleaned_data['check_type']:
3197
            check_type = CheckType.objects.get(pk=form.cleaned_data['check_type'])
3195
            check_type = CheckType.objects.filter(
3196
                slug=form.cleaned_data['check_type'], kind=kind, group=self.agenda.check_type_group
3197
            ).first()
3198 3198
        return check_type
3199 3199

  
3200 3200
    def response(self, request, booking):
3201 3201
        if request.is_ajax():
3202 3202
            booking.absence_form = BookingCheckAbsenceForm(
3203
                agenda=self.agenda, initial={'check_type': booking.user_check_type_id}
3203
                agenda=self.agenda, initial={'check_type': booking.user_check_type_slug}
3204 3204
            )
3205 3205
            booking.presence_form = BookingCheckPresenceForm(
3206
                agenda=self.agenda, initial={'check_type': booking.user_check_type_id}
3206
                agenda=self.agenda, initial={'check_type': booking.user_check_type_slug}
3207 3207
            )
3208 3208
            return render(
3209 3209
                request,
......
3228 3228

  
3229 3229
    def post(self, request, *args, **kwargs):
3230 3230
        booking = self.get_booking(**kwargs)
3231
        booking.mark_user_presence(check_type=self.get_check_type())
3231
        check_type = self.get_check_type(kind='presence')
3232
        booking.mark_user_presence(
3233
            check_type_slug=check_type.slug if check_type else None,
3234
            check_type_label=check_type.label if check_type else None,
3235
        )
3232 3236
        return self.response(request, booking)
3233 3237

  
3234 3238

  
......
3245 3249

  
3246 3250
    def post(self, request, *args, **kwargs):
3247 3251
        booking = self.get_booking(**kwargs)
3248
        booking.mark_user_absence(check_type=self.get_check_type())
3252
        check_type = self.get_check_type(kind='absence')
3253
        booking.mark_user_absence(
3254
            check_type_slug=check_type.slug if check_type else None,
3255
            check_type_label=check_type.label if check_type else None,
3256
        )
3249 3257
        return self.response(request, booking)
3250 3258

  
3251 3259

  
tests/api/datetimes/test_events_multiple_agendas.py
1242 1242
        event=event_absence_with_reason,
1243 1243
        user_external_id='xxx',
1244 1244
        user_was_present=False,
1245
        user_check_type=check_type_absence,
1245
        user_check_type_slug=check_type_absence.slug,
1246 1246
    )
1247 1247
    event_presence = Event.objects.create(
1248 1248
        slug='event-presence',
......
1261 1261
        event=event_presence_with_reason,
1262 1262
        user_external_id='xxx',
1263 1263
        user_was_present=True,
1264
        user_check_type=check_type_presence,
1264
        user_check_type_slug=check_type_presence.slug,
1265 1265
    )
1266 1266
    event_booked_future = Event.objects.create(
1267 1267
        slug='event-booked-future',
tests/api/test_booking.py
327 327
    )
328 328
    Booking.objects.create(event=event, user_external_id='42', user_was_present=False)
329 329
    booking2 = Booking.objects.create(
330
        event=event, user_external_id='42', user_was_present=False, user_check_type=check_type_absence
330
        event=event,
331
        user_external_id='42',
332
        user_was_present=False,
333
        user_check_type_slug=check_type_absence.slug,
334
        user_check_type_label=check_type_absence.label,
331 335
    )
332 336
    Booking.objects.create(
333
        event=event, user_external_id='42', user_was_present=False, user_check_type=check_type_presence
337
        event=event,
338
        user_external_id='42',
339
        user_was_present=True,
340
        user_check_type_slug=check_type_presence.slug,
341
        user_check_type_label=check_type_presence.label,
334 342
    )
335 343

  
336 344
    app.authorization = ('Basic', ('john.doe', 'password'))
......
370 378
    )
371 379
    Booking.objects.create(event=event, user_external_id='42', user_was_present=True)
372 380
    booking2 = Booking.objects.create(
373
        event=event, user_external_id='42', user_was_present=True, user_check_type=check_type_presence
381
        event=event,
382
        user_external_id='42',
383
        user_was_present=True,
384
        user_check_type_slug=check_type_presence.slug,
385
        user_check_type_label=check_type_presence.label,
374 386
    )
375 387
    Booking.objects.create(
376
        event=event, user_external_id='42', user_was_present=True, user_check_type=check_type_absence
388
        event=event,
389
        user_external_id='42',
390
        user_was_present=False,
391
        user_check_type_slug=check_type_absence.slug,
392
        user_check_type_label=check_type_absence.label,
377 393
    )
378 394

  
379 395
    app.authorization = ('Basic', ('john.doe', 'password'))
......
477 493
    )
478 494
    agenda = Agenda.objects.create(label='Foo bar', kind='events')
479 495
    event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
480
    booking = Booking.objects.create(event=event, user_was_present=flag, user_check_type=check_type)
496
    booking = Booking.objects.create(event=event, user_was_present=flag, user_check_type_slug=check_type.slug)
481 497

  
482 498
    app.authorization = ('Basic', ('john.doe', 'password'))
483 499
    resp = app.get('/api/booking/%s/' % booking.pk)
......
657 673
    # it works with label
658 674
    app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': 'Foo bar'})
659 675
    booking.refresh_from_db()
660
    assert booking.user_check_type == check_type_absence
676
    assert booking.user_check_type_slug == check_type_absence.slug
677
    assert booking.user_check_type_label == check_type_absence.label
661 678

  
662 679
    # disabled
663 680
    resp = app.patch_json(
......
671 688
    # reset
672 689
    app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': ''})
673 690
    booking.refresh_from_db()
674
    assert booking.user_check_type is None
691
    assert booking.user_check_type_slug is None
692
    assert booking.user_check_type_label is None
675 693
    app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': None})
676 694
    booking.refresh_from_db()
677
    assert booking.user_check_type is None
695
    assert booking.user_check_type_slug is None
696
    assert booking.user_check_type_label is None
678 697

  
679 698
    # make secondary bookings
680 699
    Booking.objects.create(event=event, primary_booking=booking, user_was_present=False)
......
685 704
    # it works also with slug
686 705
    app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': check_type_absence.slug})
687 706
    booking.refresh_from_db()
688
    assert booking.user_check_type == check_type_absence
707
    assert booking.user_check_type_slug == check_type_absence.slug
708
    assert booking.user_check_type_label == check_type_absence.label
689 709
    # all secondary bookings are updated
690
    assert list(booking.secondary_booking_set.values_list('user_check_type', flat=True)) == [
691
        check_type_absence.pk,
692
        check_type_absence.pk,
710
    assert list(booking.secondary_booking_set.values_list('user_check_type_slug', flat=True)) == [
711
        check_type_absence.slug,
712
        check_type_absence.slug,
693 713
    ]
694 714
    other_booking.refresh_from_db()
695
    assert other_booking.user_check_type is None  # not changed
715
    assert other_booking.user_check_type_slug is None  # not changed
716
    assert other_booking.user_check_type_label is None  # not changed
696 717

  
697 718
    # user_was_present is True, can not set user_absence_reason
698 719
    Booking.objects.update(user_was_present=True)
......
710 731
    assert resp.json['err'] == 0
711 732
    booking.refresh_from_db()
712 733
    assert booking.user_was_present is False
713
    assert booking.user_check_type == check_type_absence
734
    assert booking.user_check_type_slug == check_type_absence.slug
735
    assert booking.user_check_type_label == check_type_absence.label
714 736

  
715 737
    # mark the event as checked
716 738
    event.checked = True
......
777 799
    # it works with label
778 800
    app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': 'Foo bar'})
779 801
    booking.refresh_from_db()
780
    assert booking.user_check_type == check_type_presence
802
    assert booking.user_check_type_slug == check_type_presence.slug
803
    assert booking.user_check_type_label == check_type_presence.label
781 804

  
782 805
    # disabled
783 806
    resp = app.patch_json(
......
791 814
    # reset
792 815
    app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': ''})
793 816
    booking.refresh_from_db()
794
    assert booking.user_check_type is None
817
    assert booking.user_check_type_slug is None
818
    assert booking.user_check_type_label is None
795 819
    app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': None})
796 820
    booking.refresh_from_db()
797
    assert booking.user_check_type is None
821
    assert booking.user_check_type_slug is None
822
    assert booking.user_check_type_label is None
798 823

  
799 824
    # make secondary bookings
800 825
    Booking.objects.create(event=event, primary_booking=booking, user_was_present=True)
......
805 830
    # it works also with slug
806 831
    app.patch_json('/api/booking/%s/' % booking.pk, params={'user_presence_reason': check_type_presence.slug})
807 832
    booking.refresh_from_db()
808
    assert booking.user_check_type == check_type_presence
833
    assert booking.user_check_type_slug == check_type_presence.slug
834
    assert booking.user_check_type_label == check_type_presence.label
809 835
    # all secondary bookings are updated
810
    assert list(booking.secondary_booking_set.values_list('user_check_type', flat=True)) == [
811
        check_type_presence.pk,
812
        check_type_presence.pk,
836
    assert list(booking.secondary_booking_set.values_list('user_check_type_slug', flat=True)) == [
837
        check_type_presence.slug,
838
        check_type_presence.slug,
813 839
    ]
814 840
    other_booking.refresh_from_db()
815
    assert other_booking.user_check_type is None  # not changed
841
    assert other_booking.user_check_type_slug is None  # not changed
842
    assert other_booking.user_check_type_label is None  # not changed
816 843

  
817 844
    # user_was_present is False, can not set user_presence_reason
818 845
    Booking.objects.update(user_was_present=False)
......
830 857
    assert resp.json['err'] == 0
831 858
    booking.refresh_from_db()
832 859
    assert booking.user_was_present is True
833
    assert booking.user_check_type == check_type_presence
860
    assert booking.user_check_type_slug == check_type_presence.slug
861
    assert booking.user_check_type_label == check_type_presence.label
834 862

  
835 863
    # mark the event as checked
836 864
    event.checked = True
tests/manager/test_check_type.py
83 83
    assert CheckTypeGroup.objects.exists() is False
84 84
    assert CheckType.objects.exists() is False
85 85

  
86
    # check_type is used
87
    group = CheckTypeGroup.objects.create(label='Foo bar')
88
    check_type = CheckType.objects.create(label='Foo reason', group=group)
89
    Booking.objects.update(user_check_type=check_type)
90
    resp = app.get('/manage/check-type/group/%s/delete/' % group.pk)
91
    assert (
92
        'Can not delete this check type group: a check type of this group is set on some existing bookings.'
93
        in resp
94
    )
95
    resp.form.submit(status=404)
96

  
97 86

  
98 87
def test_delete_group_as_manager(app, manager_user, agenda_with_restrictions):
99 88
    group = CheckTypeGroup.objects.create(label='Foo bar')
......
169 158
    assert check_type.disabled is True
170 159

  
171 160
    # check_type is used
172
    Booking.objects.update(user_check_type=check_type)
161
    Booking.objects.update(user_check_type_slug=check_type.slug)
173 162
    resp = app.get('/manage/check-type/group/%s/%s/edit/' % (group.pk, check_type.pk))
174 163
    assert 'This check type is set on some existing bookings, modify it with caution.' in resp
175 164

  
......
201 190

  
202 191
    # check_type is used
203 192
    check_type = CheckType.objects.create(label='Foo reason', group=group)
204
    Booking.objects.update(user_check_type=check_type)
193
    Booking.objects.update(user_check_type_slug=check_type.slug)
205 194
    resp = app.get('/manage/check-type/group/%s/%s/delete/' % (group.pk, check_type.pk))
206 195
    assert 'Can not delete this check type: it is set on some existing bookings.' in resp
207 196
    resp.form.submit(status=404)
......
259 248
    assert 'Check type group: Foo bar' in resp
260 249

  
261 250
    # cannot change check_type group booking with non null check_type exists
262
    booking.user_check_type = check_type
251
    booking.user_check_type_slug = check_type.slug
263 252
    booking.save()
264 253
    resp = app.get('/manage/agendas/%s/check-options' % agenda.pk)
265 254
    assert 'check_type_group' not in resp.context['form'].fields
tests/manager/test_event.py
1678 1678
        user_last_name='foo-none bar-val2 reason-foo',
1679 1679
        extra_data={'bar': 'val2'},
1680 1680
        user_was_present=False,
1681
        user_check_type=check_type_absence,
1681
        user_check_type_slug=check_type_absence.slug,
1682 1682
    )
1683 1683
    Booking.objects.create(
1684 1684
        event=event,
......
1687 1687
        user_last_name='foo-none bar-val2 reason-bar',
1688 1688
        extra_data={'bar': 'val2'},
1689 1689
        user_was_present=True,
1690
        user_check_type=check_type_presence,
1690
        user_check_type_slug=check_type_presence.slug,
1691 1691
    )
1692 1692
    Booking.objects.create(
1693 1693
        event=event,
......
1696 1696
        user_last_name='foo-none bar-val2 cancelled-absence',
1697 1697
        extra_data={'bar': 'val2'},
1698 1698
        user_was_present=False,
1699
        user_check_type=check_type_absence,
1699
        user_check_type_slug=check_type_absence.slug,
1700 1700
        cancellation_datetime=now(),
1701 1701
    )
1702 1702
    Booking.objects.create(
......
1706 1706
        user_last_name='foo-none bar-val2 cancelled-presence',
1707 1707
        extra_data={'bar': 'val2'},
1708 1708
        user_was_present=True,
1709
        user_check_type=check_type_presence,
1709
        user_check_type_slug=check_type_presence.slug,
1710 1710
        cancellation_datetime=now(),
1711 1711
    )
1712 1712

  
......
1787 1787
        assert 'Subscription foo-val2 bar-val1' in resp
1788 1788
        assert 'Subscription foo-val1 bar-val2' in resp
1789 1789
        assert 'Subscription foo-none bar-val2' in resp
1790
        assert len(resp.pyquery.find('input[value=absence-%s]' % check_type_absence_disabled.pk)) == 0
1791
        assert len(resp.pyquery.find('input[value=absence-%s]' % check_type_presence_disabled.pk)) == 0
1790
        assert len(resp.pyquery.find('input[value=absence-%s]' % check_type_absence_disabled.slug)) == 0
1791
        assert len(resp.pyquery.find('input[value=absence-%s]' % check_type_presence_disabled.slug)) == 0
1792 1792

  
1793 1793
    with CaptureQueriesContext(connection) as ctx:
1794 1794
        resp = app.get(
1795 1795
            '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'extra-data-foo': 'val1'}
1796 1796
        )
1797
        assert len(ctx.captured_queries) == 13
1797
        assert len(ctx.captured_queries) == 12
1798 1798
    assert 'User none' not in resp
1799 1799
    assert 'User empty' not in resp
1800 1800
    assert 'User foo-val1 bar-none presence' in resp
......
1967 1967

  
1968 1968
    resp = app.get(
1969 1969
        '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
1970
        params={'booking-status': 'absence-%s' % check_type_absence.pk},
1970
        params={'booking-status': 'absence::%s' % check_type_absence.slug},
1971 1971
    )
1972 1972
    assert 'User none' not in resp
1973 1973
    assert 'User empty' not in resp
......
1987 1987

  
1988 1988
    resp = app.get(
1989 1989
        '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
1990
        params={'booking-status': 'presence-%s' % check_type_presence.pk},
1990
        params={'booking-status': 'presence::%s' % check_type_presence.slug},
1991 1991
    )
1992 1992
    assert 'User none' not in resp
1993 1993
    assert 'User empty' not in resp
......
2078 2078
    assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
2079 2079
    booking.refresh_from_db()
2080 2080
    assert booking.user_was_present is True
2081
    assert booking.user_check_type is None
2081
    assert booking.user_check_type_slug is None
2082
    assert booking.user_check_type_label is None
2082 2083
    secondary_booking.refresh_from_db()
2083 2084
    assert secondary_booking.user_was_present is True
2084
    assert secondary_booking.user_check_type is None
2085
    assert secondary_booking.user_check_type_slug is None
2086
    assert secondary_booking.user_check_type_label is None
2085 2087
    event.refresh_from_db()
2086 2088
    assert event.checked is False
2087 2089

  
......
2098 2100
    assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Absence'
2099 2101
    booking.refresh_from_db()
2100 2102
    assert booking.user_was_present is False
2101
    assert booking.user_check_type is None
2103
    assert booking.user_check_type_slug is None
2104
    assert booking.user_check_type_label is None
2102 2105
    secondary_booking.refresh_from_db()
2103 2106
    assert secondary_booking.user_was_present is False
2104
    assert secondary_booking.user_check_type is None
2107
    assert secondary_booking.user_check_type_slug is None
2108
    assert secondary_booking.user_check_type_label is None
2105 2109
    event.refresh_from_db()
2106 2110
    assert event.checked is True
2107 2111

  
......
2121 2125
    # set as absent with check_type
2122 2126
    resp = app.post(
2123 2127
        '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
2124
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
2128
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
2125 2129
    ).follow()
2126 2130
    assert 'Foo reason' in resp
2127 2131
    booking.refresh_from_db()
2128 2132
    assert booking.user_was_present is False
2129
    assert booking.user_check_type == check_type_absence
2133
    assert booking.user_check_type_slug == check_type_absence.slug
2134
    assert booking.user_check_type_label == check_type_absence.label
2130 2135
    secondary_booking.refresh_from_db()
2131 2136
    assert secondary_booking.user_was_present is False
2132
    assert secondary_booking.user_check_type == check_type_absence
2137
    assert secondary_booking.user_check_type_slug == check_type_absence.slug
2138
    assert secondary_booking.user_check_type_label == check_type_absence.label
2133 2139

  
2134 2140
    # set as present without check_type
2135 2141
    resp = app.post(
......
2141 2147
    assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
2142 2148
    booking.refresh_from_db()
2143 2149
    assert booking.user_was_present is True
2144
    assert booking.user_check_type is None
2150
    assert booking.user_check_type_slug is None
2151
    assert booking.user_check_type_label is None
2145 2152
    secondary_booking.refresh_from_db()
2146 2153
    assert secondary_booking.user_was_present is True
2147
    assert secondary_booking.user_check_type is None
2154
    assert secondary_booking.user_check_type_slug is None
2155
    assert secondary_booking.user_check_type_label is None
2148 2156
    event.refresh_from_db()
2149 2157
    assert event.checked is True
2150 2158

  
......
2162 2170
    # set as present with check_type
2163 2171
    resp = app.post(
2164 2172
        '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
2165
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
2173
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
2166 2174
    ).follow()
2167 2175
    assert 'Bar reason' in resp
2168 2176
    booking.refresh_from_db()
2169 2177
    assert booking.user_was_present is True
2170
    assert booking.user_check_type == check_type_presence
2178
    assert booking.user_check_type_slug == check_type_presence.slug
2179
    assert booking.user_check_type_label == check_type_presence.label
2171 2180
    secondary_booking.refresh_from_db()
2172 2181
    assert secondary_booking.user_was_present is True
2173
    assert secondary_booking.user_check_type == check_type_presence
2182
    assert secondary_booking.user_check_type_slug == check_type_presence.slug
2183
    assert secondary_booking.user_check_type_label == check_type_presence.label
2174 2184

  
2175 2185
    # mark the event as checked
2176 2186
    event.checked = True
......
2228 2238
    # set as present
2229 2239
    resp = app.post(
2230 2240
        '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
2231
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
2241
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
2232 2242
        extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
2233 2243
    )
2234 2244
    assert '<tr>' not in resp  # because this is a fragment
2235 2245
    assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present\n  \n    (Bar reason)'
2236 2246
    assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
2237 2247
    assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
2238
    assert '<option value="%s" selected>Bar reason</option>' % check_type_presence.pk in resp
2248
    assert '<option value="%s" selected>Bar reason</option>' % check_type_presence.slug in resp
2239 2249

  
2240 2250
    # set as absent
2241 2251
    resp = app.post(
2242 2252
        '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
2243
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
2253
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
2244 2254
        extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
2245 2255
    )
2246 2256
    assert '<tr>' not in resp  # because this is a fragment
2247 2257
    assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Absent\n  \n    (Foo reason)'
2248 2258
    assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
2249 2259
    assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text.startswith('Absence')
2250
    assert '<option value="%s" selected>Foo reason</option>' % check_type_absence.pk in resp
2260
    assert '<option value="%s" selected>Foo reason</option>' % check_type_absence.slug in resp
2251 2261

  
2252 2262

  
2253 2263
def test_event_check_all_bookings(app, admin_user):
......
2277 2287
    )
2278 2288
    booking1.refresh_from_db()
2279 2289
    assert booking1.user_was_present is False
2280
    assert booking1.user_check_type is None
2290
    assert booking1.user_check_type_slug is None
2291
    assert booking1.user_check_type_label is None
2281 2292
    event.refresh_from_db()
2282 2293
    assert event.checked is False
2283 2294

  
......
2303 2314
    )
2304 2315
    booking1.refresh_from_db()
2305 2316
    assert booking1.user_was_present is False
2306
    assert booking1.user_check_type is None
2317
    assert booking1.user_check_type_slug is None
2318
    assert booking1.user_check_type_label is None
2307 2319
    booking2.refresh_from_db()
2308 2320
    assert booking2.user_was_present is True
2309
    assert booking2.user_check_type is None
2321
    assert booking2.user_check_type_slug is None
2322
    assert booking2.user_check_type_label is None
2310 2323
    secondary_booking.refresh_from_db()
2311 2324
    assert secondary_booking.user_was_present is True
2312
    assert secondary_booking.user_check_type is None
2325
    assert secondary_booking.user_check_type_slug is None
2326
    assert secondary_booking.user_check_type_label is None
2313 2327
    event.refresh_from_db()
2314 2328
    assert event.checked is True
2315 2329

  
......
2319 2333
    assert 'Mark all bookings without status' in resp
2320 2334
    app.post(
2321 2335
        '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
2322
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
2336
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
2323 2337
    )
2324 2338
    booking1.refresh_from_db()
2325 2339
    assert booking1.user_was_present is False
2326
    assert booking1.user_check_type is None
2340
    assert booking1.user_check_type_slug is None
2341
    assert booking1.user_check_type_label is None
2327 2342
    booking2.refresh_from_db()
2328 2343
    assert booking2.user_was_present is True
2329
    assert booking2.user_check_type is None
2344
    assert booking2.user_check_type_slug is None
2345
    assert booking2.user_check_type_label is None
2330 2346
    booking3.refresh_from_db()
2331 2347
    assert booking3.user_was_present is False
2332
    assert booking3.user_check_type == check_type_absence
2348
    assert booking3.user_check_type_slug == check_type_absence.slug
2349
    assert booking3.user_check_type_label == check_type_absence.label
2333 2350

  
2334 2351
    booking4 = Booking.objects.create(event=event, user_first_name='User', user_last_name='52')
2335 2352
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
2336 2353
    assert 'Mark all bookings without status' in resp
2337 2354
    app.post(
2338 2355
        '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
2339
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
2356
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
2340 2357
    )
2341 2358
    booking1.refresh_from_db()
2342 2359
    assert booking1.user_was_present is False
2343
    assert booking1.user_check_type is None
2360
    assert booking1.user_check_type_slug is None
2361
    assert booking1.user_check_type_label is None
2344 2362
    booking2.refresh_from_db()
2345 2363
    assert booking2.user_was_present is True
2346
    assert booking2.user_check_type is None
2364
    assert booking2.user_check_type_slug is None
2365
    assert booking2.user_check_type_label is None
2347 2366
    booking3.refresh_from_db()
2348 2367
    assert booking3.user_was_present is False
2349
    assert booking3.user_check_type == check_type_absence
2368
    assert booking3.user_check_type_slug == check_type_absence.slug
2369
    assert booking3.user_check_type_label == check_type_absence.label
2350 2370
    booking4.refresh_from_db()
2351 2371
    assert booking4.user_was_present is True
2352
    assert booking4.user_check_type == check_type_presence
2372
    assert booking4.user_check_type_slug == check_type_presence.slug
2373
    assert booking4.user_check_type_label == check_type_presence.label
2353 2374

  
2354 2375
    # now disable check update
2355 2376
    agenda.disable_check_update = True
......
2359 2380
    assert 'Mark all bookings without status' not in resp
2360 2381
    app.post(
2361 2382
        '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
2362
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.pk},
2383
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
2363 2384
        status=404,
2364 2385
    )
2365 2386
    resp = app.post(
......
2369 2390
    )
2370 2391
    app.post(
2371 2392
        '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
2372
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.pk},
2393
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
2373 2394
        status=404,
2374 2395
    )
2375 2396
    resp = app.post(
2376
-