Projet

Général

Profil

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

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

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
......
443 444
            ('not-checked', _('Not checked')),
444 445
            ('presence', _('Presence')),
445 446
        ]
446
        if self.agenda.check_type_group:
447
            status_choices += [
448
                ('presence::%s' % r.slug, _('Presence (%s)') % r.label)
449
                for r in self.agenda.check_type_group.check_types.all()
450
                if r.kind == 'presence' and not r.disabled
451
            ]
447
        check_types = get_agenda_check_types(self.agenda)
448
        absence_check_types = [ct for ct in check_types if ct.kind == 'absence']
449
        presence_check_types = [ct for ct in check_types if ct.kind == 'presence']
450
        status_choices += [
451
            ('presence::%s' % ct.slug, _('Presence (%s)') % ct.label) for ct in presence_check_types
452
        ]
452 453
        status_choices += [('absence', _('Absence'))]
453
        if self.agenda.check_type_group:
454
            status_choices += [
455
                ('absence::%s' % r.slug, _('Absence (%s)') % r.label)
456
                for r in self.agenda.check_type_group.check_types.all()
457
                if r.kind == 'absence' and not r.disabled
458
            ]
454
        status_choices += [
455
            ('absence::%s' % ct.slug, _('Absence (%s)') % ct.label) for ct in absence_check_types
456
        ]
459 457
        self.filters['booking-status'] = django_filters.ChoiceFilter(
460 458
            label=_('Filter by status'),
461 459
            choices=status_choices,
......
501 499

  
502 500

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

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

  
516 513

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

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

  
530 526

  
531 527
class EventsTimesheetForm(forms.Form):
chrono/manager/views.py
2444 2444

  
2445 2445
    def get_check_type(self, kind):
2446 2446
        form = self.get_form()
2447
        check_type = None
2448 2447
        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
2448
            check_types = getattr(form, '%s_check_types' % kind)
2449
            for ct in check_types:
2450
                if ct.slug == form.cleaned_data['check_type']:
2451
                    return ct
2453 2452

  
2454 2453
    def response(self, request):
2455 2454
        return HttpResponseRedirect(
......
3190 3189

  
3191 3190
    def get_check_type(self, kind):
3192 3191
        form = self.get_form()
3193
        check_type = None
3194 3192
        if form.is_valid() and 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
        return check_type
3193
            check_types = getattr(form, '%s_check_types' % kind)
3194
            for ct in check_types:
3195
                if ct.slug == form.cleaned_data['check_type']:
3196
                    return ct
3199 3197

  
3200 3198
    def response(self, request, booking):
3201 3199
        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
......
1619 1611
    assert '<span class="tag">Checked</span>' in resp
1620 1612

  
1621 1613

  
1622
def test_event_check_filters(app, admin_user):
1623
    group = CheckTypeGroup.objects.create(label='Foo bar')
1624
    check_type_absence = CheckType.objects.create(label='Foo reason', group=group, kind='absence')
1625
    check_type_presence = CheckType.objects.create(label='Bar reason', group=group, kind='presence')
1626
    check_type_absence_disabled = CheckType.objects.create(
1627
        label='disabled', group=group, kind='absence', disabled=True
1628
    )
1629
    check_type_presence_disabled = CheckType.objects.create(
1630
        label='disabled too', group=group, kind='presence', disabled=True
1631
    )
1614
@mock.patch('chrono.manager.forms.get_agenda_check_types')
1615
def test_event_check_filters(check_types, app, admin_user):
1616
    check_types.return_value = [
1617
        CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
1618
        CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
1619
    ]
1632 1620
    agenda = Agenda.objects.create(
1633
        label='Events', kind='events', booking_check_filters='foo,bar', check_type_group=group
1621
        label='Events',
1622
        kind='events',
1623
        booking_check_filters='foo,bar',
1634 1624
    )
1635 1625
    event = Event.objects.create(
1636 1626
        label='xyz',
......
1678 1668
        user_last_name='foo-none bar-val2 reason-foo',
1679 1669
        extra_data={'bar': 'val2'},
1680 1670
        user_was_present=False,
1681
        user_check_type_slug=check_type_absence.slug,
1671
        user_check_type_slug='foo-reason',
1682 1672
    )
1683 1673
    Booking.objects.create(
1684 1674
        event=event,
......
1687 1677
        user_last_name='foo-none bar-val2 reason-bar',
1688 1678
        extra_data={'bar': 'val2'},
1689 1679
        user_was_present=True,
1690
        user_check_type_slug=check_type_presence.slug,
1680
        user_check_type_slug='bar-reason',
1691 1681
    )
1692 1682
    Booking.objects.create(
1693 1683
        event=event,
......
1696 1686
        user_last_name='foo-none bar-val2 cancelled-absence',
1697 1687
        extra_data={'bar': 'val2'},
1698 1688
        user_was_present=False,
1699
        user_check_type_slug=check_type_absence.slug,
1689
        user_check_type_slug='foo-reason',
1700 1690
        cancellation_datetime=now(),
1701 1691
    )
1702 1692
    Booking.objects.create(
......
1706 1696
        user_last_name='foo-none bar-val2 cancelled-presence',
1707 1697
        extra_data={'bar': 'val2'},
1708 1698
        user_was_present=True,
1709
        user_check_type_slug=check_type_presence.slug,
1699
        user_check_type_slug='bar-reason',
1710 1700
        cancellation_datetime=now(),
1711 1701
    )
1712 1702

  
......
1787 1777
        assert 'Subscription foo-val2 bar-val1' in resp
1788 1778
        assert 'Subscription foo-val1 bar-val2' in resp
1789 1779
        assert 'Subscription foo-none bar-val2' in resp
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 1780

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

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

  
1988 1976
    resp = app.get(
1989 1977
        '/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk),
1990
        params={'booking-status': 'presence::%s' % check_type_presence.slug},
1978
        params={'booking-status': 'presence::bar-reason'},
1991 1979
    )
1992 1980
    assert 'User none' not in resp
1993 1981
    assert 'User empty' not in resp
......
2044 2032
    assert resp.text.index('AA YY') < resp.text.index('BB XX') < resp.text.index('CC WW')
2045 2033

  
2046 2034

  
2047
def test_event_check_booking(app, admin_user):
2048
    group = CheckTypeGroup.objects.create(label='Foo bar')
2035
@mock.patch('chrono.manager.forms.get_agenda_check_types')
2036
def test_event_check_booking(check_types, app, admin_user):
2037
    check_types.return_value = []
2049 2038
    agenda = Agenda.objects.create(label='Events', kind='events')
2050 2039
    event = Event.objects.create(
2051 2040
        label='xyz',
......
2109 2098
    event.refresh_from_db()
2110 2099
    assert event.checked is True
2111 2100

  
2112
    agenda.check_type_group = group
2113
    agenda.save()
2114
    CheckType.objects.create(label='disabled', group=group, kind='absence', disabled=True)
2115
    CheckType.objects.create(label='disabled too', group=group, kind='presence', disabled=True)
2116
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
2117
    assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 0
2118
    assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
2119

  
2120
    check_type_absence = CheckType.objects.create(label='Foo reason', group=group, kind='absence')
2101
    check_types.return_value = [
2102
        CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
2103
    ]
2121 2104
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
2122 2105
    assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
2123 2106
    assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
......
2125 2108
    # set as absent with check_type
2126 2109
    resp = app.post(
2127 2110
        '/manage/agendas/%s/bookings/%s/absence' % (agenda.pk, booking.pk),
2128
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
2111
        params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
2129 2112
    ).follow()
2130 2113
    assert 'Foo reason' in resp
2131 2114
    booking.refresh_from_db()
2132 2115
    assert booking.user_was_present is False
2133
    assert booking.user_check_type_slug == check_type_absence.slug
2134
    assert booking.user_check_type_label == check_type_absence.label
2116
    assert booking.user_check_type_slug == 'foo-reason'
2117
    assert booking.user_check_type_label == 'Foo reason'
2135 2118
    secondary_booking.refresh_from_db()
2136 2119
    assert secondary_booking.user_was_present is False
2137
    assert secondary_booking.user_check_type_slug == check_type_absence.slug
2138
    assert secondary_booking.user_check_type_label == check_type_absence.label
2120
    assert secondary_booking.user_check_type_slug == 'foo-reason'
2121
    assert secondary_booking.user_check_type_label == 'Foo reason'
2139 2122

  
2140 2123
    # set as present without check_type
2141 2124
    resp = app.post(
......
2156 2139
    event.refresh_from_db()
2157 2140
    assert event.checked is True
2158 2141

  
2159
    agenda.check_type_group = group
2160
    agenda.save()
2161 2142
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
2162 2143
    assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
2163 2144
    assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 0
2164 2145

  
2165
    check_type_presence = CheckType.objects.create(label='Bar reason', group=group, kind='presence')
2146
    check_types.return_value = [
2147
        CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
2148
        CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
2149
    ]
2166 2150
    resp = app.get('/manage/agendas/%s/events/%s/check' % (agenda.pk, event.pk))
2167 2151
    assert len(resp.pyquery.find('td.booking-actions form.absence select')) == 1
2168 2152
    assert len(resp.pyquery.find('td.booking-actions form.presence select')) == 1
......
2170 2154
    # set as present with check_type
2171 2155
    resp = app.post(
2172 2156
        '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
2173
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
2157
        params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
2174 2158
    ).follow()
2175 2159
    assert 'Bar reason' in resp
2176 2160
    booking.refresh_from_db()
2177 2161
    assert booking.user_was_present is True
2178
    assert booking.user_check_type_slug == check_type_presence.slug
2179
    assert booking.user_check_type_label == check_type_presence.label
2162
    assert booking.user_check_type_slug == 'bar-reason'
2163
    assert booking.user_check_type_label == 'Bar reason'
2180 2164
    secondary_booking.refresh_from_db()
2181 2165
    assert secondary_booking.user_was_present is True
2182
    assert secondary_booking.user_check_type_slug == check_type_presence.slug
2183
    assert secondary_booking.user_check_type_label == check_type_presence.label
2166
    assert secondary_booking.user_check_type_slug == 'bar-reason'
2167
    assert secondary_booking.user_check_type_label == 'Bar reason'
2184 2168

  
2185 2169
    # mark the event as checked
2186 2170
    event.checked = True
......
2217 2201
    )
2218 2202

  
2219 2203

  
2220
def test_event_check_booking_ajax(app, admin_user):
2221
    group = CheckTypeGroup.objects.create(label='Foo bar')
2222
    check_type_absence = CheckType.objects.create(label='Foo reason', group=group)
2223
    check_type_presence = CheckType.objects.create(label='Bar reason', group=group, kind='presence')
2224
    agenda = Agenda.objects.create(label='Events', kind='events', check_type_group=group)
2204
@mock.patch('chrono.manager.forms.get_agenda_check_types')
2205
def test_event_check_booking_ajax(check_types, app, admin_user):
2206
    check_types.return_value = [
2207
        CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
2208
        CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
2209
    ]
2210
    agenda = Agenda.objects.create(label='Events', kind='events')
2225 2211
    event = Event.objects.create(
2226 2212
        label='xyz',
2227 2213
        start_datetime=now() - datetime.timedelta(days=1),
......
2238 2224
    # set as present
2239 2225
    resp = app.post(
2240 2226
        '/manage/agendas/%s/bookings/%s/presence' % (agenda.pk, booking.pk),
2241
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_presence.slug},
2227
        params={'csrfmiddlewaretoken': token, 'check_type': 'bar-reason'},
2242 2228
        extra_environ={'HTTP_X_REQUESTED_WITH': 'XMLHttpRequest'},
2243 2229
    )
2244 2230
    assert '<tr>' not in resp  # because this is a fragment
2245 2231
    assert resp.pyquery.find('td.booking-status')[0].text.strip() == 'Present\n  \n    (Bar reason)'
2246 2232
    assert len(resp.pyquery.find('td.booking-actions button[disabled]')) == 1
2247 2233
    assert resp.pyquery.find('td.booking-actions button[disabled]')[0].text == 'Presence'
2248
    assert '<option value="%s" selected>Bar reason</option>' % check_type_presence.slug in resp
2234
    assert '<option value="bar-reason" selected>Bar reason</option>' in resp
2249 2235

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

  
2262 2248

  
2263
def test_event_check_all_bookings(app, admin_user):
2264
    group = CheckTypeGroup.objects.create(label='Foo bar')
2265
    check_type_absence = CheckType.objects.create(label='Foo reason', group=group)
2266
    check_type_presence = CheckType.objects.create(label='Bar reason', group=group, kind='presence')
2267
    agenda = Agenda.objects.create(label='Events', kind='events', check_type_group=group)
2249
@mock.patch('chrono.manager.forms.get_agenda_check_types')
2250
def test_event_check_all_bookings(check_types, app, admin_user):
2251
    check_types.return_value = [
2252
        CheckType(slug='foo-reason', label='Foo reason', kind='absence'),
2253
        CheckType(slug='bar-reason', label='Bar reason', kind='presence'),
2254
    ]
2255
    agenda = Agenda.objects.create(label='Events', kind='events')
2268 2256
    event = Event.objects.create(
2269 2257
        label='xyz',
2270 2258
        start_datetime=now() - datetime.timedelta(days=1),
......
2333 2321
    assert 'Mark all bookings without status' in resp
2334 2322
    app.post(
2335 2323
        '/manage/agendas/%s/events/%s/absence' % (agenda.pk, event.pk),
2336
        params={'csrfmiddlewaretoken': token, 'check_type': check_type_absence.slug},
2324
        params={'csrfmiddlewaretoken': token, 'check_type': 'foo-reason'},
2337 2325
    )
2338 2326
    booking1.refresh_from_db()
2339 2327
    assert booking1.user_was_present is False
......
2345 2333
    assert booking2.user_check_type_label is None
2346 2334
    booking3.refresh_from_db()
2347 2335
    assert booking3.user_was_present is False
2348
    assert booking3.user_check_type_slug == check_type_absence.slug
2349
    assert booking3.user_check_type_label == check_type_absence.label
2336
    assert booking3.user_check_type_slug == 'foo-reason'
2337
    assert booking3.user_check_type_label == 'Foo reason'
2350 2338

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

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