agendas: add kind field to CheckType model (#63810)

This commit is contained in:
Lauréline Guérin 2022-04-14 15:06:45 +02:00
parent 4547d00787
commit ae28ec5858
No known key found for this signature in database
GPG Key ID: 1FAB9B9B4F93D473
10 changed files with 114 additions and 24 deletions

View File

@ -0,0 +1,21 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('agendas', '0119_check_types'),
]
operations = [
migrations.AddField(
model_name='checktype',
name='kind',
field=models.CharField(
choices=[('absence', 'Absence'), ('presence', 'Presence')],
default='absence',
max_length=8,
verbose_name='Kind',
),
),
]

View File

@ -3075,10 +3075,25 @@ class CheckTypeGroup(models.Model):
}
class CheckTypeManager(models.Manager):
def absences(self):
return self.filter(kind='absence')
def presences(self):
return self.filter(kind='presence')
class CheckType(models.Model):
group = models.ForeignKey(CheckTypeGroup, on_delete=models.CASCADE, related_name='check_types')
slug = models.SlugField(_('Identifier'), max_length=160)
label = models.CharField(_('Label'), max_length=150)
kind = models.CharField(
_('Kind'),
max_length=8,
choices=[('absence', _('Absence')), ('presence', _('Presence'))],
default='absence',
)
objects = CheckTypeManager()
class Meta:
ordering = ['label']
@ -3105,6 +3120,7 @@ class CheckType(models.Model):
return {
'label': self.label,
'slug': self.slug,
'kind': self.kind,
}

View File

@ -157,7 +157,7 @@ class BookingSerializer(serializers.ModelSerializer):
if not self.instance.event.agenda.check_type_group:
raise serializers.ValidationError(_('unknown absence reason'))
check_types_qs = self.instance.event.agenda.check_type_group.check_types
check_types_qs = self.instance.event.agenda.check_type_group.check_types.absences()
try:
check_type = check_types_qs.get(slug=value)
value = check_type.label

View File

@ -383,6 +383,7 @@ def get_agenda_detail(request, agenda, check_events=False):
agenda_detail['absence_reasons'] = [
{'id': r.slug, 'slug': r.slug, 'text': r.label, 'label': r.label}
for r in agenda.check_type_group.check_types.all()
if r.kind == 'absence'
]
elif agenda.accept_meetings():
agenda_detail['api'] = {
@ -2328,6 +2329,10 @@ class BookingAPI(APIView):
):
raise APIErrorBadRequest(N_('event is marked as checked'), err=5)
user_was_present = serializer.validated_data.get('user_was_present', self.booking.user_was_present)
if user_was_present is True and 'user_absence_reason' in request.data:
raise APIErrorBadRequest(N_('user is marked as present, can not set absence reason'), err=6)
serializer.save()
extra_data = {k: v for k, v in request.data.items() if k not in serializer.validated_data}
if extra_data:

View File

@ -447,7 +447,7 @@ class BookingCheckFilterSet(django_filters.FilterSet):
if self.agenda.check_type_group:
status_choices += [
('absence-%s' % r.label, _('Absence (%s)') % r.label)
for r in self.agenda.check_type_group.check_types.all()
for r in self.agenda.check_type_group.check_types.absences()
]
self.filters['booking-status'] = django_filters.ChoiceFilter(
label=_('Filter by status'),
@ -499,7 +499,7 @@ class BookingCheckAbsenceForm(forms.Form):
super().__init__(*args, **kwargs)
if agenda.check_type_group:
self.fields['check_type'].choices = [('', '---------')] + [
(r.label, r.label) for r in agenda.check_type_group.check_types.all()
(r.label, r.label) for r in agenda.check_type_group.check_types.absences()
]

View File

@ -28,9 +28,15 @@
</h3>
<div>
<ul class="objects-list single-links">
{% for check_type in object.check_types.all %}
{% for check_type in object.check_types.absences %}
<li>
<a rel="popup" href="{% url 'chrono-manager-check-type-edit' object.pk check_type.pk %}">{{ check_type }}</a>
<a rel="popup" href="{% url 'chrono-manager-check-type-edit' object.pk check_type.pk %}">{% trans "Absence" %} - {{ check_type }}</a>
<a class="delete" rel="popup" href="{% url 'chrono-manager-check-type-delete' object.pk check_type.pk %}">{% trans "delete"%}</a>
</li>
{% endfor %}
{% for check_type in object.check_types.presences %}
<li>
<a rel="popup" href="{% url 'chrono-manager-check-type-edit' object.pk check_type.pk %}">{% trans "Presence" %} - {{ check_type }}</a>
<a class="delete" rel="popup" href="{% url 'chrono-manager-check-type-delete' object.pk check_type.pk %}">{% trans "delete"%}</a>
</li>
{% endfor %}

View File

@ -20,7 +20,7 @@
<button class="submit-button"
{% if booking.user_was_present is False %}disabled{% endif %}
>{% trans "Absence" %}</button>
{% if booking.form.reason.field.choices.1 %}{{ booking.form.reason }}{% endif %}
{% if booking.form.check_type.field.choices.1 %}{{ booking.form.check_type }}{% endif %}
<script>
$(function() {
$('td[data-booking-id="{{ booking.id }}"] select').on('change',

View File

@ -40,9 +40,24 @@
{% if agenda.check_type_group %}
<li>{% trans "Check type group:" %} {{ agenda.check_type_group }}
<ul>
{% for check_type in agenda.check_type_group.check_types.all %}
<li>{{ check_type }}</li>
{% endfor %}
<li>{% trans "Absences:" %}
<ul>
{% for check_type in agenda.check_type_group.check_types.absences %}
<li>{{ check_type }}</li>
{% empty %}
<li>({% trans "No absence check type defined" %})</li>
{% endfor %}
</ul>
</li>
<li>{% trans "Presences:" %}
<ul>
{% for check_type in agenda.check_type_group.check_types.presences %}
<li>{{ check_type }}</li>
{% empty %}
<li>({% trans "No presence check type defined" %})</li>
{% endfor %}
</ul>
</li>
</ul>
</li>
{% else %}

View File

@ -522,7 +522,7 @@ def test_booking_patch_api_present(app, user, flag):
def test_booking_patch_api_absence_reason(app, user):
agenda = Agenda.objects.create(kind='events')
event = Event.objects.create(agenda=agenda, start_datetime=now(), places=10)
booking = Booking.objects.create(event=event, user_was_present=True)
booking = Booking.objects.create(event=event, user_was_present=False)
app.authorization = ('Basic', ('john.doe', 'password'))
@ -534,7 +534,8 @@ def test_booking_patch_api_absence_reason(app, user):
assert resp.json['err_desc'] == 'invalid payload'
group = CheckTypeGroup.objects.create(label='Foo')
check_type = CheckType.objects.create(group=group, label='Foo bar')
check_type_absence = CheckType.objects.create(group=group, label='Foo bar', kind='absence')
check_type_presence = CheckType.objects.create(group=group, label='Foo baz', kind='presence')
resp = app.patch_json(
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': 'foobar'}, status=400
@ -542,23 +543,32 @@ def test_booking_patch_api_absence_reason(app, user):
assert resp.json['err'] == 4
assert resp.json['err_desc'] == 'invalid payload'
# wrong kind
resp = app.patch_json(
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': 'Foo baz'}, status=400
)
assert resp.json['err'] == 4
assert resp.json['err_desc'] == 'invalid payload'
resp = app.patch_json(
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': check_type_presence.slug}, status=400
)
assert resp.json['err'] == 4
assert resp.json['err_desc'] == 'invalid payload'
# set check_type
agenda.check_type_group = group
agenda.save()
# it works with label
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': 'Foo bar'})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_check_type == 'Foo bar'
# reset
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': ''})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_check_type == ''
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': None})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_check_type == ''
# make secondary bookings
@ -568,33 +578,48 @@ def test_booking_patch_api_absence_reason(app, user):
other_booking = Booking.objects.create(event=event)
# it works also with slug
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': check_type.slug})
app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': check_type_absence.slug})
booking.refresh_from_db()
assert booking.user_was_present is True # not changed
assert booking.user_check_type == 'Foo bar'
# all secondary bookings are upadted
# all secondary bookings are updated
assert list(booking.secondary_booking_set.values_list('user_check_type', flat=True)) == [
'Foo bar',
'Foo bar',
]
assert list(booking.secondary_booking_set.values_list('user_was_present', flat=True)) == [
False,
False,
] # not changed
other_booking.refresh_from_db()
assert other_booking.user_check_type == '' # not changed
# user_was_present is True, can not set user_absence_reason
Booking.objects.update(user_was_present=True)
resp = app.patch_json(
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': check_type_absence.slug}, status=400
)
assert resp.json['err'] == 6
assert resp.json['err_desc'] == 'user is marked as present, can not set absence reason'
# but it's ok if user_was_present is set to False
resp = app.patch_json(
'/api/booking/%s/' % booking.pk,
params={'user_absence_reason': check_type_absence.slug, 'user_was_present': False},
)
assert resp.json['err'] == 0
booking.refresh_from_db()
assert booking.user_was_present is False
assert booking.user_check_type == 'Foo bar'
# mark the event as checked
event.checked = True
event.save()
resp = app.patch_json('/api/booking/%s/' % booking.pk, params={'user_absence_reason': check_type.slug})
resp = app.patch_json(
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': check_type_absence.slug}
)
assert resp.json['err'] == 0
# now disable check update
agenda.disable_check_update = True
agenda.save()
resp = app.patch_json(
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': check_type.slug}, status=400
'/api/booking/%s/' % booking.pk, params={'user_absence_reason': check_type_absence.slug}, status=400
)
assert resp.json['err'] == 5
assert resp.json['err_desc'] == 'event is marked as checked'

View File

@ -101,6 +101,7 @@ def test_add_check_type(app, admin_user):
assert check_type.label == 'Foo reason'
assert check_type.group == group
assert check_type.slug == 'foo-reason'
assert check_type.kind == 'absence'
def test_add_check_type_as_manager(app, manager_user, agenda_with_restrictions):
@ -112,7 +113,7 @@ def test_add_check_type_as_manager(app, manager_user, agenda_with_restrictions):
def test_edit_check_type(app, admin_user):
group = CheckTypeGroup.objects.create(label='Foo bar')
check_type = CheckType.objects.create(label='Foo reason', group=group)
check_type = CheckType.objects.create(label='Foo reason', group=group, kind='presence')
check_type2 = CheckType.objects.create(label='Baz', group=group)
group2 = CheckTypeGroup.objects.create(label='Foo bar')
check_type3 = CheckType.objects.create(label='Foo bar reason', group=group2)
@ -131,6 +132,7 @@ def test_edit_check_type(app, admin_user):
check_type.refresh_from_db()
assert check_type.label == 'Foo bar reason'
assert check_type.slug == 'foo-bar-reason'
assert check_type.kind == 'presence'
app.get('/manage/check-type/group/%s/%s/edit/' % (group2.pk, check_type.pk), status=404)