Projet

Général

Profil

0004-manager-use-check_types-from-lingo-66015.patch

Lauréline Guérin, 18 juin 2022 13:17

Télécharger (22,3 ko)

Voir les différences:

Subject: [PATCH 4/5] manager: use check_types from lingo (#66015)

 chrono/manager/forms.py     |  48 ++++++------
 chrono/manager/views.py     |  18 ++---
 tests/manager/test_event.py | 144 +++++++++++++++++-------------------
 3 files changed, 96 insertions(+), 114 deletions(-)
chrono/manager/forms.py
64 64
    VirtualMember,
65 65
    generate_slug,
66 66
)
67
from chrono.utils.lingo import get_agenda_check_types
67 68

  
68 69
from . import widgets
69 70
from .widgets import SplitDateTimeField, WeekdaysWidget
......
441 442
            ('not-checked', _('Not checked')),
442 443
            ('presence', _('Presence')),
443 444
        ]
444
        if self.agenda.check_type_group:
445
            status_choices += [
446
                ('presence::%s' % r.slug, _('Presence (%s)') % r.label)
447
                for r in self.agenda.check_type_group.check_types.all()
448
                if r.kind == 'presence' and not r.disabled
449
            ]
445
        check_types = get_agenda_check_types(self.agenda)
446
        absence_check_types = [ct for ct in check_types if ct.kind == 'absence']
447
        presence_check_types = [ct for ct in check_types if ct.kind == 'presence']
448
        status_choices += [
449
            ('presence::%s' % ct.slug, _('Presence (%s)') % ct.label) for ct in presence_check_types
450
        ]
450 451
        status_choices += [('absence', _('Absence'))]
451
        if self.agenda.check_type_group:
452
            status_choices += [
453
                ('absence::%s' % r.slug, _('Absence (%s)') % r.label)
454
                for r in self.agenda.check_type_group.check_types.all()
455
                if r.kind == 'absence' and not r.disabled
456
            ]
452
        status_choices += [
453
            ('absence::%s' % ct.slug, _('Absence (%s)') % ct.label) for ct in absence_check_types
454
        ]
457 455
        self.filters['booking-status'] = django_filters.ChoiceFilter(
458 456
            label=_('Filter by status'),
459 457
            choices=status_choices,
......
499 497

  
500 498

  
501 499
class BookingCheckAbsenceForm(forms.Form):
502
    check_type = forms.ChoiceField(required=False)  # and not ModelChoiceField, to reduce querysets
500
    check_type = forms.ChoiceField(required=False)
503 501

  
504 502
    def __init__(self, *args, **kwargs):
505 503
        agenda = kwargs.pop('agenda')
506 504
        super().__init__(*args, **kwargs)
507
        if agenda.check_type_group:
508
            self.fields['check_type'].choices = [('', '---------')] + [
509
                (r.slug, r.label)
510
                for r in agenda.check_type_group.check_types.all()
511
                if r.kind == 'absence' and not r.disabled
512
            ]
505
        check_types = get_agenda_check_types(agenda)
506
        self.absence_check_types = [ct for ct in check_types if ct.kind == 'absence']
507
        self.fields['check_type'].choices = [('', '---------')] + [
508
            (ct.slug, ct.label) for ct in self.absence_check_types
509
        ]
513 510

  
514 511

  
515 512
class BookingCheckPresenceForm(forms.Form):
516
    check_type = forms.ChoiceField(required=False)  # and not ModelChoiceField, to reduce querysets
513
    check_type = forms.ChoiceField(required=False)
517 514

  
518 515
    def __init__(self, *args, **kwargs):
519 516
        agenda = kwargs.pop('agenda')
520 517
        super().__init__(*args, **kwargs)
521
        if agenda.check_type_group:
522
            self.fields['check_type'].choices = [('', '---------')] + [
523
                (r.slug, r.label)
524
                for r in agenda.check_type_group.check_types.all()
525
                if r.kind == 'presence' and not r.disabled
526
            ]
518
        check_types = get_agenda_check_types(agenda)
519
        self.presence_check_types = [ct for ct in check_types if ct.kind == 'presence']
520
        self.fields['check_type'].choices = [('', '---------')] + [
521
            (ct.slug, ct.label) for ct in self.presence_check_types
522
        ]
527 523

  
528 524

  
529 525
class EventsTimesheetForm(forms.Form):
chrono/manager/views.py
2498 2498

  
2499 2499
    def get_check_type(self, kind):
2500 2500
        form = self.get_form()
2501
        check_type = None
2502 2501
        if form.is_valid() and form.cleaned_data['check_type']:
2503
            check_type = CheckType.objects.filter(
2504
                slug=form.cleaned_data['check_type'], kind=kind, group=self.agenda.check_type_group
2505
            ).first()
2506
        return check_type
2502
            check_types = getattr(form, '%s_check_types' % kind)
2503
            for ct in check_types:
2504
                if ct.slug == form.cleaned_data['check_type']:
2505
                    return ct
2507 2506

  
2508 2507
    def response(self, request):
2509 2508
        return HttpResponseRedirect(
......
3261 3260

  
3262 3261
    def get_check_type(self, kind):
3263 3262
        form = self.get_form()
3264
        check_type = None
3265 3263
        if form.is_valid() and form.cleaned_data['check_type']:
3266
            check_type = CheckType.objects.filter(
3267
                slug=form.cleaned_data['check_type'], kind=kind, group=self.agenda.check_type_group
3268
            ).first()
3269
        return check_type
3264
            check_types = getattr(form, '%s_check_types' % kind)
3265
            for ct in check_types:
3266
                if ct.slug == form.cleaned_data['check_type']:
3267
                    return ct
3270 3268

  
3271 3269
    def response(self, request, booking):
3272 3270
        if request.is_ajax():
tests/manager/test_event.py
10 10
from django.utils.timezone import localtime, make_aware, now
11 11
from webtest import Upload
12 12

  
13
from chrono.agendas.models import (
14
    Agenda,
15
    Booking,
16
    CheckType,
17
    CheckTypeGroup,
18
    Desk,
19
    Event,
20
    EventsType,
21
    Subscription,
22
)
13
from chrono.agendas.models import Agenda, Booking, Desk, Event, EventsType, Subscription
14
from chrono.utils.lingo import CheckType
23 15
from tests.utils import login
24 16

  
25 17
pytestmark = pytest.mark.django_db
......
1648 1640
    assert '<span class="tag">Checked</span>' in resp
1649 1641

  
1650 1642

  
1651
def test_event_check_filters(app, admin_user):
1652
    group = CheckTypeGroup.objects.create(label='Foo bar')
1653
    check_type_absence = CheckType.objects.create(label='Foo reason', group=group, kind='absence')
1654
    check_type_presence = CheckType.objects.create(label='Bar reason', group=group, kind='presence')
1655
    check_type_absence_disabled = CheckType.objects.create(
1656
        label='disabled', group=group, kind='absence', disabled=True
1657
    )
1658
    check_type_presence_disabled = CheckType.objects.create(
1659
        label='disabled too', group=group, kind='presence', disabled=True
1660
    )
1643
@mock.patch('chrono.manager.forms.get_agenda_check_types')
1644
def test_event_check_filters(check_types, app, admin_user):
1645
    check_types.return_value = [
1646
        CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
1647
        CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
1648
    ]
1661 1649
    agenda = Agenda.objects.create(
1662
        label='Events', kind='events', booking_check_filters='foo,bar', check_type_group=group
1650
        label='Events',
1651
        kind='events',
1652
        booking_check_filters='foo,bar',
1663 1653
    )
1664 1654
    event = Event.objects.create(
1665 1655
        label='xyz',
......
1707 1697
        user_last_name='foo-none bar-val2 reason-foo',
1708 1698
        extra_data={'bar': 'val2'},
1709 1699
        user_was_present=False,
1710
        user_check_type_slug=check_type_absence.slug,
1700
        user_check_type_slug='foo-reason',
1711 1701
    )
1712 1702
    Booking.objects.create(
1713 1703
        event=event,
......
1716 1706
        user_last_name='foo-none bar-val2 reason-bar',
1717 1707
        extra_data={'bar': 'val2'},
1718 1708
        user_was_present=True,
1719
        user_check_type_slug=check_type_presence.slug,
1709
        user_check_type_slug='bar-reason',
1720 1710
    )
1721 1711
    Booking.objects.create(
1722 1712
        event=event,
......
1725 1715
        user_last_name='foo-none bar-val2 cancelled-absence',
1726 1716
        extra_data={'bar': 'val2'},
1727 1717
        user_was_present=False,
1728
        user_check_type_slug=check_type_absence.slug,
1718
        user_check_type_slug='foo-reason',
1729 1719
        cancellation_datetime=now(),
1730 1720
    )
1731 1721
    Booking.objects.create(
......
1735 1725
        user_last_name='foo-none bar-val2 cancelled-presence',
1736 1726
        extra_data={'bar': 'val2'},
1737 1727
        user_was_present=True,
1738
        user_check_type_slug=check_type_presence.slug,
1728
        user_check_type_slug='bar-reason',
1739 1729
        cancellation_datetime=now(),
1740 1730
    )
1741 1731

  
......
1816 1806
        assert 'Subscription foo-val2 bar-val1' in resp
1817 1807
        assert 'Subscription foo-val1 bar-val2' in resp
1818 1808
        assert 'Subscription foo-none bar-val2' in resp
1819
        assert len(resp.pyquery.find('input[value=absence-%s]' % check_type_absence_disabled.slug)) == 0
1820
        assert len(resp.pyquery.find('input[value=absence-%s]' % check_type_presence_disabled.slug)) == 0
1821 1809

  
1822 1810
    with CaptureQueriesContext(connection) as ctx:
1823 1811
        resp = app.get(
1824 1812
            '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk), params={'extra-data-foo': 'val1'}
1825 1813
        )
1826
        assert len(ctx.captured_queries) == 12
1814
        assert len(ctx.captured_queries) == 11
1827 1815
    assert 'User none' not in resp
1828 1816
    assert 'User empty' not in resp
1829 1817
    assert 'User foo-val1 bar-none presence' in resp
......
1996 1984

  
1997 1985
    resp = app.get(
1998 1986
        '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
1999
        params={'booking-status': 'absence::%s' % check_type_absence.slug},
1987
        params={'booking-status': 'absence::foo-reason'},
2000 1988
    )
2001 1989
    assert 'User none' not in resp
2002 1990
    assert 'User empty' not in resp
......
2016 2004

  
2017 2005
    resp = app.get(
2018 2006
        '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
2019
        params={'booking-status': 'presence::%s' % check_type_presence.slug},
2007
        params={'booking-status': 'presence::bar-reason'},
2020 2008
    )
2021 2009
    assert 'User none' not in resp
2022 2010
    assert 'User empty' not in resp
......
2073 2061
    assert resp.text.index('AA YY') < resp.text.index('BB XX') < resp.text.index('CC WW')
2074 2062

  
2075 2063

  
2076
def test_event_check_booking(app, admin_user):
2077
    group = CheckTypeGroup.objects.create(label='Foo bar')
2064
@mock.patch('chrono.manager.forms.get_agenda_check_types')
2065
def test_event_check_booking(check_types, app, admin_user):
2066
    check_types.return_value = []
2078 2067
    agenda = Agenda.objects.create(label='Events', kind='events')
2079 2068
    event = Event.objects.create(
2080 2069
        label='xyz',
......
2138 2127
    event.refresh_from_db()
2139 2128
    assert event.checked is True
2140 2129

  
2141
    agenda.check_type_group = group
2142
    agenda.save()
2143
    CheckType.objects.create(label='disabled', group=group, kind='absence', disabled=True)
2144
    CheckType.objects.create(label='disabled too', group=group, kind='presence', disabled=True)
2145
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
2146
    assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 0
2147
    assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
2148

  
2149
    check_type_absence = CheckType.objects.create(label='Foo reason', group=group, kind='absence')
2130
    check_types.return_value = [
2131
        CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
2132
    ]
2150 2133
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
2151 2134
    assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
2152 2135
    assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
......
2154 2137
    # set as absent with check_type
2155 2138
    resp = app.post(
2156 2139
        '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
2157
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
2140
        params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
2158 2141
    ).follow()
2159 2142
    assert 'Foo reason' in resp
2160 2143
    booking.refresh_from_db()
2161 2144
    assert booking.user_was_present is False
2162
    assert booking.user_check_type_slug == check_type_absence.slug
2163
    assert booking.user_check_type_label == check_type_absence.label
2145
    assert booking.user_check_type_slug == 'foo-reason'
2146
    assert booking.user_check_type_label == 'Foo reason'
2164 2147
    secondary_booking.refresh_from_db()
2165 2148
    assert secondary_booking.user_was_present is False
2166
    assert secondary_booking.user_check_type_slug == check_type_absence.slug
2167
    assert secondary_booking.user_check_type_label == check_type_absence.label
2149
    assert secondary_booking.user_check_type_slug == 'foo-reason'
2150
    assert secondary_booking.user_check_type_label == 'Foo reason'
2168 2151

  
2169 2152
    # set as present without check_type
2170 2153
    resp = app.post(
......
2185 2168
    event.refresh_from_db()
2186 2169
    assert event.checked is True
2187 2170

  
2188
    agenda.check_type_group = group
2189
    agenda.save()
2190 2171
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
2191 2172
    assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
2192 2173
    assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
2193 2174

  
2194
    check_type_presence = CheckType.objects.create(label='Bar reason', group=group, kind='presence')
2175
    check_types.return_value = [
2176
        CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
2177
        CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
2178
    ]
2195 2179
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
2196 2180
    assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
2197 2181
    assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 1
......
2199 2183
    # set as present with check_type
2200 2184
    resp = app.post(
2201 2185
        '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
2202
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
2186
        params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
2203 2187
    ).follow()
2204 2188
    assert 'Bar reason' in resp
2205 2189
    booking.refresh_from_db()
2206 2190
    assert booking.user_was_present is True
2207
    assert booking.user_check_type_slug == check_type_presence.slug
2208
    assert booking.user_check_type_label == check_type_presence.label
2191
    assert booking.user_check_type_slug == 'bar-reason'
2192
    assert booking.user_check_type_label == 'Bar reason'
2209 2193
    secondary_booking.refresh_from_db()
2210 2194
    assert secondary_booking.user_was_present is True
2211
    assert secondary_booking.user_check_type_slug == check_type_presence.slug
2212
    assert secondary_booking.user_check_type_label == check_type_presence.label
2195
    assert secondary_booking.user_check_type_slug == 'bar-reason'
2196
    assert secondary_booking.user_check_type_label == 'Bar reason'
2213 2197

  
2214 2198
    # mark the event as checked
2215 2199
    event.checked = True
......
2246 2230
    )
2247 2231

  
2248 2232

  
2249
def test_event_check_booking_ajax(app, admin_user):
2250
    group = CheckTypeGroup.objects.create(label='Foo bar')
2251
    check_type_absence = CheckType.objects.create(label='Foo reason', group=group)
2252
    check_type_presence = CheckType.objects.create(label='Bar reason', group=group, kind='presence')
2253
    agenda = Agenda.objects.create(label='Events', kind='events', check_type_group=group)
2233
@mock.patch('chrono.manager.forms.get_agenda_check_types')
2234
def test_event_check_booking_ajax(check_types, app, admin_user):
2235
    check_types.return_value = [
2236
        CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
2237
        CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
2238
    ]
2239
    agenda = Agenda.objects.create(label='Events', kind='events')
2254 2240
    event = Event.objects.create(
2255 2241
        label='xyz',
2256 2242
        start_datetime=now() - datetime.timedelta(days=1),
......
2267 2253
    # set as present
2268 2254
    resp = app.post(
2269 2255
        '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
2270
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
2256
        params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
2271 2257
        extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
2272 2258
    )
2273 2259
    assert '<tr>' not in resp  # because this is a fragment
2274 2260
    assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present\n  \n    (Bar reason)'
2275 2261
    assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
2276 2262
    assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
2277
    assert '<option value="%s" selected>Bar reason</option>' % check_type_presence.slug in resp
2263
    assert '<option value="bar-reason" selected>Bar reason</option>' in resp
2278 2264

  
2279 2265
    # set as absent
2280 2266
    resp = app.post(
2281 2267
        '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
2282
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
2268
        params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
2283 2269
        extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
2284 2270
    )
2285 2271
    assert '<tr>' not in resp  # because this is a fragment
2286 2272
    assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Absent\n  \n    (Foo reason)'
2287 2273
    assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
2288 2274
    assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text.startswith('Absence')
2289
    assert '<option value="%s" selected>Foo reason</option>' % check_type_absence.slug in resp
2275
    assert '<option value="foo-reason" selected>Foo reason</option>' in resp
2290 2276

  
2291 2277

  
2292
def test_event_check_all_bookings(app, admin_user):
2293
    group = CheckTypeGroup.objects.create(label='Foo bar')
2294
    check_type_absence = CheckType.objects.create(label='Foo reason', group=group)
2295
    check_type_presence = CheckType.objects.create(label='Bar reason', group=group, kind='presence')
2296
    agenda = Agenda.objects.create(label='Events', kind='events', check_type_group=group)
2278
@mock.patch('chrono.manager.forms.get_agenda_check_types')
2279
def test_event_check_all_bookings(check_types, app, admin_user):
2280
    check_types.return_value = [
2281
        CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
2282
        CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
2283
    ]
2284
    agenda = Agenda.objects.create(label='Events', kind='events')
2297 2285
    event = Event.objects.create(
2298 2286
        label='xyz',
2299 2287
        start_datetime=now() - datetime.timedelta(days=1),
......
2362 2350
    assert 'Mark all bookings without status' in resp
2363 2351
    app.post(
2364 2352
        '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
2365
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
2353
        params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
2366 2354
    )
2367 2355
    booking1.refresh_from_db()
2368 2356
    assert booking1.user_was_present is False
......
2374 2362
    assert booking2.user_check_type_label is None
2375 2363
    booking3.refresh_from_db()
2376 2364
    assert booking3.user_was_present is False
2377
    assert booking3.user_check_type_slug == check_type_absence.slug
2378
    assert booking3.user_check_type_label == check_type_absence.label
2365
    assert booking3.user_check_type_slug == 'foo-reason'
2366
    assert booking3.user_check_type_label == 'Foo reason'
2379 2367

  
2380 2368
    booking4 = Booking.objects.create(event=event, user_first_name='User', user_last_name='52')
2381 2369
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
2382 2370
    assert 'Mark all bookings without status' in resp
2383 2371
    app.post(
2384 2372
        '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
2385
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
2373
        params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
2386 2374
    )
2387 2375
    booking1.refresh_from_db()
2388 2376
    assert booking1.user_was_present is False
......
2394 2382
    assert booking2.user_check_type_label is None
2395 2383
    booking3.refresh_from_db()
2396 2384
    assert booking3.user_was_present is False
2397
    assert booking3.user_check_type_slug == check_type_absence.slug
2398
    assert booking3.user_check_type_label == check_type_absence.label
2385
    assert booking3.user_check_type_slug == 'foo-reason'
2386
    assert booking3.user_check_type_label == 'Foo reason'
2399 2387
    booking4.refresh_from_db()
2400 2388
    assert booking4.user_was_present is True
2401
    assert booking4.user_check_type_slug == check_type_presence.slug
2402
    assert booking4.user_check_type_label == check_type_presence.label
2389
    assert booking4.user_check_type_slug == 'bar-reason'
2390
    assert booking4.user_check_type_label == 'Bar reason'
2403 2391

  
2404 2392
    # now disable check update
2405 2393
    agenda.disable_check_update = True
......
2409 2397
    assert 'Mark all bookings without status' not in resp
2410 2398
    app.post(
2411 2399
        '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
2412
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
2400
        params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
2413 2401
        status=404,
2414 2402
    )
2415 2403
    resp = app.post(
......
2419 2407
    )
2420 2408
    app.post(
2421 2409
        '/manage/agendas/%s/events/%s/presence' % (agenda.pk, event.pk),
2422
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
2410
        params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
2423 2411
        status=404,
2424 2412
    )
2425 2413
    resp = app.post(
2426
-